Hyprland/src/render/OpenGL.hpp

359 lines
16 KiB
C++

#pragma once
#include "../defines.hpp"
#include "../helpers/Monitor.hpp"
#include "../helpers/Color.hpp"
#include "../helpers/time/Timer.hpp"
#include "../helpers/math/Math.hpp"
#include "../helpers/Format.hpp"
#include "../helpers/sync/SyncTimeline.hpp"
#include <GLES3/gl32.h>
#include <cstdint>
#include <list>
#include <string>
#include <stack>
#include <map>
#include <cairo/cairo.h>
#include "render/SyncFDManager.hpp"
#include "types.hpp"
#include "Shader.hpp"
#include "Texture.hpp"
#include "Framebuffer.hpp"
#include "Renderbuffer.hpp"
#include "../desktop/DesktopTypes.hpp"
#include "pass/Pass.hpp"
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2ext.h>
#include <aquamarine/buffer/Buffer.hpp>
#include <hyprutils/os/FileDescriptor.hpp>
#include <hyprgraphics/resource/resources/ImageResource.hpp>
#include "../debug/TracyDefines.hpp"
#include "../protocols/core/Compositor.hpp"
#include "ShaderLoader.hpp"
#include "gl/GLFramebuffer.hpp"
#include "gl/GLRenderbuffer.hpp"
#include "pass/TexPassElement.hpp"
#define GLFB(ifb) dc<CGLFramebuffer*>(ifb.get())
struct gbm_device;
namespace Render {
class IHyprRenderer;
}
namespace Config {
class CGradientValueData;
}
namespace Render::GL {
struct SVertex {
float x, y; // position
float u, v; // uv
};
constexpr std::array<SVertex, 4> fullVerts = {{
{0.0f, 0.0f, 0.0f, 0.0f}, // top-left
{0.0f, 1.0f, 0.0f, 1.0f}, // bottom-left
{1.0f, 0.0f, 1.0f, 0.0f}, // top-right
{1.0f, 1.0f, 1.0f, 1.0f}, // bottom-right
}};
inline const float fanVertsFull[] = {-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f};
enum eMonitorRenderFBs : uint8_t {
FB_MONITOR_RENDER_MAIN = 0,
FB_MONITOR_RENDER_CURRENT = 1,
FB_MONITOR_RENDER_OUT = 2,
};
enum eMonitorExtraRenderFBs : uint8_t {
FB_MONITOR_RENDER_EXTRA_OFFLOAD = 0,
FB_MONITOR_RENDER_EXTRA_MIRROR,
FB_MONITOR_RENDER_EXTRA_MIRROR_SWAP,
FB_MONITOR_RENDER_EXTRA_OFF_MAIN,
FB_MONITOR_RENDER_EXTRA_MONITOR_MIRROR,
FB_MONITOR_RENDER_EXTRA_BLUR,
};
struct SFragShaderDesc {
Render::ePreparedFragmentShader id;
const char* file;
};
struct SPreparedShaders {
std::string TEXVERTSRC;
std::string TEXVERTSRC320;
std::array<std::map<Render::ShaderFeatureFlags, SP<CShader>>, Render::SH_FRAG_LAST> fragVariants;
};
struct SCurrentRenderData {
PHLMONITORREF pMonitor;
Mat3x3 projection;
Mat3x3 savedProjection;
Mat3x3 monitorProjection;
SP<IFramebuffer> currentFB = nullptr; // current rendering to
SP<IFramebuffer> mainFB = nullptr; // main to render to
SP<IFramebuffer> outFB = nullptr; // out to render to (if offloaded, etc)
CRegion damage;
CRegion finalDamage; // damage used for funal off -> main
Render::SRenderModifData renderModif;
float mouseZoomFactor = 1.f;
bool mouseZoomUseMouse = true; // true by default
bool useNearestNeighbor = false;
bool blockScreenShader = false;
bool simplePass = false;
bool transformDamage = true;
bool noSimplify = false;
Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1);
Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
CBox clipBox = {}; // scaled coordinates
CRegion clipRegion;
uint32_t discardMode = DISCARD_OPAQUE;
float discardOpacity = 0.f;
PHLLSREF currentLS;
PHLWINDOWREF currentWindow;
WP<CWLSurfaceResource> surface;
};
class CEGLSync : public ISyncFDManager {
public:
static UP<CEGLSync> create();
~CEGLSync() override;
bool isValid() override;
private:
CEGLSync() : ISyncFDManager() {};
EGLSyncKHR m_sync = EGL_NO_SYNC_KHR;
friend class CHyprOpenGLImpl;
};
class CHyprOpenGLImpl {
public:
CHyprOpenGLImpl();
~CHyprOpenGLImpl();
struct SRectRenderData {
const CRegion* damage = nullptr;
int round = 0;
float roundingPower = 2.F;
bool blur = false;
float blurA = 1.F;
bool xray = false;
};
struct STextureRenderData {
bool blur = false;
float blurA = 1.F, overallA = 1.F;
bool blockBlurOptimization = false;
SP<ITexture> blurredBG;
const CRegion* damage = nullptr;
SP<CWLSurfaceResource> surface = nullptr;
float a = 1.F;
int round = 0;
float roundingPower = 2.F;
bool discardActive = false;
bool allowCustomUV = false;
bool allowDim = true;
bool noAA = false; // unused
GLenum wrapX = GL_CLAMP_TO_EDGE, wrapY = GL_CLAMP_TO_EDGE;
bool cmBackToSRGB = false;
bool finalMonitorCM = false;
uint32_t discardMode = DISCARD_OPAQUE;
float discardOpacity = 0.f;
CRegion clipRegion;
PHLLSREF currentLS;
Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1);
Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
};
struct SBorderRenderData {
int round = 0;
float roundingPower = 2.F;
int borderSize = 1;
float a = 1.0;
int outerRound = -1; /* use round */
};
void makeEGLCurrent();
void begin(PHLMONITOR, const CRegion& damage, SP<IFramebuffer> fb = nullptr, std::optional<CRegion> finalDamage = {});
void beginSimple(PHLMONITOR, const CRegion& damage, SP<IRenderbuffer> rb = nullptr, SP<IFramebuffer> fb = nullptr);
void end();
void renderRect(const CBox&, const CHyprColor&, SRectRenderData data);
void renderTexture(SP<ITexture>, const CBox&, STextureRenderData data);
void renderRoundedShadow(const CBox&, int round, float roundingPower, int range, const CHyprColor& color, float a = 1.0);
void renderInnerGlow(const CBox&, int round, float roundingPower, int range, const CHyprColor& color, int glowPower, float a = 1.0);
void renderBorder(const CBox&, const Config::CGradientValueData&, SBorderRenderData data);
void renderBorder(const CBox&, const Config::CGradientValueData&, const Config::CGradientValueData&, float lerp, SBorderRenderData data);
void renderTextureMatte(SP<ITexture> tex, const CBox& pBox, SP<IFramebuffer> matte);
void renderTexturePrimitive(SP<ITexture> tex, const CBox& box);
void setViewport(GLint x, GLint y, GLsizei width, GLsizei height);
void setCapStatus(int cap, bool status);
void blend(bool enabled);
void scissor(const CBox&, bool transform = true);
void scissor(const pixman_box32*, bool transform = true);
void scissor(const int x, const int y, const int w, const int h, bool transform = true);
void destroyMonitorResources(PHLMONITORREF);
void preRender(PHLMONITOR);
void saveBufferForMirror(const CBox&);
void applyScreenShader(const std::string& path);
void renderOffToMain(SP<IFramebuffer> off);
std::vector<SDRMFormat> getDRMFormats();
std::vector<uint64_t> getDRMFormatModifiers(DRMFormat format);
EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs);
bool initShaders(const std::string& path = "");
WP<CShader> useShader(WP<CShader> prog);
bool explicitSyncSupported();
WP<CShader> getShaderVariant(Render::ePreparedFragmentShader frag, Render::ShaderFeatureFlags features = 0);
bool m_shadersInitialized = false;
SP<SPreparedShaders> m_shaders;
Hyprutils::OS::CFileDescriptor m_gbmFD;
gbm_device* m_gbmDevice = nullptr;
EGLContext m_eglContext = nullptr;
EGLDisplay m_eglDisplay = nullptr;
EGLDeviceEXT m_eglDevice = nullptr;
std::map<PHLMONITORREF, SP<IFramebuffer>> m_monitorBGFBs;
struct {
PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES = nullptr;
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = nullptr;
PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR = nullptr;
PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = nullptr;
PFNEGLQUERYDMABUFFORMATSEXTPROC eglQueryDmaBufFormatsEXT = nullptr;
PFNEGLQUERYDMABUFMODIFIERSEXTPROC eglQueryDmaBufModifiersEXT = nullptr;
PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = nullptr;
PFNEGLDEBUGMESSAGECONTROLKHRPROC eglDebugMessageControlKHR = nullptr;
PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT = nullptr;
PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT = nullptr;
PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT = nullptr;
PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR = nullptr;
PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR = nullptr;
PFNEGLDUPNATIVEFENCEFDANDROIDPROC eglDupNativeFenceFDANDROID = nullptr;
PFNEGLWAITSYNCKHRPROC eglWaitSyncKHR = nullptr;
} m_proc;
struct {
bool EXT_read_format_bgra = false;
bool EXT_image_dma_buf_import = false;
bool EXT_image_dma_buf_import_modifiers = false;
bool KHR_context_flush_control = false;
bool KHR_display_reference = false;
bool IMG_context_priority = false;
bool EXT_create_context_robustness = false;
bool EGL_ANDROID_native_fence_sync_ext = false;
} m_exts;
enum eEGLContextVersion : uint8_t {
EGL_CONTEXT_GLES_2_0 = 0,
EGL_CONTEXT_GLES_3_0,
EGL_CONTEXT_GLES_3_2,
};
eEGLContextVersion m_eglContextVersion = EGL_CONTEXT_GLES_3_2;
enum eCachedCapStatus : uint8_t {
CAP_STATUS_BLEND = 0,
CAP_STATUS_SCISSOR_TEST,
CAP_STATUS_STENCIL_TEST,
CAP_STATUS_END
};
private:
struct {
GLint x = 0;
GLint y = 0;
GLsizei width = 0;
GLsizei height = 0;
} m_lastViewport;
std::array<bool, CAP_STATUS_END> m_capStatus = {};
std::vector<SDRMFormat> m_drmFormats;
bool m_hasModifiers = false;
int m_drmFD = -1;
std::string m_extensions;
bool m_fakeFrame = false;
bool m_applyFinalShader = false;
bool m_blend = false;
bool m_offloadedFramebuffer = false;
bool m_cmSupported = true;
SP<CShader> m_finalScreenShader;
GLuint m_currentProgram;
void initDRMFormats();
void initEGL(bool gbm);
EGLDeviceEXT eglDeviceFromDRMFD(int drmFD);
// for the final shader
std::array<CTimer, POINTER_PRESSED_HISTORY_LENGTH> m_pressedHistoryTimers = {};
std::array<Vector2D, POINTER_PRESSED_HISTORY_LENGTH> m_pressedHistoryPositions = {};
GLint m_pressedHistoryKilled = 0;
GLint m_pressedHistoryTouched = 0;
//
std::optional<std::vector<uint64_t>> getModsForFormat(EGLint format);
// returns the out FB, can be either Mirror or MirrorSwap
SP<IFramebuffer> blurFramebufferWithDamage(float a, CRegion* damage, CGLFramebuffer& source);
void passCMUniforms(WP<CShader>, const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
bool modifySDR, float sdrMinLuminance, int sdrMaxLuminance, const SCMSettings& settings);
void passCMUniforms(WP<CShader>, const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1);
void passCMUniforms(WP<CShader>, const NColorManagement::PImageDescription imageDescription);
void passCMUniforms(WP<CShader>, const NColorManagement::PImageDescription imageDescription, const SCMSettings& settings);
void renderRectInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
void renderRectWithBlurInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
void renderRectWithDamageInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
WP<CShader> renderToOutputInternal();
WP<CShader> renderToFBInternal(SP<ITexture> tex, const STextureRenderData& data, eTextureType texType, const CBox& newBox);
void renderTextureInternal(SP<ITexture>, const CBox&, const STextureRenderData& data);
void renderTextureWithBlurInternal(SP<ITexture>, const CBox&, const STextureRenderData& data);
friend class IHyprRenderer;
friend class CHyprGLRenderer;
friend class CGLElementRenderer;
friend class CTexPassElement;
friend class CPreBlurElement;
friend class CSurfacePassElement;
};
inline UP<CHyprOpenGLImpl> g_pHyprOpenGL;
}