opengl: optimize shaders and reduce unneeded drawcalls (#10364)

* opengl: remove unnecessery glflush calls

glflushing forces the driver to break batching and issue commands
prematurely and prevents optimisations like command reordering and
merging.

many glFunctions already internally glflushes and eglsync creation still
has a glflush at end render. so lets reduce the overhead of these calls.

* opengl: reduce glUseProgram calls

apitrace shows cases where the same program gets called multiple times,
add a helper function that keeps track of current program and only call
it once on same program. reduces slight overhead.

* opengl: use more efficient vertex array object

use a more modern vertex array object approach with the shaders, makes
it a onetime setup on shader creation instead of once per drawcall, also
should make the driver not have to revalidate the vertex format on each
call.
This commit is contained in:
Tom Englund 2025-05-11 18:36:20 +02:00 committed by GitHub
parent 390a357859
commit 04124988e8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 108 additions and 99 deletions

View File

@ -1487,7 +1487,6 @@ void CCompositor::cleanupFadingOut(const MONITORID& monid) {
Debug::log(LOG, "Cleanup: destroyed a layersurface"); Debug::log(LOG, "Cleanup: destroyed a layersurface");
glFlush(); // to free mem NOW.
return; return;
} }
} }

View File

@ -584,7 +584,6 @@ SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager
g_pHyprOpenGL->renderTexture(texture, xbox, 1.F); g_pHyprOpenGL->renderTexture(texture, xbox, 1.F);
g_pHyprOpenGL->end(); g_pHyprOpenGL->end();
glFlush();
g_pHyprOpenGL->m_renderData.pMonitor.reset(); g_pHyprOpenGL->m_renderData.pMonitor.reset();
g_pHyprRenderer->onRenderbufferDestroy(RBO.get()); g_pHyprRenderer->onRenderbufferDestroy(RBO.get());

View File

