summaryrefslogtreecommitdiff
path: root/src/render/OpenGL.hpp
blob: b18e91084fee62f1ce9374c5422008406644101c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
#pragma once

#include "../defines.hpp"
#include "../helpers/Monitor.hpp"
#include "../helpers/Color.hpp"
#include "../helpers/Timer.hpp"
#include "../helpers/Region.hpp"
#include <list>
#include <unordered_map>

#include <cairo/cairo.h>

#include "Shader.hpp"
#include "Texture.hpp"
#include "Framebuffer.hpp"
#include "Transformer.hpp"
#include "Renderbuffer.hpp"

#include <GLES2/gl2ext.h>

#include "../debug/TracyDefines.hpp"

class CHyprRenderer;

inline const float fullVerts[] = {
    1, 0, // top right
    0, 0, // top left
    1, 1, // bottom right
    0, 1, // bottom left
};
inline const float fanVertsFull[] = {-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f};

enum eDiscardMode {
    DISCARD_OPAQUE = 1,
    DISCARD_ALPHA  = 1 << 1
};

struct SRenderModifData {
    enum eRenderModifType {
        RMOD_TYPE_SCALE,        /* scale by a float */
        RMOD_TYPE_SCALECENTER,  /* scale by a float from the center */
        RMOD_TYPE_TRANSLATE,    /* translate by a Vector2D */
        RMOD_TYPE_ROTATE,       /* rotate by a float in rad from top left */
        RMOD_TYPE_ROTATECENTER, /* rotate by a float in rad from center */
    };

    std::vector<std::pair<eRenderModifType, std::any>> modifs;

    void                                               applyToBox(CBox& box);
};

struct SGLPixelFormat {
    uint32_t drmFormat        = DRM_FORMAT_INVALID;
    GLint    glInternalFormat = 0;
    GLint    glFormat         = 0;
    GLint    glType           = 0;
    bool     withAlpha        = false;
};

struct SMonitorRenderData {
    CFramebuffer offloadFB;
    CFramebuffer mirrorFB;     // these are used for some effects,
    CFramebuffer mirrorSwapFB; // etc
    CFramebuffer offMainFB;

    CFramebuffer monitorMirrorFB; // used for mirroring outputs

    CTexture     stencilTex;

    CFramebuffer blurFB;
    bool         blurFBDirty        = true;
    bool         blurFBShouldRender = false;

    // Shaders
    bool    m_bShadersInitialized = false;
    CShader m_shQUAD;
    CShader m_shRGBA;
    CShader m_shPASSTHRURGBA;
    CShader m_shMATTE;
    CShader m_shRGBX;
    CShader m_shEXT;
    CShader m_shBLUR1;
    CShader m_shBLUR2;
    CShader m_shBLURPREPARE;
    CShader m_shBLURFINISH;
    CShader m_shSHADOW;
    CShader m_shBORDER1;
    CShader m_shGLITCH;
    //
};

struct SCurrentRenderData {
    CMonitor*           pMonitor   = nullptr;
    CWorkspace*         pWorkspace = nullptr;
    float               projection[9];
    float               savedProjection[9];

    SMonitorRenderData* pCurrentMonData = nullptr;
    CFramebuffer*       currentFB       = nullptr; // current rendering to
    CFramebuffer*       mainFB          = nullptr; // main to render to
    CFramebuffer*       outFB           = nullptr; // out to render to (if offloaded, etc)

    CRegion             damage;
    CRegion             finalDamage; // damage used for funal off -> main

    SRenderModifData    renderModif;
    float               mouseZoomFactor    = 1.f;
    bool                mouseZoomUseMouse  = true; // true by default
    bool                useNearestNeighbor = false;
    bool                forceIntrospection = false; // cleaned in ::end()

    Vector2D            primarySurfaceUVTopLeft     = Vector2D(-1, -1);
    Vector2D            primarySurfaceUVBottomRight = Vector2D(-1, -1);

    CBox                clipBox = {}; // scaled coordinates

    uint32_t            discardMode    = DISCARD_OPAQUE;
    float               discardOpacity = 0.f;
};

class CGradientValueData;

class CHyprOpenGLImpl {
  public:
    CHyprOpenGLImpl();

    void                  begin(CMonitor*, const CRegion& damage, CFramebuffer* fb = nullptr, std::optional<CRegion> finalDamage = {});
    void                  end();

