diff options
| author | Vaxry <43317083+vaxerski@users.noreply.github.com> | 2024-06-08 10:07:59 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-06-08 10:07:59 +0200 |
| commit | 6967a31450441fc5605c05db6f65505dace4b263 (patch) | |
| tree | 255a3cff7f3e2eb8a50c952eab9b270a7937561d /src/render | |
| parent | c31d9ef4172452f6f219f91d9b87a24d91f0cf3a (diff) | |
wayland/core: move to new impl (#6268)
* wayland/core/dmabuf: move to new impl
it's the final countdown
Diffstat (limited to 'src/render')
| -rw-r--r-- | src/render/Framebuffer.cpp | 27 | ||||
| -rw-r--r-- | src/render/Framebuffer.hpp | 21 | ||||
| -rw-r--r-- | src/render/OpenGL.cpp | 453 | ||||
| -rw-r--r-- | src/render/OpenGL.hpp | 159 | ||||
| -rw-r--r-- | src/render/Renderbuffer.cpp | 24 | ||||
| -rw-r--r-- | src/render/Renderbuffer.hpp | 3 | ||||
| -rw-r--r-- | src/render/Renderer.cpp | 255 | ||||
| -rw-r--r-- | src/render/Renderer.hpp | 19 | ||||
| -rw-r--r-- | src/render/Texture.cpp | 106 | ||||
| -rw-r--r-- | src/render/Texture.hpp | 18 | ||||
| -rw-r--r-- | src/render/decorations/CHyprGroupBarDecoration.cpp | 50 | ||||
| -rw-r--r-- | src/render/decorations/CHyprGroupBarDecoration.hpp | 2 |
12 files changed, 683 insertions, 454 deletions
diff --git a/src/render/Framebuffer.cpp b/src/render/Framebuffer.cpp index 83325dd7..67629e23 100644 --- a/src/render/Framebuffer.cpp +++ b/src/render/Framebuffer.cpp @@ -1,22 +1,26 @@ #include "Framebuffer.hpp" #include "OpenGL.hpp" +CFramebuffer::CFramebuffer() { + m_cTex = makeShared<CTexture>(); +} + bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) { bool firstAlloc = false; RASSERT((w > 1 && h > 1), "cannot alloc a FB with negative / zero size! (attempted {}x{})", w, h); - uint32_t glFormat = drmFormatToGL(drmFormat); - uint32_t glType = glFormatToType(glFormat); + uint32_t glFormat = FormatUtils::drmFormatToGL(drmFormat); + uint32_t glType = FormatUtils::glFormatToType(glFormat); if (m_iFb == (uint32_t)-1) { firstAlloc = true; glGenFramebuffers(1, &m_iFb); } - if (m_cTex.m_iTexID == 0) { + if (m_cTex->m_iTexID == 0) { firstAlloc = true; - glGenTextures(1, &m_cTex.m_iTexID); - glBindTexture(GL_TEXTURE_2D, m_cTex.m_iTexID); + m_cTex->allocate(); + glBindTexture(GL_TEXTURE_2D, m_cTex->m_iTexID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -24,11 +28,11 @@ bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) { } if (firstAlloc || m_vSize != Vector2D(w, h)) { - glBindTexture(GL_TEXTURE_2D, m_cTex.m_iTexID); + glBindTexture(GL_TEXTURE_2D, m_cTex->m_iTexID); glTexImage2D(GL_TEXTURE_2D, 0, glFormat, w, h, 0, GL_RGBA, glType, 0); glBindFramebuffer(GL_FRAMEBUFFER, m_iFb); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_cTex.m_iTexID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_cTex->m_iTexID, 0); // TODO: Allow this with gles2 #ifndef GLES2 @@ -87,12 +91,9 @@ void CFramebuffer::release() { if (m_iFb != (uint32_t)-1 && m_iFb) glDeleteFramebuffers(1, &m_iFb); - if (m_cTex.m_iTexID) - glDeleteTextures(1, &m_cTex.m_iTexID); - - m_cTex.m_iTexID = 0; - m_iFb = -1; - m_vSize = Vector2D(); + m_cTex->destroyTexture(); + m_iFb = -1; + m_vSize = Vector2D(); } CFramebuffer::~CFramebuffer() { diff --git a/src/render/Framebuffer.hpp b/src/render/Framebuffer.hpp index 22809158..a46a4859 100644 --- a/src/render/Framebuffer.hpp +++ b/src/render/Framebuffer.hpp @@ -5,19 +5,20 @@ class CFramebuffer { public: + CFramebuffer(); ~CFramebuffer(); - bool alloc(int w, int h, uint32_t format = GL_RGBA); - void addStencil(); - void bind(); - void release(); - void reset(); - bool isAllocated(); + bool alloc(int w, int h, uint32_t format = GL_RGBA); + void addStencil(); + void bind(); + void release(); + void reset(); + bool isAllocated(); - Vector2D m_vSize; + Vector2D m_vSize; - CTexture m_cTex; - GLuint m_iFb = -1; + SP<CTexture> m_cTex; + GLuint m_iFb = -1; - CTexture* m_pStencilTex = nullptr; + SP<CTexture> m_pStencilTex; };
\ No newline at end of file diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index a1e6f73e..d4e8faa6 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -7,6 +7,8 @@ #include "../config/ConfigValue.hpp" #include "../desktop/LayerSurface.hpp" #include "../protocols/LayerShell.hpp" +#include "../protocols/core/Compositor.hpp" +#include <xf86drm.h> inline void loadGLProc(void* pProc, const char* name) { void* proc = (void*)eglGetProcAddress(name); @@ -21,7 +23,8 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, wlr_egl_get_context(g_pCompositor->m_sWLREGL)), "Couldn't unset current EGL!"); - auto* const EXTENSIONS = (const char*)glGetString(GL_EXTENSIONS); + auto* const EXTENSIONS = (const char*)glGetString(GL_EXTENSIONS); + const std::string EGLEXTENSIONS = (const char*)eglQueryString(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_EXTENSIONS); RASSERT(EXTENSIONS, "Couldn't retrieve openGL extensions!"); @@ -33,12 +36,25 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { Debug::log(LOG, "Using: {}", (char*)glGetString(GL_VERSION)); Debug::log(LOG, "Vendor: {}", (char*)glGetString(GL_VENDOR)); Debug::log(LOG, "Renderer: {}", (char*)glGetString(GL_RENDERER)); - Debug::log(LOG, "Supported extensions size: {}", std::count(m_szExtensions.begin(), m_szExtensions.end(), ' ')); + Debug::log(LOG, "Supported extensions: ({}) {}", std::count(m_szExtensions.begin(), m_szExtensions.end(), ' '), m_szExtensions); loadGLProc(&m_sProc.glEGLImageTargetRenderbufferStorageOES, "glEGLImageTargetRenderbufferStorageOES"); + loadGLProc(&m_sProc.eglCreateImageKHR, "eglCreateImageKHR"); loadGLProc(&m_sProc.eglDestroyImageKHR, "eglDestroyImageKHR"); + loadGLProc(&m_sProc.eglQueryDmaBufFormatsEXT, "eglQueryDmaBufFormatsEXT"); + loadGLProc(&m_sProc.eglQueryDmaBufModifiersEXT, "eglQueryDmaBufModifiersEXT"); + loadGLProc(&m_sProc.glEGLImageTargetTexture2DOES, "glEGLImageTargetTexture2DOES"); - m_sExts.EXT_read_format_bgra = m_szExtensions.contains("GL_EXT_read_format_bgra"); + m_sExts.EXT_read_format_bgra = m_szExtensions.contains("GL_EXT_read_format_bgra"); + m_sExts.EXT_image_dma_buf_import = EGLEXTENSIONS.contains("EXT_image_dma_buf_import"); + m_sExts.EXT_image_dma_buf_import_modifiers = EGLEXTENSIONS.contains("EXT_image_dma_buf_import_modifiers"); + + RASSERT(m_szExtensions.contains("GL_EXT_texture_format_BGRA8888"), "GL_EXT_texture_format_BGRA8888 support by the GPU driver is required"); + + if (!m_sExts.EXT_read_format_bgra) + Debug::log(WARN, "Your GPU does not support GL_EXT_read_format_bgra, this may cause issues with texture importing"); + if (!m_sExts.EXT_image_dma_buf_import || !m_sExts.EXT_image_dma_buf_import_modifiers) + Debug::log(WARN, "Your GPU does not support DMABUFs, this will possibly cause issues and will take a hit on the performance."); #ifdef USE_TRACY_GPU @@ -54,6 +70,8 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { Debug::log(WARN, "!RENDERER: Using the legacy GLES2 renderer!"); #endif + initDRMFormats(); + static auto P = g_pHookSystem->hookDynamic("preRender", [&](void* self, SCallbackInfo& info, std::any data) { preRender(std::any_cast<CMonitor*>(data)); }); RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), "Couldn't unset current EGL!"); @@ -61,6 +79,171 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { m_tGlobalTimer.reset(); } +std::vector<uint64_t> CHyprOpenGLImpl::getModsForFormat(EGLint format) { + // TODO: return std::expected when clang supports it + + if (!m_sExts.EXT_image_dma_buf_import_modifiers) + return {}; + + EGLint len = 0; + if (!m_sProc.eglQueryDmaBufModifiersEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), format, 0, nullptr, nullptr, &len)) { + Debug::log(ERR, "EGL: Failed to query mods"); + return {}; + } + + if (len <= 0) + return {}; + + std::vector<uint64_t> mods; + std::vector<EGLBoolean> external; + + mods.resize(len); + external.resize(len); + + m_sProc.eglQueryDmaBufModifiersEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), format, len, mods.data(), external.data(), &len); + + std::vector<uint64_t> result; + for (size_t i = 0; i < mods.size(); ++i) { + if (external.at(i)) + continue; + + result.push_back(mods.at(i)); + } + + return result; +} + +void CHyprOpenGLImpl::initDRMFormats() { + const auto DISABLE_MODS = envEnabled("HYPRLAND_EGL_NO_MODIFIERS"); + if (DISABLE_MODS) + Debug::log(WARN, "HYPRLAND_EGL_NO_MODIFIERS set, disabling modifiers"); + + if (!m_sExts.EXT_image_dma_buf_import) { + Debug::log(ERR, "EGL: No dmabuf import, DMABufs will not work."); + return; + } + + std::vector<EGLint> formats; + + if (!m_sExts.EXT_image_dma_buf_import_modifiers || !m_sProc.eglQueryDmaBufFormatsEXT) { + formats.push_back(DRM_FORMAT_ARGB8888); + formats.push_back(DRM_FORMAT_XRGB8888); + Debug::log(WARN, "EGL: No mod support"); + } else { + EGLint len = 0; + m_sProc.eglQueryDmaBufFormatsEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), 0, nullptr, &len); + formats.resize(len); + m_sProc.eglQueryDmaBufFormatsEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), len, formats.data(), &len); + } + + if (formats.size() == 0) { + Debug::log(ERR, "EGL: Failed to get formats, DMABufs will not work."); + return; + } + + wlr_log(WLR_DEBUG, "Supported DMA-BUF formats:"); + + std::vector<SDRMFormat> dmaFormats; + + for (auto& fmt : formats) { + std::vector<uint64_t> mods; + if (!DISABLE_MODS) + mods = getModsForFormat(fmt); + else + mods = {DRM_FORMAT_MOD_LINEAR}; + + m_bHasModifiers = m_bHasModifiers || mods.size() > 0; + + if (mods.size() == 0) + continue; + + dmaFormats.push_back(SDRMFormat{ + .format = fmt, + .mods = mods, + }); + + std::vector<std::pair<uint64_t, std::string>> modifierData; + + auto fmtName = drmGetFormatName(fmt); + Debug::log(LOG, "EGL: GPU Supports Format {} (0x{:x})", fmtName ? fmtName : "?unknown?", fmt); + for (auto& mod : mods) { + auto modName = drmGetFormatModifierName(mod); + modifierData.emplace_back(std::make_pair<>(mod, modName ? modName : "?unknown?")); + free(modName); + } + free(fmtName); + + mods.clear(); + std::sort(modifierData.begin(), modifierData.end(), [](const auto& a, const auto& b) { + if (a.first == 0) + return false; + if (a.second.contains("DCC")) + return false; + return true; + }); + + for (auto& [m, name] : modifierData) { + Debug::log(LOG, "EGL: | with modifier {} (0x{:x})", name, m); + mods.emplace_back(m); + } + } + + Debug::log(LOG, "EGL: {} formats found in total. Some modifiers may be omitted as they are external-only.", dmaFormats.size()); + + drmFormats = dmaFormats; +} + +EGLImageKHR CHyprOpenGLImpl::createEGLImage(const SDMABUFAttrs& attrs) { + std::vector<uint32_t> attribs; + + attribs.push_back(EGL_WIDTH); + attribs.push_back(attrs.size.x); + attribs.push_back(EGL_HEIGHT); + attribs.push_back(attrs.size.y); + attribs.push_back(EGL_LINUX_DRM_FOURCC_EXT); + attribs.push_back(attrs.format); + + struct { + EGLint fd; + EGLint offset; + EGLint pitch; + EGLint modlo; + EGLint modhi; + } attrNames[4] = { + {EGL_DMA_BUF_PLANE0_FD_EXT, EGL_DMA_BUF_PLANE0_OFFSET_EXT, EGL_DMA_BUF_PLANE0_PITCH_EXT, EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT}, + {EGL_DMA_BUF_PLANE1_FD_EXT, EGL_DMA_BUF_PLANE1_OFFSET_EXT, EGL_DMA_BUF_PLANE1_PITCH_EXT, EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT}, + {EGL_DMA_BUF_PLANE2_FD_EXT, EGL_DMA_BUF_PLANE2_OFFSET_EXT, EGL_DMA_BUF_PLANE2_PITCH_EXT, EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT}, + {EGL_DMA_BUF_PLANE3_FD_EXT, EGL_DMA_BUF_PLANE3_OFFSET_EXT, EGL_DMA_BUF_PLANE3_PITCH_EXT, EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT}}; + + for (int i = 0; i < attrs.planes; i++) { + attribs.push_back(attrNames[i].fd); + attribs.push_back(attrs.fds[i]); + attribs.push_back(attrNames[i].offset); + attribs.push_back(attrs.offsets[i]); + attribs.push_back(attrNames[i].pitch); + attribs.push_back(attrs.strides[i]); + if (m_bHasModifiers && attrs.modifier != DRM_FORMAT_MOD_INVALID) { + attribs.push_back(attrNames[i].modlo); + attribs.push_back(attrs.modifier & 0xFFFFFFFF); + attribs.push_back(attrNames[i].modhi); + attribs.push_back(attrs.modifier >> 32); + } + } + + attribs.push_back(EGL_IMAGE_PRESERVED_KHR); + attribs.push_back(EGL_TRUE); + + attribs.push_back(EGL_NONE); + + EGLImageKHR image = m_sProc.eglCreateImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, (int*)attribs.data()); + if (image == EGL_NO_IMAGE_KHR) { + Debug::log(ERR, "EGL: EGLCreateImageKHR failed: {}", eglGetError()); + return EGL_NO_IMAGE_KHR; + } + + return image; +} + void CHyprOpenGLImpl::logShaderError(const GLuint& shader, bool program) { GLint maxLength = 0; if (program) @@ -339,12 +522,12 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebu // ensure a framebuffer for the monitor exists if (m_RenderData.pCurrentMonData->offloadFB.m_vSize != pMonitor->vecPixelSize) { - m_RenderData.pCurrentMonData->stencilTex.allocate(); + m_RenderData.pCurrentMonData->stencilTex->allocate(); - m_RenderData.pCurrentMonData->offloadFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; - m_RenderData.pCurrentMonData->mirrorFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; - m_RenderData.pCurrentMonData->mirrorSwapFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; - m_RenderData.pCurrentMonData->offMainFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; + m_RenderData.pCurrentMonData->offloadFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; + m_RenderData.pCurrentMonData->mirrorFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; + m_RenderData.pCurrentMonData->mirrorSwapFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; + m_RenderData.pCurrentMonData->offMainFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; m_RenderData.pCurrentMonData->offloadFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat); m_RenderData.pCurrentMonData->mirrorFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat); @@ -381,8 +564,8 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebu // we can render to the rbo / fbo (fake) directly const auto PFBO = fb ? fb : PRBO->getFB(); m_RenderData.currentFB = PFBO; - if (PFBO->m_pStencilTex != &m_RenderData.pCurrentMonData->stencilTex) { - PFBO->m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; + if (PFBO->m_pStencilTex != m_RenderData.pCurrentMonData->stencilTex) { + PFBO->m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; PFBO->addStencil(); } PFBO->bind(); @@ -863,19 +1046,7 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion scissor((CBox*)nullptr); } -void CHyprOpenGLImpl::renderTexture(wlr_texture* tex, CBox* pBox, float alpha, int round, bool allowCustomUV) { - RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - - renderTexture(CTexture(tex), pBox, alpha, round, false, allowCustomUV); -} - -void CHyprOpenGLImpl::renderTextureWithDamage(wlr_texture* tex, CBox* pBox, CRegion* damage, float alpha, int round, bool allowCustomUV) { - RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - - renderTextureWithDamage(CTexture(tex), pBox, damage, alpha, round, false, allowCustomUV); -} - -void CHyprOpenGLImpl::renderTexture(const CTexture& tex, CBox* pBox, float alpha, int round, bool discardActive, bool allowCustomUV) { +void CHyprOpenGLImpl::renderTexture(SP<CTexture> tex, CBox* pBox, float alpha, int round, bool discardActive, bool allowCustomUV) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); renderTextureInternalWithDamage(tex, pBox, alpha, &m_RenderData.damage, round, discardActive, false, allowCustomUV, true); @@ -883,7 +1054,7 @@ void CHyprOpenGLImpl::renderTexture(const CTexture& tex, CBox* pBox, float alpha scissor((CBox*)nullptr); } -void CHyprOpenGLImpl::renderTextureWithDamage(const CTexture& tex, CBox* pBox, CRegion* damage, float alpha, int round, bool discardActive, bool allowCustomUV) { +void CHyprOpenGLImpl::renderTextureWithDamage(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, int round, bool discardActive, bool allowCustomUV) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); renderTextureInternalWithDamage(tex, pBox, alpha, damage, round, discardActive, false, allowCustomUV, true); @@ -891,10 +1062,10 @@ void CHyprOpenGLImpl::renderTextureWithDamage(const CTexture& tex, CBox* pBox, C scissor((CBox*)nullptr); } -void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox* pBox, float alpha, CRegion* damage, int round, bool discardActive, bool noAA, bool allowCustomUV, +void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, CBox* pBox, float alpha, CRegion* damage, int round, bool discardActive, bool noAA, bool allowCustomUV, bool allowDim) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!"); + RASSERT((tex->m_iTexID > 0), "Attempted to draw NULL texture!"); TRACY_GPU_ZONE("RenderTextureInternalWithDamage"); @@ -934,11 +1105,11 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox* shader = &m_RenderData.pCurrentMonData->m_shPASSTHRURGBA; usingFinalShader = true; } else { - switch (tex.m_iType) { + switch (tex->m_iType) { case TEXTURE_RGBA: shader = &m_RenderData.pCurrentMonData->m_shRGBA; break; case TEXTURE_RGBX: shader = &m_RenderData.pCurrentMonData->m_shRGBX; break; case TEXTURE_EXTERNAL: shader = &m_RenderData.pCurrentMonData->m_shEXT; break; - default: RASSERT(false, "tex.m_iTarget unsupported!"); + default: RASSERT(false, "tex->m_iTarget unsupported!"); } } } @@ -947,14 +1118,14 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox* shader = &m_RenderData.pCurrentMonData->m_shRGBX; glActiveTexture(GL_TEXTURE0); - glBindTexture(tex.m_iTarget, tex.m_iTexID); + glBindTexture(tex->m_iTarget, tex->m_iTexID); if (m_RenderData.useNearestNeighbor) { - glTexParameteri(tex.m_iTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(tex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(tex->m_iTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(tex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } else { - glTexParameteri(tex.m_iTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(tex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(tex->m_iTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(tex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } glUseProgram(shader->program); @@ -1057,12 +1228,12 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox* glDisableVertexAttribArray(shader->posAttrib); glDisableVertexAttribArray(shader->texAttrib); - glBindTexture(tex.m_iTarget, 0); + glBindTexture(tex->m_iTarget, 0); } -void CHyprOpenGLImpl::renderTexturePrimitive(const CTexture& tex, CBox* pBox) { +void CHyprOpenGLImpl::renderTexturePrimitive(SP<CTexture> tex, CBox* pBox) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!"); + RASSERT((tex->m_iTexID > 0), "Attempted to draw NULL texture!"); TRACY_GPU_ZONE("RenderTexturePrimitive"); @@ -1083,7 +1254,7 @@ void CHyprOpenGLImpl::renderTexturePrimitive(const CTexture& tex, CBox* pBox) { CShader* shader = &m_RenderData.pCurrentMonData->m_shPASSTHRURGBA; glActiveTexture(GL_TEXTURE0); - glBindTexture(tex.m_iTarget, tex.m_iTexID); + glBindTexture(tex->m_iTarget, tex->m_iTexID); glUseProgram(shader->program); @@ -1111,12 +1282,12 @@ void CHyprOpenGLImpl::renderTexturePrimitive(const CTexture& tex, CBox* pBox) { glDisableVertexAttribArray(shader->posAttrib); glDisableVertexAttribArray(shader->texAttrib); - glBindTexture(tex.m_iTarget, 0); + glBindTexture(tex->m_iTarget, 0); } -void CHyprOpenGLImpl::renderTextureMatte(const CTexture& tex, CBox* pBox, CFramebuffer& matte) { +void CHyprOpenGLImpl::renderTextureMatte(SP<CTexture> tex, CBox* pBox, CFramebuffer& matte) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!"); + RASSERT((tex->m_iTexID > 0), "Attempted to draw NULL texture!"); TRACY_GPU_ZONE("RenderTextureMatte"); @@ -1148,10 +1319,10 @@ void CHyprOpenGLImpl::renderTextureMatte(const CTexture& tex, CBox* pBox, CFrame glUniform1i(shader->alphaMatte, 1); glActiveTexture(GL_TEXTURE0); - glBindTexture(tex.m_iTarget, tex.m_iTexID); + glBindTexture(tex->m_iTarget, tex->m_iTexID); glActiveTexture(GL_TEXTURE0 + 1); - glBindTexture(matte.m_cTex.m_iTarget, matte.m_cTex.m_iTexID); + glBindTexture(matte.m_cTex->m_iTarget, matte.m_cTex->m_iTexID); glVertexAttribPointer(shader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); glVertexAttribPointer(shader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); @@ -1169,7 +1340,7 @@ void CHyprOpenGLImpl::renderTextureMatte(const CTexture& tex, CBox* pBox, CFrame glDisableVertexAttribArray(shader->posAttrib); glDisableVertexAttribArray(shader->texAttrib); - glBindTexture(tex.m_iTarget, 0); + glBindTexture(tex->m_iTarget, 0); } // This probably isn't the fastest @@ -1221,9 +1392,9 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glActiveTexture(GL_TEXTURE0); - glBindTexture(m_RenderData.currentFB->m_cTex.m_iTarget, m_RenderData.currentFB->m_cTex.m_iTexID); + glBindTexture(m_RenderData.currentFB->m_cTex->m_iTarget, m_RenderData.currentFB->m_cTex->m_iTexID); - glTexParameteri(m_RenderData.currentFB->m_cTex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(m_RenderData.currentFB->m_cTex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glUseProgram(m_RenderData.pCurrentMonData->m_shBLURPREPARE.program); @@ -1265,9 +1436,9 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glActiveTexture(GL_TEXTURE0); - glBindTexture(currentRenderToFB->m_cTex.m_iTarget, currentRenderToFB->m_cTex.m_iTexID); + glBindTexture(currentRenderToFB->m_cTex->m_iTarget, currentRenderToFB->m_cTex->m_iTexID); - glTexParameteri(currentRenderToFB->m_cTex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(currentRenderToFB->m_cTex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glUseProgram(pShader->program); @@ -1315,7 +1486,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o // draw the things. // first draw is swap -> mirr PMIRRORFB->bind(); - glBindTexture(PMIRRORSWAPFB->m_cTex.m_iTarget, PMIRRORSWAPFB->m_cTex.m_iTexID); + glBindTexture(PMIRRORSWAPFB->m_cTex->m_iTarget, PMIRRORSWAPFB->m_cTex->m_iTexID); // damage region will be scaled, make a temp CRegion tempDamage{damage}; @@ -1343,9 +1514,9 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glActiveTexture(GL_TEXTURE0); - glBindTexture(currentRenderToFB->m_cTex.m_iTarget, currentRenderToFB->m_cTex.m_iTexID); + glBindTexture(currentRenderToFB->m_cTex->m_iTarget, currentRenderToFB->m_cTex->m_iTexID); - glTexParameteri(currentRenderToFB->m_cTex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(currentRenderToFB->m_cTex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glUseProgram(m_RenderData.pCurrentMonData->m_shBLURFINISH.program); @@ -1383,7 +1554,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o } // finish - glBindTexture(PMIRRORFB->m_cTex.m_iTarget, 0); + glBindTexture(PMIRRORFB->m_cTex->m_iTarget, 0); blend(BLENDBEFORE); @@ -1417,23 +1588,23 @@ void CHyprOpenGLImpl::preRender(CMonitor* pMonitor) { if (pWindow->m_sAdditionalConfigData.forceNoBlur) return false; - if (pWindow->m_pWLSurface.small() && !pWindow->m_pWLSurface.m_bFillIgnoreSmall) + if (pWindow->m_pWLSurface->small() && !pWindow->m_pWLSurface->m_bFillIgnoreSmall) return true; - const auto PSURFACE = pWindow->m_pWLSurface.wlr(); + const auto PSURFACE = pWindow->m_pWLSurface->resource(); const auto PWORKSPACE = pWindow->m_pWorkspace; const float A = pWindow->m_fAlpha.value() * pWindow->m_fActiveInactiveAlpha.value() * PWORKSPACE->m_fAlpha.value(); if (A >= 1.f) { - if (PSURFACE->opaque) - return false; + // if (PSURFACE->opaque) + // return false; CRegion inverseOpaque; - pixman_box32_t surfbox = {0, 0, PSURFACE->current.width, PSURFACE->current.height}; - CRegion opaqueRegion{&PSURFACE->current.opaque}; - inverseOpaque.set(opaqueRegion).invert(&surfbox).intersect(0, 0, PSURFACE->current.width, PSURFACE->current.height); + pixman_box32_t surfbox = {0, 0, PSURFACE->current.size.x, PSURFACE->current.size.y}; + CRegion opaqueRegion{PSURFACE->current.opaque}; + inverseOpaque.set(opaqueRegion).invert(&surfbox).intersect(0, 0, PSURFACE->current.size.x, PSURFACE->current.size.y); if (inverseOpaque.empty()) return false; @@ -1461,8 +1632,8 @@ void CHyprOpenGLImpl::preRender(CMonitor* pMonitor) { if (!ls->layerSurface || ls->xray != 1) continue; - if (ls->layerSurface->surface->opaque && ls->alpha.value() >= 1.f) - continue; + // if (ls->layerSurface->surface->opaque && ls->alpha.value() >= 1.f) + // continue; hasWindows = true; break; @@ -1527,7 +1698,7 @@ bool CHyprOpenGLImpl::shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWin static auto PBLURNEWOPTIMIZE = CConfigValue<Hyprlang::INT>("decoration:blur:new_optimizations"); static auto PBLURXRAY = CConfigValue<Hyprlang::INT>("decoration:blur:xray"); - if (!m_RenderData.pCurrentMonData->blurFB.m_cTex.m_iTexID) + if (!m_RenderData.pCurrentMonData->blurFB.m_cTex->m_iTexID) return false; if (pWindow && pWindow->m_sAdditionalConfigData.xray.toUnderlying() == 0) @@ -1545,7 +1716,7 @@ bool CHyprOpenGLImpl::shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWin return false; } -void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, CBox* pBox, float a, wlr_surface* pSurface, int round, bool blockBlurOptimization, float blurA) { +void CHyprOpenGLImpl::renderTextureWithBlur(SP<CTexture> tex, CBox* pBox, float a, SP<CWLSurfaceResource> pSurface, int round, bool blockBlurOptimization, float blurA) { RASSERT(m_RenderData.pMonitor, "Tried to render texture with blur without begin()!"); static auto PBLURENABLED = CConfigValue<Hyprlang::INT>("decoration:blur:enabled"); @@ -1570,11 +1741,11 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, CBox* pBox, flo // amazing hack: the surface has an opaque region! CRegion inverseOpaque; - if (a >= 1.f && std::round(pSurface->current.width * m_RenderData.pMonitor->scale) == pBox->w && - std::round(pSurface->current.height * m_RenderData.pMonitor->scale) == pBox->h) { - pixman_box32_t surfbox = {0, 0, pSurface->current.width * pSurface->current.scale, pSurface->current.height * pSurface->current.scale}; - inverseOpaque = &pSurface->current.opaque; - inverseOpaque.invert(&surfbox).intersect(0, 0, pSurface->current.width * pSurface->current.scale, pSurface->current.height * pSurface->current.scale); + if (a >= 1.f && std::round(pSurface->current.size.x * m_RenderData.pMonitor->scale) == pBox->w && + std::round(pSurface->current.size.y * m_RenderData.pMonitor->scale) == pBox->h) { + pixman_box32_t surfbox = {0, 0, pSurface->current.size.x * pSurface->current.scale, pSurface->current.size.y * pSurface->current.scale}; + inverseOpaque = pSurface->current.opaque; + inverseOpaque.invert(&surfbox).intersect(0, 0, pSurface->current.size.x * pSurface->current.scale, pSurface->current.size.y * pSurface->current.scale); if (inverseOpaque.empty()) { renderTexture(tex, pBox, a, round, false, true); @@ -1765,7 +1936,7 @@ void CHyprOpenGLImpl::makeRawWindowSnapshot(PHLWINDOW pWindow, CFramebuffer* pFr g_pHyprRenderer->makeEGLCurrent(); - pFramebuffer->m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; + pFramebuffer->m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; pFramebuffer->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->drmFormat); @@ -1903,7 +2074,7 @@ void CHyprOpenGLImpl::renderSnapshot(PHLWINDOW pWindow) { const auto FBDATA = &m_mWindowFramebuffers.at(ref); - if (!FBDATA->m_cTex.m_iTexID) + if (!FBDATA->m_cTex->m_iTexID) return; const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); @@ -1942,7 +2113,7 @@ void CHyprOpenGLImpl::renderSnapshot(PHLLS pLayer) { const auto FBDATA = &m_mLayerFramebuffers.at(pLayer); - if (!FBDATA->m_cTex.m_iTexID) + if (!FBDATA->m_cTex->m_iTexID) return; const auto PMONITOR = g_pCompositor->getMonitorFromID(pLayer->monitorID); @@ -2077,7 +2248,7 @@ void CHyprOpenGLImpl::renderMirrored() { monbox.y = (monitor->vecTransformedSize.y - monbox.h) / 2; const auto PFB = &m_mMonitorRenderResources[mirrored].monitorMirrorFB; - if (!PFB->isAllocated() || PFB->m_cTex.m_iTexID <= 0) + if (!PFB->isAllocated() || PFB->m_cTex->m_iTexID <= 0) return; // replace monitor projection to undo the mirrored monitor's projection @@ -2179,12 +2350,12 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { } // create a new one with cairo - CTexture tex; + SP<CTexture> tex = makeShared<CTexture>(); - const auto CAIROISURFACE = cairo_image_surface_create_from_png(texPath.c_str()); - const auto CAIROFORMAT = cairo_image_surface_get_format(CAIROISURFACE); + const auto CAIROISURFACE = cairo_image_surface_create_from_png(texPath.c_str()); + const auto CAIROFORMAT = cairo_image_surface_get_format(CAIROISURFACE); - tex.allocate(); + tex->allocate(); const Vector2D IMAGESIZE = {cairo_image_surface_get_width(CAIROISURFACE), cairo_image_surface_get_height(CAIROISURFACE)}; // calc the target box @@ -2220,8 +2391,8 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { cairo_surface_flush(CAIROSURFACE); - CBox box = {origin.x, origin.y, IMAGESIZE.x * scale, IMAGESIZE.y * scale}; - tex.m_vSize = IMAGESIZE * scale; + CBox box = {origin.x, origin.y, IMAGESIZE.x * scale, IMAGESIZE.y * scale}; + tex->m_vSize = IMAGESIZE * scale; // copy the data to an OpenGL texture we have const GLint glIFormat = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? @@ -2235,7 +2406,7 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { const GLint glType = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_FLOAT : GL_UNSIGNED_BYTE; const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); - glBindTexture(GL_TEXTURE_2D, tex.m_iTexID); + glBindTexture(GL_TEXTURE_2D, tex->m_iTexID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); #ifndef GLES2 @@ -2244,7 +2415,7 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); } #endif - glTexImage2D(GL_TEXTURE_2D, 0, glIFormat, tex.m_vSize.x, tex.m_vSize.y, 0, glFormat, glType, DATA); + glTexImage2D(GL_TEXTURE_2D, 0, glIFormat, tex->m_vSize.x, tex->m_vSize.y, 0, glFormat, glType, DATA); cairo_surface_destroy(CAIROSURFACE); cairo_surface_destroy(CAIROISURFACE); @@ -2293,7 +2464,7 @@ void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) { RESIT->second.monitorMirrorFB.release(); RESIT->second.blurFB.release(); RESIT->second.offMainFB.release(); - RESIT->second.stencilTex.destroyTexture(); + RESIT->second.stencilTex->destroyTexture(); g_pHyprOpenGL->m_mMonitorRenderResources.erase(RESIT); } @@ -2343,109 +2514,6 @@ void CHyprOpenGLImpl::setRenderModifEnabled(bool enabled) { m_RenderData.renderModif.enabled = enabled; } -inline const SGLPixelFormat GLES2_FORMATS[] = { - { - .drmFormat = DRM_FORMAT_ARGB8888, - .glFormat = GL_BGRA_EXT, - .glType = GL_UNSIGNED_BYTE, - .withAlpha = true, - }, - { - .drmFormat = DRM_FORMAT_XRGB8888, - .glFormat = GL_BGRA_EXT, - .glType = GL_UNSIGNED_BYTE, - .withAlpha = false, - }, - { - .drmFormat = DRM_FORMAT_XBGR8888, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_BYTE, - .withAlpha = false, - }, - { - .drmFormat = DRM_FORMAT_ABGR8888, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_BYTE, - .withAlpha = true, - }, - { - .drmFormat = DRM_FORMAT_BGR888, - .glFormat = GL_RGB, - .glType = GL_UNSIGNED_BYTE, - .withAlpha = false, - }, -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - { - .drmFormat = DRM_FORMAT_RGBX4444, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_SHORT_4_4_4_4, - .withAlpha = false, - }, - { - .drmFormat = DRM_FORMAT_RGBA4444, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_SHORT_4_4_4_4, - .withAlpha = true, - }, - { - .drmFormat = DRM_FORMAT_RGBX5551, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_SHORT_5_5_5_1, - .withAlpha = false, - }, - { - .drmFormat = DRM_FORMAT_RGBA5551, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_SHORT_5_5_5_1, - .withAlpha = true, - }, - { - .drmFormat = DRM_FORMAT_RGB565, - .glFormat = GL_RGB, - .glType = GL_UNSIGNED_SHORT_5_6_5, - .withAlpha = false, - }, - { - .drmFormat = DRM_FORMAT_XBGR2101010, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_INT_2_10_10_10_REV_EXT, - .withAlpha = false, - }, - { - .drmFormat = DRM_FORMAT_ABGR2101010, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_INT_2_10_10_10_REV_EXT, - .withAlpha = true, - }, - { - .drmFormat = DRM_FORMAT_XBGR16161616F, - .glFormat = GL_RGBA, - .glType = GL_HALF_FLOAT_OES, - .withAlpha = false, - }, - { - .drmFormat = DRM_FORMAT_ABGR16161616F, - .glFormat = GL_RGBA, - .glType = GL_HALF_FLOAT_OES, - .withAlpha = true, - }, - { - .drmFormat = DRM_FORMAT_XBGR16161616, - .glInternalFormat = GL_RGBA16_EXT, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_SHORT, - .withAlpha = false, - }, - { - .drmFormat = DRM_FORMAT_ABGR16161616, - .glInternalFormat = GL_RGBA16_EXT, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_SHORT, - .withAlpha = true, - }, -#endif -}; - uint32_t CHyprOpenGLImpl::getPreferredReadFormat(CMonitor* pMonitor) { GLint glf = -1, glt = -1, as = 0; /*glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &glf); @@ -2453,14 +2521,12 @@ uint32_t CHyprOpenGLImpl::getPreferredReadFormat(CMonitor* pMonitor) { glGetIntegerv(GL_ALPHA_BITS, &as);*/ if (glf == 0 || glt == 0) { - glf = drmFormatToGL(pMonitor->drmFormat); - glt = glFormatToType(glf); + glf = FormatUtils::drmFormatToGL(pMonitor->drmFormat); + glt = FormatUtils::glFormatToType(glf); } - for (auto& fmt : GLES2_FORMATS) { - if (fmt.glFormat == glf && fmt.glType == glt && fmt.withAlpha == (as > 0)) - return fmt.drmFormat; - } + if (const auto FMT = FormatUtils::getPixelFormatFromGL(glf, glt, as > 0); FMT) + return FMT->drmFormat; if (m_sExts.EXT_read_format_bgra) return DRM_FORMAT_XRGB8888; @@ -2468,13 +2534,8 @@ uint32_t CHyprOpenGLImpl::getPreferredReadFormat(CMonitor* pMonitor) { return DRM_FORMAT_XBGR8888; } -const SGLPixelFormat* CHyprOpenGLImpl::getPixelFormatFromDRM(uint32_t drmFormat) { - for (auto& fmt : GLES2_FORMATS) { - if (fmt.drmFormat == drmFormat) - return &fmt; - } - - return nullptr; +std::vector<SDRMFormat> CHyprOpenGLImpl::getDRMFormats() { + return drmFormats; } void SRenderModifData::applyToBox(CBox& box) { diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index ca9eecc6..db0f8ea1 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -5,6 +5,7 @@ #include "../helpers/Color.hpp" #include "../helpers/Timer.hpp" #include "../helpers/Region.hpp" +#include "../helpers/Format.hpp" #include <list> #include <unordered_map> #include <map> @@ -54,14 +55,6 @@ struct SRenderModifData { bool enabled = true; }; -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, @@ -70,7 +63,7 @@ struct SMonitorRenderData { CFramebuffer monitorMirrorFB; // used for mirroring outputs, does not contain artifacts like offloadFB - CTexture stencilTex; + SP<CTexture> stencilTex = makeShared<CTexture>(); CFramebuffer blurFB; bool blurFBDirty = true; @@ -132,74 +125,73 @@ class CHyprOpenGLImpl { public: CHyprOpenGLImpl(); - void begin(CMonitor*, const CRegion& damage, CFramebuffer* fb = nullptr, std::optional<CRegion> finalDamage = {}); - void beginSimple(CMonitor*, const CRegion& damage, CRenderbuffer* rb = nullptr, CFramebuffer* fb = nullptr); - void end(); + void begin(CMonitor*, const CRegion& damage, CFramebuffer* fb = nullptr, std::optional<CRegion> finalDamage = {}); + void beginSimple(CMonitor*, const CRegion& damage, CRenderbuffer* rb = nullptr, CFramebuffer* fb = nullptr); + 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 renderTextureWithDamage(wlr_texture*, CBox*, CRegion* damage, 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 renderTextureWithDamage(const CTexture&, CBox*, CRegion* damage, 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 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(SP<CTexture>, CBox*, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false); + void renderTextureWithDamage(SP<CTexture>, CBox*, CRegion* damage, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false); + void renderTextureWithBlur(SP<CTexture>, CBox*, float a, SP<CWLSurfaceResource> 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(SP<CTexture> tex, CBox* pBox, CFramebuffer& matte); - void setMonitorTransformEnabled(bool enabled); - void setRenderModifEnabled(bool enabled); + void setMonitorTransformEnabled(bool enabled); + void setRenderModifEnabled(bool enabled); - void saveMatrix(); - void setMatrixScaleTranslate(const Vector2D& translate, const float& scale); - void restoreMatrix(); + void saveMatrix(); + void setMatrixScaleTranslate(const Vector2D& translate, const float& scale); + void restoreMatrix(); - void blend(bool enabled); + void blend(bool enabled); - void makeWindowSnapshot(PHLWINDOW); - void makeRawWindowSnapshot(PHLWINDOW, CFramebuffer*); - void makeLayerSnapshot(PHLLS); - void renderSnapshot(PHLWINDOW); - void renderSnapshot(PHLLS); - bool shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindow); + void makeWindowSnapshot(PHLWINDOW); + void makeRawWindowSnapshot(PHLWINDOW, CFramebuffer*); + void makeLayerSnapshot(PHLLS); + void renderSnapshot(PHLWINDOW); + void renderSnapshot(PHLLS); + bool shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW 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 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 destroyMonitorResources(CMonitor*); - void markBlurDirtyForMonitor(CMonitor*); + void markBlurDirtyForMonitor(CMonitor*); - void preWindowPass(); - bool preBlurQueued(); - void preRender(CMonitor*); + void preWindowPass(); + bool preBlurQueued(); + void preRender(CMonitor*); - void saveBufferForMirror(CBox*); - void renderMirrored(); + void saveBufferForMirror(CBox*); + void renderMirrored(); - void applyScreenShader(const std::string& path); + void applyScreenShader(const std::string& path); - void bindOffMain(); - void renderOffToMain(CFramebuffer* off); - void bindBackOnMain(); + void bindOffMain(); + void renderOffToMain(CFramebuffer* off); + void bindBackOnMain(); - void setDamage(const CRegion& damage, std::optional<CRegion> finalDamage = {}); + void setDamage(const CRegion& damage, std::optional<CRegion> finalDamage = {}); - uint32_t getPreferredReadFormat(CMonitor* pMonitor); - const SGLPixelFormat* getPixelFormatFromDRM(uint32_t drmFormat); + uint32_t getPreferredReadFormat(CMonitor* pMonitor); + std::vector<SDRMFormat> getDRMFormats(); + EGLImageKHR createEGLImage(const SDMABUFAttrs& attrs); - SCurrentRenderData m_RenderData; + SCurrentRenderData m_RenderData; - GLint m_iCurrentOutputFb = 0; + GLint m_iCurrentOutputFb = 0; - bool m_bReloadScreenShader = true; // at launch it can be set + bool m_bReloadScreenShader = true; // at launch it can be set - PHLWINDOWREF m_pCurrentWindow; // hack to get the current rendered window - PHLLS m_pCurrentLayer; // hack to get the current rendered layer + PHLWINDOWREF m_pCurrentWindow; // hack to get the current rendered window + PHLLS m_pCurrentLayer; // hack to get the current rendered layer std::map<PHLWINDOWREF, CFramebuffer> m_mWindowFramebuffers; std::map<PHLLSREF, CFramebuffer> m_mLayerFramebuffers; @@ -208,41 +200,52 @@ class CHyprOpenGLImpl { struct { PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES = nullptr; + PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = nullptr; + PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR = nullptr; PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = nullptr; + PFNEGLQUERYDMABUFFORMATSEXTPROC eglQueryDmaBufFormatsEXT = nullptr; + PFNEGLQUERYDMABUFMODIFIERSEXTPROC eglQueryDmaBufModifiersEXT = nullptr; } m_sProc; struct { - bool EXT_read_format_bgra = false; + bool EXT_read_format_bgra = false; + bool EXT_image_dma_buf_import = false; + bool EXT_image_dma_buf_import_modifiers = false; } m_sExts; private: - std::list<GLuint> m_lBuffers; - std::list<GLuint> m_lTextures; + std::list<GLuint> m_lBuffers; + std::list<GLuint> m_lTextures; + + std::vector<SDRMFormat> drmFormats; + bool m_bHasModifiers = false; - int m_iDRMFD; - std::string m_szExtensions; + 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; + 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; + 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(); + 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(); + void initDRMFormats(); + std::vector<uint64_t> getModsForFormat(EGLint format); // 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, + void renderTextureInternalWithDamage(SP<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 renderTexturePrimitive(SP<CTexture> tex, CBox* pBox); void renderSplash(cairo_t* const, cairo_surface_t* const, double offset, const Vector2D& size); void preBlurForCurrentMonitor(); diff --git a/src/render/Renderbuffer.cpp b/src/render/Renderbuffer.cpp index 5003f600..694485c2 100644 --- a/src/render/Renderbuffer.cpp +++ b/src/render/Renderbuffer.cpp @@ -1,6 +1,7 @@ #include "Renderbuffer.hpp" #include "OpenGL.hpp" #include "../Compositor.hpp" +#include "../protocols/types/Buffer.hpp" #include <dlfcn.h> @@ -61,6 +62,29 @@ CRenderbuffer::CRenderbuffer(wlr_buffer* buffer, uint32_t format) : m_pWlrBuffer &buffer->events.destroy, [this](void* owner, void* data) { g_pHyprRenderer->onRenderbufferDestroy(this); }, this, "CRenderbuffer"); } +CRenderbuffer::CRenderbuffer(SP<IWLBuffer> buffer, uint32_t format) : m_pHLBuffer(buffer), m_uDrmFormat(format) { + auto dma = buffer->dmabuf(); + + m_iImage = g_pHyprOpenGL->createEGLImage(dma); + if (m_iImage == EGL_NO_IMAGE_KHR) + throw std::runtime_error("createEGLImage failed"); + + glGenRenderbuffers(1, &m_iRBO); + glBindRenderbuffer(GL_RENDERBUFFER, m_iRBO); + g_pHyprOpenGL->m_sProc.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, (GLeglImageOES)m_iImage); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + glGenFramebuffers(1, &m_sFramebuffer.m_iFb); + m_sFramebuffer.m_vSize = buffer->size; + m_sFramebuffer.bind(); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_iRBO); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + throw std::runtime_error("rbo: glCheckFramebufferStatus failed"); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + void CRenderbuffer::bind() { glBindRenderbuffer(GL_RENDERBUFFER, m_iRBO); bindFB(); diff --git a/src/render/Renderbuffer.hpp b/src/render/Renderbuffer.hpp index 2a8bf250..ed7050c5 100644 --- a/src/render/Renderbuffer.hpp +++ b/src/render/Renderbuffer.hpp @@ -3,10 +3,12 @@ #include "Framebuffer.hpp" class CMonitor; +class IWLBuffer; class CRenderbuffer { public: CRenderbuffer(wlr_buffer* buffer, uint32_t format); + CRenderbuffer(SP<IWLBuffer> buffer, uint32_t format); ~CRenderbuffer(); void bind(); @@ -16,6 +18,7 @@ class CRenderbuffer { uint32_t getFormat(); wlr_buffer* m_pWlrBuffer = nullptr; + WP<IWLBuffer> m_pHLBuffer = {}; DYNLISTENER(destroyBuffer); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 40ae953e..2a6cbb3b 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1,6 +1,5 @@ #include "Renderer.hpp" #include "../Compositor.hpp" -#include "linux-dmabuf-unstable-v1-protocol.h" #include "../helpers/Region.hpp" #include <algorithm> #include "../config/ConfigValue.hpp" @@ -13,6 +12,7 @@ #include "../protocols/XDGShell.hpp" #include "../protocols/PresentationTime.hpp" #include "../protocols/core/DataDevice.hpp" +#include "../protocols/core/Compositor.hpp" extern "C" { #include <xf86drm.h> @@ -90,19 +90,24 @@ CHyprRenderer::CHyprRenderer() { wl_event_source_timer_update(m_pCursorTicker, 500); } -static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) { - const auto TEXTURE = wlr_surface_get_texture(surface); - const auto RDATA = (SRenderData*)data; - const auto INTERACTIVERESIZEINPROGRESS = RDATA->pWindow && g_pInputManager->currentlyDraggedWindow.lock() == RDATA->pWindow && g_pInputManager->dragMode == MBIND_RESIZE; +static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* data) { + if (!surface->current.buffer || !surface->current.buffer->texture) + return; + + const auto& TEXTURE = surface->current.buffer->texture; + const auto RDATA = (SRenderData*)data; + const auto INTERACTIVERESIZEINPROGRESS = RDATA->pWindow && g_pInputManager->currentlyDraggedWindow.lock() == RDATA->pWindow && g_pInputManager->dragMode == MBIND_RESIZE; - if (!TEXTURE) + // this is bad, probably has been logged elsewhere. Means the texture failed + // uploading to the GPU. + if (!TEXTURE->m_iTexID) return; TRACY_GPU_ZONE("RenderSurface"); double outputX = -RDATA->pMonitor->vecPosition.x, outputY = -RDATA->pMonitor->vecPosition.y; - auto* const PSURFACE = CWLSurface::surfaceFromWlr(surface); + auto PSURFACE = CWLSurface::fromResource(surface); const float ALPHA = RDATA->alpha * RDATA->fadeAlpha * (PSURFACE ? PSURFACE->m_pAlphaModifier : 1.F); @@ -140,7 +145,7 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) } } else { // here we clamp to 2, these might be some tiny specks - windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, std::max(surface->current.width, 2), std::max(surface->current.height, 2)}; + windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, std::max((float)surface->current.size.x, 2.F), std::max((float)surface->current.size.y, 2.F)}; if (RDATA->pWindow && RDATA->pWindow->m_vRealSize.isBeingAnimated() && RDATA->surface && RDATA->surface != surface && RDATA->squishOversized /* subsurface */) { // adjust subsurfaces to the window windowBox.width = (windowBox.width / RDATA->pWindow->m_vReportedSize.x) * RDATA->pWindow->m_vRealSize.value().x; @@ -155,15 +160,23 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) windowBox.height = RDATA->h - y; } - if (windowBox.width <= 1 || windowBox.height <= 1) + if (windowBox.width <= 1 || windowBox.height <= 1) { + if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) { + surface->frame(RDATA->when); + auto FEEDBACK = makeShared<CQueuedPresentationData>(surface); + FEEDBACK->attachMonitor(RDATA->pMonitor); + FEEDBACK->discarded(); + PROTO::presentation->queueData(FEEDBACK); + } return; // invisible + } windowBox.scale(RDATA->pMonitor->scale); windowBox.round(); const bool MISALIGNEDFSV1 = std::floor(RDATA->pMonitor->scale) != RDATA->pMonitor->scale /* Fractional */ && surface->current.scale == 1 /* fs protocol */ && - windowBox.size() != Vector2D{surface->current.buffer_width, surface->current.buffer_height} /* misaligned */ && - DELTALESSTHAN(windowBox.width, surface->current.buffer_width, 3) && DELTALESSTHAN(windowBox.height, surface->current.buffer_height, 3) /* off by one-or-two */ && + windowBox.size() != surface->current.buffer->size /* misaligned */ && DELTALESSTHAN(windowBox.width, surface->current.buffer->size.x, 3) && + DELTALESSTHAN(windowBox.height, surface->current.buffer->size.y, 3) /* off by one-or-two */ && (!RDATA->pWindow || (!RDATA->pWindow->m_vRealSize.isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */; g_pHyprRenderer->calculateUVForSurface(RDATA->pWindow, surface, RDATA->surface == surface, windowBox.size(), MISALIGNEDFSV1); @@ -183,8 +196,8 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) if (RDATA->dontRound) rounding = 0; - const bool WINDOWOPAQUE = RDATA->pWindow && RDATA->pWindow->m_pWLSurface.wlr() == surface ? RDATA->pWindow->opaque() : false; - const bool CANDISABLEBLEND = ALPHA >= 1.f && rounding == 0 && (WINDOWOPAQUE || surface->opaque); + const bool WINDOWOPAQUE = RDATA->pWindow && RDATA->pWindow->m_pWLSurface->resource() == surface ? RDATA->pWindow->opaque() : false; + const bool CANDISABLEBLEND = ALPHA >= 1.f && rounding == 0 && WINDOWOPAQUE; if (CANDISABLEBLEND) g_pHyprOpenGL->blend(false); @@ -195,16 +208,16 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) if (RDATA->blur) g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, surface, rounding, RDATA->blockBlurOptimization, RDATA->fadeAlpha); else - g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding, true); + g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding); } else { if (RDATA->blur && RDATA->popup) g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, surface, rounding, true, RDATA->fadeAlpha); else - g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding, true); + g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding); } if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) { - wlr_surface_send_frame_done(surface, RDATA->when); + surface->frame(RDATA->when); auto FEEDBACK = makeShared<CQueuedPresentationData>(surface); FEEDBACK->attachMonitor(RDATA->pMonitor); FEEDBACK->presented(); @@ -506,7 +519,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec if (ignoreAllGeometry) decorate = false; - renderdata.surface = pWindow->m_pWLSurface.wlr(); + renderdata.surface = pWindow->m_pWLSurface->resource(); renderdata.dontRound = (pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) || (!pWindow->m_sSpecialRenderData.rounding); renderdata.fadeAlpha = pWindow->m_fAlpha.value() * (pWindow->m_bPinned ? 1.f : PWORKSPACE->m_fAlpha.value()); renderdata.alpha = pWindow->m_fActiveInactiveAlpha.value(); @@ -576,7 +589,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec if ((pWindow->m_bIsX11 && *PXWLUSENN) || pWindow->m_sAdditionalConfigData.nearestNeighbor.toUnderlying()) g_pHyprOpenGL->m_RenderData.useNearestNeighbor = true; - if (!pWindow->m_sAdditionalConfigData.forceNoBlur && pWindow->m_pWLSurface.small() && !pWindow->m_pWLSurface.m_bFillIgnoreSmall && renderdata.blur && *PBLUR) { + if (!pWindow->m_sAdditionalConfigData.forceNoBlur && pWindow->m_pWLSurface->small() && !pWindow->m_pWLSurface->m_bFillIgnoreSmall && renderdata.blur && *PBLUR) { CBox wb = {renderdata.x - pMonitor->vecPosition.x, renderdata.y - pMonitor->vecPosition.y, renderdata.w, renderdata.h}; wb.scale(pMonitor->scale).round(); g_pHyprOpenGL->renderRectWithBlur(&wb, CColor(0, 0, 0, 0), renderdata.dontRound ? 0 : renderdata.rounding - 1, renderdata.fadeAlpha, @@ -584,7 +597,8 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec renderdata.blur = false; } - wlr_surface_for_each_surface(pWindow->m_pWLSurface.wlr(), renderSurface, &renderdata); + pWindow->m_pWLSurface->resource()->breadthfirst([](SP<CWLSurfaceResource> s, const Vector2D& offset, void* data) { renderSurface(s, offset.x, offset.y, data); }, + &renderdata); g_pHyprOpenGL->m_RenderData.useNearestNeighbor = false; @@ -641,14 +655,15 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec pWindow->m_pPopupHead->breadthfirst( [](CPopup* popup, void* data) { - if (!popup->m_sWLSurface.wlr()) + if (!popup->m_pWLSurface || !popup->m_pWLSurface->resource()) return; auto pos = popup->coordsRelativeToParent(); auto rd = (SRenderData*)data; Vector2D oldPos = {rd->x, rd->y}; rd->x += pos.x; rd->y += pos.y; - wlr_surface_for_each_surface(popup->m_sWLSurface.wlr(), renderSurface, rd); + popup->m_pWLSurface->resource()->breadthfirst([](SP<CWLSurfaceResource> s, const Vector2D& offset, void* data) { renderSurface(s, offset.x, offset.y, data); }, + data); rd->x = oldPos.x; rd->y = oldPos.y; }, @@ -698,7 +713,7 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, CMonitor* pMonitor, timespec* time SRenderData renderdata = {pMonitor, time, REALPOS.x, REALPOS.y}; renderdata.fadeAlpha = pLayer->alpha.value(); renderdata.blur = pLayer->forceBlur; - renderdata.surface = pLayer->layerSurface->surface; + renderdata.surface = pLayer->surface->resource(); renderdata.decorate = false; renderdata.w = REALSIZ.x; renderdata.h = REALSIZ.y; @@ -717,7 +732,7 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, CMonitor* pMonitor, timespec* time } if (!popups) - wlr_surface_for_each_surface(pLayer->layerSurface->surface, renderSurface, &renderdata); + pLayer->surface->resource()->breadthfirst([](SP<CWLSurfaceResource> s, const Vector2D& offset, void* data) { renderSurface(s, offset.x, offset.y, data); }, &renderdata); renderdata.squishOversized = false; // don't squish popups renderdata.dontRound = true; @@ -726,11 +741,11 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, CMonitor* pMonitor, timespec* time if (popups) { pLayer->popupHead->breadthfirst( [](CPopup* popup, void* data) { - if (!popup->m_sWLSurface.wlr()) + if (!popup->m_pWLSurface || !popup->m_pWLSurface->resource()) return; Vector2D pos = popup->coordsRelativeToParent(); - renderSurface(popup->m_sWLSurface.wlr(), pos.x, pos.y, data); + renderSurface(popup->m_pWLSurface->resource(), pos.x, pos.y, data); }, &renderdata); } @@ -746,15 +761,15 @@ void CHyprRenderer::renderIMEPopup(CInputPopup* pPopup, CMonitor* pMonitor, time SRenderData renderdata = {pMonitor, time, POS.x, POS.y}; - const auto SURF = pPopup->getWlrSurface(); + const auto SURF = pPopup->getSurface(); renderdata.blur = false; renderdata.surface = SURF; renderdata.decorate = false; - renderdata.w = SURF->current.width; - renderdata.h = SURF->current.height; + renderdata.w = SURF->current.size.x; + renderdata.h = SURF->current.size.y; - wlr_surface_for_each_surface(SURF, renderSurface, &renderdata); + SURF->breadthfirst([](SP<CWLSurfaceResource> s, const Vector2D& offset, void* data) { renderSurface(s, offset.x, offset.y, data); }, &renderdata); } void CHyprRenderer::renderSessionLockSurface(SSessionLockSurface* pSurface, CMonitor* pMonitor, timespec* time) { @@ -766,7 +781,7 @@ void CHyprRenderer::renderSessionLockSurface(SSessionLockSurface* pSurface, CMon renderdata.w = pMonitor->vecSize.x; renderdata.h = pMonitor->vecSize.y; - wlr_surface_for_each_surface(pSurface->surface->surface(), renderSurface, &renderdata); + renderdata.surface->breadthfirst([](SP<CWLSurfaceResource> s, const Vector2D& offset, void* data) { renderSurface(s, offset.x, offset.y, data); }, &renderdata); } void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* time, const Vector2D& translate, const float& scale) { @@ -966,17 +981,15 @@ void CHyprRenderer::renderLockscreen(CMonitor* pMonitor, timespec* now, const CB } } -void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, wlr_surface* pSurface, bool main, const Vector2D& projSize, bool fixMisalignedFSV1) { +void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface, bool main, const Vector2D& projSize, bool fixMisalignedFSV1) { if (!pWindow || !pWindow->m_bIsX11) { Vector2D uvTL; Vector2D uvBR = Vector2D(1, 1); - if (pSurface->current.viewport.has_src) { + if (pSurface->current.viewport.hasSource) { // we stretch it to dest. if no dest, to 1,1 - wlr_fbox bufferSource; - wlr_surface_get_buffer_source_box(pSurface, &bufferSource); - - Vector2D bufferSize = Vector2D(pSurface->buffer->texture->width, pSurface->buffer->texture->height); + Vector2D bufferSize = pSurface->current.buffer->size; + auto bufferSource = pSurface->current.viewport.source; // calculate UV for the basic src_box. Assume dest == size. Scale to dest later uvTL = Vector2D(bufferSource.x / bufferSize.x, bufferSource.y / bufferSize.y); @@ -991,8 +1004,8 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, wlr_surface* pSurfa if (projSize != Vector2D{} && fixMisalignedFSV1) { // instead of nearest_neighbor (we will repeat / skip) // just cut off / expand surface - const Vector2D PIXELASUV = Vector2D{1, 1} / Vector2D{pSurface->buffer->texture->width, pSurface->buffer->texture->height}; - const Vector2D MISALIGNMENT = Vector2D{pSurface->buffer->texture->width, pSurface->buffer->texture->height} - projSize; + const Vector2D PIXELASUV = Vector2D{1, 1} / pSurface->current.buffer->size; + const Vector2D MISALIGNMENT = pSurface->current.buffer->size - projSize; if (MISALIGNMENT != Vector2D{}) uvBR -= MISALIGNMENT * PIXELASUV; } @@ -1013,10 +1026,10 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, wlr_surface* pSurfa // ignore X and Y, adjust uv if (geom.x != 0 || geom.y != 0 || geom.width > pWindow->m_vRealSize.value().x || geom.height > pWindow->m_vRealSize.value().y) { - const auto XPERC = (double)geom.x / (double)pSurface->current.width; - const auto YPERC = (double)geom.y / (double)pSurface->current.height; - const auto WPERC = (double)(geom.x + geom.width) / (double)pSurface->current.width; - const auto HPERC = (double)(geom.y + geom.height) / (double)pSurface->current.height; + const auto XPERC = (double)geom.x / (double)pSurface->current.size.x; + const auto YPERC = (double)geom.y / (double)pSurface->current.size.y; + const auto WPERC = (double)(geom.x + geom.width) / (double)pSurface->current.size.x; + const auto HPERC = (double)(geom.y + geom.height) / (double)pSurface->current.size.y; const auto TOADDTL = Vector2D(XPERC * (uvBR.x - uvTL.x), YPERC * (uvBR.y - uvTL.y)); uvBR = uvBR - Vector2D(1.0 - WPERC * (uvBR.x - uvTL.x), 1.0 - HPERC * (uvBR.y - uvTL.y)); @@ -1025,8 +1038,8 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, wlr_surface* pSurfa // TODO: make this passed to the func. Might break in the future. auto maxSize = pWindow->m_vRealSize.value(); - if (pWindow->m_pWLSurface.small() && !pWindow->m_pWLSurface.m_bFillIgnoreSmall) - maxSize = pWindow->m_pWLSurface.getViewporterCorrectedSize(); + if (pWindow->m_pWLSurface->small() && !pWindow->m_pWLSurface->m_bFillIgnoreSmall) + maxSize = pWindow->m_pWLSurface->getViewporterCorrectedSize(); if (geom.width > maxSize.x) uvBR.x = uvBR.x * (maxSize.x / geom.width); @@ -1048,53 +1061,51 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, wlr_surface* pSurfa } } -void countSubsurfacesIter(wlr_surface* pSurface, int x, int y, void* data) { - *(int*)data += 1; -} - bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) { - if (!pMonitor->mirrors.empty() || pMonitor->isMirror() || m_bDirectScanoutBlocked) - return false; // do not DS if this monitor is being mirrored. Will break the functionality. + return false; // FIXME: fix when we move to new lib for backend. - if (!wlr_output_is_direct_scanout_allowed(pMonitor->output)) - return false; + // if (!pMonitor->mirrors.empty() || pMonitor->isMirror() || m_bDirectScanoutBlocked) + // return false; // do not DS if this monitor is being mirrored. Will break the functionality. - const auto PCANDIDATE = pMonitor->solitaryClient.lock(); + // if (!wlr_output_is_direct_scanout_allowed(pMonitor->output)) + // return false; - if (!PCANDIDATE) - return false; + // const auto PCANDIDATE = pMonitor->solitaryClient.lock(); - const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE); + // if (!PCANDIDATE) + // return false; - if (!PSURFACE || PSURFACE->current.scale != pMonitor->output->scale || PSURFACE->current.transform != pMonitor->output->transform) - return false; + // const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE); - // finally, we should be GTG. - wlr_output_state_set_buffer(pMonitor->state.wlr(), &PSURFACE->buffer->base); + // if (!PSURFACE || PSURFACE->current.scale != pMonitor->output->scale || PSURFACE->current.transform != pMonitor->output->transform) + // return false; - if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) - return false; + // // finally, we should be GTG. + // wlr_output_state_set_buffer(pMonitor->state.wlr(), &PSURFACE->buffer->base); - timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - wlr_surface_send_frame_done(PSURFACE, &now); - auto FEEDBACK = makeShared<CQueuedPresentationData>(PSURFACE); - FEEDBACK->attachMonitor(pMonitor); - FEEDBACK->presented(); - FEEDBACK->setPresentationType(true); - PROTO::presentation->queueData(FEEDBACK); - - if (pMonitor->state.commit()) { - if (m_pLastScanout.expired()) { - m_pLastScanout = PCANDIDATE; - Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle); - } - } else { - m_pLastScanout.reset(); - return false; - } + // if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) + // return false; - return true; + // timespec now; + // clock_gettime(CLOCK_MONOTONIC, &now); + // PSURFACE->frame(&now); + // auto FEEDBACK = makeShared<CQueuedPresentationData>(PSURFACE); + // FEEDBACK->attachMonitor(pMonitor); + // FEEDBACK->presented(); + // FEEDBACK->setPresentationType(true); + // PROTO::presentation->queueData(FEEDBACK); + + // if (pMonitor->state.commit()) { + // if (m_pLastScanout.expired()) { + // m_pLastScanout = PCANDIDATE; + // Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle); + // } + // } else { + // m_pLastScanout.reset(); + // return false; + // } + + // return true; } void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { @@ -1430,53 +1441,52 @@ void CHyprRenderer::renderWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, void CHyprRenderer::sendFrameEventsToWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now) { for (auto& w : g_pCompositor->m_vWindows) { - if (w->isHidden() || !w->m_bIsMapped || w->m_bFadingOut || !w->m_pWLSurface.wlr()) + if (w->isHidden() || !w->m_bIsMapped || w->m_bFadingOut || !w->m_pWLSurface->resource()) continue; if (!shouldRenderWindow(w, pMonitor)) continue; - wlr_surface_for_each_surface( - w->m_pWLSurface.wlr(), [](wlr_surface* s, int x, int y, void* data) { wlr_surface_send_frame_done(s, (timespec*)data); }, now); + w->m_pWLSurface->resource()->breadthfirst([now](SP<CWLSurfaceResource> r, const Vector2D& offset, void* d) { r->frame(now); }, nullptr); } for (auto& lsl : pMonitor->m_aLayerSurfaceLayers) { for (auto& ls : lsl) { - if (ls->fadingOut || !ls->surface.wlr()) + if (ls->fadingOut || !ls->surface->resource()) continue; - wlr_surface_for_each_surface( - ls->surface.wlr(), [](wlr_surface* s, int x, int y, void* data) { wlr_surface_send_frame_done(s, (timespec*)data); }, now); + ls->surface->resource()->breadthfirst([now](SP<CWLSurfaceResource> r, const Vector2D& offset, void* d) { r->frame(now); }, nullptr); } } } void CHyprRenderer::setWindowScanoutMode(PHLWINDOW pWindow) { - if (!g_pCompositor->m_sWLRLinuxDMABuf || g_pSessionLockManager->isSessionLocked()) - return; + // FIXME: fix when moved to new impl + // if (!g_pCompositor->m_sWLRLinuxDMABuf || g_pSessionLockManager->isSessionLocked()) + // return; - if (!pWindow->m_bIsFullscreen) { - wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, pWindow->m_pWLSurface.wlr(), nullptr); - Debug::log(LOG, "Scanout mode OFF set for {}", pWindow); - return; - } + // if (!pWindow->m_bIsFullscreen) { + // wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, pWindow->m_pWLSurface->resource(), nullptr); + // Debug::log(LOG, "Scanout mode OFF set for {}", pWindow); + // return; + // } - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + // const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); - const wlr_linux_dmabuf_feedback_v1_init_options INIT_OPTIONS = { - .main_renderer = g_pCompositor->m_sWLRRenderer, - .scanout_primary_output = PMONITOR->output, - }; + // const wlr_linux_dmabuf_feedback_v1_init_options INIT_OPTIONS = { + // .main_renderer = g_pCompositor->m_sWLRRenderer, + // .scanout_primary_output = PMONITOR->output, + // }; - wlr_linux_dmabuf_feedback_v1 feedback = {0}; + // wlr_linux_dmabuf_feedback_v1 feedback = {0}; - if (!wlr_linux_dmabuf_feedback_v1_init_with_options(&feedback, &INIT_OPTIONS)) - return; + // if (!wlr_linux_dmabuf_feedback_v1_init_with_options(&feedback, &INIT_OPTIONS)) + // return; - wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, pWindow->m_pWLSurface.wlr(), &feedback); - wlr_linux_dmabuf_feedback_v1_finish(&feedback); + // wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, pWindow->m_pWLSurface->resource(), &feedback); + // wlr_linux_dmabuf_feedback_v1_finish(&feedback); - Debug::log(LOG, "Scanout mode ON set for {}", pWindow); + // Debug::log(LOG, "Scanout mode ON set for {}", pWindow); } // taken from Sway. @@ -1662,26 +1672,25 @@ void CHyprRenderer::arrangeLayersForMonitor(const int& monitor) { g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitor); } -void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y, double scale) { +void CHyprRenderer::damageSurface(SP<CWLSurfaceResource> pSurface, double x, double y, double scale) { if (!pSurface) return; // wut? if (g_pCompositor->m_bUnsafeState) return; - const auto WLSURF = CWLSurface::surfaceFromWlr(pSurface); + const auto WLSURF = CWLSurface::fromResource(pSurface); CRegion damageBox = WLSURF ? WLSURF->logicalDamage() : CRegion{}; if (!WLSURF) { Debug::log(ERR, "BUG THIS: No CWLSurface for surface in damageSurface!!!"); - wlr_surface_get_effective_damage(pSurface, damageBox.pixman()); + return; } if (scale != 1.0) damageBox.scale(scale); // schedule frame events - if (!wl_list_empty(&pSurface->current.frame_callback_list)) - g_pCompositor->scheduleFrameForMonitor(g_pCompositor->getMonitorFromVector(Vector2D(x, y))); + g_pCompositor->scheduleFrameForMonitor(g_pCompositor->getMonitorFromVector(Vector2D(x, y))); if (damageBox.empty()) return; @@ -1836,7 +1845,6 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR pMonitor->onDisconnect(); pMonitor->events.modeChanged.emit(); - pMonitor->updateGlobal(); return true; } @@ -2242,12 +2250,11 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR EMIT_HOOK_EVENT("monitorLayoutChanged", nullptr); pMonitor->events.modeChanged.emit(); - pMonitor->updateGlobal(); return true; } -void CHyprRenderer::setCursorSurface(CWLSurface* surf, int hotspotX, int hotspotY, bool force) { +void CHyprRenderer::setCursorSurface(SP<CWLSurface> surf, int hotspotX, int hotspotY, bool force) { m_bCursorHasSurface = surf; m_sLastCursorData.name = ""; @@ -2464,8 +2471,8 @@ bool CHyprRenderer::canSkipBackBufferClear(CMonitor* pMonitor) { continue; // TODO: cache maybe? - CRegion opaque = &ls->layerSurface->surface->opaque_region; - CBox lsbox = {0, 0, ls->layerSurface->surface->current.buffer_width, ls->layerSurface->surface->current.buffer_height}; + CRegion opaque = ls->layerSurface->surface->current.opaque; + CBox lsbox = {{}, ls->layerSurface->surface->current.size}; opaque.invert(lsbox); if (!opaque.empty()) @@ -2544,6 +2551,15 @@ CRenderbuffer* CHyprRenderer::getOrCreateRenderbuffer(wlr_buffer* buffer, uint32 return m_vRenderbuffers.emplace_back(std::make_unique<CRenderbuffer>(buffer, fmt)).get(); } +CRenderbuffer* CHyprRenderer::getOrCreateRenderbuffer(SP<IWLBuffer> buffer, uint32_t fmt) { + auto it = std::find_if(m_vRenderbuffers.begin(), m_vRenderbuffers.end(), [&](const auto& other) { return other->m_pHLBuffer == buffer; }); + + if (it != m_vRenderbuffers.end()) + return it->get(); + + return m_vRenderbuffers.emplace_back(std::make_unique<CRenderbuffer>(buffer, fmt)).get(); +} + void CHyprRenderer::makeEGLCurrent() { if (!g_pCompositor) return; @@ -2556,7 +2572,7 @@ void CHyprRenderer::unsetEGL() { eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } -bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, wlr_buffer* buffer, CFramebuffer* fb, bool simple) { +bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, SP<IWLBuffer> buffer, CFramebuffer* fb, bool simple) { makeEGLCurrent(); @@ -2586,10 +2602,13 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode return false; } } else - m_pCurrentWlrBuffer = wlr_buffer_lock(buffer); + m_pCurrentHLBuffer = buffer; try { - m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentWlrBuffer, pMonitor->drmFormat); + if (m_pCurrentWlrBuffer) + m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentWlrBuffer, pMonitor->drmFormat); + else + m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentHLBuffer.lock(), pMonitor->drmFormat); } catch (std::exception& e) { Debug::log(ERR, "getOrCreateRenderbuffer failed for {}", pMonitor->szName); wlr_buffer_unlock(m_pCurrentWlrBuffer); diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index da38fed2..f88bfebf 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -12,6 +12,7 @@ struct SMonitorRule; class CWorkspace; class CWindow; class CInputPopup; +class IWLBuffer; // TODO: add fuller damage tracking for updating only parts of a window enum DAMAGETRACKINGMODES { @@ -44,7 +45,7 @@ class CHyprRenderer { void renderMonitor(CMonitor* pMonitor); void arrangeLayersForMonitor(const int&); - void damageSurface(wlr_surface*, double, double, double scale = 1.0); + void damageSurface(SP<CWLSurfaceResource>, double, double, double scale = 1.0); void damageWindow(PHLWINDOW, bool forceFull = false); void damageBox(CBox*); void damageBox(const int& x, const int& y, const int& w, const int& h); @@ -57,14 +58,14 @@ class CHyprRenderer { void ensureCursorRenderingMode(); bool shouldRenderCursor(); void setCursorHidden(bool hide); - void calculateUVForSurface(PHLWINDOW, wlr_surface*, bool main = false, const Vector2D& projSize = {}, bool fixMisalignedFSV1 = false); + void calculateUVForSurface(PHLWINDOW, SP<CWLSurfaceResource>, bool main = false, const Vector2D& projSize = {}, bool fixMisalignedFSV1 = false); std::tuple<float, float, float> getRenderTimes(CMonitor* pMonitor); // avg max min void renderLockscreen(CMonitor* pMonitor, timespec* now, const CBox& geometry); void setOccludedForBackLayers(CRegion& region, PHLWORKSPACE pWorkspace); void setOccludedForMainWorkspace(CRegion& region, PHLWORKSPACE pWorkspace); // TODO: merge occlusion methods bool canSkipBackBufferClear(CMonitor* pMonitor); void recheckSolitaryForMonitor(CMonitor* pMonitor); - void setCursorSurface(CWLSurface* surf, int hotspotX, int hotspotY, bool force = false); + void setCursorSurface(SP<CWLSurface> surf, int hotspotX, int hotspotY, bool force = false); void setCursorFromName(const std::string& name, bool force = false); void onRenderbufferDestroy(CRenderbuffer* rb); CRenderbuffer* getCurrentRBO(); @@ -74,7 +75,7 @@ class CHyprRenderer { // if RENDER_MODE_NORMAL, provided damage will be written to. // otherwise, it will be the one used. - bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, wlr_buffer* buffer = nullptr, CFramebuffer* fb = nullptr, bool simple = false); + bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP<IWLBuffer> buffer = {}, CFramebuffer* fb = nullptr, bool simple = false); void endRender(); bool m_bBlockSurfaceFeedback = false; @@ -98,10 +99,10 @@ class CHyprRenderer { CTimer m_tRenderTimer; struct { - int hotspotX; - int hotspotY; - std::optional<CWLSurface*> surf = nullptr; - std::string name; + int hotspotX; + int hotspotY; + std::optional<SP<CWLSurface>> surf; + std::string name; } m_sLastCursorData; private: @@ -121,6 +122,7 @@ class CHyprRenderer { bool m_bCursorHasSurface = false; CRenderbuffer* m_pCurrentRenderbuffer = nullptr; wlr_buffer* m_pCurrentWlrBuffer = nullptr; + WP<IWLBuffer> m_pCurrentHLBuffer = {}; eRenderMode m_eRenderMode = RENDER_MODE_NORMAL; bool m_bNvidia = false; @@ -132,6 +134,7 @@ class CHyprRenderer { } m_sCursorHiddenConditions; CRenderbuffer* getOrCreateRenderbuffer(wlr_buffer* buffer, uint32_t fmt); + CRenderbuffer* getOrCreateRenderbuffer(SP<IWLBuffer> buffer, uint32_t fmt); std::vector<std::unique_ptr<CRenderbuffer>> m_vRenderbuffers; friend class CHyprOpenGLImpl; diff --git a/src/render/Texture.cpp b/src/render/Texture.cpp index 1820d0fb..aef8e4ac 100644 --- a/src/render/Texture.cpp +++ b/src/render/Texture.cpp @@ -1,16 +1,54 @@ #include "Texture.hpp" +#include "Renderer.hpp" +#include "../Compositor.hpp" +#include "../protocols/types/Buffer.hpp" +#include "../helpers/Format.hpp" CTexture::CTexture() { // naffin' } +CTexture::~CTexture() { + if (m_bNonOwning) + return; + + g_pHyprRenderer->makeEGLCurrent(); + destroyTexture(); +} + +CTexture::CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size_) { + g_pHyprRenderer->makeEGLCurrent(); + + const auto format = FormatUtils::getPixelFormatFromDRM(drmFormat); + ASSERT(format); + + m_iType = format->withAlpha ? TEXTURE_RGBA : TEXTURE_RGBX; + m_vSize = size_; + allocate(); + + GLCALL(glBindTexture(GL_TEXTURE_2D, m_iTexID)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); +#ifndef GLES2 + if (format->flipRB) { + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED)); + } +#endif + GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / format->bytesPerBlock)); + GLCALL(glTexImage2D(GL_TEXTURE_2D, 0, format->glInternalFormat ? format->glInternalFormat : format->glFormat, size_.x, size_.y, 0, format->glFormat, format->glType, pixels)); + GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0)); + GLCALL(glBindTexture(GL_TEXTURE_2D, 0)); +} + CTexture::CTexture(wlr_texture* tex) { RASSERT(wlr_texture_is_gles2(tex), "wlr_texture provided to CTexture that isn't GLES2!"); wlr_gles2_texture_attribs attrs; wlr_gles2_texture_get_attribs(tex, &attrs); - m_iTarget = attrs.target; - m_iTexID = attrs.tex; + m_iTarget = attrs.target; + m_iTexID = attrs.tex; + m_bNonOwning = true; if (m_iTarget == GL_TEXTURE_2D) m_iType = attrs.has_alpha ? TEXTURE_RGBA : TEXTURE_RGBX; @@ -20,14 +58,72 @@ CTexture::CTexture(wlr_texture* tex) { m_vSize = Vector2D(tex->width, tex->height); } +CTexture::CTexture(const SDMABUFAttrs& attrs, void* image) { + if (!g_pHyprOpenGL->m_sProc.glEGLImageTargetTexture2DOES) { + Debug::log(ERR, "Cannot create a dmabuf texture: no glEGLImageTargetTexture2DOES"); + return; + } + + m_iTarget = GL_TEXTURE_2D; + m_iType = TEXTURE_RGBA; + m_vSize = attrs.size; + m_iType = FormatUtils::isFormatOpaque(attrs.format) ? TEXTURE_RGBX : TEXTURE_RGBA; + allocate(); + m_pEglImage = image; + + GLCALL(glBindTexture(GL_TEXTURE_2D, m_iTexID)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + GLCALL(g_pHyprOpenGL->m_sProc.glEGLImageTargetTexture2DOES(m_iTarget, image)); + GLCALL(glBindTexture(GL_TEXTURE_2D, 0)); +} + +void CTexture::update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage) { + g_pHyprRenderer->makeEGLCurrent(); + + const auto format = FormatUtils::getPixelFormatFromDRM(drmFormat); + ASSERT(format); + + glBindTexture(GL_TEXTURE_2D, m_iTexID); + + auto rects = damage.copy().intersect(CBox{{}, m_vSize}).getRects(); + +#ifndef GLES2 + if (format->flipRB) { + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED)); + } +#endif + + for (auto& rect : rects) { + GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / format->bytesPerBlock)); + GLCALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, rect.x1)); + GLCALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, rect.y1)); + + int width = rect.x2 - rect.x1; + int height = rect.y2 - rect.y1; + GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x1, rect.y1, width, height, format->glFormat, format->glType, pixels)); + } + + GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0)); + GLCALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0)); + GLCALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0)); + + glBindTexture(GL_TEXTURE_2D, 0); +} + void CTexture::destroyTexture() { if (m_iTexID) { - glDeleteTextures(1, &m_iTexID); + GLCALL(glDeleteTextures(1, &m_iTexID)); m_iTexID = 0; } + + if (m_pEglImage) + g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), m_pEglImage); + m_pEglImage = nullptr; } void CTexture::allocate() { if (!m_iTexID) - glGenTextures(1, &m_iTexID); -}
\ No newline at end of file + GLCALL(glGenTextures(1, &m_iTexID)); +} diff --git a/src/render/Texture.hpp b/src/render/Texture.hpp index 93a6aa5f..fa1ca4fe 100644 --- a/src/render/Texture.hpp +++ b/src/render/Texture.hpp @@ -2,6 +2,10 @@ #include "../defines.hpp" +class IWLBuffer; +struct SDMABUFAttrs; +class CRegion; + enum TEXTURETYPE { TEXTURE_INVALID, // Invalid TEXTURE_RGBA, // 4 channels @@ -12,13 +16,27 @@ enum TEXTURETYPE { class CTexture { public: CTexture(); + + CTexture(CTexture&) = delete; + CTexture(CTexture&&) = delete; + CTexture(const CTexture&&) = delete; + CTexture(const CTexture&) = delete; + + CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size); CTexture(wlr_texture*); + // this ctor takes ownership of the eglImage. + CTexture(const SDMABUFAttrs&, void* image); + ~CTexture(); + void destroyTexture(); void allocate(); + void update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage); TEXTURETYPE m_iType = TEXTURE_RGBA; GLenum m_iTarget = GL_TEXTURE_2D; GLuint m_iTexID = 0; Vector2D m_vSize; + void* m_pEglImage = nullptr; + bool m_bNonOwning = false; // wlr };
\ No newline at end of file diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 04f69aaa..d96f2c3c 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -6,23 +6,23 @@ #include <pango/pangocairo.h> // shared things to conserve VRAM -static CTexture m_tGradientActive; -static CTexture m_tGradientInactive; -static CTexture m_tGradientLockedActive; -static CTexture m_tGradientLockedInactive; +static SP<CTexture> m_tGradientActive = makeShared<CTexture>(); +static SP<CTexture> m_tGradientInactive = makeShared<CTexture>(); +static SP<CTexture> m_tGradientLockedActive = makeShared<CTexture>(); +static SP<CTexture> m_tGradientLockedInactive = makeShared<CTexture>(); -constexpr int BAR_INDICATOR_HEIGHT = 3; -constexpr int BAR_PADDING_OUTER_VERT = 2; -constexpr int BAR_PADDING_OUTER_HORZ = 2; -constexpr int BAR_TEXT_PAD = 2; -constexpr int BAR_HORIZONTAL_PADDING = 2; +constexpr int BAR_INDICATOR_HEIGHT = 3; +constexpr int BAR_PADDING_OUTER_VERT = 2; +constexpr int BAR_PADDING_OUTER_HORZ = 2; +constexpr int BAR_TEXT_PAD = 2; +constexpr int BAR_HORIZONTAL_PADDING = 2; CHyprGroupBarDecoration::CHyprGroupBarDecoration(PHLWINDOW pWindow) : IHyprWindowDecoration(pWindow) { static auto PGRADIENTS = CConfigValue<Hyprlang::INT>("group:groupbar:enabled"); static auto PENABLED = CConfigValue<Hyprlang::INT>("group:groupbar:gradients"); m_pWindow = pWindow; - if (m_tGradientActive.m_iTexID == 0 && *PENABLED && *PGRADIENTS) + if (m_tGradientActive->m_iTexID == 0 && *PENABLED && *PGRADIENTS) refreshGroupBarGradients(); } @@ -157,10 +157,9 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) { rect.scale(pMonitor->scale); if (*PGRADIENTS) { - const auto& GRADIENTTEX = - (m_dwGroupMembers[WINDOWINDEX].lock() == g_pCompositor->m_pLastWindow.lock() ? (GROUPLOCKED ? m_tGradientLockedActive : m_tGradientActive) : - (GROUPLOCKED ? m_tGradientLockedInactive : m_tGradientInactive)); - if (GRADIENTTEX.m_iTexID != 0) + const auto GRADIENTTEX = (m_dwGroupMembers[WINDOWINDEX] == g_pCompositor->m_pLastWindow ? (GROUPLOCKED ? m_tGradientLockedActive : m_tGradientActive) : + (GROUPLOCKED ? m_tGradientLockedInactive : m_tGradientInactive)); + if (GRADIENTTEX->m_iTexID != 0) g_pHyprOpenGL->renderTexture(GRADIENTTEX, &rect, 1.0); } @@ -204,6 +203,7 @@ void CHyprGroupBarDecoration::invalidateTextures() { } CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float monitorScale) { + tex = makeShared<CTexture>(); szContent = pWindow->m_szTitle; pWindowOwner = pWindow; const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, bufferSize.x, bufferSize.y); @@ -254,8 +254,8 @@ CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float // copy the data to an OpenGL texture we have const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); - tex.allocate(); - glBindTexture(GL_TEXTURE_2D, tex.m_iTexID); + tex->allocate(); + glBindTexture(GL_TEXTURE_2D, tex->m_iTexID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -272,10 +272,10 @@ CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float } CTitleTex::~CTitleTex() { - tex.destroyTexture(); + tex->destroyTexture(); } -void renderGradientTo(CTexture& tex, CGradientValueData* grad) { +void renderGradientTo(SP<CTexture> tex, CGradientValueData* grad) { if (!g_pCompositor->m_pLastMonitor) return; @@ -308,8 +308,8 @@ void renderGradientTo(CTexture& tex, CGradientValueData* grad) { // copy the data to an OpenGL texture we have const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); - tex.allocate(); - glBindTexture(GL_TEXTURE_2D, tex.m_iTexID); + tex->allocate(); + glBindTexture(GL_TEXTURE_2D, tex->m_iTexID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -340,11 +340,11 @@ void refreshGroupBarGradients() { g_pHyprRenderer->makeEGLCurrent(); - if (m_tGradientActive.m_iTexID != 0) { - m_tGradientActive.destroyTexture(); - m_tGradientInactive.destroyTexture(); - m_tGradientLockedActive.destroyTexture(); - m_tGradientLockedInactive.destroyTexture(); + if (m_tGradientActive->m_iTexID != 0) { + m_tGradientActive->destroyTexture(); + m_tGradientInactive->destroyTexture(); + m_tGradientLockedActive->destroyTexture(); + m_tGradientLockedInactive->destroyTexture(); } if (!*PENABLED || !*PGRADIENTS) diff --git a/src/render/decorations/CHyprGroupBarDecoration.hpp b/src/render/decorations/CHyprGroupBarDecoration.hpp index e3f553c5..64870d45 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.hpp +++ b/src/render/decorations/CHyprGroupBarDecoration.hpp @@ -12,7 +12,7 @@ class CTitleTex { CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float monitorScale); ~CTitleTex(); - CTexture tex; + SP<CTexture> tex; std::string szContent; PHLWINDOWREF pWindowOwner; }; |