@ -977,6 +977,7 @@ bool CHyprOpenGLImpl::initShaders() {
shaders->m_shCM.applyTint = glGetUniformLocation(prog, "applyTint"); shaders->m_shCM.applyTint = glGetUniformLocation(prog, "applyTint");
shaders->m_shCM.tint = glGetUniformLocation(prog, "tint"); shaders->m_shCM.tint = glGetUniformLocation(prog, "tint");
shaders->m_shCM.useAlphaMatte = glGetUniformLocation(prog, "useAlphaMatte"); shaders->m_shCM.useAlphaMatte = glGetUniformLocation(prog, "useAlphaMatte");
shaders->m_shCM.createVao();
} else } else
Debug::log(ERR, Debug::log(ERR,
"WARNING: CM Shader failed compiling, color management will not work. It's likely because your GPU is an old piece of garbage, don't file bug reports " "WARNING: CM Shader failed compiling, color management will not work. It's likely because your GPU is an old piece of garbage, don't file bug reports "
@ -1006,6 +1007,7 @@ bool CHyprOpenGLImpl::initShaders() {
shaders->m_shQUAD.proj = glGetUniformLocation(prog, "proj"); shaders->m_shQUAD.proj = glGetUniformLocation(prog, "proj");
shaders->m_shQUAD.color = glGetUniformLocation(prog, "color"); shaders->m_shQUAD.color = glGetUniformLocation(prog, "color");
shaders->m_shQUAD.posAttrib = glGetAttribLocation(prog, "pos"); shaders->m_shQUAD.posAttrib = glGetAttribLocation(prog, "pos");
shaders->m_shQUAD.createVao();
prog = createProgram(shaders->TEXVERTSRC, TEXFRAGSRCRGBA, isDynamic); prog = createProgram(shaders->TEXVERTSRC, TEXFRAGSRCRGBA, isDynamic);
if (!prog) if (!prog)
@ -1025,6 +1027,7 @@ bool CHyprOpenGLImpl::initShaders() {
shaders->m_shRGBA.applyTint = glGetUniformLocation(prog, "applyTint"); shaders->m_shRGBA.applyTint = glGetUniformLocation(prog, "applyTint");
shaders->m_shRGBA.tint = glGetUniformLocation(prog, "tint"); shaders->m_shRGBA.tint = glGetUniformLocation(prog, "tint");
shaders->m_shRGBA.useAlphaMatte = glGetUniformLocation(prog, "useAlphaMatte"); shaders->m_shRGBA.useAlphaMatte = glGetUniformLocation(prog, "useAlphaMatte");
shaders->m_shRGBA.createVao();
prog = createProgram(shaders->TEXVERTSRC, TEXFRAGSRCRGBAPASSTHRU, isDynamic); prog = createProgram(shaders->TEXVERTSRC, TEXFRAGSRCRGBAPASSTHRU, isDynamic);
if (!prog) if (!prog)
@ -1034,6 +1037,7 @@ bool CHyprOpenGLImpl::initShaders() {
shaders->m_shPASSTHRURGBA.tex = glGetUniformLocation(prog, "tex"); shaders->m_shPASSTHRURGBA.tex = glGetUniformLocation(prog, "tex");
shaders->m_shPASSTHRURGBA.texAttrib = glGetAttribLocation(prog, "texcoord"); shaders->m_shPASSTHRURGBA.texAttrib = glGetAttribLocation(prog, "texcoord");
shaders->m_shPASSTHRURGBA.posAttrib = glGetAttribLocation(prog, "pos"); shaders->m_shPASSTHRURGBA.posAttrib = glGetAttribLocation(prog, "pos");
shaders->m_shPASSTHRURGBA.createVao();
prog = createProgram(shaders->TEXVERTSRC, TEXFRAGSRCRGBAMATTE, isDynamic); prog = createProgram(shaders->TEXVERTSRC, TEXFRAGSRCRGBAMATTE, isDynamic);
if (!prog) if (!prog)
@ -1044,6 +1048,7 @@ bool CHyprOpenGLImpl::initShaders() {
shaders->m_shMATTE.alphaMatte = glGetUniformLocation(prog, "texMatte"); shaders->m_shMATTE.alphaMatte = glGetUniformLocation(prog, "texMatte");
shaders->m_shMATTE.texAttrib = glGetAttribLocation(prog, "texcoord"); shaders->m_shMATTE.texAttrib = glGetAttribLocation(prog, "texcoord");
shaders->m_shMATTE.posAttrib = glGetAttribLocation(prog, "pos"); shaders->m_shMATTE.posAttrib = glGetAttribLocation(prog, "pos");
shaders->m_shMATTE.createVao();
prog = createProgram(shaders->TEXVERTSRC, FRAGGLITCH, isDynamic); prog = createProgram(shaders->TEXVERTSRC, FRAGGLITCH, isDynamic);
if (!prog) if (!prog)
@ -1056,6 +1061,7 @@ bool CHyprOpenGLImpl::initShaders() {
shaders->m_shGLITCH.distort = glGetUniformLocation(prog, "distort"); shaders->m_shGLITCH.distort = glGetUniformLocation(prog, "distort");
shaders->m_shGLITCH.time = glGetUniformLocation(prog, "time"); shaders->m_shGLITCH.time = glGetUniformLocation(prog, "time");
shaders->m_shGLITCH.fullSize = glGetUniformLocation(prog, "screenSize"); shaders->m_shGLITCH.fullSize = glGetUniformLocation(prog, "screenSize");
shaders->m_shGLITCH.createVao();
prog = createProgram(shaders->TEXVERTSRC, TEXFRAGSRCRGBX, isDynamic); prog = createProgram(shaders->TEXVERTSRC, TEXFRAGSRCRGBX, isDynamic);
if (!prog) if (!prog)
@ -1072,6 +1078,7 @@ bool CHyprOpenGLImpl::initShaders() {
shaders->m_shRGBX.discardAlphaValue = glGetUniformLocation(prog, "discardAlphaValue"); shaders->m_shRGBX.discardAlphaValue = glGetUniformLocation(prog, "discardAlphaValue");
shaders->m_shRGBX.applyTint = glGetUniformLocation(prog, "applyTint"); shaders->m_shRGBX.applyTint = glGetUniformLocation(prog, "applyTint");
shaders->m_shRGBX.tint = glGetUniformLocation(prog, "tint"); shaders->m_shRGBX.tint = glGetUniformLocation(prog, "tint");
shaders->m_shRGBX.createVao();
prog = createProgram(shaders->TEXVERTSRC, TEXFRAGSRCEXT, isDynamic); prog = createProgram(shaders->TEXVERTSRC, TEXFRAGSRCEXT, isDynamic);
if (!prog) if (!prog)
@ -1088,6 +1095,7 @@ bool CHyprOpenGLImpl::initShaders() {
shaders->m_shEXT.discardAlphaValue = glGetUniformLocation(prog, "discardAlphaValue"); shaders->m_shEXT.discardAlphaValue = glGetUniformLocation(prog, "discardAlphaValue");
shaders->m_shEXT.applyTint = glGetUniformLocation(prog, "applyTint"); shaders->m_shEXT.applyTint = glGetUniformLocation(prog, "applyTint");
shaders->m_shEXT.tint = glGetUniformLocation(prog, "tint"); shaders->m_shEXT.tint = glGetUniformLocation(prog, "tint");
shaders->m_shEXT.createVao();
prog = createProgram(shaders->TEXVERTSRC, FRAGBLUR1, isDynamic); prog = createProgram(shaders->TEXVERTSRC, FRAGBLUR1, isDynamic);
if (!prog) if (!prog)
@ -1103,6 +1111,7 @@ bool CHyprOpenGLImpl::initShaders() {
shaders->m_shBLUR1.passes = glGetUniformLocation(prog, "passes"); shaders->m_shBLUR1.passes = glGetUniformLocation(prog, "passes");
shaders->m_shBLUR1.vibrancy = glGetUniformLocation(prog, "vibrancy"); shaders->m_shBLUR1.vibrancy = glGetUniformLocation(prog, "vibrancy");
shaders->m_shBLUR1.vibrancy_darkness = glGetUniformLocation(prog, "vibrancy_darkness"); shaders->m_shBLUR1.vibrancy_darkness = glGetUniformLocation(prog, "vibrancy_darkness");
shaders->m_shBLUR1.createVao();
prog = createProgram(shaders->TEXVERTSRC, FRAGBLUR2, isDynamic); prog = createProgram(shaders->TEXVERTSRC, FRAGBLUR2, isDynamic);
if (!prog) if (!prog)
@ -1115,6 +1124,7 @@ bool CHyprOpenGLImpl::initShaders() {
shaders->m_shBLUR2.texAttrib = glGetAttribLocation(prog, "texcoord"); shaders->m_shBLUR2.texAttrib = glGetAttribLocation(prog, "texcoord");
shaders->m_shBLUR2.radius = glGetUniformLocation(prog, "radius"); shaders->m_shBLUR2.radius = glGetUniformLocation(prog, "radius");
shaders->m_shBLUR2.halfpixel = glGetUniformLocation(prog, "halfpixel"); shaders->m_shBLUR2.halfpixel = glGetUniformLocation(prog, "halfpixel");
shaders->m_shBLUR2.createVao();
prog = createProgram(m_cmSupported ? shaders->TEXVERTSRC300 : shaders->TEXVERTSRC, FRAGBLURPREPARE, isDynamic); prog = createProgram(m_cmSupported ? shaders->TEXVERTSRC300 : shaders->TEXVERTSRC, FRAGBLURPREPARE, isDynamic);
if (!prog) if (!prog)
@ -1129,6 +1139,7 @@ bool CHyprOpenGLImpl::initShaders() {
shaders->m_shBLURPREPARE.texAttrib = glGetAttribLocation(prog, "texcoord"); shaders->m_shBLURPREPARE.texAttrib = glGetAttribLocation(prog, "texcoord");
shaders->m_shBLURPREPARE.contrast = glGetUniformLocation(prog, "contrast"); shaders->m_shBLURPREPARE.contrast = glGetUniformLocation(prog, "contrast");
shaders->m_shBLURPREPARE.brightness = glGetUniformLocation(prog, "brightness"); shaders->m_shBLURPREPARE.brightness = glGetUniformLocation(prog, "brightness");
shaders->m_shBLURPREPARE.createVao();
prog = createProgram(m_cmSupported ? shaders->TEXVERTSRC300 : shaders->TEXVERTSRC, FRAGBLURFINISH, isDynamic); prog = createProgram(m_cmSupported ? shaders->TEXVERTSRC300 : shaders->TEXVERTSRC, FRAGBLURFINISH, isDynamic);
if (!prog) if (!prog)
@ -1142,6 +1153,7 @@ bool CHyprOpenGLImpl::initShaders() {
shaders->m_shBLURFINISH.texAttrib = glGetAttribLocation(prog, "texcoord"); shaders->m_shBLURFINISH.texAttrib = glGetAttribLocation(prog, "texcoord");
shaders->m_shBLURFINISH.brightness = glGetUniformLocation(prog, "brightness"); shaders->m_shBLURFINISH.brightness = glGetUniformLocation(prog, "brightness");
shaders->m_shBLURFINISH.noise = glGetUniformLocation(prog, "noise"); shaders->m_shBLURFINISH.noise = glGetUniformLocation(prog, "noise");
shaders->m_shBLURFINISH.createVao();
prog = createProgram(m_cmSupported ? shaders->TEXVERTSRC300 : shaders->TEXVERTSRC, FRAGSHADOW, isDynamic); prog = createProgram(m_cmSupported ? shaders->TEXVERTSRC300 : shaders->TEXVERTSRC, FRAGSHADOW, isDynamic);
if (!prog) if (!prog)
@ -1157,6 +1169,7 @@ bool CHyprOpenGLImpl::initShaders() {
shaders->m_shSHADOW.range = glGetUniformLocation(prog, "range"); shaders->m_shSHADOW.range = glGetUniformLocation(prog, "range");
shaders->m_shSHADOW.shadowPower = glGetUniformLocation(prog, "shadowPower"); shaders->m_shSHADOW.shadowPower = glGetUniformLocation(prog, "shadowPower");
shaders->m_shSHADOW.color = glGetUniformLocation(prog, "color"); shaders->m_shSHADOW.color = glGetUniformLocation(prog, "color");
shaders->m_shSHADOW.createVao();
prog = createProgram(m_cmSupported ? shaders->TEXVERTSRC300 : shaders->TEXVERTSRC, FRAGBORDER1, isDynamic); prog = createProgram(m_cmSupported ? shaders->TEXVERTSRC300 : shaders->TEXVERTSRC, FRAGBORDER1, isDynamic);
if (!prog) if (!prog)
@ -1181,6 +1194,8 @@ bool CHyprOpenGLImpl::initShaders() {
shaders->m_shBORDER1.angle2 = glGetUniformLocation(prog, "angle2"); shaders->m_shBORDER1.angle2 = glGetUniformLocation(prog, "angle2");
shaders->m_shBORDER1.gradientLerp = glGetUniformLocation(prog, "gradientLerp"); shaders->m_shBORDER1.gradientLerp = glGetUniformLocation(prog, "gradientLerp");
shaders->m_shBORDER1.alpha = glGetUniformLocation(prog, "alpha"); shaders->m_shBORDER1.alpha = glGetUniformLocation(prog, "alpha");
shaders->m_shBORDER1.createVao();
} catch (const std::exception& e) { } catch (const std::exception& e) {
if (!m_shadersInitialized) if (!m_shadersInitialized)
throw e; throw e;
@ -1375,7 +1390,7 @@ void CHyprOpenGLImpl::renderRectWithDamage(const CBox& box, const CHyprColor& co
newBox, wlTransformToHyprutils(invertTransform(!m_endFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_renderData.pMonitor->m_transform)), newBox.rot); newBox, wlTransformToHyprutils(invertTransform(!m_endFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_renderData.pMonitor->m_transform)), newBox.rot);
Mat3x3 glMatrix = m_renderData.projection.copy().multiply(matrix); Mat3x3 glMatrix = m_renderData.projection.copy().multiply(matrix);
glUseProgram(m_shaders->m_shQUAD.program); useProgram(m_shaders->m_shQUAD.program);
#ifndef GLES2 #ifndef GLES2
glUniformMatrix3fv(m_shaders->m_shQUAD.proj, 1, GL_TRUE, glMatrix.getMatrix().data()); glUniformMatrix3fv(m_shaders->m_shQUAD.proj, 1, GL_TRUE, glMatrix.getMatrix().data());
@ -1400,9 +1415,7 @@ void CHyprOpenGLImpl::renderRectWithDamage(const CBox& box, const CHyprColor& co
glUniform1f(m_shaders->m_shQUAD.radius, round); glUniform1f(m_shaders->m_shQUAD.radius, round);
glUniform1f(m_shaders->m_shQUAD.roundingPower, roundingPower); glUniform1f(m_shaders->m_shQUAD.roundingPower, roundingPower);
glVertexAttribPointer(m_shaders->m_shQUAD.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); glBindVertexArray(m_shaders->m_shQUAD.shaderVao);
glEnableVertexAttribArray(m_shaders->m_shQUAD.posAttrib);
if (m_renderData.clipBox.width != 0 && m_renderData.clipBox.height != 0) { if (m_renderData.clipBox.width != 0 && m_renderData.clipBox.height != 0) {
CRegion damageClip{m_renderData.clipBox.x, m_renderData.clipBox.y, m_renderData.clipBox.width, m_renderData.clipBox.height}; CRegion damageClip{m_renderData.clipBox.x, m_renderData.clipBox.y, m_renderData.clipBox.width, m_renderData.clipBox.height};
@ -1421,7 +1434,7 @@ void CHyprOpenGLImpl::renderRectWithDamage(const CBox& box, const CHyprColor& co
} }
} }
glDisableVertexAttribArray(m_shaders->m_shQUAD.posAttrib); glBindVertexArray(0);
scissor(nullptr); scissor(nullptr);
} }
@ -1581,7 +1594,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, const CB
if (!skipCM && !usingFinalShader && (texType == TEXTURE_RGBA || texType == TEXTURE_RGBX)) if (!skipCM && !usingFinalShader && (texType == TEXTURE_RGBA || texType == TEXTURE_RGBX))
shader = &m_shaders->m_shCM; shader = &m_shaders->m_shCM;
glUseProgram(shader->program); useProgram(shader->program);
if (shader == &m_shaders->m_shCM) { if (shader == &m_shaders->m_shCM) {
glUniform1i(shader->texType, texType); glUniform1i(shader->texType, texType);
@ -1655,22 +1668,20 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, const CB
glUniform1i(shader->applyTint, 0); glUniform1i(shader->applyTint, 0);
} }
const float verts[] = { glBindVertexArray(shader->shaderVao);
m_renderData.primarySurfaceUVBottomRight.x, m_renderData.primarySurfaceUVTopLeft.y, // top right if (allowCustomUV && m_renderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) {
m_renderData.primarySurfaceUVTopLeft.x, m_renderData.primarySurfaceUVTopLeft.y, // top left const float customUVs[] = {
m_renderData.primarySurfaceUVBottomRight.x, m_renderData.primarySurfaceUVBottomRight.y, // bottom right m_renderData.primarySurfaceUVBottomRight.x, m_renderData.primarySurfaceUVTopLeft.y, m_renderData.primarySurfaceUVTopLeft.x,
m_renderData.primarySurfaceUVTopLeft.x, m_renderData.primarySurfaceUVBottomRight.y, // bottom left m_renderData.primarySurfaceUVTopLeft.y, m_renderData.primarySurfaceUVBottomRight.x, m_renderData.primarySurfaceUVBottomRight.y,
}; m_renderData.primarySurfaceUVTopLeft.x, m_renderData.primarySurfaceUVBottomRight.y,
};
glVertexAttribPointer(shader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); glBindBuffer(GL_ARRAY_BUFFER, shader->shaderVboUv);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(customUVs), customUVs);
if (allowCustomUV && m_renderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) } else {
glVertexAttribPointer(shader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, verts); glBindBuffer(GL_ARRAY_BUFFER, shader->shaderVboUv);
else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(fullVerts), fullVerts);
glVertexAttribPointer(shader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); }
glEnableVertexAttribArray(shader->posAttrib);
glEnableVertexAttribArray(shader->texAttrib);
if (!m_renderData.clipBox.empty() || !m_renderData.clipRegion.empty()) { if (!m_renderData.clipBox.empty() || !m_renderData.clipRegion.empty()) {
CRegion damageClip = m_renderData.clipBox; CRegion damageClip = m_renderData.clipBox;
@ -1695,9 +1706,8 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, const CB
} }
} }
glDisableVertexAttribArray(shader->posAttrib); glBindVertexArray(0);
glDisableVertexAttribArray(shader->texAttrib); glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindTexture(tex->m_target, 0); glBindTexture(tex->m_target, 0);
} }
@ -1723,7 +1733,7 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP<CTexture> tex, const CBox& box)
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(tex->m_target, tex->m_texID); glBindTexture(tex->m_target, tex->m_texID);
glUseProgram(shader->program); useProgram(shader->program);
#ifndef GLES2 #ifndef GLES2
glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix.getMatrix().data()); glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix.getMatrix().data());
@ -1733,11 +1743,7 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP<CTexture> tex, const CBox& box)
#endif #endif
glUniform1i(shader->tex, 0); glUniform1i(shader->tex, 0);
glVertexAttribPointer(shader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); glBindVertexArray(shader->shaderVao);
glVertexAttribPointer(shader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glEnableVertexAttribArray(shader->posAttrib);
glEnableVertexAttribArray(shader->texAttrib);
for (auto const& RECT : m_renderData.damage.getRects()) { for (auto const& RECT : m_renderData.damage.getRects()) {
scissor(&RECT); scissor(&RECT);
@ -1746,9 +1752,7 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP<CTexture> tex, const CBox& box)
scissor(nullptr); scissor(nullptr);
glDisableVertexAttribArray(shader->posAttrib); glBindVertexArray(0);
glDisableVertexAttribArray(shader->texAttrib);
glBindTexture(tex->m_target, 0); glBindTexture(tex->m_target, 0);
} }
@ -1771,7 +1775,7 @@ void CHyprOpenGLImpl::renderTextureMatte(SP<CTexture> tex, const CBox& box, CFra
SShader* shader = &m_shaders->m_shMATTE; SShader* shader = &m_shaders->m_shMATTE;
glUseProgram(shader->program); useProgram(shader->program);
#ifndef GLES2 #ifndef GLES2
glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix.getMatrix().data()); glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix.getMatrix().data());
@ -1789,11 +1793,7 @@ void CHyprOpenGLImpl::renderTextureMatte(SP<CTexture> tex, const CBox& box, CFra
auto matteTex = matte.getTexture(); auto matteTex = matte.getTexture();
glBindTexture(matteTex->m_target, matteTex->m_texID); glBindTexture(matteTex->m_target, matteTex->m_texID);
glVertexAttribPointer(shader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); glBindVertexArray(shader->shaderVao);
glVertexAttribPointer(shader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glEnableVertexAttribArray(shader->posAttrib);
glEnableVertexAttribArray(shader->texAttrib);
for (auto const& RECT : m_renderData.damage.getRects()) { for (auto const& RECT : m_renderData.damage.getRects()) {
scissor(&RECT); scissor(&RECT);
@ -1802,9 +1802,7 @@ void CHyprOpenGLImpl::renderTextureMatte(SP<CTexture> tex, const CBox& box, CFra
scissor(nullptr); scissor(nullptr);
glDisableVertexAttribArray(shader->posAttrib); glBindVertexArray(0);
glDisableVertexAttribArray(shader->texAttrib);
glBindTexture(tex->m_target, 0); glBindTexture(tex->m_target, 0);
} }
@ -1868,7 +1866,7 @@ CFramebuffer* CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* origi
glTexParameteri(currentTex->m_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(currentTex->m_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glUseProgram(m_shaders->m_shBLURPREPARE.program); useProgram(m_shaders->m_shBLURPREPARE.program);
// From FB to sRGB // From FB to sRGB
const bool skipCM = !m_cmSupported || m_renderData.pMonitor->m_imageDescription == SImageDescription{}; const bool skipCM = !m_cmSupported || m_renderData.pMonitor->m_imageDescription == SImageDescription{};
@ -1897,11 +1895,7 @@ CFramebuffer* CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* origi
glUniform1f(m_shaders->m_shBLURPREPARE.brightness, *PBLURBRIGHTNESS); glUniform1f(m_shaders->m_shBLURPREPARE.brightness, *PBLURBRIGHTNESS);
glUniform1i(m_shaders->m_shBLURPREPARE.tex, 0); glUniform1i(m_shaders->m_shBLURPREPARE.tex, 0);
glVertexAttribPointer(m_shaders->m_shBLURPREPARE.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); glBindVertexArray(m_shaders->m_shBLURPREPARE.shaderVao);
glVertexAttribPointer(m_shaders->m_shBLURPREPARE.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glEnableVertexAttribArray(m_shaders->m_shBLURPREPARE.posAttrib);
glEnableVertexAttribArray(m_shaders->m_shBLURPREPARE.texAttrib);
if (!damage.empty()) { if (!damage.empty()) {
for (auto const& RECT : damage.getRects()) { for (auto const& RECT : damage.getRects()) {
@ -1910,9 +1904,7 @@ CFramebuffer* CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* origi
} }
} }
glDisableVertexAttribArray(m_shaders->m_shBLURPREPARE.posAttrib); glBindVertexArray(0);
glDisableVertexAttribArray(m_shaders->m_shBLURPREPARE.texAttrib);
currentRenderToFB = PMIRRORSWAPFB; currentRenderToFB = PMIRRORSWAPFB;
} }
@ -1931,7 +1923,7 @@ CFramebuffer* CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* origi
glTexParameteri(currentTex->m_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(currentTex->m_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glUseProgram(pShader->program); useProgram(pShader->program);
// prep two shaders // prep two shaders
#ifndef GLES2 #ifndef GLES2
@ -1950,12 +1942,7 @@ CFramebuffer* CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* origi
glUniform2f(m_shaders->m_shBLUR2.halfpixel, 0.5f / (m_renderData.pMonitor->m_pixelSize.x * 2.f), 0.5f / (m_renderData.pMonitor->m_pixelSize.y * 2.f)); glUniform2f(m_shaders->m_shBLUR2.halfpixel, 0.5f / (m_renderData.pMonitor->m_pixelSize.x * 2.f), 0.5f / (m_renderData.pMonitor->m_pixelSize.y * 2.f));
glUniform1i(pShader->tex, 0); glUniform1i(pShader->tex, 0);
glVertexAttribPointer(pShader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); glBindVertexArray(pShader->shaderVao);
glVertexAttribPointer(pShader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glEnableVertexAttribArray(pShader->posAttrib);
glEnableVertexAttribArray(pShader->texAttrib);
if (!pDamage->empty()) { if (!pDamage->empty()) {
for (auto const& RECT : pDamage->getRects()) { for (auto const& RECT : pDamage->getRects()) {
scissor(&RECT, false /* this region is already transformed */); scissor(&RECT, false /* this region is already transformed */);
@ -1963,8 +1950,7 @@ CFramebuffer* CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* origi
} }
} }
glDisableVertexAttribArray(pShader->posAttrib); glBindVertexArray(0);
glDisableVertexAttribArray(pShader->texAttrib);
if (currentRenderToFB != PMIRRORFB) if (currentRenderToFB != PMIRRORFB)
currentRenderToFB = PMIRRORFB; currentRenderToFB = PMIRRORFB;
@ -2009,7 +1995,7 @@ CFramebuffer* CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* origi
glTexParameteri(currentTex->m_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(currentTex->m_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glUseProgram(m_shaders->m_shBLURFINISH.program); useProgram(m_shaders->m_shBLURFINISH.program);
#ifndef GLES2 #ifndef GLES2
glUniformMatrix3fv(m_shaders->m_shBLURFINISH.proj, 1, GL_TRUE, glMatrix.getMatrix().data()); glUniformMatrix3fv(m_shaders->m_shBLURFINISH.proj, 1, GL_TRUE, glMatrix.getMatrix().data());
@ -2022,11 +2008,7 @@ CFramebuffer* CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* origi
glUniform1i(m_shaders->m_shBLURFINISH.tex, 0); glUniform1i(m_shaders->m_shBLURFINISH.tex, 0);
glVertexAttribPointer(m_shaders->m_shBLURFINISH.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); glBindVertexArray(m_shaders->m_shBLURFINISH.shaderVao);
glVertexAttribPointer(m_shaders->m_shBLURFINISH.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glEnableVertexAttribArray(m_shaders->m_shBLURFINISH.posAttrib);
glEnableVertexAttribArray(m_shaders->m_shBLURFINISH.texAttrib);
if (!damage.empty()) { if (!damage.empty()) {
for (auto const& RECT : damage.getRects()) { for (auto const& RECT : damage.getRects()) {
@ -2035,8 +2017,7 @@ CFramebuffer* CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* origi
} }
} }
glDisableVertexAttribArray(m_shaders->m_shBLURFINISH.posAttrib); glBindVertexArray(0);
glDisableVertexAttribArray(m_shaders->m_shBLURFINISH.texAttrib);
if (currentRenderToFB != PMIRRORFB) if (currentRenderToFB != PMIRRORFB)
currentRenderToFB = PMIRRORFB; currentRenderToFB = PMIRRORFB;
@ -2352,7 +2333,7 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& gr
const auto BLEND = m_blend; const auto BLEND = m_blend;
blend(true); blend(true);
glUseProgram(m_shaders->m_shBORDER1.program); useProgram(m_shaders->m_shBORDER1.program);
const bool skipCM = !m_cmSupported || m_renderData.pMonitor->m_imageDescription == SImageDescription{}; const bool skipCM = !m_cmSupported || m_renderData.pMonitor->m_imageDescription == SImageDescription{};
glUniform1i(m_shaders->m_shBORDER1.skipCM, skipCM); glUniform1i(m_shaders->m_shBORDER1.skipCM, skipCM);
@ -2387,11 +2368,7 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& gr
glUniform1f(m_shaders->m_shBORDER1.roundingPower, roundingPower); glUniform1f(m_shaders->m_shBORDER1.roundingPower, roundingPower);
glUniform1f(m_shaders->m_shBORDER1.thick, scaledBorderSize); glUniform1f(m_shaders->m_shBORDER1.thick, scaledBorderSize);
glVertexAttribPointer(m_shaders->m_shBORDER1.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); glBindVertexArray(m_shaders->m_shBORDER1.shaderVao);
glVertexAttribPointer(m_shaders->m_shBORDER1.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glEnableVertexAttribArray(m_shaders->m_shBORDER1.posAttrib);
glEnableVertexAttribArray(m_shaders->m_shBORDER1.texAttrib);
if (m_renderData.clipBox.width != 0 && m_renderData.clipBox.height != 0) { if (m_renderData.clipBox.width != 0 && m_renderData.clipBox.height != 0) {
CRegion damageClip{m_renderData.clipBox.x, m_renderData.clipBox.y, m_renderData.clipBox.width, m_renderData.clipBox.height}; CRegion damageClip{m_renderData.clipBox.x, m_renderData.clipBox.y, m_renderData.clipBox.width, m_renderData.clipBox.height};
@ -2410,8 +2387,7 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& gr
} }
} }
glDisableVertexAttribArray(m_shaders->m_shBORDER1.posAttrib); glBindVertexArray(0);
glDisableVertexAttribArray(m_shaders->m_shBORDER1.texAttrib);
blend(BLEND); blend(BLEND);
} }
@ -2450,7 +2426,7 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& gr
const auto BLEND = m_blend; const auto BLEND = m_blend;
blend(true); blend(true);
glUseProgram(m_shaders->m_shBORDER1.program); useProgram(m_shaders->m_shBORDER1.program);
#ifndef GLES2 #ifndef GLES2
glUniformMatrix3fv(m_shaders->m_shBORDER1.proj, 1, GL_TRUE, glMatrix.getMatrix().data()); glUniformMatrix3fv(m_shaders->m_shBORDER1.proj, 1, GL_TRUE, glMatrix.getMatrix().data());
@ -2484,11 +2460,7 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& gr
glUniform1f(m_shaders->m_shBORDER1.roundingPower, roundingPower); glUniform1f(m_shaders->m_shBORDER1.roundingPower, roundingPower);
glUniform1f(m_shaders->m_shBORDER1.thick, scaledBorderSize); glUniform1f(m_shaders->m_shBORDER1.thick, scaledBorderSize);
glVertexAttribPointer(m_shaders->m_shBORDER1.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); glBindVertexArray(m_shaders->m_shBORDER1.shaderVao);
glVertexAttribPointer(m_shaders->m_shBORDER1.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glEnableVertexAttribArray(m_shaders->m_shBORDER1.posAttrib);
glEnableVertexAttribArray(m_shaders->m_shBORDER1.texAttrib);
if (m_renderData.clipBox.width != 0 && m_renderData.clipBox.height != 0) { if (m_renderData.clipBox.width != 0 && m_renderData.clipBox.height != 0) {
CRegion damageClip{m_renderData.clipBox.x, m_renderData.clipBox.y, m_renderData.clipBox.width, m_renderData.clipBox.height}; CRegion damageClip{m_renderData.clipBox.x, m_renderData.clipBox.y, m_renderData.clipBox.width, m_renderData.clipBox.height};
@ -2507,9 +2479,7 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& gr
} }
} }
glDisableVertexAttribArray(m_shaders->m_shBORDER1.posAttrib); glBindVertexArray(0);
glDisableVertexAttribArray(m_shaders->m_shBORDER1.texAttrib);
blend(BLEND); blend(BLEND);
} }
@ -2538,7 +2508,7 @@ void CHyprOpenGLImpl::renderRoundedShadow(const CBox& box, int round, float roun
blend(true); blend(true);
glUseProgram(m_shaders->m_shSHADOW.program); useProgram(m_shaders->m_shSHADOW.program);
const bool skipCM = !m_cmSupported || m_renderData.pMonitor->m_imageDescription == SImageDescription{}; const bool skipCM = !m_cmSupported || m_renderData.pMonitor->m_imageDescription == SImageDescription{};
glUniform1i(m_shaders->m_shSHADOW.skipCM, skipCM); glUniform1i(m_shaders->m_shSHADOW.skipCM, skipCM);
if (!skipCM) if (!skipCM)
@ -2565,11 +2535,7 @@ void CHyprOpenGLImpl::renderRoundedShadow(const CBox& box, int round, float roun
glUniform1f(m_shaders->m_shSHADOW.range, range); glUniform1f(m_shaders->m_shSHADOW.range, range);
glUniform1f(m_shaders->m_shSHADOW.shadowPower, SHADOWPOWER); glUniform1f(m_shaders->m_shSHADOW.shadowPower, SHADOWPOWER);
glVertexAttribPointer(m_shaders->m_shSHADOW.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); glBindVertexArray(m_shaders->m_shSHADOW.shaderVao);
glVertexAttribPointer(m_shaders->m_shSHADOW.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glEnableVertexAttribArray(m_shaders->m_shSHADOW.posAttrib);
glEnableVertexAttribArray(m_shaders->m_shSHADOW.texAttrib);
if (m_renderData.clipBox.width != 0 && m_renderData.clipBox.height != 0) { if (m_renderData.clipBox.width != 0 && m_renderData.clipBox.height != 0) {
CRegion damageClip{m_renderData.clipBox.x, m_renderData.clipBox.y, m_renderData.clipBox.width, m_renderData.clipBox.height}; CRegion damageClip{m_renderData.clipBox.x, m_renderData.clipBox.y, m_renderData.clipBox.width, m_renderData.clipBox.height};
@ -2588,8 +2554,7 @@ void CHyprOpenGLImpl::renderRoundedShadow(const CBox& box, int round, float roun
} }
} }
glDisableVertexAttribArray(m_shaders->m_shSHADOW.posAttrib); glBindVertexArray(0);
glDisableVertexAttribArray(m_shaders->m_shSHADOW.texAttrib);
} }
void CHyprOpenGLImpl::saveBufferForMirror(const CBox& box) { void CHyprOpenGLImpl::saveBufferForMirror(const CBox& box) {
@ -2861,6 +2826,14 @@ void CHyprOpenGLImpl::initMissingAssetTexture() {
m_missingAssetTexture = tex; m_missingAssetTexture = tex;
} }
void CHyprOpenGLImpl::useProgram(GLuint prog) {
if (m_currentProgram == prog)
return;
glUseProgram(prog);
m_currentProgram = prog;
}
void CHyprOpenGLImpl::initAssets() { void CHyprOpenGLImpl::initAssets() {
initMissingAssetTexture(); initMissingAssetTexture();

View File

@ -312,6 +312,7 @@ class CHyprOpenGLImpl {
SShader m_finalScreenShader; SShader m_finalScreenShader;
CTimer m_globalTimer; CTimer m_globalTimer;
GLuint m_currentProgram;
SP<CTexture> m_missingAssetTexture; SP<CTexture> m_missingAssetTexture;
SP<CTexture> m_backgroundTexture; SP<CTexture> m_backgroundTexture;
@ -328,6 +329,7 @@ class CHyprOpenGLImpl {
EGLDeviceEXT eglDeviceFromDRMFD(int drmFD); EGLDeviceEXT eglDeviceFromDRMFD(int drmFD);
void initAssets(); void initAssets();
void initMissingAssetTexture(); void initMissingAssetTexture();
void useProgram(GLuint prog);
// //
std::optional<std::vector<uint64_t>> getModsForFormat(EGLint format); std::optional<std::vector<uint64_t>> getModsForFormat(EGLint format);

View File

@ -2280,9 +2280,6 @@ void CHyprRenderer::endRender(const std::function<void()>& renderingDoneCallback
g_pHyprOpenGL->m_renderData.mouseZoomUseMouse = true; g_pHyprOpenGL->m_renderData.mouseZoomUseMouse = true;
} }
// send all queued opengl commands so rendering starts happening immediately
glFlush();
if (m_renderMode == RENDER_MODE_FULL_FAKE) if (m_renderMode == RENDER_MODE_FULL_FAKE)
return; return;

View File

@ -1,14 +1,48 @@
#include "Shader.hpp" #include "Shader.hpp"
#include "render/OpenGL.hpp"
SShader::~SShader() { SShader::~SShader() {
destroy(); destroy();
} }
void SShader::createVao() {
glGenVertexArrays(1, &shaderVao);
glBindVertexArray(shaderVao);
if (posAttrib != -1) {
glGenBuffers(1, &shaderVboPos);
glBindBuffer(GL_ARRAY_BUFFER, shaderVboPos);
glBufferData(GL_ARRAY_BUFFER, sizeof(fullVerts), fullVerts, GL_STATIC_DRAW);
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
}
// UV VBO (dynamic, may be updated per frame)
if (texAttrib != -1) {
glGenBuffers(1, &shaderVboUv);
glBindBuffer(GL_ARRAY_BUFFER, shaderVboUv);
glBufferData(GL_ARRAY_BUFFER, sizeof(fullVerts), fullVerts, GL_DYNAMIC_DRAW); // Initial dummy UVs
glEnableVertexAttribArray(texAttrib);
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
}
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void SShader::destroy() { void SShader::destroy() {
if (program == 0) if (program == 0)
return; return;
glDeleteProgram(program); if (shaderVao)
glDeleteVertexArrays(1, &shaderVao);
if (shaderVboPos)
glDeleteBuffers(1, &shaderVboPos);
if (shaderVboUv)
glDeleteBuffers(1, &shaderVboUv);
glDeleteProgram(program);
program = 0; program = 0;
} }

View File

@ -32,6 +32,10 @@ struct SShader {
GLint discardAlpha = -1; GLint discardAlpha = -1;
GLfloat discardAlphaValue = -1; GLfloat discardAlphaValue = -1;
GLuint shaderVao = 0;
GLuint shaderVboPos = 0;
GLuint shaderVboUv = 0;
GLint topLeft = -1; GLint topLeft = -1;
GLint bottomRight = -1; GLint bottomRight = -1;
GLint fullSize = -1; GLint fullSize = -1;
@ -76,5 +80,6 @@ struct SShader {
GLint brightness = -1; GLint brightness = -1;
GLint noise = -1; GLint noise = -1;
void createVao();
void destroy(); void destroy();
}; };