From 4152ac76d0813d9d0f67d2f04653a13fa6e17433 Mon Sep 17 00:00:00 2001 From: UjinT34 <41110182+UjinT34@users.noreply.github.com> Date: Sat, 7 Mar 2026 00:44:10 +0300 Subject: [PATCH] renderer: refactor Texture, Framebuffer and Renderbuffer (#13437) Part 1 of the renderer refactors --- src/debug/HyprDebugOverlay.cpp | 12 +- src/debug/HyprDebugOverlay.hpp | 2 +- src/debug/HyprNotificationOverlay.cpp | 13 +- src/debug/HyprNotificationOverlay.hpp | 4 +- src/helpers/Monitor.cpp | 2 +- src/helpers/cm/ColorManagement.hpp | 4 +- src/helpers/cm/ICC.cpp | 2 +- src/hyprerror/HyprError.cpp | 30 +- src/hyprerror/HyprError.hpp | 5 +- src/managers/PointerManager.cpp | 9 +- src/managers/PointerManager.hpp | 8 +- .../screenshare/CursorshareSession.cpp | 12 +- src/managers/screenshare/ScreenshareFrame.cpp | 36 ++- .../screenshare/ScreenshareManager.hpp | 2 +- src/protocols/SinglePixel.cpp | 4 +- src/protocols/types/Buffer.hpp | 2 +- src/protocols/types/DMABuffer.cpp | 19 +- src/protocols/types/SurfaceState.cpp | 5 +- src/protocols/types/SurfaceState.hpp | 6 +- src/render/Framebuffer.cpp | 134 +-------- src/render/Framebuffer.hpp | 46 +-- src/render/OpenGL.cpp | 204 ++++++++------ src/render/OpenGL.hpp | 134 ++++----- src/render/Renderbuffer.cpp | 71 +---- src/render/Renderbuffer.hpp | 25 +- src/render/Renderer.cpp | 166 ++++++++++- src/render/Renderer.hpp | 33 ++- src/render/Texture.cpp | 263 +----------------- src/render/Texture.hpp | 74 ++--- src/render/Transformer.hpp | 2 +- .../decorations/CHyprDropShadowDecoration.cpp | 12 +- .../decorations/CHyprGroupBarDecoration.cpp | 47 ++-- .../decorations/CHyprGroupBarDecoration.hpp | 8 +- src/render/gl/GLFramebuffer.cpp | 170 +++++++++++ src/render/gl/GLFramebuffer.hpp | 30 ++ src/render/gl/GLRenderbuffer.cpp | 71 +++++ src/render/gl/GLRenderbuffer.hpp | 20 ++ src/render/gl/GLTexture.cpp | 223 +++++++++++++++ src/render/gl/GLTexture.hpp | 49 ++++ src/render/pass/FramebufferElement.cpp | 14 +- src/render/pass/Pass.cpp | 2 +- src/render/pass/Pass.hpp | 4 +- src/render/pass/SurfacePassElement.hpp | 4 +- src/render/pass/TexPassElement.hpp | 4 +- src/render/pass/TextureMatteElement.cpp | 4 +- src/render/pass/TextureMatteElement.hpp | 6 +- 46 files changed, 1154 insertions(+), 843 deletions(-) create mode 100644 src/render/gl/GLFramebuffer.cpp create mode 100644 src/render/gl/GLFramebuffer.hpp create mode 100644 src/render/gl/GLRenderbuffer.cpp create mode 100644 src/render/gl/GLRenderbuffer.hpp create mode 100644 src/render/gl/GLTexture.cpp create mode 100644 src/render/gl/GLTexture.hpp diff --git a/src/debug/HyprDebugOverlay.cpp b/src/debug/HyprDebugOverlay.cpp index 8f4189b0..17ce12fa 100644 --- a/src/debug/HyprDebugOverlay.cpp +++ b/src/debug/HyprDebugOverlay.cpp @@ -8,7 +8,7 @@ #include "../desktop/state/FocusState.hpp" CHyprDebugOverlay::CHyprDebugOverlay() { - m_texture = makeShared(); + m_texture = g_pHyprRenderer->createTexture(); } void CHyprMonitorDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs) { @@ -259,15 +259,7 @@ void CHyprDebugOverlay::draw() { cairo_surface_flush(m_cairoSurface); // copy the data to an OpenGL texture we have - const auto DATA = cairo_image_surface_get_data(m_cairoSurface); - m_texture->allocate(); - m_texture->bind(); - m_texture->setTexParameter(GL_TEXTURE_MAG_FILTER, GL_NEAREST); - m_texture->setTexParameter(GL_TEXTURE_MIN_FILTER, GL_NEAREST); - m_texture->setTexParameter(GL_TEXTURE_SWIZZLE_R, GL_BLUE); - m_texture->setTexParameter(GL_TEXTURE_SWIZZLE_B, GL_RED); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->m_pixelSize.x, PMONITOR->m_pixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); + m_texture = g_pHyprRenderer->createTexture(m_cairoSurface); CTexPassElement::SRenderData data; data.tex = m_texture; diff --git a/src/debug/HyprDebugOverlay.hpp b/src/debug/HyprDebugOverlay.hpp index 72987d94..bf188359 100644 --- a/src/debug/HyprDebugOverlay.hpp +++ b/src/debug/HyprDebugOverlay.hpp @@ -42,7 +42,7 @@ class CHyprDebugOverlay { cairo_surface_t* m_cairoSurface = nullptr; cairo_t* m_cairo = nullptr; - SP m_texture; + SP m_texture; friend class CHyprMonitorDebugOverlay; friend class CHyprRenderer; diff --git a/src/debug/HyprNotificationOverlay.cpp b/src/debug/HyprNotificationOverlay.cpp index 6b3c3ea8..e67b0434 100644 --- a/src/debug/HyprNotificationOverlay.cpp +++ b/src/debug/HyprNotificationOverlay.cpp @@ -28,8 +28,6 @@ CHyprNotificationOverlay::CHyprNotificationOverlay() { g_pHyprRenderer->damageBox(m_lastDamage); }); - - m_texture = makeShared(); } CHyprNotificationOverlay::~CHyprNotificationOverlay() { @@ -232,16 +230,7 @@ void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) { m_lastDamage = damage; - // copy the data to an OpenGL texture we have - const auto DATA = cairo_image_surface_get_data(m_cairoSurface); - m_texture->allocate(); - m_texture->bind(); - m_texture->setTexParameter(GL_TEXTURE_MAG_FILTER, GL_NEAREST); - m_texture->setTexParameter(GL_TEXTURE_MIN_FILTER, GL_NEAREST); - m_texture->setTexParameter(GL_TEXTURE_SWIZZLE_R, GL_BLUE); - m_texture->setTexParameter(GL_TEXTURE_SWIZZLE_B, GL_RED); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, MONSIZE.x, MONSIZE.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); + m_texture = g_pHyprRenderer->createTexture(m_cairoSurface); CTexPassElement::SRenderData data; data.tex = m_texture; diff --git a/src/debug/HyprNotificationOverlay.hpp b/src/debug/HyprNotificationOverlay.hpp index 868eb05b..ec7aed72 100644 --- a/src/debug/HyprNotificationOverlay.hpp +++ b/src/debug/HyprNotificationOverlay.hpp @@ -18,7 +18,7 @@ enum eIconBackend : uint8_t { static const std::array, 3 /* backends */> ICONS_ARRAY = { std::array{"[!]", "[i]", "[Hint]", "[Err]", "[?]", "[ok]", ""}, std::array{"", "", "", "", "", "󰸞", ""}, std::array{"", "", "", "", "", ""}}; -static const std::array ICONS_COLORS = {CHyprColor{255.0 / 255.0, 204 / 255.0, 102 / 255.0, 1.0}, +static const std::array ICONS_COLORS = {CHyprColor{1.0, 204 / 255.0, 102 / 255.0, 1.0}, CHyprColor{128 / 255.0, 255 / 255.0, 255 / 255.0, 1.0}, CHyprColor{179 / 255.0, 255 / 255.0, 204 / 255.0, 1.0}, CHyprColor{255 / 255.0, 77 / 255.0, 77 / 255.0, 1.0}, @@ -57,7 +57,7 @@ class CHyprNotificationOverlay { PHLMONITORREF m_lastMonitor; Vector2D m_lastSize = Vector2D(-1, -1); - SP m_texture; + SP m_texture; }; inline UP g_pHyprNotificationOverlay; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 557a6315..07156ff1 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -1879,7 +1879,7 @@ uint16_t CMonitor::isDSBlocked(bool full) { // we can't scanout shm buffers. const auto params = PSURFACE->m_current.buffer->dmabuf(); - if (!params.success || !PSURFACE->m_current.texture->m_eglImage /* dmabuf */) { + if (!params.success || !PSURFACE->m_current.texture->isDMA() /* dmabuf */) { reasons |= DS_BLOCK_DMA; if (!full) return reasons; diff --git a/src/helpers/cm/ColorManagement.hpp b/src/helpers/cm/ColorManagement.hpp index 9938ffbf..0103e2a4 100644 --- a/src/helpers/cm/ColorManagement.hpp +++ b/src/helpers/cm/ColorManagement.hpp @@ -17,7 +17,7 @@ #define HDR_REF_LUMINANCE 203.0 #define HLG_MAX_LUMINANCE 1000.0 -class CTexture; +class ITexture; namespace NColorManagement { enum eNoShader : uint8_t { @@ -219,7 +219,7 @@ namespace NColorManagement { bool present = false; size_t lutSize = 33; std::vector lutDataPacked; - SP lutTexture; + SP lutTexture; std::optional vcgt; } icc; diff --git a/src/helpers/cm/ICC.cpp b/src/helpers/cm/ICC.cpp index 34045543..00140c62 100644 --- a/src/helpers/cm/ICC.cpp +++ b/src/helpers/cm/ICC.cpp @@ -226,7 +226,7 @@ static std::expected buildIcc3DLut(cmsHPROFILE profile, SImag Log::logger->log(Log::DEBUG, "3D LUT constructed, size {}", image.icc.lutDataPacked.size()); // upload - image.icc.lutTexture = makeShared(image.icc.lutDataPacked, image.icc.lutSize); + image.icc.lutTexture = g_pHyprRenderer->createTexture(image.icc.lutDataPacked, image.icc.lutSize); return {}; } diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index 360bdfdc..60bf0a78 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -30,8 +30,6 @@ CHyprError::CHyprError() { if (m_fadeOpacity->isBeingAnimated() || m_monitorChanged) g_pHyprRenderer->damageBox(m_damageBox); }); - - m_texture = makeShared(); } void CHyprError::queueCreate(std::string message, const CHyprColor& color) { @@ -40,8 +38,8 @@ void CHyprError::queueCreate(std::string message, const CHyprColor& color) { } void CHyprError::createQueued() { - if (m_isCreated) - m_texture->destroyTexture(); + if (m_isCreated && m_texture) + m_texture.reset(); m_fadeOpacity->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn")); @@ -145,12 +143,13 @@ void CHyprError::createQueued() { // copy the data to an OpenGL texture we have const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); - m_texture->allocate(); - m_texture->bind(); - m_texture->setTexParameter(GL_TEXTURE_MAG_FILTER, GL_NEAREST); - m_texture->setTexParameter(GL_TEXTURE_MIN_FILTER, GL_NEAREST); - m_texture->setTexParameter(GL_TEXTURE_SWIZZLE_R, GL_BLUE); - m_texture->setTexParameter(GL_TEXTURE_SWIZZLE_B, GL_RED); + auto tex = texture(); + tex->allocate(PMONITOR->m_pixelSize); + tex->bind(); + tex->setTexParameter(GL_TEXTURE_MAG_FILTER, GL_NEAREST); + tex->setTexParameter(GL_TEXTURE_MIN_FILTER, GL_NEAREST); + tex->setTexParameter(GL_TEXTURE_SWIZZLE_R, GL_BLUE); + tex->setTexParameter(GL_TEXTURE_SWIZZLE_B, GL_RED); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->m_pixelSize.x, PMONITOR->m_pixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); @@ -187,7 +186,8 @@ void CHyprError::draw() { if (!m_fadeOpacity->isBeingAnimated()) { if (m_fadeOpacity->value() == 0.f) { m_queuedDestroy = false; - m_texture->destroyTexture(); + if (m_texture) + m_texture.reset(); m_isCreated = false; m_queued = ""; @@ -218,7 +218,7 @@ void CHyprError::draw() { m_monitorChanged = false; CTexPassElement::SRenderData data; - data.tex = m_texture; + data.tex = texture(); data.box = monbox; data.a = m_fadeOpacity->value(); @@ -239,3 +239,9 @@ bool CHyprError::active() { float CHyprError::height() { return m_lastHeight; } + +SP CHyprError::texture() { + if (!m_texture) + m_texture = g_pHyprRenderer->createTexture(); + return m_texture; +} \ No newline at end of file diff --git a/src/hyprerror/HyprError.hpp b/src/hyprerror/HyprError.hpp index f4bc43d8..48b9e805 100644 --- a/src/hyprerror/HyprError.hpp +++ b/src/hyprerror/HyprError.hpp @@ -18,13 +18,16 @@ class CHyprError { bool active(); float height(); // logical + // + SP texture(); + private: void createQueued(); std::string m_queued = ""; CHyprColor m_queuedColor; bool m_queuedDestroy = false; bool m_isCreated = false; - SP m_texture; + SP m_texture; PHLANIMVAR m_fadeOpacity; CBox m_damageBox = {0, 0, 0, 0}; float m_lastHeight = 0.F; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index c802d3e1..7256e176 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -8,6 +8,7 @@ #include "../protocols/IdleNotify.hpp" #include "../protocols/core/Compositor.hpp" #include "../protocols/core/Seat.hpp" +#include "debug/log/Logger.hpp" #include "eventLoop/EventLoopManager.hpp" #include "../render/pass/TexPassElement.hpp" #include "../managers/input/InputManager.hpp" @@ -22,6 +23,8 @@ #include #include #include +#include +#include #include using namespace Hyprutils::Utils; @@ -407,7 +410,7 @@ bool CPointerManager::setHWCursorBuffer(SP state, SP CPointerManager::renderHWCursorBuffer(SP state, SP texture) { +SP CPointerManager::renderHWCursorBuffer(SP state, SP texture) { auto maxSize = state->monitor->m_output->cursorPlaneSize(); auto const& cursorSize = m_currentCursorImage.size; @@ -900,13 +903,13 @@ const CPointerManager::SCursorImage& CPointerManager::currentCursorImage() { return m_currentCursorImage; } -SP CPointerManager::getCurrentCursorTexture() { +SP CPointerManager::getCurrentCursorTexture() { if (!m_currentCursorImage.pBuffer && (!m_currentCursorImage.surface || !m_currentCursorImage.surface->resource()->m_current.texture)) return nullptr; if (m_currentCursorImage.pBuffer) { if (!m_currentCursorImage.bufferTex) - m_currentCursorImage.bufferTex = makeShared(m_currentCursorImage.pBuffer, true); + m_currentCursorImage.bufferTex = g_pHyprRenderer->createTexture(m_currentCursorImage.pBuffer, true); return m_currentCursorImage.bufferTex; } diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp index 218541a4..a4fe1971 100644 --- a/src/managers/PointerManager.hpp +++ b/src/managers/PointerManager.hpp @@ -12,7 +12,7 @@ class CMonitor; class IHID; -class CTexture; +class ITexture; AQUAMARINE_FORWARD(IBuffer); @@ -71,7 +71,7 @@ class CPointerManager { struct SCursorImage { SP pBuffer; - SP bufferTex; + SP bufferTex; WP surface; Vector2D hotspot; @@ -83,7 +83,7 @@ class CPointerManager { }; const SCursorImage& currentCursorImage(); - SP getCurrentCursorTexture(); + SP getCurrentCursorTexture(); struct { CSignalT<> cursorChanged; @@ -181,7 +181,7 @@ class CPointerManager { std::vector> m_monitorStates; SP stateFor(PHLMONITOR mon); bool attemptHardwareCursor(SP state); - SP renderHWCursorBuffer(SP state, SP texture); + SP renderHWCursorBuffer(SP state, SP texture); bool setHWCursorBuffer(SP state, SP buf); struct { diff --git a/src/managers/screenshare/CursorshareSession.cpp b/src/managers/screenshare/CursorshareSession.cpp index 2322625f..703832ab 100644 --- a/src/managers/screenshare/CursorshareSession.cpp +++ b/src/managers/screenshare/CursorshareSession.cpp @@ -169,10 +169,10 @@ bool CCursorshareSession::copy() { return false; } - CFramebuffer outFB; - outFB.alloc(m_bufferSize.x, m_bufferSize.y, m_format); + auto outFB = g_pHyprRenderer->createFB(); + outFB->alloc(m_bufferSize.x, m_bufferSize.y, m_format); - if (!g_pHyprRenderer->beginRender(m_pendingFrame.monitor, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &outFB, true)) { + if (!g_pHyprRenderer->beginRender(m_pendingFrame.monitor, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, outFB, true)) { LOGM(Log::ERR, "Can't copy: failed to begin rendering to shm"); return false; } @@ -182,8 +182,8 @@ bool CCursorshareSession::copy() { g_pHyprRenderer->endRender(); g_pHyprOpenGL->m_renderData.pMonitor = m_pendingFrame.monitor; - outFB.bind(); - glBindFramebuffer(GL_READ_FRAMEBUFFER, outFB.getFBID()); + outFB->bind(); + glBindFramebuffer(GL_READ_FRAMEBUFFER, GLFB(outFB)->getFBID()); glPixelStorei(GL_PACK_ALIGNMENT, 1); @@ -212,7 +212,7 @@ bool CCursorshareSession::copy() { g_pHyprOpenGL->m_renderData.pMonitor.reset(); m_pendingFrame.buffer->endDataPtr(); - outFB.unbind(); + GLFB(outFB)->unbind(); glPixelStorei(GL_PACK_ALIGNMENT, 4); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); diff --git a/src/managers/screenshare/ScreenshareFrame.cpp b/src/managers/screenshare/ScreenshareFrame.cpp index 18d5aac9..d747ecee 100644 --- a/src/managers/screenshare/ScreenshareFrame.cpp +++ b/src/managers/screenshare/ScreenshareFrame.cpp @@ -10,6 +10,7 @@ #include "../../helpers/Monitor.hpp" #include "../../desktop/view/Window.hpp" #include "../../desktop/state/FocusState.hpp" +#include using namespace Screenshare; @@ -133,7 +134,7 @@ void CScreenshareFrame::copy() { // store a snapshot before the permission popup so we don't break screenshots const auto PERM = g_pDynamicPermissionManager->clientPermissionMode(m_session->m_client, PERMISSION_TYPE_SCREENCOPY); if (PERM == PERMISSION_RULE_ALLOW_MODE_PENDING) { - if (!m_session->m_tempFB.isAllocated()) + if (!m_session->m_tempFB || !m_session->m_tempFB->isAllocated()) storeTempFB(); // don't copy a frame while allow is pending because screenshot tools will only take the first frame we give, which is empty @@ -159,10 +160,7 @@ void CScreenshareFrame::renderMonitor() { const auto PMONITOR = m_session->monitor(); - if (!g_pHyprOpenGL->m_monitorRenderResources.contains(PMONITOR)) - return; // wtf? - - auto TEXTURE = g_pHyprOpenGL->m_monitorRenderResources[PMONITOR].monitorMirrorFB.getTexture(); + auto TEXTURE = g_pHyprRenderer->createTexture(PMONITOR->m_output->state->state().buffer); const bool IS_CM_AWARE = PROTO::colorManagement && PROTO::colorManagement->isClientCMAware(m_session->m_client); g_pHyprOpenGL->m_renderData.transformDamage = false; @@ -328,10 +326,10 @@ void CScreenshareFrame::render() { return; } - if (m_session->m_tempFB.isAllocated()) { + if (m_session->m_tempFB && m_session->m_tempFB->isAllocated()) { CBox texbox = {{}, m_bufferSize}; - g_pHyprOpenGL->renderTexture(m_session->m_tempFB.getTexture(), texbox, {}); - m_session->m_tempFB.release(); + g_pHyprOpenGL->renderTexture(m_session->m_tempFB->getTexture(), texbox, {}); + m_session->m_tempFB->release(); return; } @@ -384,12 +382,12 @@ bool CScreenshareFrame::copyShm() { return false; } - const auto PMONITOR = m_session->monitor(); + const auto PMONITOR = m_session->monitor(); - CFramebuffer outFB; - outFB.alloc(m_bufferSize.x, m_bufferSize.y, shm.format); + auto outFB = g_pHyprRenderer->createFB(); + outFB->alloc(m_bufferSize.x, m_bufferSize.y, shm.format); - if (!g_pHyprRenderer->beginRender(PMONITOR, m_damage, RENDER_MODE_FULL_FAKE, nullptr, &outFB, true)) { + if (!g_pHyprRenderer->beginRender(PMONITOR, m_damage, RENDER_MODE_FULL_FAKE, nullptr, outFB, true)) { LOGM(Log::ERR, "Can't copy: failed to begin rendering"); return false; } @@ -401,8 +399,8 @@ bool CScreenshareFrame::copyShm() { g_pHyprRenderer->endRender(); g_pHyprOpenGL->m_renderData.pMonitor = PMONITOR; - outFB.bind(); - glBindFramebuffer(GL_READ_FRAMEBUFFER, outFB.getFBID()); + outFB->bind(); + glBindFramebuffer(GL_READ_FRAMEBUFFER, GLFB(outFB)->getFBID()); glPixelStorei(GL_PACK_ALIGNMENT, 1); @@ -444,7 +442,7 @@ bool CScreenshareFrame::copyShm() { }); } - outFB.unbind(); + GLFB(outFB)->unbind(); glPixelStorei(GL_PACK_ALIGNMENT, 4); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); @@ -459,13 +457,13 @@ bool CScreenshareFrame::copyShm() { } void CScreenshareFrame::storeTempFB() { - g_pHyprRenderer->makeEGLCurrent(); - - m_session->m_tempFB.alloc(m_bufferSize.x, m_bufferSize.y); + if (!m_session->m_tempFB) + m_session->m_tempFB = g_pHyprRenderer->createFB(); + m_session->m_tempFB->alloc(m_bufferSize.x, m_bufferSize.y); CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX}; - if (!g_pHyprRenderer->beginRender(m_session->monitor(), fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &m_session->m_tempFB, true)) { + if (!g_pHyprRenderer->beginRender(m_session->monitor(), fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, m_session->m_tempFB, true)) { LOGM(Log::ERR, "Can't copy: failed to begin rendering to temp fb"); return; } diff --git a/src/managers/screenshare/ScreenshareManager.hpp b/src/managers/screenshare/ScreenshareManager.hpp index d62585ae..5a4ada5e 100644 --- a/src/managers/screenshare/ScreenshareManager.hpp +++ b/src/managers/screenshare/ScreenshareManager.hpp @@ -75,7 +75,7 @@ namespace Screenshare { std::vector m_formats; Vector2D m_bufferSize = Vector2D(0, 0); - CFramebuffer m_tempFB; + SP m_tempFB; SP m_shareStopTimer; bool m_sharing = false; diff --git a/src/protocols/SinglePixel.cpp b/src/protocols/SinglePixel.cpp index 51c3551c..c32379a3 100644 --- a/src/protocols/SinglePixel.cpp +++ b/src/protocols/SinglePixel.cpp @@ -12,11 +12,11 @@ CSinglePixelBuffer::CSinglePixelBuffer(uint32_t id, wl_client* client, CHyprColo m_opaque = col_.a >= 1.F; - m_texture = makeShared(DRM_FORMAT_ARGB8888, rc(&m_color), 4, Vector2D{1, 1}); + m_texture = g_pHyprRenderer->createTexture(DRM_FORMAT_ARGB8888, rc(&m_color), 4, Vector2D{1, 1}); m_resource = CWLBufferResource::create(makeShared(client, 1, id)); - m_success = m_texture->m_texID; + m_success = m_texture->ok(); size = {1, 1}; diff --git a/src/protocols/types/Buffer.hpp b/src/protocols/types/Buffer.hpp index bda44ebc..afff11a5 100644 --- a/src/protocols/types/Buffer.hpp +++ b/src/protocols/types/Buffer.hpp @@ -26,7 +26,7 @@ class IHLBuffer : public Aquamarine::IBuffer { void onBackendRelease(const std::function& fn); void addReleasePoint(CDRMSyncPointState& point); - SP m_texture; + SP m_texture; bool m_opaque = false; SP m_resource; std::vector> m_syncReleasers; diff --git a/src/protocols/types/DMABuffer.cpp b/src/protocols/types/DMABuffer.cpp index f3c3e067..86db8ca6 100644 --- a/src/protocols/types/DMABuffer.cpp +++ b/src/protocols/types/DMABuffer.cpp @@ -13,31 +13,28 @@ using namespace Hyprutils::OS; CDMABuffer::CDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs const& attrs_) : m_attrs(attrs_) { - g_pHyprRenderer->makeEGLCurrent(); - m_listeners.resourceDestroy = events.destroy.listen([this] { closeFDs(); m_listeners.resourceDestroy.reset(); }); - size = m_attrs.size; - m_resource = CWLBufferResource::create(makeShared(client, 1, id)); - auto eglImage = g_pHyprOpenGL->createEGLImage(m_attrs); + size = m_attrs.size; + m_resource = CWLBufferResource::create(makeShared(client, 1, id)); + m_opaque = NFormatUtils::isFormatOpaque(m_attrs.format); + m_texture = g_pHyprRenderer->createTexture(m_attrs, m_opaque); // texture takes ownership of the eglImage - if UNLIKELY (!eglImage) { + if UNLIKELY (!m_texture) { Log::logger->log(Log::ERR, "CDMABuffer: failed to import EGLImage, retrying as implicit"); m_attrs.modifier = DRM_FORMAT_MOD_INVALID; - eglImage = g_pHyprOpenGL->createEGLImage(m_attrs); + m_texture = g_pHyprRenderer->createTexture(m_attrs, m_opaque); - if UNLIKELY (!eglImage) { + if UNLIKELY (!m_texture) { Log::logger->log(Log::ERR, "CDMABuffer: failed to import EGLImage"); return; } } - m_texture = makeShared(m_attrs, eglImage); // texture takes ownership of the eglImage - m_opaque = NFormatUtils::isFormatOpaque(m_attrs.format); - m_success = m_texture->m_texID; + m_success = m_texture->ok(); if UNLIKELY (!m_success) Log::logger->log(Log::ERR, "Failed to create a dmabuf: texture is null"); diff --git a/src/protocols/types/SurfaceState.cpp b/src/protocols/types/SurfaceState.cpp index 46f2a563..da98d3fb 100644 --- a/src/protocols/types/SurfaceState.cpp +++ b/src/protocols/types/SurfaceState.cpp @@ -1,6 +1,7 @@ #include "SurfaceState.hpp" #include "helpers/Format.hpp" #include "protocols/types/Buffer.hpp" +#include "render/Renderer.hpp" #include "render/Texture.hpp" Vector2D SSurfaceState::sourceSize() { @@ -34,7 +35,7 @@ CRegion SSurfaceState::accumulateBufferDamage() { return bufferDamage; } -void SSurfaceState::updateSynchronousTexture(SP lastTexture) { +void SSurfaceState::updateSynchronousTexture(SP lastTexture) { auto [dataPtr, fmt, size] = buffer->beginDataPtr(0); if (dataPtr) { auto drmFmt = NFormatUtils::shmToDRM(fmt); @@ -43,7 +44,7 @@ void SSurfaceState::updateSynchronousTexture(SP lastTexture) { texture = lastTexture; texture->update(drmFmt, dataPtr, stride, accumulateBufferDamage()); } else - texture = makeShared(drmFmt, dataPtr, stride, bufferSize); + texture = g_pHyprRenderer->createTexture(drmFmt, dataPtr, stride, bufferSize); } buffer->endDataPtr(); } diff --git a/src/protocols/types/SurfaceState.hpp b/src/protocols/types/SurfaceState.hpp index f6caa83c..d5b7e4b9 100644 --- a/src/protocols/types/SurfaceState.hpp +++ b/src/protocols/types/SurfaceState.hpp @@ -6,7 +6,7 @@ #include "../WaylandProtocol.hpp" #include "./Buffer.hpp" -class CTexture; +class ITexture; class CDRMSyncPointState; class CWLCallbackResource; @@ -88,8 +88,8 @@ struct SSurfaceState { eLockReason lockMask = LOCK_REASON_NONE; // texture of surface content, used for rendering - SP texture; - void updateSynchronousTexture(SP lastTexture); + SP texture; + void updateSynchronousTexture(SP lastTexture); // fifo bool barrierSet = false; diff --git a/src/render/Framebuffer.cpp b/src/render/Framebuffer.cpp index 23bbd643..b2ff7e68 100644 --- a/src/render/Framebuffer.cpp +++ b/src/render/Framebuffer.cpp @@ -1,140 +1,30 @@ #include "Framebuffer.hpp" -#include "OpenGL.hpp" -CFramebuffer::CFramebuffer() { - ; -} +IFramebuffer::IFramebuffer(const std::string& name) : m_name(name) {} -bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) { - bool firstAlloc = false; +bool IFramebuffer::alloc(int w, int h, uint32_t format) { RASSERT((w > 0 && h > 0), "cannot alloc a FB with negative / zero size! (attempted {}x{})", w, h); const bool sizeChanged = (m_size != Vector2D(w, h)); - const bool formatChanged = (drmFormat != m_drmFormat); + const bool formatChanged = (format != m_drmFormat); - if (!m_tex) { - m_tex = makeShared(); - m_tex->allocate(); - m_tex->bind(); - m_tex->setTexParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - m_tex->setTexParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - m_tex->setTexParameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR); - m_tex->setTexParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR); - firstAlloc = true; - } + if (m_fbAllocated && !sizeChanged && !formatChanged) + return true; - if (!m_fbAllocated) { - glGenFramebuffers(1, &m_fb); - m_fbAllocated = true; - firstAlloc = true; - } - - if (firstAlloc || sizeChanged || formatChanged) { - const auto format = NFormatUtils::getPixelFormatFromDRM(drmFormat); - m_tex->bind(); - glTexImage2D(GL_TEXTURE_2D, 0, format->glInternalFormat ? format->glInternalFormat : format->glFormat, w, h, 0, format->glFormat, format->glType, nullptr); - glBindFramebuffer(GL_FRAMEBUFFER, m_fb); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_tex->m_texID, 0); - - if (m_stencilTex) { - m_stencilTex->bind(); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, w, h, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_stencilTex->m_texID, 0); - - glDisable(GL_DEPTH_TEST); - glDepthMask(GL_FALSE); - } - - auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - RASSERT((status == GL_FRAMEBUFFER_COMPLETE), "Framebuffer incomplete, couldn't create! (FB status: {}, GL Error: 0x{:x})", status, sc(glGetError())); - - Log::logger->log(Log::DEBUG, "Framebuffer created, status {}", status); - } - - glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - m_drmFormat = drmFormat; - m_size = Vector2D(w, h); - - return true; + m_size = {w, h}; + m_drmFormat = format; + m_fbAllocated = internalAlloc(w, h, format); + return m_fbAllocated; } -void CFramebuffer::addStencil(SP tex) { - if (m_stencilTex == tex) - return; - - m_stencilTex = tex; - m_stencilTex->bind(); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, m_size.x, m_size.y, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr); - - glBindFramebuffer(GL_FRAMEBUFFER, m_fb); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_stencilTex->m_texID, 0); - - glDisable(GL_DEPTH_TEST); - glDepthMask(GL_FALSE); - - auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - RASSERT((status == GL_FRAMEBUFFER_COMPLETE), "Failed adding a stencil to fbo!", status); - - m_stencilTex->unbind(); - glBindFramebuffer(GL_FRAMEBUFFER, 0); -} - -void CFramebuffer::bind() { - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fb); - - if (g_pHyprOpenGL) - g_pHyprOpenGL->setViewport(0, 0, g_pHyprOpenGL->m_renderData.pMonitor->m_pixelSize.x, g_pHyprOpenGL->m_renderData.pMonitor->m_pixelSize.y); - else - glViewport(0, 0, m_size.x, m_size.y); -} - -void CFramebuffer::unbind() { - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); -} - -void CFramebuffer::release() { - if (m_fbAllocated) { - glBindFramebuffer(GL_FRAMEBUFFER, m_fb); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - glDeleteFramebuffers(1, &m_fb); - m_fbAllocated = false; - m_fb = 0; - } - - if (m_tex) - m_tex.reset(); - - m_size = Vector2D(); -} - -CFramebuffer::~CFramebuffer() { - release(); -} - -bool CFramebuffer::isAllocated() { +bool IFramebuffer::isAllocated() { return m_fbAllocated && m_tex; } -SP CFramebuffer::getTexture() { +SP IFramebuffer::getTexture() { return m_tex; } -GLuint CFramebuffer::getFBID() { - return m_fbAllocated ? m_fb : 0; -} - -SP CFramebuffer::getStencilTex() { +SP IFramebuffer::getStencilTex() { return m_stencilTex; } - -void CFramebuffer::invalidate(const std::vector& attachments) { - if (!isAllocated()) - return; - - glInvalidateFramebuffer(GL_FRAMEBUFFER, attachments.size(), attachments.data()); -} diff --git a/src/render/Framebuffer.hpp b/src/render/Framebuffer.hpp index e6c93876..7e33f227 100644 --- a/src/render/Framebuffer.hpp +++ b/src/render/Framebuffer.hpp @@ -3,34 +3,38 @@ #include "../defines.hpp" #include "../helpers/Format.hpp" #include "Texture.hpp" +#include #include -class CFramebuffer { - public: - CFramebuffer(); - ~CFramebuffer(); +class CHLBufferReference; + +class IFramebuffer { + public: + IFramebuffer() = default; + IFramebuffer(const std::string& name); + virtual ~IFramebuffer() = default; + + virtual bool alloc(int w, int h, uint32_t format = DRM_FORMAT_ARGB8888); + virtual void release() = 0; + virtual bool readPixels(CHLBufferReference buffer, uint32_t offsetX = 0, uint32_t offsetY = 0, uint32_t width = 0, uint32_t height = 0) = 0; + + virtual void bind() = 0; - bool alloc(int w, int h, uint32_t format = DRM_FORMAT_ARGB8888); - void addStencil(SP tex); - void bind(); - void unbind(); - void release(); - void reset(); bool isAllocated(); - SP getTexture(); - SP getStencilTex(); - GLuint getFBID(); - void invalidate(const std::vector& attachments); + SP getTexture(); + SP getStencilTex(); + + virtual void addStencil(SP tex) = 0; Vector2D m_size; - DRMFormat m_drmFormat = 0 /* DRM_FORMAT_INVALID */; + DRMFormat m_drmFormat = DRM_FORMAT_INVALID; - private: - SP m_tex; - GLuint m_fb = -1; + protected: + virtual bool internalAlloc(int w, int h, uint32_t format = DRM_FORMAT_ARGB8888) = 0; + + SP m_tex; bool m_fbAllocated = false; - SP m_stencilTex; - - friend class CRenderbuffer; + SP m_stencilTex; + std::string m_name; // name for logging }; diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 7fe001d4..83ad05ca 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -50,6 +50,8 @@ #include "ShaderLoader.hpp" #include "Texture.hpp" #include +#include "gl/GLFramebuffer.hpp" +#include "gl/GLTexture.hpp" using namespace Hyprutils::OS; using namespace NColorManagement; @@ -644,7 +646,7 @@ EGLImageKHR CHyprOpenGLImpl::createEGLImage(const Aquamarine::SDMABUFAttrs& attr return image; } -void CHyprOpenGLImpl::beginSimple(PHLMONITOR pMonitor, const CRegion& damage, SP rb, CFramebuffer* fb) { +void CHyprOpenGLImpl::beginSimple(PHLMONITOR pMonitor, const CRegion& damage, SP rb, SP fb) { m_renderData.pMonitor = pMonitor; const GLenum RESETSTATUS = glGetGraphicsResetStatus(); @@ -697,7 +699,7 @@ void CHyprOpenGLImpl::beginSimple(PHLMONITOR pMonitor, const CRegion& damage, SP pushMonitorTransformEnabled(false); } -void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, CFramebuffer* fb, std::optional finalDamage) { +void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, SP fb, std::optional finalDamage) { m_renderData.pMonitor = pMonitor; const GLenum RESETSTATUS = glGetGraphicsResetStatus(); @@ -721,7 +723,8 @@ void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, CFrameb m_renderData.monitorProjection = pMonitor->m_projMatrix; - if (m_monitorRenderResources.contains(pMonitor) && m_monitorRenderResources.at(pMonitor).offloadFB.m_size != pMonitor->m_pixelSize) + if (m_monitorRenderResources.contains(pMonitor) && + (!m_monitorRenderResources.at(pMonitor).offloadFB || m_monitorRenderResources.at(pMonitor).offloadFB->m_size != pMonitor->m_pixelSize)) destroyMonitorResources(pMonitor); m_renderData.pCurrentMonData = &m_monitorRenderResources[pMonitor]; @@ -732,26 +735,30 @@ void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, CFrameb const auto DRM_FORMAT = fb ? fb->m_drmFormat : pMonitor->m_output->state->state().drmFormat; // ensure a framebuffer for the monitor exists - if (m_renderData.pCurrentMonData->offloadFB.m_size != pMonitor->m_pixelSize || DRM_FORMAT != m_renderData.pCurrentMonData->offloadFB.m_drmFormat) { - m_renderData.pCurrentMonData->stencilTex->allocate(); + if (!m_renderData.pCurrentMonData->offloadFB || m_renderData.pCurrentMonData->offloadFB->m_size != pMonitor->m_pixelSize || + DRM_FORMAT != m_renderData.pCurrentMonData->offloadFB->m_drmFormat) { + m_renderData.pCurrentMonData->stencilTex = g_pHyprRenderer->createStencilTexture(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y); + m_renderData.pCurrentMonData->offloadFB = g_pHyprRenderer->createFB(); + m_renderData.pCurrentMonData->mirrorFB = g_pHyprRenderer->createFB(); + m_renderData.pCurrentMonData->mirrorSwapFB = g_pHyprRenderer->createFB(); - m_renderData.pCurrentMonData->offloadFB.alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, DRM_FORMAT); - m_renderData.pCurrentMonData->mirrorFB.alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, DRM_FORMAT); - m_renderData.pCurrentMonData->mirrorSwapFB.alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, DRM_FORMAT); + m_renderData.pCurrentMonData->offloadFB->addStencil(m_renderData.pCurrentMonData->stencilTex); + m_renderData.pCurrentMonData->mirrorFB->addStencil(m_renderData.pCurrentMonData->stencilTex); + m_renderData.pCurrentMonData->mirrorSwapFB->addStencil(m_renderData.pCurrentMonData->stencilTex); - m_renderData.pCurrentMonData->offloadFB.addStencil(m_renderData.pCurrentMonData->stencilTex); - m_renderData.pCurrentMonData->mirrorFB.addStencil(m_renderData.pCurrentMonData->stencilTex); - m_renderData.pCurrentMonData->mirrorSwapFB.addStencil(m_renderData.pCurrentMonData->stencilTex); + m_renderData.pCurrentMonData->offloadFB->alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, DRM_FORMAT); + m_renderData.pCurrentMonData->mirrorFB->alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, DRM_FORMAT); + m_renderData.pCurrentMonData->mirrorSwapFB->alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, DRM_FORMAT); } - const bool HAS_MIRROR_FB = m_renderData.pCurrentMonData->monitorMirrorFB.isAllocated(); + const bool HAS_MIRROR_FB = m_renderData.pCurrentMonData->monitorMirrorFB && m_renderData.pCurrentMonData->monitorMirrorFB->isAllocated(); const bool NEEDS_COPY_FB = needsACopyFB(m_renderData.pMonitor.lock()); if (HAS_MIRROR_FB && !NEEDS_COPY_FB) - m_renderData.pCurrentMonData->monitorMirrorFB.release(); - else if (!HAS_MIRROR_FB && NEEDS_COPY_FB) - m_renderData.pCurrentMonData->monitorMirrorFB.alloc(m_renderData.pMonitor->m_pixelSize.x, m_renderData.pMonitor->m_pixelSize.y, - m_renderData.pMonitor->m_output->state->state().drmFormat); + m_renderData.pCurrentMonData->monitorMirrorFB->release(); + else if (!HAS_MIRROR_FB && NEEDS_COPY_FB && m_renderData.pCurrentMonData->monitorMirrorFB) + m_renderData.pCurrentMonData->monitorMirrorFB->alloc(m_renderData.pMonitor->m_pixelSize.x, m_renderData.pMonitor->m_pixelSize.y, + m_renderData.pMonitor->m_output->state->state().drmFormat); m_renderData.transformDamage = true; if (HAS_MIRROR_FB != NEEDS_COPY_FB) { @@ -771,8 +778,8 @@ void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, CFrameb applyScreenShader(*PSHADER); } - m_renderData.pCurrentMonData->offloadFB.bind(); - m_renderData.currentFB = &m_renderData.pCurrentMonData->offloadFB; + m_renderData.pCurrentMonData->offloadFB->bind(); + m_renderData.currentFB = m_renderData.pCurrentMonData->offloadFB; m_offloadedFramebuffer = true; m_renderData.mainFB = m_renderData.currentFB; @@ -819,9 +826,9 @@ void CHyprOpenGLImpl::end() { m_finalScreenShader->program() >= 1 || g_pHyprRenderer->m_crashingInProgress || m_renderData.pMonitor->m_imageDescription->value() != SImageDescription{}; if LIKELY (!PRIMITIVE_BLOCKED || g_pHyprRenderer->m_renderMode != RENDER_MODE_NORMAL) - renderTexturePrimitive(m_renderData.pCurrentMonData->offloadFB.getTexture(), monbox); + renderTexturePrimitive(m_renderData.pCurrentMonData->offloadFB->getTexture(), monbox); else // we need to use renderTexture if we do any CM whatsoever. - renderTexture(m_renderData.pCurrentMonData->offloadFB.getTexture(), monbox, {.finalMonitorCM = true}); + renderTexture(m_renderData.pCurrentMonData->offloadFB->getTexture(), monbox, {.finalMonitorCM = true}); blend(true); @@ -831,14 +838,22 @@ void CHyprOpenGLImpl::end() { } // invalidate our render FBs to signal to the driver we don't need them anymore - m_renderData.pCurrentMonData->mirrorFB.bind(); - m_renderData.pCurrentMonData->mirrorFB.invalidate({GL_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0}); - m_renderData.pCurrentMonData->mirrorSwapFB.bind(); - m_renderData.pCurrentMonData->mirrorSwapFB.invalidate({GL_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0}); - m_renderData.pCurrentMonData->offloadFB.bind(); - m_renderData.pCurrentMonData->offloadFB.invalidate({GL_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0}); - m_renderData.pCurrentMonData->offMainFB.bind(); - m_renderData.pCurrentMonData->offMainFB.invalidate({GL_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0}); + if (m_renderData.pCurrentMonData->mirrorFB) { + m_renderData.pCurrentMonData->mirrorFB->bind(); + GLFB(m_renderData.pCurrentMonData->mirrorFB)->invalidate({GL_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0}); + } + if (m_renderData.pCurrentMonData->mirrorSwapFB) { + m_renderData.pCurrentMonData->mirrorSwapFB->bind(); + GLFB(m_renderData.pCurrentMonData->mirrorSwapFB)->invalidate({GL_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0}); + } + if (m_renderData.pCurrentMonData->offloadFB) { + m_renderData.pCurrentMonData->offloadFB->bind(); + GLFB(m_renderData.pCurrentMonData->offloadFB)->invalidate({GL_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0}); + } + if (m_renderData.pCurrentMonData->offMainFB) { + m_renderData.pCurrentMonData->offMainFB->bind(); + GLFB(m_renderData.pCurrentMonData->offMainFB)->invalidate({GL_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0}); + } // reset our data m_renderData.pMonitor.reset(); @@ -853,8 +868,8 @@ void CHyprOpenGLImpl::end() { // if we dropped to offMain, release it now. // if there is a plugin constantly using it, this might be a bit slow, // but I haven't seen a single plugin yet use these, so it's better to drop a bit of vram. - if UNLIKELY (m_renderData.pCurrentMonData->offMainFB.isAllocated()) - m_renderData.pCurrentMonData->offMainFB.release(); + if UNLIKELY (m_renderData.pCurrentMonData->offMainFB && m_renderData.pCurrentMonData->offMainFB->isAllocated()) + m_renderData.pCurrentMonData->offMainFB->release(); static const auto GLDEBUG = CConfigValue("debug:gl_debugging"); @@ -1064,7 +1079,7 @@ void CHyprOpenGLImpl::renderRectWithBlurInternal(const CBox& box, const CHyprCol CRegion damage{m_renderData.damage}; damage.intersect(box); - CFramebuffer* POUTFB = data.xray ? &m_renderData.pCurrentMonData->blurFB : blurMainFramebufferWithDamage(data.blurA, &damage); + auto POUTFB = data.xray ? m_renderData.pCurrentMonData->blurFB : blurMainFramebufferWithDamage(data.blurA, &damage); m_renderData.currentFB->bind(); @@ -1135,7 +1150,7 @@ void CHyprOpenGLImpl::renderRectWithDamageInternal(const CBox& box, const CHyprC scissor(nullptr); } -void CHyprOpenGLImpl::renderTexture(SP tex, const CBox& box, STextureRenderData data) { +void CHyprOpenGLImpl::renderTexture(SP tex, const CBox& box, STextureRenderData data) { RASSERT(m_renderData.pMonitor, "Tried to render texture without begin()!"); if (!data.damage) { @@ -1460,9 +1475,9 @@ WP CHyprOpenGLImpl::renderToFBInternal(const STextureRenderData& data, return shader; } -void CHyprOpenGLImpl::renderTextureInternal(SP tex, const CBox& box, const STextureRenderData& data) { +void CHyprOpenGLImpl::renderTextureInternal(SP tex, const CBox& box, const STextureRenderData& data) { RASSERT(m_renderData.pMonitor, "Tried to render texture without begin()!"); - RASSERT((tex->m_texID > 0), "Attempted to draw nullptr texture!"); + RASSERT((tex->ok()), "Attempted to draw nullptr texture!"); TRACY_GPU_ZONE("RenderTextureInternalWithDamage"); @@ -1558,9 +1573,9 @@ void CHyprOpenGLImpl::renderTextureInternal(SP tex, const CBox& box, c tex->unbind(); } -void CHyprOpenGLImpl::renderTexturePrimitive(SP tex, const CBox& box) { +void CHyprOpenGLImpl::renderTexturePrimitive(SP tex, const CBox& box) { RASSERT(m_renderData.pMonitor, "Tried to render texture without begin()!"); - RASSERT((tex->m_texID > 0), "Attempted to draw nullptr texture!"); + RASSERT((tex->ok()), "Attempted to draw nullptr texture!"); TRACY_GPU_ZONE("RenderTexturePrimitive"); @@ -1603,9 +1618,9 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP tex, const CBox& box) tex->unbind(); } -void CHyprOpenGLImpl::renderTextureMatte(SP tex, const CBox& box, CFramebuffer& matte) { +void CHyprOpenGLImpl::renderTextureMatte(SP tex, const CBox& box, SP matte) { RASSERT(m_renderData.pMonitor, "Tried to render texture without begin()!"); - RASSERT((tex->m_texID > 0), "Attempted to draw nullptr texture!"); + RASSERT((tex->ok()), "Attempted to draw nullptr texture!"); TRACY_GPU_ZONE("RenderTextureMatte"); @@ -1629,7 +1644,7 @@ void CHyprOpenGLImpl::renderTextureMatte(SP tex, const CBox& box, CFra tex->bind(); glActiveTexture(GL_TEXTURE0 + 1); - auto matteTex = matte.getTexture(); + auto matteTex = matte->getTexture(); matteTex->bind(); glBindVertexArray(shader->getUniformLocation(SHADER_SHADER_VAO)); @@ -1648,16 +1663,16 @@ void CHyprOpenGLImpl::renderTextureMatte(SP tex, const CBox& box, CFra // but it works... well, I guess? // // Dual (or more) kawase blur -CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* originalDamage) { +SP CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* originalDamage) { if (!m_renderData.currentFB->getTexture()) { Log::logger->log(Log::ERR, "BUG THIS: null fb texture while attempting to blur main fb?! (introspection off?!)"); - return &m_renderData.pCurrentMonData->mirrorFB; // return something to sample from at least + return m_renderData.pCurrentMonData->mirrorFB; // return something to sample from at least } - return blurFramebufferWithDamage(a, originalDamage, *m_renderData.currentFB); + return blurFramebufferWithDamage(a, originalDamage, *GLFB(m_renderData.currentFB)); } -CFramebuffer* CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* originalDamage, CFramebuffer& source) { +SP CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* originalDamage, CGLFramebuffer& source) { TRACY_GPU_ZONE("RenderBlurFramebufferWithDamage"); const auto BLENDBEFORE = m_blend; @@ -1685,10 +1700,10 @@ CFramebuffer* CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* origi damage.expand(std::clamp(*PBLURSIZE, sc(1), sc(40)) * pow(2, BLUR_PASSES)); // helper - const auto PMIRRORFB = &m_renderData.pCurrentMonData->mirrorFB; - const auto PMIRRORSWAPFB = &m_renderData.pCurrentMonData->mirrorSwapFB; + const auto PMIRRORFB = m_renderData.pCurrentMonData->mirrorFB; + const auto PMIRRORSWAPFB = m_renderData.pCurrentMonData->mirrorSwapFB; - CFramebuffer* currentRenderToFB = PMIRRORFB; + auto currentRenderToFB = PMIRRORFB; // Begin with base color adjustments - global brightness and contrast // TODO: make this a part of the first pass maybe to save on a drawcall? @@ -1960,9 +1975,12 @@ void CHyprOpenGLImpl::preBlurForCurrentMonitor() { const auto POUTFB = blurMainFramebufferWithDamage(1, &fakeDamage); // render onto blurFB - m_renderData.pCurrentMonData->blurFB.alloc(m_renderData.pMonitor->m_pixelSize.x, m_renderData.pMonitor->m_pixelSize.y, - m_renderData.pMonitor->m_output->state->state().drmFormat); - m_renderData.pCurrentMonData->blurFB.bind(); + if (!m_renderData.pCurrentMonData->blurFB) + m_renderData.pCurrentMonData->blurFB = g_pHyprRenderer->createFB(); + + m_renderData.pCurrentMonData->blurFB->alloc(m_renderData.pMonitor->m_pixelSize.x, m_renderData.pMonitor->m_pixelSize.y, + m_renderData.pMonitor->m_output->state->state().drmFormat); + m_renderData.pCurrentMonData->blurFB->bind(); clear(CHyprColor(0, 0, 0, 0)); @@ -1998,7 +2016,7 @@ bool CHyprOpenGLImpl::shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWin static auto PBLURNEWOPTIMIZE = CConfigValue("decoration:blur:new_optimizations"); static auto PBLURXRAY = CConfigValue("decoration:blur:xray"); - if (!m_renderData.pCurrentMonData->blurFB.getTexture()) + if (!m_renderData.pCurrentMonData->blurFB || !m_renderData.pCurrentMonData->blurFB->getTexture()) return false; if (pWindow && pWindow->m_ruleApplicator->xray().hasValue() && !pWindow->m_ruleApplicator->xray().valueOrDefault()) @@ -2016,7 +2034,7 @@ bool CHyprOpenGLImpl::shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWin return false; } -void CHyprOpenGLImpl::renderTextureWithBlurInternal(SP tex, const CBox& box, const STextureRenderData& data) { +void CHyprOpenGLImpl::renderTextureWithBlurInternal(SP tex, const CBox& box, const STextureRenderData& data) { RASSERT(m_renderData.pMonitor, "Tried to render texture with blur without begin()!"); TRACY_GPU_ZONE("RenderTextureWithBlur"); @@ -2056,16 +2074,16 @@ void CHyprOpenGLImpl::renderTextureWithBlurInternal(SP tex, const CBox inverseOpaque.scale(m_renderData.pMonitor->m_scale); // vvv TODO: layered blur fbs? - const bool USENEWOPTIMIZE = shouldUseNewBlurOptimizations(m_renderData.currentLS.lock(), m_renderData.currentWindow.lock()) && !data.blockBlurOptimization; + const bool USENEWOPTIMIZE = shouldUseNewBlurOptimizations(m_renderData.currentLS.lock(), m_renderData.currentWindow.lock()) && !data.blockBlurOptimization; - CFramebuffer* POUTFB = nullptr; + SP POUTFB = nullptr; if (!USENEWOPTIMIZE) { inverseOpaque.translate(box.pos()); m_renderData.renderModif.applyToRegion(inverseOpaque); inverseOpaque.intersect(texDamage); POUTFB = blurMainFramebufferWithDamage(data.a, &inverseOpaque); } else - POUTFB = &m_renderData.pCurrentMonData->blurFB; + POUTFB = m_renderData.pCurrentMonData->blurFB; m_renderData.currentFB->bind(); @@ -2161,7 +2179,7 @@ void CHyprOpenGLImpl::renderTextureWithBlurInternal(SP tex, const CBox .blurredBG = blurredBG, }); - m_renderData.currentFB->invalidate({GL_STENCIL_ATTACHMENT}); + GLFB(m_renderData.currentFB)->invalidate({GL_STENCIL_ATTACHMENT}); scissor(nullptr); } @@ -2410,7 +2428,14 @@ void CHyprOpenGLImpl::renderRoundedShadow(const CBox& box, int round, float roun } void CHyprOpenGLImpl::saveBufferForMirror(const CBox& box) { - m_renderData.pCurrentMonData->monitorMirrorFB.bind(); + if (!m_renderData.pCurrentMonData->monitorMirrorFB) + m_renderData.pCurrentMonData->monitorMirrorFB = g_pHyprRenderer->createFB(); + + if (!m_renderData.pCurrentMonData->monitorMirrorFB->isAllocated()) + m_renderData.pCurrentMonData->monitorMirrorFB->alloc(m_renderData.pMonitor->m_pixelSize.x, m_renderData.pMonitor->m_pixelSize.y, + m_renderData.pMonitor->m_output->state->state().drmFormat); + + m_renderData.pCurrentMonData->monitorMirrorFB->bind(); blend(false); @@ -2443,7 +2468,7 @@ void CHyprOpenGLImpl::renderMirrored() { monbox.x = (monitor->m_transformedSize.x - monbox.w) / 2; monbox.y = (monitor->m_transformedSize.y - monbox.h) / 2; - const auto PFB = &m_monitorRenderResources[mirrored].monitorMirrorFB; + auto PFB = m_monitorRenderResources[mirrored].monitorMirrorFB; if (!PFB->isAllocated() || !PFB->getTexture()) return; @@ -2517,7 +2542,7 @@ std::string CHyprOpenGLImpl::resolveAssetPath(const std::string& filename) { return fullPath; } -SP CHyprOpenGLImpl::loadAsset(const std::string& filename) { +SP CHyprOpenGLImpl::loadAsset(const std::string& filename) { const std::string fullPath = resolveAssetPath(filename); @@ -2539,12 +2564,11 @@ SP CHyprOpenGLImpl::loadAsset(const std::string& filename) { return tex; } -SP CHyprOpenGLImpl::texFromCairo(cairo_surface_t* cairo) { +SP CHyprOpenGLImpl::texFromCairo(cairo_surface_t* cairo) { const auto CAIROFORMAT = cairo_image_surface_get_format(cairo); - auto tex = makeShared(); + auto tex = makeShared(); - tex->allocate(); - tex->m_size = {cairo_image_surface_get_width(cairo), cairo_image_surface_get_height(cairo)}; + tex->allocate({cairo_image_surface_get_width(cairo), cairo_image_surface_get_height(cairo)}); const GLint glIFormat = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_RGB32F : GL_RGBA; const GLint glFormat = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_RGB : GL_RGBA; @@ -2565,8 +2589,8 @@ SP CHyprOpenGLImpl::texFromCairo(cairo_surface_t* cairo) { return tex; } -SP CHyprOpenGLImpl::renderText(const std::string& text, CHyprColor col, int pt, bool italic, const std::string& fontFamily, int maxWidth, int weight) { - SP tex = makeShared(); +SP CHyprOpenGLImpl::renderText(const std::string& text, CHyprColor col, int pt, bool italic, const std::string& fontFamily, int maxWidth, int weight) { + SP tex = makeShared(); static auto FONT = CConfigValue("misc:font_family"); @@ -2628,8 +2652,7 @@ SP CHyprOpenGLImpl::renderText(const std::string& text, CHyprColor col cairo_surface_flush(CAIROSURFACE); - tex->allocate(); - tex->m_size = {cairo_image_surface_get_width(CAIROSURFACE), cairo_image_surface_get_height(CAIROSURFACE)}; + tex->allocate({cairo_image_surface_get_width(CAIROSURFACE), cairo_image_surface_get_height(CAIROSURFACE)}); const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); tex->bind(); @@ -2646,8 +2669,8 @@ SP CHyprOpenGLImpl::renderText(const std::string& text, CHyprColor col } void CHyprOpenGLImpl::initMissingAssetTexture() { - SP tex = makeShared(); - tex->allocate(); + SP tex = makeShared(); + tex->allocate({512, 512}); const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 512, 512); const auto CAIRO = cairo_create(CAIROSURFACE); @@ -2799,16 +2822,19 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(PHLMONITOR pMonitor) { if (!m_backgroundResource->m_ready) return; + if (!m_monitorBGFBs.contains(pMonitor)) + m_monitorBGFBs[pMonitor] = g_pHyprRenderer->createFB(); + // release the last tex if exists - const auto PFB = &m_monitorBGFBs[pMonitor]; + auto PFB = m_monitorBGFBs[pMonitor]; PFB->release(); PFB->alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, pMonitor->m_output->state->state().drmFormat); // create a new one with cairo - SP tex = makeShared(); + SP tex = makeShared(); - tex->allocate(); + tex->allocate(pMonitor->m_pixelSize); const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y); const auto CAIRO = cairo_create(CAIROSURFACE); @@ -2850,7 +2876,7 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(PHLMONITOR pMonitor) { blend(true); clear(CHyprColor{0, 0, 0, 1}); - SP backgroundTexture = texFromCairo(m_backgroundResource->m_asset.cairoSurface->cairo()); + SP backgroundTexture = texFromCairo(m_backgroundResource->m_asset.cairoSurface->cairo()); // first render the background if (backgroundTexture) { @@ -2905,7 +2931,7 @@ void CHyprOpenGLImpl::clearWithTex() { data.box = {0, 0, m_renderData.pMonitor->m_transformedSize.x, m_renderData.pMonitor->m_transformedSize.y}; data.a = m_renderData.pMonitor->m_backgroundOpacity->value(); data.flipEndFrame = true; - data.tex = TEXIT->second.getTexture(); + data.tex = TEXIT->second->getTexture(); g_pHyprRenderer->m_renderPass.add(makeUnique(std::move(data))); } } @@ -2918,19 +2944,19 @@ void CHyprOpenGLImpl::destroyMonitorResources(PHLMONITORREF pMonitor) { auto RESIT = g_pHyprOpenGL->m_monitorRenderResources.find(pMonitor); if (RESIT != g_pHyprOpenGL->m_monitorRenderResources.end()) { - RESIT->second.mirrorFB.release(); - RESIT->second.offloadFB.release(); - RESIT->second.mirrorSwapFB.release(); - RESIT->second.monitorMirrorFB.release(); - RESIT->second.blurFB.release(); - RESIT->second.offMainFB.release(); - RESIT->second.stencilTex->destroyTexture(); + RESIT->second.mirrorFB.reset(); + RESIT->second.offloadFB.reset(); + RESIT->second.mirrorSwapFB.reset(); + RESIT->second.monitorMirrorFB.reset(); + RESIT->second.blurFB.reset(); + RESIT->second.offMainFB.reset(); + RESIT->second.stencilTex.reset(); g_pHyprOpenGL->m_monitorRenderResources.erase(RESIT); } auto TEXIT = g_pHyprOpenGL->m_monitorBGFBs.find(pMonitor); if (TEXIT != g_pHyprOpenGL->m_monitorBGFBs.end()) { - TEXIT->second.release(); + TEXIT->second.reset(); g_pHyprOpenGL->m_monitorBGFBs.erase(TEXIT); } @@ -2951,19 +2977,21 @@ void CHyprOpenGLImpl::restoreMatrix() { } void CHyprOpenGLImpl::bindOffMain() { - if (!m_renderData.pCurrentMonData->offMainFB.isAllocated()) { - m_renderData.pCurrentMonData->offMainFB.alloc(m_renderData.pMonitor->m_pixelSize.x, m_renderData.pMonitor->m_pixelSize.y, - m_renderData.pMonitor->m_output->state->state().drmFormat); + if (!m_renderData.pCurrentMonData->offMainFB) + m_renderData.pCurrentMonData->offMainFB = g_pHyprRenderer->createFB(); - m_renderData.pCurrentMonData->offMainFB.addStencil(m_renderData.pCurrentMonData->stencilTex); + if (!m_renderData.pCurrentMonData->offMainFB->isAllocated()) { + m_renderData.pCurrentMonData->offMainFB->addStencil(m_renderData.pCurrentMonData->stencilTex); + m_renderData.pCurrentMonData->offMainFB->alloc(m_renderData.pMonitor->m_pixelSize.x, m_renderData.pMonitor->m_pixelSize.y, + m_renderData.pMonitor->m_output->state->state().drmFormat); } - m_renderData.pCurrentMonData->offMainFB.bind(); + m_renderData.pCurrentMonData->offMainFB->bind(); clear(CHyprColor(0, 0, 0, 0)); - m_renderData.currentFB = &m_renderData.pCurrentMonData->offMainFB; + m_renderData.currentFB = m_renderData.pCurrentMonData->offMainFB; } -void CHyprOpenGLImpl::renderOffToMain(CFramebuffer* off) { +void CHyprOpenGLImpl::renderOffToMain(CGLFramebuffer* off) { CBox monbox = {0, 0, m_renderData.pMonitor->m_transformedSize.x, m_renderData.pMonitor->m_transformedSize.y}; renderTexturePrimitive(off->getTexture(), monbox); } diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 82b34119..c9008447 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -20,6 +20,7 @@ #include "Texture.hpp" #include "Framebuffer.hpp" #include "Renderbuffer.hpp" +#include "desktop/DesktopTypes.hpp" #include "pass/Pass.hpp" #include @@ -32,9 +33,14 @@ #include "../debug/TracyDefines.hpp" #include "../protocols/core/Compositor.hpp" #include "render/ShaderLoader.hpp" +#include "render/gl/GLFramebuffer.hpp" +#include "render/gl/GLRenderbuffer.hpp" +#include "render/gl/GLTexture.hpp" + +#define GLFB(ifb) dc(ifb.get()) struct gbm_device; -class CHyprRenderer; +class IHyprRenderer; struct SVertex { float x, y; // position @@ -108,17 +114,17 @@ struct SPreparedShaders { }; struct SMonitorRenderData { - CFramebuffer offloadFB; - CFramebuffer mirrorFB; // these are used for some effects, - CFramebuffer mirrorSwapFB; // etc - CFramebuffer offMainFB; - CFramebuffer monitorMirrorFB; // used for mirroring outputs / screencopy, does not contain artifacts like offloadFB and is in sRGB - CFramebuffer blurFB; + SP offloadFB; + SP mirrorFB; // these are used for some effects, + SP mirrorSwapFB; // etc + SP offMainFB; + SP monitorMirrorFB; // used for mirroring outputs, does not contain artifacts like offloadFB + SP blurFB; - SP stencilTex = makeShared(); + SP stencilTex = makeShared(); - bool blurFBDirty = true; - bool blurFBShouldRender = false; + bool blurFBDirty = true; + bool blurFBShouldRender = false; }; struct SCurrentRenderData { @@ -129,9 +135,9 @@ struct SCurrentRenderData { // FIXME: raw pointer galore! SMonitorRenderData* pCurrentMonData = nullptr; - CFramebuffer* currentFB = nullptr; // current rendering to - CFramebuffer* mainFB = nullptr; // main to render to - CFramebuffer* outFB = nullptr; // out to render to (if offloaded, etc) + SP currentFB = nullptr; // current rendering to + SP mainFB = nullptr; // main to render to + SP outFB = nullptr; // out to render to (if offloaded, etc) CRegion damage; CRegion finalDamage; // damage used for funal off -> main @@ -213,7 +219,7 @@ class CHyprOpenGLImpl { bool noCM = false; bool finalMonitorCM = false; SP cmBackToSRGBSource; - SP blurredBG; + SP blurredBG; }; struct SBorderRenderData { @@ -224,17 +230,17 @@ class CHyprOpenGLImpl { int outerRound = -1; /* use round */ }; - void begin(PHLMONITOR, const CRegion& damage, CFramebuffer* fb = nullptr, std::optional finalDamage = {}); - void beginSimple(PHLMONITOR, const CRegion& damage, SP rb = nullptr, CFramebuffer* fb = nullptr); + void begin(PHLMONITOR, const CRegion& damage, SP fb = nullptr, std::optional finalDamage = {}); + void beginSimple(PHLMONITOR, const CRegion& damage, SP rb = nullptr, SP fb = nullptr); void end(); void renderRect(const CBox&, const CHyprColor&, SRectRenderData data); - void renderTexture(SP, const CBox&, STextureRenderData data); + void renderTexture(SP, const CBox&, STextureRenderData data); void renderRoundedShadow(const CBox&, int round, float roundingPower, int range, const CHyprColor& color, float a = 1.0); void renderBorder(const CBox&, const CGradientValueData&, SBorderRenderData data); void renderBorder(const CBox&, const CGradientValueData&, const CGradientValueData&, float lerp, SBorderRenderData data); - void renderTextureMatte(SP tex, const CBox& pBox, CFramebuffer& matte); - void renderTexturePrimitive(SP tex, const CBox& box); + void renderTextureMatte(SP tex, const CBox& pBox, SP matte); + void renderTexturePrimitive(SP tex, const CBox& box); void pushMonitorTransformEnabled(bool enabled); void popMonitorTransformEnabled(); @@ -271,49 +277,49 @@ class CHyprOpenGLImpl { void applyScreenShader(const std::string& path); void bindOffMain(); - void renderOffToMain(CFramebuffer* off); + void renderOffToMain(CGLFramebuffer* off); void bindBackOnMain(); bool needsACopyFB(PHLMONITOR mon); std::string resolveAssetPath(const std::string& file); - SP loadAsset(const std::string& file); - SP texFromCairo(cairo_surface_t* cairo); - SP renderText(const std::string& text, CHyprColor col, int pt, bool italic = false, const std::string& fontFamily = "", int maxWidth = 0, int weight = 400); + SP loadAsset(const std::string& file); + SP texFromCairo(cairo_surface_t* cairo); + SP renderText(const std::string& text, CHyprColor col, int pt, bool italic = false, const std::string& fontFamily = "", int maxWidth = 0, int weight = 400); void setDamage(const CRegion& damage, std::optional finalDamage = {}); DRMFormat getPreferredReadFormat(PHLMONITOR pMonitor); - std::vector getDRMFormats(); - std::vector getDRMFormatModifiers(DRMFormat format); - EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); + std::vector getDRMFormats(); + std::vector getDRMFormatModifiers(DRMFormat format); + EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); - bool initShaders(const std::string& path = ""); + bool initShaders(const std::string& path = ""); - WP useShader(WP prog); + WP useShader(WP prog); - bool explicitSyncSupported(); - WP getShaderVariant(Render::ePreparedFragmentShader frag, Render::ShaderFeatureFlags features = 0); + bool explicitSyncSupported(); + WP getShaderVariant(Render::ePreparedFragmentShader frag, Render::ShaderFeatureFlags features = 0); - bool m_shadersInitialized = false; - SP m_shaders; + bool m_shadersInitialized = false; + SP m_shaders; - SCurrentRenderData m_renderData; + SCurrentRenderData m_renderData; - Hyprutils::OS::CFileDescriptor m_gbmFD; - gbm_device* m_gbmDevice = nullptr; - EGLContext m_eglContext = nullptr; - EGLDisplay m_eglDisplay = nullptr; - EGLDeviceEXT m_eglDevice = nullptr; - uint m_failedAssetsNo = 0; + Hyprutils::OS::CFileDescriptor m_gbmFD; + gbm_device* m_gbmDevice = nullptr; + EGLContext m_eglContext = nullptr; + EGLDisplay m_eglDisplay = nullptr; + EGLDeviceEXT m_eglDevice = nullptr; + uint m_failedAssetsNo = 0; - bool m_reloadScreenShader = true; // at launch it can be set + bool m_reloadScreenShader = true; // at launch it can be set - std::map m_windowFramebuffers; - std::map m_layerFramebuffers; - std::map, CFramebuffer> m_popupFramebuffers; - std::map m_monitorRenderResources; - std::map m_monitorBGFBs; + std::map> m_windowFramebuffers; + std::map> m_layerFramebuffers; + std::map, SP> m_popupFramebuffers; + std::map m_monitorRenderResources; + std::map> m_monitorBGFBs; struct { PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES = nullptr; @@ -344,7 +350,7 @@ class CHyprOpenGLImpl { bool EGL_ANDROID_native_fence_sync_ext = false; } m_exts; - SP m_screencopyDeniedTexture; + SP m_screencopyDeniedTexture; enum eEGLContextVersion : uint8_t { EGL_CONTEXT_GLES_2_0 = 0, @@ -385,10 +391,10 @@ class CHyprOpenGLImpl { bool m_monitorTransformEnabled = false; // do not modify directly std::stack m_monitorTransformStack; - SP m_missingAssetTexture; - SP m_lockDeadTexture; - SP m_lockDead2Texture; - SP m_lockTtyTextTexture; + SP m_missingAssetTexture; + SP m_lockDeadTexture; + SP m_lockDead2Texture; + SP m_lockTtyTextTexture; SP m_finalScreenShader; CTimer m_globalTimer; GLuint m_currentProgram; @@ -414,22 +420,22 @@ class CHyprOpenGLImpl { std::optional> getModsForFormat(EGLint format); // returns the out FB, can be either Mirror or MirrorSwap - CFramebuffer* blurMainFramebufferWithDamage(float a, CRegion* damage); - CFramebuffer* blurFramebufferWithDamage(float a, CRegion* damage, CFramebuffer& source); + SP blurMainFramebufferWithDamage(float a, CRegion* damage); + SP blurFramebufferWithDamage(float a, CRegion* damage, CGLFramebuffer& source); - void passCMUniforms(WP, const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription, - bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1); - void passCMUniforms(WP, const NColorManagement::PImageDescription imageDescription); - void renderSplash(cairo_t* const, cairo_surface_t* const, double offset, const Vector2D& size); - void renderRectInternal(const CBox&, const CHyprColor&, const SRectRenderData& data); - void renderRectWithBlurInternal(const CBox&, const CHyprColor&, const SRectRenderData& data); - void renderRectWithDamageInternal(const CBox&, const CHyprColor&, const SRectRenderData& data); - WP renderToOutputInternal(); - WP renderToFBInternal(const STextureRenderData& data, eTextureType texType, const CBox& newBox); - void renderTextureInternal(SP, const CBox&, const STextureRenderData& data); - void renderTextureWithBlurInternal(SP, const CBox&, const STextureRenderData& data); + void passCMUniforms(WP, const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription, + bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1); + void passCMUniforms(WP, const NColorManagement::PImageDescription imageDescription); + void renderSplash(cairo_t* const, cairo_surface_t* const, double offset, const Vector2D& size); + void renderRectInternal(const CBox&, const CHyprColor&, const SRectRenderData& data); + void renderRectWithBlurInternal(const CBox&, const CHyprColor&, const SRectRenderData& data); + void renderRectWithDamageInternal(const CBox&, const CHyprColor&, const SRectRenderData& data); + WP renderToOutputInternal(); + WP renderToFBInternal(const STextureRenderData& data, eTextureType texType, const CBox& newBox); + void renderTextureInternal(SP, const CBox&, const STextureRenderData& data); + void renderTextureWithBlurInternal(SP, const CBox&, const STextureRenderData& data); - void preBlurForCurrentMonitor(); + void preBlurForCurrentMonitor(); friend class CHyprRenderer; friend class CTexPassElement; diff --git a/src/render/Renderbuffer.cpp b/src/render/Renderbuffer.cpp index ebc4958f..bab4f73e 100644 --- a/src/render/Renderbuffer.cpp +++ b/src/render/Renderbuffer.cpp @@ -1,74 +1,21 @@ #include "Renderbuffer.hpp" -#include "Renderer.hpp" -#include "OpenGL.hpp" -#include "../Compositor.hpp" -#include "../protocols/types/Buffer.hpp" +#include "Framebuffer.hpp" +#include "render/Renderer.hpp" +#include "render/gl/GLRenderbuffer.hpp" +#include #include #include #include -CRenderbuffer::~CRenderbuffer() { - if (!g_pCompositor || g_pCompositor->m_isShuttingDown || !g_pHyprRenderer) - return; - - g_pHyprRenderer->makeEGLCurrent(); - - unbind(); - m_framebuffer.release(); - - if (m_rbo) - glDeleteRenderbuffers(1, &m_rbo); - - if (m_image != EGL_NO_IMAGE_KHR) - g_pHyprOpenGL->m_proc.eglDestroyImageKHR(g_pHyprOpenGL->m_eglDisplay, m_image); +IRenderbuffer::IRenderbuffer(SP buffer, uint32_t format) : m_hlBuffer(buffer) { + m_listeners.destroyBuffer = buffer->events.destroy.listen([this] { g_pHyprRenderer->onRenderbufferDestroy(dc(this)); }); } -CRenderbuffer::CRenderbuffer(SP buffer, uint32_t format) : m_hlBuffer(buffer), m_drmFormat(format) { - auto dma = buffer->dmabuf(); - - m_image = g_pHyprOpenGL->createEGLImage(dma); - if (m_image == EGL_NO_IMAGE_KHR) { - Log::logger->log(Log::ERR, "rb: createEGLImage failed"); - return; - } - - glGenRenderbuffers(1, &m_rbo); - glBindRenderbuffer(GL_RENDERBUFFER, m_rbo); - g_pHyprOpenGL->m_proc.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, m_image); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - - glGenFramebuffers(1, &m_framebuffer.m_fb); - m_framebuffer.m_fbAllocated = true; - m_framebuffer.m_size = buffer->size; - m_framebuffer.m_drmFormat = dma.format; - m_framebuffer.bind(); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rbo); - - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - Log::logger->log(Log::ERR, "rbo: glCheckFramebufferStatus failed"); - return; - } - - m_framebuffer.unbind(); - - m_listeners.destroyBuffer = buffer->events.destroy.listen([this] { g_pHyprRenderer->onRenderbufferDestroy(this); }); - - m_good = true; -} - -bool CRenderbuffer::good() { +bool IRenderbuffer::good() { return m_good; } -void CRenderbuffer::bind() { - m_framebuffer.bind(); -} - -void CRenderbuffer::unbind() { - m_framebuffer.unbind(); -} - -CFramebuffer* CRenderbuffer::getFB() { - return &m_framebuffer; +SP IRenderbuffer::getFB() { + return m_framebuffer; } diff --git a/src/render/Renderbuffer.hpp b/src/render/Renderbuffer.hpp index 90c539b1..c33144d3 100644 --- a/src/render/Renderbuffer.hpp +++ b/src/render/Renderbuffer.hpp @@ -5,27 +5,22 @@ #include "Framebuffer.hpp" #include -class CMonitor; - -class CRenderbuffer { +class IRenderbuffer { public: - CRenderbuffer(SP buffer, uint32_t format); - ~CRenderbuffer(); + IRenderbuffer(SP buffer, uint32_t format); + virtual ~IRenderbuffer() = default; bool good(); - void bind(); - void unbind(); - CFramebuffer* getFB(); - uint32_t getFormat(); + SP getFB(); + + virtual void bind() = 0; + virtual void unbind() = 0; WP m_hlBuffer; - private: - void* m_image = nullptr; - GLuint m_rbo = 0; - CFramebuffer m_framebuffer; - uint32_t m_drmFormat = 0; - bool m_good = false; + protected: + SP m_framebuffer; + bool m_good = false; struct { CHyprSignalListener destroyBuffer; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 8a1cf4b3..165f580a 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -3,6 +3,7 @@ #include "../helpers/math/Math.hpp" #include #include +#include #include #include "../config/ConfigValue.hpp" #include "../config/ConfigManager.hpp" @@ -29,10 +30,12 @@ #include "../layout/LayoutManager.hpp" #include "../layout/space/Space.hpp" #include "../i18n/Engine.hpp" +#include "desktop/DesktopTypes.hpp" #include "../event/EventBus.hpp" #include "helpers/CursorShapes.hpp" +#include "helpers/MainLoopExecutor.hpp" #include "helpers/Monitor.hpp" -#include "helpers/cm/ColorManagement.hpp" +#include "macros.hpp" #include "pass/TexPassElement.hpp" #include "pass/ClearPassElement.hpp" #include "pass/RectPassElement.hpp" @@ -42,7 +45,18 @@ #include "../protocols/ColorManagement.hpp" #include "../protocols/types/ContentType.hpp" #include "../helpers/MiscFunctions.hpp" +#include "render/AsyncResourceGatherer.hpp" +#include "render/Framebuffer.hpp" #include "render/OpenGL.hpp" +#include "render/Texture.hpp" +#include "render/gl/GLFramebuffer.hpp" +#include "render/gl/GLTexture.hpp" +#include +#include +#include +#include +#include +#include #include using namespace Hyprutils::Utils; @@ -643,13 +657,13 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, const T } if (TRANSFORMERSPRESENT) { - CFramebuffer* last = g_pHyprOpenGL->m_renderData.currentFB; + IFramebuffer* last = g_pHyprOpenGL->m_renderData.currentFB.get(); for (auto const& t : pWindow->m_transformers) { last = t->transform(last); } g_pHyprOpenGL->bindBackOnMain(); - g_pHyprOpenGL->renderOffToMain(last); + g_pHyprOpenGL->renderOffToMain(dc(last)); } } @@ -733,6 +747,36 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, const T g_pHyprOpenGL->m_renderData.currentWindow.reset(); } +SP CHyprRenderer::createTexture(const SP buffer, bool keepDataCopy) { + if (!buffer) + return createTexture(); + + auto attrs = buffer->dmabuf(); + + if (!attrs.success) { + // attempt shm + auto shm = buffer->shm(); + + if (!shm.success) { + Log::logger->log(Log::ERR, "Cannot create a texture: buffer has no dmabuf or shm"); + return createTexture(buffer->opaque); + } + + auto [pixelData, fmt, bufLen] = buffer->beginDataPtr(0); + + return createTexture(fmt, pixelData, bufLen, shm.size, keepDataCopy, buffer->opaque); + } + + auto tex = createTexture(attrs, buffer->opaque); + + if (!tex) { + Log::logger->log(Log::ERR, "Cannot create a texture: failed to create an Image"); + return createTexture(buffer->opaque); + } + + return tex; +} + void CHyprRenderer::renderLayer(PHLLS pLayer, PHLMONITOR pMonitor, const Time::steady_tp& time, bool popups, bool lockscreen) { if (!pLayer) return; @@ -2313,13 +2357,13 @@ void CHyprRenderer::initiateManualCrash() { **PDT = 0; } -SP CHyprRenderer::getOrCreateRenderbuffer(SP buffer, uint32_t fmt) { +SP CHyprRenderer::getOrCreateRenderbuffer(SP buffer, uint32_t fmt) { auto it = std::ranges::find_if(m_renderbuffers, [&](const auto& other) { return other->m_hlBuffer == buffer; }); if (it != m_renderbuffers.end()) return *it; - auto buf = makeShared(buffer, fmt); + auto buf = makeShared(buffer, fmt); if (!buf->good()) return nullptr; @@ -2343,7 +2387,7 @@ void CHyprRenderer::unsetEGL() { eglMakeCurrent(g_pHyprOpenGL->m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } -bool CHyprRenderer::beginRender(PHLMONITOR pMonitor, CRegion& damage, eRenderMode mode, SP buffer, CFramebuffer* fb, bool simple) { +bool CHyprRenderer::beginRender(PHLMONITOR pMonitor, CRegion& damage, eRenderMode mode, SP buffer, SP fb, bool simple) { makeEGLCurrent(); @@ -2475,11 +2519,11 @@ void CHyprRenderer::endRender(const std::function& renderingDoneCallback } } -void CHyprRenderer::onRenderbufferDestroy(CRenderbuffer* rb) { +void CHyprRenderer::onRenderbufferDestroy(CGLRenderbuffer* rb) { std::erase_if(m_renderbuffers, [&](const auto& rbo) { return rbo.get() == rb; }); } -SP CHyprRenderer::getCurrentRBO() { +SP CHyprRenderer::getCurrentRBO() { return m_currentRenderbuffer; } @@ -2532,7 +2576,10 @@ void CHyprRenderer::makeSnapshot(PHLWINDOW pWindow) { makeEGLCurrent(); - const auto PFRAMEBUFFER = &g_pHyprOpenGL->m_windowFramebuffers[ref]; + if (!g_pHyprOpenGL->m_windowFramebuffers.contains(ref)) + g_pHyprOpenGL->m_windowFramebuffers[ref] = g_pHyprRenderer->createFB(); + + const auto PFRAMEBUFFER = g_pHyprOpenGL->m_windowFramebuffers[ref]; PFRAMEBUFFER->alloc(PMONITOR->m_pixelSize.x, PMONITOR->m_pixelSize.y, DRM_FORMAT_ABGR8888); @@ -2565,7 +2612,10 @@ void CHyprRenderer::makeSnapshot(PHLLS pLayer) { makeEGLCurrent(); - const auto PFRAMEBUFFER = &g_pHyprOpenGL->m_layerFramebuffers[pLayer]; + if (!g_pHyprOpenGL->m_layerFramebuffers.contains(pLayer)) + g_pHyprOpenGL->m_layerFramebuffers[pLayer] = g_pHyprRenderer->createFB(); + + const auto PFRAMEBUFFER = g_pHyprOpenGL->m_layerFramebuffers[pLayer]; PFRAMEBUFFER->alloc(PMONITOR->m_pixelSize.x, PMONITOR->m_pixelSize.y, DRM_FORMAT_ABGR8888); @@ -2599,7 +2649,10 @@ void CHyprRenderer::makeSnapshot(WP popup) { makeEGLCurrent(); - const auto PFRAMEBUFFER = &g_pHyprOpenGL->m_popupFramebuffers[popup]; + if (!g_pHyprOpenGL->m_popupFramebuffers.contains(popup)) + g_pHyprOpenGL->m_popupFramebuffers[popup] = g_pHyprRenderer->createFB(); + + const auto PFRAMEBUFFER = g_pHyprOpenGL->m_popupFramebuffers[popup]; PFRAMEBUFFER->alloc(PMONITOR->m_pixelSize.x, PMONITOR->m_pixelSize.y, DRM_FORMAT_ABGR8888); @@ -2648,7 +2701,7 @@ void CHyprRenderer::renderSnapshot(PHLWINDOW pWindow) { if (!g_pHyprOpenGL->m_windowFramebuffers.contains(ref)) return; - const auto FBDATA = &g_pHyprOpenGL->m_windowFramebuffers.at(ref); + const auto FBDATA = g_pHyprOpenGL->m_windowFramebuffers.at(ref); if (!FBDATA->getTexture()) return; @@ -2704,7 +2757,7 @@ void CHyprRenderer::renderSnapshot(PHLLS pLayer) { if (!g_pHyprOpenGL->m_layerFramebuffers.contains(pLayer)) return; - const auto FBDATA = &g_pHyprOpenGL->m_layerFramebuffers.at(pLayer); + const auto FBDATA = g_pHyprOpenGL->m_layerFramebuffers.at(pLayer); if (!FBDATA->getTexture()) return; @@ -2748,7 +2801,7 @@ void CHyprRenderer::renderSnapshot(WP popup) { static CConfigValue PBLURIGNOREA = CConfigValue("decoration:blur:popups_ignorealpha"); - const auto FBDATA = &g_pHyprOpenGL->m_popupFramebuffers.at(popup); + const auto FBDATA = g_pHyprOpenGL->m_popupFramebuffers.at(popup); if (!FBDATA->getTexture()) return; @@ -2813,4 +2866,89 @@ bool CHyprRenderer::shouldBlur(WP p) { bool CHyprRenderer::reloadShaders(const std::string& path) { return g_pHyprOpenGL->initShaders(path); +} + +SP CHyprRenderer::createStencilTexture(const int width, const int height) { + makeEGLCurrent(); + auto tex = makeShared(); + tex->allocate({width, height}); + + return tex; +} + +SP CHyprRenderer::createTexture(bool opaque) { + makeEGLCurrent(); + return makeShared(opaque); +} + +SP CHyprRenderer::createTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy, bool opaque) { + makeEGLCurrent(); + return makeShared(drmFormat, pixels, stride, size, keepDataCopy, opaque); +} + +SP CHyprRenderer::createTexture(const Aquamarine::SDMABUFAttrs& attrs, bool opaque) { + makeEGLCurrent(); + const auto image = g_pHyprOpenGL->createEGLImage(attrs); + if (!image) + return nullptr; + return makeShared(attrs, image, opaque); +} + +SP CHyprRenderer::createTexture(const int width, const int height, unsigned char* const data) { + makeEGLCurrent(); + SP tex = makeShared(); + + tex->allocate({width, height}); + + tex->m_size = {width, height}; + // copy the data to an OpenGL texture we have + const GLint glFormat = GL_RGBA; + const GLint glType = GL_UNSIGNED_BYTE; + + tex->bind(); + tex->setTexParameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR); + tex->setTexParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR); + tex->setTexParameter(GL_TEXTURE_SWIZZLE_R, GL_BLUE); + tex->setTexParameter(GL_TEXTURE_SWIZZLE_B, GL_RED); + + glTexImage2D(GL_TEXTURE_2D, 0, glFormat, tex->m_size.x, tex->m_size.y, 0, glFormat, glType, data); + tex->unbind(); + + return tex; +} + +SP CHyprRenderer::createTexture(cairo_surface_t* cairo) { + makeEGLCurrent(); + const auto CAIROFORMAT = cairo_image_surface_get_format(cairo); + auto tex = makeShared(); + + tex->allocate({cairo_image_surface_get_width(cairo), cairo_image_surface_get_height(cairo)}); + + const GLint glIFormat = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_RGB32F : GL_RGBA; + const GLint glFormat = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_RGB : GL_RGBA; + const GLint glType = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_FLOAT : GL_UNSIGNED_BYTE; + + const auto DATA = cairo_image_surface_get_data(cairo); + tex->bind(); + tex->setTexParameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR); + tex->setTexParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + if (CAIROFORMAT != CAIRO_FORMAT_RGB96F) { + tex->setTexParameter(GL_TEXTURE_SWIZZLE_R, GL_BLUE); + tex->setTexParameter(GL_TEXTURE_SWIZZLE_B, GL_RED); + } + + glTexImage2D(GL_TEXTURE_2D, 0, glIFormat, tex->m_size.x, tex->m_size.y, 0, glFormat, glType, DATA); + + return tex; +} + +SP CHyprRenderer::createTexture(std::span lut3D, size_t N) { + makeEGLCurrent(); + return makeShared(lut3D, N); +} + +SP CHyprRenderer::createFB(const std::string& name) { + makeEGLCurrent(); + return makeShared(name); } \ No newline at end of file diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 74b70283..bd14c219 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -13,7 +13,8 @@ #include "../helpers/math/Math.hpp" #include "../helpers/time/Time.hpp" #include "../../protocols/cursor-shape-v1.hpp" -#include "helpers/cm/ColorManagement.hpp" +#include "render/Framebuffer.hpp" +#include "render/Texture.hpp" struct SMonitorRule; class CWorkspace; @@ -108,8 +109,8 @@ class CHyprRenderer { void renderLockscreen(PHLMONITOR pMonitor, const Time::steady_tp& now, const CBox& geometry); void setCursorSurface(SP surf, int hotspotX, int hotspotY, bool force = false); void setCursorFromName(const std::string& name, bool force = false); - void onRenderbufferDestroy(CRenderbuffer* rb); - SP getCurrentRBO(); + void onRenderbufferDestroy(CGLRenderbuffer* rb); + SP getCurrentRBO(); bool isNvidia(); bool isIntel(); bool isSoftware(); @@ -129,7 +130,7 @@ class CHyprRenderer { // if RENDER_MODE_NORMAL, provided damage will be written to. // otherwise, it will be the one used. - bool beginRender(PHLMONITOR pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP buffer = {}, CFramebuffer* fb = nullptr, bool simple = false); + bool beginRender(PHLMONITOR pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP buffer = {}, SP fb = nullptr, bool simple = false); void endRender(const std::function& renderingDoneCallback = {}); bool m_bBlockSurfaceFeedback = false; @@ -157,11 +158,21 @@ class CHyprRenderer { std::string name; } m_lastCursorData; - CRenderPass m_renderPass = {}; + CRenderPass m_renderPass = {}; - SCMSettings getCMSettings(const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription, - SP surface = nullptr, bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1); - bool reloadShaders(const std::string& path = ""); + SP createStencilTexture(const int width, const int height); + SP createTexture(bool opaque = false); + SP createTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false, bool opaque = false); + SP createTexture(const Aquamarine::SDMABUFAttrs&, bool opaque = false); + SP createTexture(const int width, const int height, unsigned char* const); + SP createTexture(cairo_surface_t* cairo); + SP createTexture(const SP buffer, bool keepDataCopy = false); + SP createTexture(std::span lut3D, size_t N); + SP createFB(const std::string& name = ""); + + SCMSettings getCMSettings(const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription, + SP surface = nullptr, bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1); + bool reloadShaders(const std::string& path = ""); private: void arrangeLayerArray(PHLMONITOR, const std::vector&, bool, CBox*); @@ -188,7 +199,7 @@ class CHyprRenderer { bool m_cursorHidden = false; bool m_cursorHiddenByCondition = false; bool m_cursorHasSurface = false; - SP m_currentRenderbuffer = nullptr; + SP m_currentRenderbuffer = nullptr; SP m_currentBuffer = nullptr; eRenderMode m_renderMode = RENDER_MODE_NORMAL; bool m_nvidia = false; @@ -203,8 +214,8 @@ class CHyprRenderer { bool hiddenOnKeyboard = false; } m_cursorHiddenConditions; - SP getOrCreateRenderbuffer(SP buffer, uint32_t fmt); - std::vector> m_renderbuffers; + SP getOrCreateRenderbuffer(SP buffer, uint32_t fmt); + std::vector> m_renderbuffers; std::vector m_renderUnfocused; SP m_renderUnfocusedTimer; diff --git a/src/render/Texture.cpp b/src/render/Texture.cpp index 1a35e488..28ae4b41 100644 --- a/src/render/Texture.cpp +++ b/src/render/Texture.cpp @@ -1,265 +1,24 @@ #include "Texture.hpp" -#include "Renderer.hpp" -#include "../Compositor.hpp" -#include "../protocols/types/Buffer.hpp" -#include "../helpers/Format.hpp" #include -CTexture::CTexture() = default; - -CTexture::~CTexture() { - if (!g_pCompositor || g_pCompositor->m_isShuttingDown || !g_pHyprRenderer) - return; - - g_pHyprRenderer->makeEGLCurrent(); - destroyTexture(); -} - -CTexture::CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size_, bool keepDataCopy) : m_drmFormat(drmFormat), m_keepDataCopy(keepDataCopy) { - createFromShm(drmFormat, pixels, stride, size_); -} - -CTexture::CTexture(const Aquamarine::SDMABUFAttrs& attrs, void* image) { - createFromDma(attrs, image); -} - -CTexture::CTexture(const SP buffer, bool keepDataCopy) : m_keepDataCopy(keepDataCopy) { - if (!buffer) - return; - - m_opaque = buffer->opaque; - - auto attrs = buffer->dmabuf(); - - if (!attrs.success) { - // attempt shm - auto shm = buffer->shm(); - - if (!shm.success) { - Log::logger->log(Log::ERR, "Cannot create a texture: buffer has no dmabuf or shm"); - return; - } - - auto [pixelData, fmt, bufLen] = buffer->beginDataPtr(0); - - m_drmFormat = fmt; - - createFromShm(fmt, pixelData, bufLen, shm.size); - return; - } - - auto image = g_pHyprOpenGL->createEGLImage(buffer->dmabuf()); - - if (!image) { - Log::logger->log(Log::ERR, "Cannot create a texture: failed to create an EGLImage"); - return; - } - - createFromDma(attrs, image); -} - -CTexture::CTexture(std::span lut3D, size_t N) : m_type(TEXTURE_3D_LUT), m_target(GL_TEXTURE_3D), m_size(lut3D.size() / 3, 1), m_isSynchronous(true) { - allocate(); - bind(); - - GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); - setTexParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR); - setTexParameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR); - setTexParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - setTexParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - setTexParameter(GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - - // Expand RGB->RGBA on upload (alpha=1) - std::vector rgba; - rgba.resize(N * N * N * 4); - for (size_t i = 0, j = 0; i < N * N * N; ++i, j += 3) { - rgba[i * 4 + 0] = lut3D[j + 0]; - rgba[i * 4 + 1] = lut3D[j + 1]; - rgba[i * 4 + 2] = lut3D[j + 2]; - rgba[i * 4 + 3] = 1.F; - } - - GLCALL(glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA16F, N, N, N, 0, GL_RGBA, GL_FLOAT, rgba.data())); - - unbind(); -} - -void CTexture::createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size_) { - g_pHyprRenderer->makeEGLCurrent(); - - const auto format = NFormatUtils::getPixelFormatFromDRM(drmFormat); - ASSERT(format); - - m_type = format->withAlpha ? TEXTURE_RGBA : TEXTURE_RGBX; - m_size = size_; - m_isSynchronous = true; - m_target = GL_TEXTURE_2D; - allocate(); - bind(); - setTexParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - setTexParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - if (format->swizzle.has_value()) - swizzle(format->swizzle.value()); - - bool alignmentChanged = false; - if (format->bytesPerBlock != 4) { - const GLint alignment = (stride % 4 == 0) ? 4 : 1; - GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, alignment)); - alignmentChanged = true; - } - - 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)); - if (alignmentChanged) - GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 4)); - - unbind(); - - if (m_keepDataCopy) { - m_dataCopy.resize(stride * size_.y); - memcpy(m_dataCopy.data(), pixels, stride * size_.y); +ITexture::ITexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy, bool opaque) : + m_size(size), m_opaque(opaque), m_drmFormat(drmFormat), m_keepDataCopy(keepDataCopy) { + if (m_keepDataCopy && stride && pixels) { + m_dataCopy.resize(stride * size.y); + memcpy(m_dataCopy.data(), pixels, stride * size.y); } } -void CTexture::createFromDma(const Aquamarine::SDMABUFAttrs& attrs, void* image) { - if (!g_pHyprOpenGL->m_proc.glEGLImageTargetTexture2DOES) { - Log::logger->log(Log::ERR, "Cannot create a dmabuf texture: no glEGLImageTargetTexture2DOES"); - return; - } +ITexture::ITexture(std::span lut3D, size_t N) : m_type(TEXTURE_3D_LUT), m_size(lut3D.size() / 3, 1), m_isSynchronous(true) {} - m_opaque = NFormatUtils::isFormatOpaque(attrs.format); - - // #TODO external only formats should be external aswell. - // also needs a seperate color shader. - /*if (NFormatUtils::isFormatYUV(attrs.format)) { - m_target = GL_TEXTURE_EXTERNAL_OES; - m_type = TEXTURE_EXTERNAL; - } else {*/ - m_target = GL_TEXTURE_2D; - m_type = NFormatUtils::isFormatOpaque(attrs.format) ? TEXTURE_RGBX : TEXTURE_RGBA; - //} - - m_size = attrs.size; - allocate(); - m_eglImage = image; - - bind(); - setTexParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - setTexParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - GLCALL(g_pHyprOpenGL->m_proc.glEGLImageTargetTexture2DOES(m_target, image)); - unbind(); +bool ITexture::ok() { + return false; } -void CTexture::update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage) { - if (damage.empty()) - return; - - g_pHyprRenderer->makeEGLCurrent(); - - const auto format = NFormatUtils::getPixelFormatFromDRM(drmFormat); - ASSERT(format); - - bind(); - - if (format->swizzle.has_value()) - swizzle(format->swizzle.value()); - - bool alignmentChanged = false; - if (format->bytesPerBlock != 4) { - const GLint alignment = (stride % 4 == 0) ? 4 : 1; - GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, alignment)); - alignmentChanged = true; - } - - GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / format->bytesPerBlock)); - - damage.copy().intersect(CBox{{}, m_size}).forEachRect([&format, &pixels](const auto& rect) { - 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)); - }); - - if (alignmentChanged) - GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 4)); - - GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0)); - GLCALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0)); - GLCALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0)); - - unbind(); - - if (m_keepDataCopy) { - m_dataCopy.resize(stride * m_size.y); - memcpy(m_dataCopy.data(), pixels, stride * m_size.y); - } +bool ITexture::isDMA() { + return false; } -void CTexture::destroyTexture() { - if (m_texID) { - GLCALL(glDeleteTextures(1, &m_texID)); - m_texID = 0; - } - - if (m_eglImage) - g_pHyprOpenGL->m_proc.eglDestroyImageKHR(g_pHyprOpenGL->m_eglDisplay, m_eglImage); - m_eglImage = nullptr; - m_cachedStates.fill(std::nullopt); -} - -void CTexture::allocate() { - if (!m_texID) - GLCALL(glGenTextures(1, &m_texID)); -} - -const std::vector& CTexture::dataCopy() { +const std::vector& ITexture::dataCopy() { return m_dataCopy; } - -void CTexture::bind() { - GLCALL(glBindTexture(m_target, m_texID)); -} - -void CTexture::unbind() { - GLCALL(glBindTexture(m_target, 0)); -} - -constexpr std::optional CTexture::getCacheStateIndex(GLenum pname) { - switch (pname) { - case GL_TEXTURE_WRAP_S: return TEXTURE_PAR_WRAP_S; - case GL_TEXTURE_WRAP_T: return TEXTURE_PAR_WRAP_T; - case GL_TEXTURE_MAG_FILTER: return TEXTURE_PAR_MAG_FILTER; - case GL_TEXTURE_MIN_FILTER: return TEXTURE_PAR_MIN_FILTER; - case GL_TEXTURE_SWIZZLE_R: return TEXTURE_PAR_SWIZZLE_R; - case GL_TEXTURE_SWIZZLE_B: return TEXTURE_PAR_SWIZZLE_B; - default: return std::nullopt; - } -} - -void CTexture::setTexParameter(GLenum pname, GLint param) { - const auto cacheIndex = getCacheStateIndex(pname); - - if (!cacheIndex) { - GLCALL(glTexParameteri(m_target, pname, param)); - return; - } - - const auto idx = cacheIndex.value(); - - if (m_cachedStates[idx] == param) - return; - - m_cachedStates[idx] = param; - GLCALL(glTexParameteri(m_target, pname, param)); -} - -void CTexture::swizzle(const std::array& colors) { - setTexParameter(GL_TEXTURE_SWIZZLE_R, colors.at(0)); - setTexParameter(GL_TEXTURE_SWIZZLE_G, colors.at(1)); - setTexParameter(GL_TEXTURE_SWIZZLE_B, colors.at(2)); - setTexParameter(GL_TEXTURE_SWIZZLE_A, colors.at(3)); -} diff --git a/src/render/Texture.hpp b/src/render/Texture.hpp index a5806e26..38c3ff01 100644 --- a/src/render/Texture.hpp +++ b/src/render/Texture.hpp @@ -16,61 +16,43 @@ enum eTextureType : int8_t { TEXTURE_EXTERNAL, // EGLImage }; -class CTexture { +class ITexture { public: - CTexture(); + ITexture(ITexture&) = delete; + ITexture(ITexture&&) = delete; + ITexture(const ITexture&&) = delete; + ITexture(const ITexture&) = delete; - CTexture(CTexture&) = delete; - CTexture(CTexture&&) = delete; - CTexture(const CTexture&&) = delete; - CTexture(const CTexture&) = delete; + virtual ~ITexture() = default; - CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false); - CTexture(std::span lut3D, size_t N); + virtual void setTexParameter(GLenum pname, GLint param) = 0; + virtual void allocate(const Vector2D& size, uint32_t drmFormat = 0) = 0; + virtual void update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage) = 0; + virtual void bind() {}; + virtual void unbind() {}; + virtual bool ok(); + virtual bool isDMA(); - CTexture(const SP buffer, bool keepDataCopy = false); - // this ctor takes ownership of the eglImage. - CTexture(const Aquamarine::SDMABUFAttrs&, void* image); - ~CTexture(); - - void destroyTexture(); - void allocate(); - void update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage); const std::vector& dataCopy(); - void bind(); - void unbind(); - void setTexParameter(GLenum pname, GLint param); - void swizzle(const std::array& colors); - eTextureType m_type = TEXTURE_RGBA; - GLenum m_target = GL_TEXTURE_2D; - GLuint m_texID = 0; - Vector2D m_size = {}; - void* m_eglImage = nullptr; - eTransform m_transform = HYPRUTILS_TRANSFORM_NORMAL; - bool m_opaque = false; + eTextureType m_type = TEXTURE_RGBA; + Vector2D m_size = {}; + eTransform m_transform = HYPRUTILS_TRANSFORM_NORMAL; + bool m_opaque = false; + uint32_t m_drmFormat = 0; // for shm bool m_isSynchronous = false; - GLenum magFilter = GL_LINEAR; // useNearestNeighbor overwrites these - GLenum minFilter = GL_LINEAR; + // TODO move to GLTexture + GLuint m_texID = 0; + GLenum magFilter = GL_LINEAR; // useNearestNeighbor overwrites these + GLenum minFilter = GL_LINEAR; - private: - enum eTextureParam : uint8_t { - TEXTURE_PAR_WRAP_S = 0, - TEXTURE_PAR_WRAP_T, - TEXTURE_PAR_MAG_FILTER, - TEXTURE_PAR_MIN_FILTER, - TEXTURE_PAR_SWIZZLE_R, - TEXTURE_PAR_SWIZZLE_B, - TEXTURE_PAR_LAST, - }; + protected: + ITexture() = default; + ITexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false, bool opaque = false); + ITexture(std::span lut3D, size_t N); - void createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size); - void createFromDma(const Aquamarine::SDMABUFAttrs&, void* image); - inline constexpr std::optional getCacheStateIndex(GLenum pname); - - bool m_keepDataCopy = false; - std::vector m_dataCopy; - std::array, TEXTURE_PAR_LAST> m_cachedStates; + bool m_keepDataCopy = false; + std::vector m_dataCopy; }; diff --git a/src/render/Transformer.hpp b/src/render/Transformer.hpp index 048b1898..8f401859 100644 --- a/src/render/Transformer.hpp +++ b/src/render/Transformer.hpp @@ -14,7 +14,7 @@ class IWindowTransformer { // called by Hyprland. For more data about what is being rendered, inspect render data. // returns the out fb. - virtual CFramebuffer* transform(CFramebuffer* in) = 0; + virtual IFramebuffer* transform(IFramebuffer* in) = 0; // called by Hyprland before a window main pass is started. virtual void preWindowRender(CSurfacePassElement::SRenderData* pRenderData); diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index dd82abc5..5e1b6e8a 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.cpp +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -155,9 +155,9 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) { g_pHyprOpenGL->m_renderData.currentWindow = m_window; // we'll take the liberty of using this as it should not be used rn - CFramebuffer& alphaFB = g_pHyprOpenGL->m_renderData.pCurrentMonData->mirrorFB; - CFramebuffer& alphaSwapFB = g_pHyprOpenGL->m_renderData.pCurrentMonData->mirrorSwapFB; - auto* LASTFB = g_pHyprOpenGL->m_renderData.currentFB; + auto alphaFB = g_pHyprOpenGL->m_renderData.pCurrentMonData->mirrorFB; + auto alphaSwapFB = g_pHyprOpenGL->m_renderData.pCurrentMonData->mirrorSwapFB; + auto LASTFB = g_pHyprOpenGL->m_renderData.currentFB; fullBox.scale(pMonitor->m_scale).round(); @@ -188,7 +188,7 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) { g_pHyprOpenGL->m_renderData.damage.subtract(windowBox.copy().expand(-ROUNDING * pMonitor->m_scale)).intersect(saveDamage); g_pHyprOpenGL->m_renderData.renderModif.applyToRegion(g_pHyprOpenGL->m_renderData.damage); - alphaFB.bind(); + alphaFB->bind(); // build the matte // 10-bit formats have dogshit alpha channels, so we have to use the matte to its fullest. @@ -202,7 +202,7 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) { g_pHyprOpenGL->renderRect(windowBox, CHyprColor(0, 0, 0, 1.0), {.round = (ROUNDING + 1 /* This fixes small pixel gaps. */) * pMonitor->m_scale, .roundingPower = ROUNDINGPOWER}); - alphaSwapFB.bind(); + alphaSwapFB->bind(); // alpha swap just has the shadow color. It will be the "texture" to render. g_pHyprOpenGL->renderRect(fullBox, PWINDOW->m_realShadowColor->value().stripA(), {.round = 0}); @@ -213,7 +213,7 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) { g_pHyprOpenGL->pushMonitorTransformEnabled(true); g_pHyprOpenGL->setRenderModifEnabled(false); - g_pHyprOpenGL->renderTextureMatte(alphaSwapFB.getTexture(), monbox, alphaFB); + g_pHyprOpenGL->renderTextureMatte(alphaSwapFB->getTexture(), monbox, alphaFB); g_pHyprOpenGL->setRenderModifEnabled(true); g_pHyprOpenGL->popMonitorTransformEnabled(); diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index beb5efcd..6ce69261 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -13,10 +13,10 @@ #include "../../layout/supplementary/DragController.hpp" // shared things to conserve VRAM -static SP m_tGradientActive = makeShared(); -static SP m_tGradientInactive = makeShared(); -static SP m_tGradientLockedActive = makeShared(); -static SP m_tGradientLockedInactive = makeShared(); +static SP m_tGradientActive; +static SP m_tGradientInactive; +static SP m_tGradientLockedActive; +static SP m_tGradientLockedInactive; constexpr int BAR_TEXT_PAD = 2; @@ -24,7 +24,16 @@ CHyprGroupBarDecoration::CHyprGroupBarDecoration(PHLWINDOW pWindow) : IHyprWindo static auto PGRADIENTS = CConfigValue("group:groupbar:enabled"); static auto PENABLED = CConfigValue("group:groupbar:gradients"); - if (m_tGradientActive->m_texID == 0 && *PENABLED && *PGRADIENTS) + if (!m_tGradientActive) + m_tGradientActive = g_pHyprRenderer->createTexture(); + if (!m_tGradientInactive) + m_tGradientInactive = g_pHyprRenderer->createTexture(); + if (!m_tGradientLockedActive) + m_tGradientLockedActive = g_pHyprRenderer->createTexture(); + if (!m_tGradientLockedInactive) + m_tGradientLockedInactive = g_pHyprRenderer->createTexture(); + + if (!m_tGradientActive->ok() && *PENABLED && *PGRADIENTS) refreshGroupBarGradients(); } @@ -196,7 +205,7 @@ void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) { if (*PGRADIENTS) { const auto GRADIENTTEX = (m_dwGroupMembers[WINDOWINDEX] == Desktop::focusState()->window() ? (GROUPLOCKED ? m_tGradientLockedActive : m_tGradientActive) : (GROUPLOCKED ? m_tGradientLockedInactive : m_tGradientInactive)); - if (GRADIENTTEX->m_texID) { + if (GRADIENTTEX->ok()) { CTexPassElement::SRenderData data; data.tex = GRADIENTTEX; data.blur = blur; @@ -234,7 +243,7 @@ void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) { Vector2D{(m_barWidth - (*PTEXTPADDING * 2)) * pMonitor->m_scale, (*PTITLEFONTSIZE + 2L * BAR_TEXT_PAD) * pMonitor->m_scale}, pMonitor->m_scale)) .get(); - SP titleTex; + SP titleTex; if (m_dwGroupMembers[WINDOWINDEX] == Desktop::focusState()->window()) titleTex = GROUPLOCKED ? pTitleTex->m_texLockedActive : pTitleTex->m_texActive; else @@ -307,7 +316,7 @@ CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float #undef RENDER_TEXT } -static void renderGradientTo(SP tex, CGradientValueData* grad) { +static void renderGradientTo(SP tex, CGradientValueData* grad) { if (!Desktop::focusState()->monitor()) return; @@ -339,15 +348,7 @@ static void renderGradientTo(SP tex, CGradientValueData* grad) { cairo_surface_flush(CAIROSURFACE); // copy the data to an OpenGL texture we have - const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); - tex->allocate(); - tex->bind(); - tex->setTexParameter(GL_TEXTURE_MAG_FILTER, GL_NEAREST); - tex->setTexParameter(GL_TEXTURE_MIN_FILTER, GL_NEAREST); - tex->setTexParameter(GL_TEXTURE_SWIZZLE_R, GL_BLUE); - tex->setTexParameter(GL_TEXTURE_SWIZZLE_B, GL_RED); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bufferSize.x, bufferSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); + tex = g_pHyprRenderer->createTexture(CAIROSURFACE); // delete cairo cairo_destroy(CAIRO); @@ -367,13 +368,11 @@ void refreshGroupBarGradients() { auto* const GROUPCOLACTIVELOCKED = sc((PGROUPCOLACTIVELOCKED.ptr())->getData()); auto* const GROUPCOLINACTIVELOCKED = sc((PGROUPCOLINACTIVELOCKED.ptr())->getData()); - g_pHyprRenderer->makeEGLCurrent(); - - if (m_tGradientActive->m_texID != 0) { - m_tGradientActive->destroyTexture(); - m_tGradientInactive->destroyTexture(); - m_tGradientLockedActive->destroyTexture(); - m_tGradientLockedInactive->destroyTexture(); + if (m_tGradientActive && m_tGradientActive->ok()) { + m_tGradientActive.reset(); + m_tGradientInactive.reset(); + m_tGradientLockedActive.reset(); + m_tGradientLockedInactive.reset(); } if (!*PENABLED || !*PGRADIENTS) diff --git a/src/render/decorations/CHyprGroupBarDecoration.hpp b/src/render/decorations/CHyprGroupBarDecoration.hpp index 3e5d3c2d..5c3f4ae5 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.hpp +++ b/src/render/decorations/CHyprGroupBarDecoration.hpp @@ -12,10 +12,10 @@ class CTitleTex { CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float monitorScale); ~CTitleTex() = default; - SP m_texActive; - SP m_texInactive; - SP m_texLockedActive; - SP m_texLockedInactive; + SP m_texActive; + SP m_texInactive; + SP m_texLockedActive; + SP m_texLockedInactive; std::string m_content; PHLWINDOWREF m_windowOwner; diff --git a/src/render/gl/GLFramebuffer.cpp b/src/render/gl/GLFramebuffer.cpp new file mode 100644 index 00000000..d821f766 --- /dev/null +++ b/src/render/gl/GLFramebuffer.cpp @@ -0,0 +1,170 @@ +#include "GLFramebuffer.hpp" +#include "../OpenGL.hpp" +#include "../Renderer.hpp" +#include "macros.hpp" +#include "render/Framebuffer.hpp" + +CGLFramebuffer::CGLFramebuffer() : IFramebuffer() {} +CGLFramebuffer::CGLFramebuffer(const std::string& name) : IFramebuffer(name) {} + +bool CGLFramebuffer::internalAlloc(int w, int h, uint32_t drmFormat) { + g_pHyprRenderer->makeEGLCurrent(); + + bool firstAlloc = false; + + if (!m_tex) { + m_tex = g_pHyprRenderer->createTexture(); + m_tex->allocate({w, h}); + m_tex->bind(); + m_tex->setTexParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + m_tex->setTexParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + m_tex->setTexParameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR); + m_tex->setTexParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR); + firstAlloc = true; + } + + if (!m_fbAllocated) { + glGenFramebuffers(1, &m_fb); + m_fbAllocated = true; + firstAlloc = true; + } + + if (firstAlloc) { + const auto format = NFormatUtils::getPixelFormatFromDRM(drmFormat); + m_tex->bind(); + glTexImage2D(GL_TEXTURE_2D, 0, format->glInternalFormat ? format->glInternalFormat : format->glFormat, w, h, 0, format->glFormat, format->glType, nullptr); + glBindFramebuffer(GL_FRAMEBUFFER, m_fb); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_tex->m_texID, 0); + + if (m_stencilTex && m_stencilTex->ok()) { + m_stencilTex->bind(); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, w, h, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_stencilTex->m_texID, 0); + + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + } + + auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + RASSERT((status == GL_FRAMEBUFFER_COMPLETE), "Framebuffer incomplete, couldn't create! (FB status: {}, GL Error: 0x{:x})", status, sc(glGetError())); + + if (m_stencilTex && m_stencilTex->ok()) + m_stencilTex->unbind(); + + Log::logger->log(Log::DEBUG, "Framebuffer created, status {}", status); + } + + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + return true; +} + +void CGLFramebuffer::addStencil(SP tex) { + if (m_stencilTex == tex) + return; + + RASSERT(!m_fbAllocated, "Should add stencil tex prior to FB allocation") + m_stencilTex = tex; +} + +void CGLFramebuffer::bind() { + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fb); + + if (g_pHyprOpenGL) + g_pHyprOpenGL->setViewport(0, 0, g_pHyprOpenGL->m_renderData.pMonitor->m_pixelSize.x, g_pHyprOpenGL->m_renderData.pMonitor->m_pixelSize.y); + else + glViewport(0, 0, m_size.x, m_size.y); +} + +void CGLFramebuffer::unbind() { + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); +} + +void CGLFramebuffer::release() { + if (m_fbAllocated) { + glBindFramebuffer(GL_FRAMEBUFFER, m_fb); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glDeleteFramebuffers(1, &m_fb); + m_fbAllocated = false; + m_fb = 0; + } + + if (m_tex) + m_tex.reset(); + + m_size = Vector2D(); +} + +bool CGLFramebuffer::readPixels(CHLBufferReference buffer, uint32_t offsetX, uint32_t offsetY, uint32_t width, uint32_t height) { + auto shm = buffer->shm(); + auto [pixelData, fmt, bufLen] = buffer->beginDataPtr(0); // no need for end, cuz it's shm + + const auto PFORMAT = NFormatUtils::getPixelFormatFromDRM(shm.format); + if (!PFORMAT) { + LOGM(Log::ERR, "Can't copy: failed to find a pixel format"); + return false; + } + + g_pHyprRenderer->makeEGLCurrent(); + glBindFramebuffer(GL_READ_FRAMEBUFFER, getFBID()); + bind(); + + glPixelStorei(GL_PACK_ALIGNMENT, 1); + + uint32_t packStride = NFormatUtils::minStride(PFORMAT, m_size.x); + int glFormat = PFORMAT->glFormat; + + if (glFormat == GL_RGBA) + glFormat = GL_BGRA_EXT; + + if (glFormat != GL_BGRA_EXT && glFormat != GL_RGB) { + if (PFORMAT->swizzle.has_value()) { + std::array RGBA = SWIZZLE_RGBA; + std::array BGRA = SWIZZLE_BGRA; + if (PFORMAT->swizzle == RGBA) + glFormat = GL_RGBA; + else if (PFORMAT->swizzle == BGRA) + glFormat = GL_BGRA_EXT; + else { + LOGM(Log::ERR, "Copied frame via shm might be broken or color flipped"); + glFormat = GL_RGBA; + } + } + } + + // This could be optimized by using a pixel buffer object to make this async, + // but really clients should just use a dma buffer anyways. + if (packStride == sc(shm.stride)) { + glReadPixels(offsetX, offsetY, width > 0 ? width : m_size.x, height > 0 ? height : m_size.y, glFormat, PFORMAT->glType, pixelData); + } else { + const auto h = height > 0 ? height : m_size.y; + for (size_t i = 0; i < h; ++i) { + uint32_t y = i; + glReadPixels(offsetX, offsetY + y, width > 0 ? width : m_size.x, 1, glFormat, PFORMAT->glType, pixelData + i * shm.stride); + } + } + + unbind(); + glPixelStorei(GL_PACK_ALIGNMENT, 4); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + return true; +} + +CGLFramebuffer::~CGLFramebuffer() { + release(); +} + +GLuint CGLFramebuffer::getFBID() { + return m_fbAllocated ? m_fb : 0; +} + +void CGLFramebuffer::invalidate(const std::vector& attachments) { + if (!isAllocated()) + return; + + glInvalidateFramebuffer(GL_FRAMEBUFFER, attachments.size(), attachments.data()); +} diff --git a/src/render/gl/GLFramebuffer.hpp b/src/render/gl/GLFramebuffer.hpp new file mode 100644 index 00000000..c171444e --- /dev/null +++ b/src/render/gl/GLFramebuffer.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "../../defines.hpp" +#include "../Texture.hpp" +#include "../Framebuffer.hpp" +#include + +class CGLFramebuffer : public IFramebuffer { + public: + CGLFramebuffer(); + CGLFramebuffer(const std::string& name); + ~CGLFramebuffer(); + + void addStencil(SP tex) override; + void release() override; + bool readPixels(CHLBufferReference buffer, uint32_t offsetX = 0, uint32_t offsetY = 0, uint32_t width = 0, uint32_t height = 0) override; + + void bind() override; + void unbind(); + GLuint getFBID(); + void invalidate(const std::vector& attachments); + + protected: + bool internalAlloc(int w, int h, uint32_t format = DRM_FORMAT_ARGB8888) override; + + private: + GLuint m_fb = -1; + + friend class CGLRenderbuffer; +}; diff --git a/src/render/gl/GLRenderbuffer.cpp b/src/render/gl/GLRenderbuffer.cpp new file mode 100644 index 00000000..8299d0e4 --- /dev/null +++ b/src/render/gl/GLRenderbuffer.cpp @@ -0,0 +1,71 @@ +#include "GLRenderbuffer.hpp" +#include "../Renderer.hpp" +#include "../OpenGL.hpp" +#include "../../Compositor.hpp" +#include "../Framebuffer.hpp" +#include "GLFramebuffer.hpp" +#include "render/Renderbuffer.hpp" +#include +#include +#include + +#include + +CGLRenderbuffer::~CGLRenderbuffer() { + if (!g_pCompositor || g_pCompositor->m_isShuttingDown || !g_pHyprRenderer) + return; + + g_pHyprRenderer->makeEGLCurrent(); + + unbind(); + m_framebuffer->release(); + + if (m_rbo) + glDeleteRenderbuffers(1, &m_rbo); + + if (m_image != EGL_NO_IMAGE_KHR) + g_pHyprOpenGL->m_proc.eglDestroyImageKHR(g_pHyprOpenGL->m_eglDisplay, m_image); +} + +CGLRenderbuffer::CGLRenderbuffer(SP buffer, uint32_t format) : IRenderbuffer(buffer, format) { + auto dma = buffer->dmabuf(); + + m_image = g_pHyprOpenGL->createEGLImage(dma); + if (m_image == EGL_NO_IMAGE_KHR) { + Log::logger->log(Log::ERR, "rb: createEGLImage failed"); + return; + } + + glGenRenderbuffers(1, &m_rbo); + glBindRenderbuffer(GL_RENDERBUFFER, m_rbo); + g_pHyprOpenGL->m_proc.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, m_image); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + m_framebuffer = makeShared(); + glGenFramebuffers(1, &GLFB(m_framebuffer)->m_fb); + GLFB(m_framebuffer)->m_fbAllocated = true; + m_framebuffer->m_size = buffer->size; + m_framebuffer->m_drmFormat = dma.format; + m_framebuffer->bind(); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rbo); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + Log::logger->log(Log::ERR, "rbo: glCheckFramebufferStatus failed"); + return; + } + + GLFB(m_framebuffer)->unbind(); + + m_listeners.destroyBuffer = buffer->events.destroy.listen([this] { g_pHyprRenderer->onRenderbufferDestroy(this); }); + + m_good = true; +} + +void CGLRenderbuffer::bind() { + g_pHyprRenderer->makeEGLCurrent(); + m_framebuffer->bind(); +} + +void CGLRenderbuffer::unbind() { + GLFB(m_framebuffer)->unbind(); +} diff --git a/src/render/gl/GLRenderbuffer.hpp b/src/render/gl/GLRenderbuffer.hpp new file mode 100644 index 00000000..8367f702 --- /dev/null +++ b/src/render/gl/GLRenderbuffer.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include "../../helpers/memory/Memory.hpp" +#include "../Renderbuffer.hpp" +#include + +class CMonitor; + +class CGLRenderbuffer : public IRenderbuffer { + public: + CGLRenderbuffer(SP buffer, uint32_t format); + ~CGLRenderbuffer(); + + void bind() override; + void unbind() override; + + private: + void* m_image = nullptr; + GLuint m_rbo = 0; +}; diff --git a/src/render/gl/GLTexture.cpp b/src/render/gl/GLTexture.cpp new file mode 100644 index 00000000..6a1fb172 --- /dev/null +++ b/src/render/gl/GLTexture.cpp @@ -0,0 +1,223 @@ +#include "GLTexture.hpp" +#include "../Renderer.hpp" +#include "../../Compositor.hpp" +#include "../../helpers/Format.hpp" +#include "render/Texture.hpp" +#include + +CGLTexture::CGLTexture(bool opaque) { + m_opaque = opaque; +} + +CGLTexture::~CGLTexture() { + if (!g_pCompositor || g_pCompositor->m_isShuttingDown || !g_pHyprRenderer) + return; + + g_pHyprRenderer->makeEGLCurrent(); + if (m_texID) { + GLCALL(glDeleteTextures(1, &m_texID)); + m_texID = 0; + } + + if (m_eglImage) + g_pHyprOpenGL->m_proc.eglDestroyImageKHR(g_pHyprOpenGL->m_eglDisplay, m_eglImage); + m_eglImage = nullptr; + m_cachedStates.fill(std::nullopt); +} + +CGLTexture::CGLTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size_, bool keepDataCopy, bool opaque) : + ITexture(drmFormat, pixels, stride, size_, keepDataCopy, opaque) { + + g_pHyprRenderer->makeEGLCurrent(); + + const auto format = NFormatUtils::getPixelFormatFromDRM(drmFormat); + ASSERT(format); + + m_type = format->withAlpha ? TEXTURE_RGBA : TEXTURE_RGBX; + m_size = size_; + m_isSynchronous = true; + m_target = GL_TEXTURE_2D; + allocate(size_); + bind(); + setTexParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + setTexParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + if (format->swizzle.has_value()) + swizzle(format->swizzle.value()); + + bool alignmentChanged = false; + if (format->bytesPerBlock != 4) { + const GLint alignment = (stride % 4 == 0) ? 4 : 1; + GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, alignment)); + alignmentChanged = true; + } + + 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)); + if (alignmentChanged) + GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 4)); + + unbind(); +} + +CGLTexture::CGLTexture(const Aquamarine::SDMABUFAttrs& attrs, void* image, bool opaque) { + m_opaque = opaque; + if (!g_pHyprOpenGL->m_proc.glEGLImageTargetTexture2DOES) { + Log::logger->log(Log::ERR, "Cannot create a dmabuf texture: no glEGLImageTargetTexture2DOES"); + return; + } + + m_opaque = NFormatUtils::isFormatOpaque(attrs.format); + + // #TODO external only formats should be external aswell. + // also needs a seperate color shader. + /*if (NFormatUtils::isFormatYUV(attrs.format)) { + m_target = GL_TEXTURE_EXTERNAL_OES; + m_type = TEXTURE_EXTERNAL; + } else {*/ + m_target = GL_TEXTURE_2D; + m_type = NFormatUtils::isFormatOpaque(attrs.format) ? TEXTURE_RGBX : TEXTURE_RGBA; + //} + + allocate(attrs.size); + m_eglImage = image; + + bind(); + setTexParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + setTexParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + GLCALL(g_pHyprOpenGL->m_proc.glEGLImageTargetTexture2DOES(m_target, image)); + unbind(); +} + +CGLTexture::CGLTexture(std::span lut3D, size_t N) : ITexture(lut3D, N), m_target(GL_TEXTURE_3D) { + allocate({}); + bind(); + + GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); + setTexParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR); + setTexParameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR); + setTexParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + setTexParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + setTexParameter(GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + // Expand RGB->RGBA on upload (alpha=1) + std::vector rgba; + rgba.resize(N * N * N * 4); + for (size_t i = 0, j = 0; i < N * N * N; ++i, j += 3) { + rgba[i * 4 + 0] = lut3D[j + 0]; + rgba[i * 4 + 1] = lut3D[j + 1]; + rgba[i * 4 + 2] = lut3D[j + 2]; + rgba[i * 4 + 3] = 1.F; + } + + GLCALL(glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA16F, N, N, N, 0, GL_RGBA, GL_FLOAT, rgba.data())); + + unbind(); +} + +void CGLTexture::update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage) { + if (damage.empty()) + return; + + g_pHyprRenderer->makeEGLCurrent(); + + const auto format = NFormatUtils::getPixelFormatFromDRM(drmFormat); + ASSERT(format); + + bind(); + + if (format->swizzle.has_value()) + swizzle(format->swizzle.value()); + + bool alignmentChanged = false; + if (format->bytesPerBlock != 4) { + const GLint alignment = (stride % 4 == 0) ? 4 : 1; + GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, alignment)); + alignmentChanged = true; + } + + GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / format->bytesPerBlock)); + + damage.copy().intersect(CBox{{}, m_size}).forEachRect([&format, &pixels](const auto& rect) { + 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)); + }); + + if (alignmentChanged) + GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 4)); + + GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0)); + GLCALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0)); + GLCALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0)); + + unbind(); + + if (m_keepDataCopy) { + m_dataCopy.resize(stride * m_size.y); + memcpy(m_dataCopy.data(), pixels, stride * m_size.y); + } +} + +void CGLTexture::allocate(const Vector2D& size, uint32_t drmFormat) { + if (!m_texID) + GLCALL(glGenTextures(1, &m_texID)); + m_size = size; + m_drmFormat = drmFormat; +} + +void CGLTexture::bind() { + GLCALL(glBindTexture(m_target, m_texID)); +} + +void CGLTexture::unbind() { + GLCALL(glBindTexture(m_target, 0)); +} + +bool CGLTexture::ok() { + return m_texID > 0; +} + +bool CGLTexture::isDMA() { + return m_eglImage; +} + +constexpr std::optional CGLTexture::getCacheStateIndex(GLenum pname) { + switch (pname) { + case GL_TEXTURE_WRAP_S: return TEXTURE_PAR_WRAP_S; + case GL_TEXTURE_WRAP_T: return TEXTURE_PAR_WRAP_T; + case GL_TEXTURE_MAG_FILTER: return TEXTURE_PAR_MAG_FILTER; + case GL_TEXTURE_MIN_FILTER: return TEXTURE_PAR_MIN_FILTER; + case GL_TEXTURE_SWIZZLE_R: return TEXTURE_PAR_SWIZZLE_R; + case GL_TEXTURE_SWIZZLE_B: return TEXTURE_PAR_SWIZZLE_B; + default: return std::nullopt; + } +} + +void CGLTexture::setTexParameter(GLenum pname, GLint param) { + const auto cacheIndex = getCacheStateIndex(pname); + + if (!cacheIndex) { + GLCALL(glTexParameteri(m_target, pname, param)); + return; + } + + const auto idx = cacheIndex.value(); + + if (m_cachedStates[idx] == param) + return; + + m_cachedStates[idx] = param; + GLCALL(glTexParameteri(m_target, pname, param)); +} + +void CGLTexture::swizzle(const std::array& colors) { + setTexParameter(GL_TEXTURE_SWIZZLE_R, colors.at(0)); + setTexParameter(GL_TEXTURE_SWIZZLE_G, colors.at(1)); + setTexParameter(GL_TEXTURE_SWIZZLE_B, colors.at(2)); + setTexParameter(GL_TEXTURE_SWIZZLE_A, colors.at(3)); +} diff --git a/src/render/gl/GLTexture.hpp b/src/render/gl/GLTexture.hpp new file mode 100644 index 00000000..34510e90 --- /dev/null +++ b/src/render/gl/GLTexture.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include "../Texture.hpp" +#include +#include + +class CGLTexture : public ITexture { + public: + using ITexture::ITexture; + + CGLTexture(CGLTexture&) = delete; + CGLTexture(CGLTexture&&) = delete; + CGLTexture(const CGLTexture&&) = delete; + CGLTexture(const CGLTexture&) = delete; + + CGLTexture(bool opaque = false); + CGLTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false, bool opaque = false); + CGLTexture(const Aquamarine::SDMABUFAttrs&, void* image, bool opaque = false); + CGLTexture(std::span lut3D, size_t N); + ~CGLTexture(); + + void allocate(const Vector2D& size, uint32_t drmFormat = 0) override; + void update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage) override; + void bind() override; + void unbind() override; + void setTexParameter(GLenum pname, GLint param) override; + bool ok() override; + bool isDMA() override; + + private: + void* m_eglImage = nullptr; + + enum eTextureParam : uint8_t { + TEXTURE_PAR_WRAP_S = 0, + TEXTURE_PAR_WRAP_T, + TEXTURE_PAR_MAG_FILTER, + TEXTURE_PAR_MIN_FILTER, + TEXTURE_PAR_SWIZZLE_R, + TEXTURE_PAR_SWIZZLE_B, + TEXTURE_PAR_LAST, + }; + + GLenum m_target = GL_TEXTURE_2D; + + void swizzle(const std::array& colors); + constexpr std::optional getCacheStateIndex(GLenum pname); + + std::array, TEXTURE_PAR_LAST> m_cachedStates; +}; diff --git a/src/render/pass/FramebufferElement.cpp b/src/render/pass/FramebufferElement.cpp index 77a29fba..bc7c686a 100644 --- a/src/render/pass/FramebufferElement.cpp +++ b/src/render/pass/FramebufferElement.cpp @@ -6,7 +6,7 @@ CFramebufferElement::CFramebufferElement(const CFramebufferElement::SFramebuffer } void CFramebufferElement::draw(const CRegion& damage) { - CFramebuffer* fb = nullptr; + SP fb = nullptr; if (m_data.main) { switch (m_data.framebufferID) { @@ -22,12 +22,12 @@ void CFramebufferElement::draw(const CRegion& damage) { } else { switch (m_data.framebufferID) { - case FB_MONITOR_RENDER_EXTRA_OFFLOAD: fb = &g_pHyprOpenGL->m_renderData.pCurrentMonData->offloadFB; break; - case FB_MONITOR_RENDER_EXTRA_MIRROR: fb = &g_pHyprOpenGL->m_renderData.pCurrentMonData->mirrorFB; break; - case FB_MONITOR_RENDER_EXTRA_MIRROR_SWAP: fb = &g_pHyprOpenGL->m_renderData.pCurrentMonData->mirrorSwapFB; break; - case FB_MONITOR_RENDER_EXTRA_OFF_MAIN: fb = &g_pHyprOpenGL->m_renderData.pCurrentMonData->offMainFB; break; - case FB_MONITOR_RENDER_EXTRA_MONITOR_MIRROR: fb = &g_pHyprOpenGL->m_renderData.pCurrentMonData->monitorMirrorFB; break; - case FB_MONITOR_RENDER_EXTRA_BLUR: fb = &g_pHyprOpenGL->m_renderData.pCurrentMonData->blurFB; break; + case FB_MONITOR_RENDER_EXTRA_OFFLOAD: fb = g_pHyprOpenGL->m_renderData.pCurrentMonData->offloadFB; break; + case FB_MONITOR_RENDER_EXTRA_MIRROR: fb = g_pHyprOpenGL->m_renderData.pCurrentMonData->mirrorFB; break; + case FB_MONITOR_RENDER_EXTRA_MIRROR_SWAP: fb = g_pHyprOpenGL->m_renderData.pCurrentMonData->mirrorSwapFB; break; + case FB_MONITOR_RENDER_EXTRA_OFF_MAIN: fb = g_pHyprOpenGL->m_renderData.pCurrentMonData->offMainFB; break; + case FB_MONITOR_RENDER_EXTRA_MONITOR_MIRROR: fb = g_pHyprOpenGL->m_renderData.pCurrentMonData->monitorMirrorFB; break; + case FB_MONITOR_RENDER_EXTRA_BLUR: fb = g_pHyprOpenGL->m_renderData.pCurrentMonData->blurFB; break; } if (!fb) { diff --git a/src/render/pass/Pass.cpp b/src/render/pass/Pass.cpp index 3c82c84c..a4436516 100644 --- a/src/render/pass/Pass.cpp +++ b/src/render/pass/Pass.cpp @@ -216,7 +216,7 @@ void CRenderPass::renderDebugData() { std::unordered_map offsets; // render focus stuff - auto renderHLSurface = [&offsets](SP texture, SP surface, const CHyprColor& color) { + auto renderHLSurface = [&offsets](SP texture, SP surface, const CHyprColor& color) { if (!surface || !texture) return; diff --git a/src/render/pass/Pass.hpp b/src/render/pass/Pass.hpp index 435b5301..b45af88b 100644 --- a/src/render/pass/Pass.hpp +++ b/src/render/pass/Pass.hpp @@ -4,7 +4,7 @@ #include "PassElement.hpp" class CGradientValueData; -class CTexture; +class ITexture; class CRenderPass { public: @@ -36,7 +36,7 @@ class CRenderPass { struct { bool present = false; - SP keyboardFocusText, pointerFocusText, lastWindowText; + SP keyboardFocusText, pointerFocusText, lastWindowText; } m_debugData; friend class CHyprOpenGLImpl; diff --git a/src/render/pass/SurfacePassElement.hpp b/src/render/pass/SurfacePassElement.hpp index f4dbb45a..058744de 100644 --- a/src/render/pass/SurfacePassElement.hpp +++ b/src/render/pass/SurfacePassElement.hpp @@ -4,7 +4,7 @@ #include "../../helpers/time/Time.hpp" class CWLSurfaceResource; -class CTexture; +class ITexture; class CSyncTimeline; class CSurfacePassElement : public IPassElement { @@ -16,7 +16,7 @@ class CSurfacePassElement : public IPassElement { void* data = nullptr; SP surface = nullptr; - SP texture = nullptr; + SP texture = nullptr; bool mainSurface = true; double w = 0, h = 0; int rounding = 0; diff --git a/src/render/pass/TexPassElement.hpp b/src/render/pass/TexPassElement.hpp index a922843d..770e8b05 100644 --- a/src/render/pass/TexPassElement.hpp +++ b/src/render/pass/TexPassElement.hpp @@ -3,13 +3,13 @@ #include class CWLSurfaceResource; -class CTexture; +class ITexture; class CSyncTimeline; class CTexPassElement : public IPassElement { public: struct SRenderData { - SP tex; + SP tex; CBox box; float a = 1.F; float blurA = 1.F; diff --git a/src/render/pass/TextureMatteElement.cpp b/src/render/pass/TextureMatteElement.cpp index aeeeabc6..8023df8b 100644 --- a/src/render/pass/TextureMatteElement.cpp +++ b/src/render/pass/TextureMatteElement.cpp @@ -9,11 +9,11 @@ void CTextureMatteElement::draw(const CRegion& damage) { if (m_data.disableTransformAndModify) { g_pHyprOpenGL->pushMonitorTransformEnabled(true); g_pHyprOpenGL->setRenderModifEnabled(false); - g_pHyprOpenGL->renderTextureMatte(m_data.tex, m_data.box, *m_data.fb); + g_pHyprOpenGL->renderTextureMatte(m_data.tex, m_data.box, m_data.fb); g_pHyprOpenGL->setRenderModifEnabled(true); g_pHyprOpenGL->popMonitorTransformEnabled(); } else - g_pHyprOpenGL->renderTextureMatte(m_data.tex, m_data.box, *m_data.fb); + g_pHyprOpenGL->renderTextureMatte(m_data.tex, m_data.box, m_data.fb); } bool CTextureMatteElement::needsLiveBlur() { diff --git a/src/render/pass/TextureMatteElement.hpp b/src/render/pass/TextureMatteElement.hpp index 57d0e1e3..273c6474 100644 --- a/src/render/pass/TextureMatteElement.hpp +++ b/src/render/pass/TextureMatteElement.hpp @@ -2,14 +2,14 @@ #include "PassElement.hpp" #include "../Framebuffer.hpp" -class CTexture; +class ITexture; class CTextureMatteElement : public IPassElement { public: struct STextureMatteData { CBox box; - SP tex; - SP fb; + SP tex; + SP fb; bool disableTransformAndModify = false; };