    void                  renderRect(CBox*, const CColor&, int round = 0);
    void                  renderRectWithBlur(CBox*, const CColor&, int round = 0, float blurA = 1.f, bool xray = false);
    void                  renderRectWithDamage(CBox*, const CColor&, CRegion* damage, int round = 0);
    void                  renderTexture(wlr_texture*, CBox*, float a, int round = 0, bool allowCustomUV = false);
    void                  renderTexture(const CTexture&, CBox*, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false);
    void                  renderTextureWithBlur(const CTexture&, CBox*, float a, wlr_surface* pSurface, int round = 0, bool blockBlurOptimization = false, float blurA = 1.f);
    void                  renderRoundedShadow(CBox*, int round, int range, const CColor& color, float a = 1.0);
    void                  renderBorder(CBox*, const CGradientValueData&, int round, int borderSize, float a = 1.0, int outerRound = -1 /* use round */);
    void                  renderTextureMatte(const CTexture& tex, CBox* pBox, CFramebuffer& matte);

    void                  setMonitorTransformEnabled(bool enabled);

    void                  saveMatrix();
    void                  setMatrixScaleTranslate(const Vector2D& translate, const float& scale);
    void                  restoreMatrix();

    void                  blend(bool enabled);

    void                  makeWindowSnapshot(CWindow*);
    void                  makeRawWindowSnapshot(CWindow*, CFramebuffer*);
    void                  makeLayerSnapshot(SLayerSurface*);
    void                  renderSnapshot(CWindow**);
    void                  renderSnapshot(SLayerSurface**);
    bool                  shouldUseNewBlurOptimizations(SLayerSurface* pLayer, CWindow* pWindow);

    void                  clear(const CColor&);
    void                  clearWithTex();
    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(CMonitor*);

    void                  markBlurDirtyForMonitor(CMonitor*);

    void                  preWindowPass();
    bool                  preBlurQueued();
    void                  preRender(CMonitor*);

    void                  saveBufferForMirror();
    void                  renderMirrored();

    void                  applyScreenShader(const std::string& path);

    void                  bindOffMain();
    void                  renderOffToMain(CFramebuffer* off);
    void                  bindBackOnMain();

    void                  setDamage(const CRegion& damage, std::optional<CRegion> finalDamage = {});

    uint32_t              getPreferredReadFormat(CMonitor* pMonitor);
    const SGLPixelFormat* getPixelFormatFromDRM(uint32_t drmFormat);

    SCurrentRenderData    m_RenderData;

    GLint                 m_iCurrentOutputFb = 0;

    bool                  m_bReloadScreenShader = true; // at launch it can be set

    CWindow*              m_pCurrentWindow = nullptr; // hack to get the current rendered window
    SLayerSurface*        m_pCurrentLayer  = nullptr; // hack to get the current rendered layer

    std::unordered_map<CWindow*, CFramebuffer>        m_mWindowFramebuffers;
    std::unordered_map<SLayerSurface*, CFramebuffer>  m_mLayerFramebuffers;
    std::unordered_map<CMonitor*, SMonitorRenderData> m_mMonitorRenderResources;
    std::unordered_map<CMonitor*, CFramebuffer>       m_mMonitorBGFBs;

    struct {
        PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES = nullptr;
        PFNEGLDESTROYIMAGEKHRPROC                     eglDestroyImageKHR                     = nullptr;
    } m_sProc;

    struct {
        bool EXT_read_format_bgra = false;
    } m_sExts;

  private:
    std::list<GLuint> m_lBuffers;
    std::list<GLuint> m_lTextures;

    int               m_iDRMFD;
    std::string       m_szExtensions;

    bool              m_bFakeFrame            = false;
    bool              m_bEndFrame             = false;
    bool              m_bApplyFinalShader     = false;
    bool              m_bBlend                = false;
    bool              m_bOffloadedFramebuffer = false;

    CShader           m_sFinalScreenShader;
    CTimer            m_tGlobalTimer;

    void              logShaderError(const GLuint&, bool program = false);
    GLuint            createProgram(const std::string&, const std::string&, bool dynamic = false);
    GLuint            compileShader(const GLuint&, std::string, bool dynamic = false);
    void              createBGTextureForMonitor(CMonitor*);
    void              initShaders();

    // returns the out FB, can be either Mirror or MirrorSwap
    CFramebuffer* blurMainFramebufferWithDamage(float a, CRegion* damage);

    void          renderTextureInternalWithDamage(const CTexture&, CBox* pBox, float a, CRegion* damage, int round = 0, bool discardOpaque = false, bool noAA = false,
                                                  bool allowCustomUV = false, bool allowDim = false);
    void          renderTexturePrimitive(const CTexture& tex, CBox* pBox);
    void          renderSplash(cairo_t* const, cairo_surface_t* const, double offset, const Vector2D& size);

    void          preBlurForCurrentMonitor();

    bool          passRequiresIntrospection(CMonitor* pMonitor);

    friend class CHyprRenderer;
};

inline std::unique_ptr<CHyprOpenGLImpl> g_pHyprOpenGL;