summaryrefslogtreecommitdiff
path: root/src/render
diff options
context:
space:
mode:
authorUjinT34 <41110182+UjinT34@users.noreply.github.com>2026-03-07 21:21:23 +0300
committerGitHub <noreply@github.com>2026-03-07 18:21:23 +0000
commit02f30ea15b349d1ed98b608ed06ec88c834592dd (patch)
tree5148a3935c43b64f209f2b13e2a0b1bbe987444b /src/render
parentb227efc8492468cc925014a6c8446a3d044b01e8 (diff)
renderer: refactor gl renderer (#13488)
Diffstat (limited to 'src/render')
-rw-r--r--src/render/GLRenderer.cpp405
-rw-r--r--src/render/GLRenderer.hpp52
-rw-r--r--src/render/OpenGL.cpp705
-rw-r--r--src/render/OpenGL.hpp62
-rw-r--r--src/render/Renderer.cpp1157
-rw-r--r--src/render/Renderer.hpp249
-rw-r--r--src/render/decorations/CHyprBorderDecoration.cpp1
-rw-r--r--src/render/decorations/CHyprDropShadowDecoration.cpp165
-rw-r--r--src/render/decorations/CHyprDropShadowDecoration.hpp18
-rw-r--r--src/render/gl/GLFramebuffer.cpp9
-rw-r--r--src/render/pass/BorderPassElement.hpp1
-rw-r--r--src/render/pass/Pass.cpp44
-rw-r--r--src/render/pass/RectPassElement.hpp6
-rw-r--r--src/render/pass/SurfacePassElement.hpp3
-rw-r--r--src/render/pass/TexPassElement.hpp46
15 files changed, 1641 insertions, 1282 deletions
diff --git a/src/render/GLRenderer.cpp b/src/render/GLRenderer.cpp
new file mode 100644
index 00000000..c1f64837
--- /dev/null
+++ b/src/render/GLRenderer.cpp
@@ -0,0 +1,405 @@
+#include "GLRenderer.hpp"
+#include <aquamarine/output/Output.hpp>
+#include "../config/ConfigValue.hpp"
+#include "../managers/CursorManager.hpp"
+#include "../managers/PointerManager.hpp"
+#include "../protocols/SessionLock.hpp"
+#include "../protocols/LayerShell.hpp"
+#include "../protocols/PresentationTime.hpp"
+#include "../protocols/core/DataDevice.hpp"
+#include "../protocols/core/Compositor.hpp"
+#include "../debug/HyprDebugOverlay.hpp"
+#include "helpers/Monitor.hpp"
+#include "pass/TexPassElement.hpp"
+#include "pass/ClearPassElement.hpp"
+#include "pass/RectPassElement.hpp"
+#include "pass/SurfacePassElement.hpp"
+#include "debug/log/Logger.hpp"
+#include "../protocols/types/ContentType.hpp"
+#include "render/OpenGL.hpp"
+#include "render/Renderer.hpp"
+#include "render/gl/GLFramebuffer.hpp"
+#include "render/gl/GLTexture.hpp"
+#include "decorations/CHyprDropShadowDecoration.hpp"
+
+#include <cstdint>
+#include <hyprutils/memory/SharedPtr.hpp>
+#include <hyprutils/utils/ScopeGuard.hpp>
+using namespace Hyprutils::Utils;
+using namespace Hyprutils::OS;
+using enum NContentType::eContentType;
+using namespace NColorManagement;
+
+extern "C" {
+#include <xf86drm.h>
+}
+
+CHyprGLRenderer::CHyprGLRenderer() : IHyprRenderer() {}
+
+void CHyprGLRenderer::initRender() {
+ g_pHyprOpenGL->makeEGLCurrent();
+ g_pHyprRenderer->m_renderData.pMonitor = renderData().pMonitor;
+}
+
+bool CHyprGLRenderer::initRenderBuffer(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) {
+ try {
+ m_currentRenderbuffer = getOrCreateRenderbuffer(m_currentBuffer, fmt);
+ } catch (std::exception& e) {
+ Log::logger->log(Log::ERR, "getOrCreateRenderbuffer failed for {}", NFormatUtils::drmFormatName(fmt));
+ return false;
+ }
+
+ return m_currentRenderbuffer;
+}
+
+bool CHyprGLRenderer::beginFullFakeRenderInternal(PHLMONITOR pMonitor, CRegion& damage, SP<IFramebuffer> fb, bool simple) {
+ initRender();
+
+ RASSERT(fb, "Cannot render FULL_FAKE without a provided fb!");
+ fb->bind();
+ if (simple)
+ g_pHyprOpenGL->beginSimple(pMonitor, damage, nullptr, fb);
+ else
+ g_pHyprOpenGL->begin(pMonitor, damage, fb);
+ return true;
+}
+
+bool CHyprGLRenderer::beginRenderInternal(PHLMONITOR pMonitor, CRegion& damage, bool simple) {
+
+ m_currentRenderbuffer->bind();
+ if (simple)
+ g_pHyprOpenGL->beginSimple(pMonitor, damage, m_currentRenderbuffer);
+ else
+ g_pHyprOpenGL->begin(pMonitor, damage);
+
+ return true;
+}
+
+void CHyprGLRenderer::endRender(const std::function<void()>& renderingDoneCallback) {
+ const auto PMONITOR = g_pHyprRenderer->m_renderData.pMonitor;
+ static auto PNVIDIAANTIFLICKER = CConfigValue<Hyprlang::INT>("opengl:nvidia_anti_flicker");
+
+ g_pHyprRenderer->m_renderData.damage = m_renderPass.render(g_pHyprRenderer->m_renderData.damage);
+
+ auto cleanup = CScopeGuard([this]() {
+ if (m_currentRenderbuffer)
+ m_currentRenderbuffer->unbind();
+ m_currentRenderbuffer = nullptr;
+ m_currentBuffer = nullptr;
+ });
+
+ if (m_renderMode != RENDER_MODE_TO_BUFFER_READ_ONLY)
+ g_pHyprOpenGL->end();
+ else {
+ g_pHyprRenderer->m_renderData.pMonitor.reset();
+ g_pHyprRenderer->m_renderData.mouseZoomFactor = 1.f;
+ g_pHyprRenderer->m_renderData.mouseZoomUseMouse = true;
+ }
+
+ if (m_renderMode == RENDER_MODE_FULL_FAKE)
+ return;
+
+ if (m_renderMode == RENDER_MODE_NORMAL)
+ PMONITOR->m_output->state->setBuffer(m_currentBuffer);
+
+ if (!explicitSyncSupported()) {
+ Log::logger->log(Log::TRACE, "renderer: Explicit sync unsupported, falling back to implicit in endRender");
+
+ // nvidia doesn't have implicit sync, so we have to explicitly wait here, llvmpipe and other software renderer seems to bug out aswell.
+ if ((isNvidia() && *PNVIDIAANTIFLICKER) || isSoftware())
+ glFinish();
+ else
+ glFlush(); // mark an implicit sync point
+
+ m_usedAsyncBuffers.clear(); // release all buffer refs and hope implicit sync works
+ if (renderingDoneCallback)
+ renderingDoneCallback();
+
+ return;
+ }
+
+ UP<CEGLSync> eglSync = CEGLSync::create();
+ if LIKELY (eglSync && eglSync->isValid()) {
+ for (auto const& buf : m_usedAsyncBuffers) {
+ for (const auto& releaser : buf->m_syncReleasers) {
+ releaser->addSyncFileFd(eglSync->fd());
+ }
+ }
+
+ // release buffer refs with release points now, since syncReleaser handles actual buffer release based on EGLSync
+ std::erase_if(m_usedAsyncBuffers, [](const auto& buf) { return !buf->m_syncReleasers.empty(); });
+
+ // release buffer refs without release points when EGLSync sync_file/fence is signalled
+ g_pEventLoopManager->doOnReadable(eglSync->fd().duplicate(), [renderingDoneCallback, prevbfs = std::move(m_usedAsyncBuffers)]() mutable {
+ prevbfs.clear();
+ if (renderingDoneCallback)
+ renderingDoneCallback();
+ });
+ m_usedAsyncBuffers.clear();
+
+ if (m_renderMode == RENDER_MODE_NORMAL) {
+ PMONITOR->m_inFence = eglSync->takeFd();
+ PMONITOR->m_output->state->setExplicitInFence(PMONITOR->m_inFence.get());
+ }
+ } else {
+ Log::logger->log(Log::ERR, "renderer: Explicit sync failed, releasing resources");
+
+ m_usedAsyncBuffers.clear(); // release all buffer refs and hope implicit sync works
+ if (renderingDoneCallback)
+ renderingDoneCallback();
+ }
+}
+
+void CHyprGLRenderer::renderOffToMain(IFramebuffer* off) {
+ g_pHyprOpenGL->renderOffToMain(off);
+}
+
+SP<IRenderbuffer> CHyprGLRenderer::getOrCreateRenderbufferInternal(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) {
+ g_pHyprOpenGL->makeEGLCurrent();
+ return makeShared<CGLRenderbuffer>(buffer, fmt);
+}
+
+SP<ITexture> CHyprGLRenderer::createStencilTexture(const int width, const int height) {
+ g_pHyprOpenGL->makeEGLCurrent();
+ auto tex = makeShared<CGLTexture>();
+ tex->allocate({width, height});
+
+ return tex;
+}
+
+SP<ITexture> CHyprGLRenderer::createTexture(bool opaque) {
+ g_pHyprOpenGL->makeEGLCurrent();
+ return makeShared<CGLTexture>(opaque);
+}
+
+SP<ITexture> CHyprGLRenderer::createTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy, bool opaque) {
+ g_pHyprOpenGL->makeEGLCurrent();
+ return makeShared<CGLTexture>(drmFormat, pixels, stride, size, keepDataCopy, opaque);
+}
+
+SP<ITexture> CHyprGLRenderer::createTexture(const Aquamarine::SDMABUFAttrs& attrs, bool opaque) {
+ g_pHyprOpenGL->makeEGLCurrent();
+ const auto image = g_pHyprOpenGL->createEGLImage(attrs);
+ if (!image)
+ return nullptr;
+ return makeShared<CGLTexture>(attrs, image, opaque);
+}
+
+SP<ITexture> CHyprGLRenderer::createTexture(const int width, const int height, unsigned char* const data) {
+ g_pHyprOpenGL->makeEGLCurrent();
+ SP<ITexture> tex = makeShared<CGLTexture>();
+
+ 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<ITexture> CHyprGLRenderer::createTexture(cairo_surface_t* cairo) {
+ g_pHyprOpenGL->makeEGLCurrent();
+ const auto CAIROFORMAT = cairo_image_surface_get_format(cairo);
+ auto tex = makeShared<CGLTexture>();
+
+ 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<ITexture> CHyprGLRenderer::createTexture(std::span<const float> lut3D, size_t N) {
+ g_pHyprOpenGL->makeEGLCurrent();
+ return makeShared<CGLTexture>(lut3D, N);
+}
+
+bool CHyprGLRenderer::explicitSyncSupported() {
+ return g_pHyprOpenGL->explicitSyncSupported();
+}
+
+std::vector<SDRMFormat> CHyprGLRenderer::getDRMFormats() {
+ return g_pHyprOpenGL->getDRMFormats();
+}
+
+std::vector<uint64_t> CHyprGLRenderer::getDRMFormatModifiers(DRMFormat format) {
+ return g_pHyprOpenGL->getDRMFormatModifiers(format);
+}
+
+SP<IFramebuffer> CHyprGLRenderer::createFB(const std::string& name) {
+ g_pHyprOpenGL->makeEGLCurrent();
+ return makeShared<CGLFramebuffer>(name);
+}
+
+void CHyprGLRenderer::disableScissor() {
+ g_pHyprOpenGL->scissor(nullptr);
+}
+
+void CHyprGLRenderer::blend(bool enabled) {
+ g_pHyprOpenGL->blend(enabled);
+}
+
+void CHyprGLRenderer::drawShadow(const CBox& box, int round, float roundingPower, int range, CHyprColor color, float a) {
+ g_pHyprOpenGL->renderRoundedShadow(box, round, roundingPower, range, color, a);
+}
+
+SP<ITexture> CHyprGLRenderer::blurFramebuffer(SP<IFramebuffer> source, float a, CRegion* originalDamage) {
+ auto src = GLFB(source);
+ return g_pHyprOpenGL->blurFramebufferWithDamage(a, originalDamage, *src)->getTexture();
+}
+
+void CHyprGLRenderer::setViewport(int x, int y, int width, int height) {
+ g_pHyprOpenGL->setViewport(x, y, width, height);
+}
+
+bool CHyprGLRenderer::reloadShaders(const std::string& path) {
+ return g_pHyprOpenGL->initShaders(path);
+}
+
+void CHyprGLRenderer::draw(CBorderPassElement* element, const CRegion& damage) {
+ const auto m_data = element->m_data;
+ if (m_data.hasGrad2)
+ g_pHyprOpenGL->renderBorder(
+ m_data.box, m_data.grad1, m_data.grad2, m_data.lerp,
+ {.round = m_data.round, .roundingPower = m_data.roundingPower, .borderSize = m_data.borderSize, .a = m_data.a, .outerRound = m_data.outerRound});
+ else
+ g_pHyprOpenGL->renderBorder(
+ m_data.box, m_data.grad1,
+ {.round = m_data.round, .roundingPower = m_data.roundingPower, .borderSize = m_data.borderSize, .a = m_data.a, .outerRound = m_data.outerRound});
+};
+
+void CHyprGLRenderer::draw(CClearPassElement* element, const CRegion& damage) {
+ g_pHyprOpenGL->clear(element->m_data.color);
+};
+
+void CHyprGLRenderer::draw(CFramebufferElement* element, const CRegion& damage) {
+ const auto m_data = element->m_data;
+ SP<IFramebuffer> fb = nullptr;
+
+ if (m_data.main) {
+ switch (m_data.framebufferID) {
+ case FB_MONITOR_RENDER_MAIN: fb = g_pHyprRenderer->m_renderData.mainFB; break;
+ case FB_MONITOR_RENDER_CURRENT: fb = g_pHyprRenderer->m_renderData.currentFB; break;
+ case FB_MONITOR_RENDER_OUT: fb = g_pHyprRenderer->m_renderData.outFB; break;
+ default: fb = nullptr;
+ }
+
+ if (!fb) {
+ Log::logger->log(Log::ERR, "BUG THIS: CFramebufferElement::draw: main but null");
+ return;
+ }
+
+ } else {
+ switch (m_data.framebufferID) {
+ case FB_MONITOR_RENDER_EXTRA_OFFLOAD: fb = g_pHyprRenderer->m_renderData.pMonitor->m_offloadFB; break;
+ case FB_MONITOR_RENDER_EXTRA_MIRROR: fb = m_renderData.pMonitor->m_mirrorFB; break;
+ case FB_MONITOR_RENDER_EXTRA_MIRROR_SWAP: fb = m_renderData.pMonitor->m_mirrorSwapFB; break;
+ case FB_MONITOR_RENDER_EXTRA_OFF_MAIN: fb = g_pHyprRenderer->m_renderData.pMonitor->m_offMainFB; break;
+ case FB_MONITOR_RENDER_EXTRA_MONITOR_MIRROR: fb = g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB; break;
+ case FB_MONITOR_RENDER_EXTRA_BLUR: fb = g_pHyprRenderer->m_renderData.pMonitor->m_blurFB; break;
+ default: fb = nullptr;
+ }
+
+ if (!fb) {
+ Log::logger->log(Log::ERR, "BUG THIS: CFramebufferElement::draw: not main but null");
+ return;
+ }
+ }
+
+ fb->bind();
+};
+
+void CHyprGLRenderer::draw(CPreBlurElement* element, const CRegion& damage) {
+ auto dmg = damage;
+ g_pHyprRenderer->preBlurForCurrentMonitor(&dmg);
+};
+
+void CHyprGLRenderer::draw(CRectPassElement* element, const CRegion& damage) {
+ const auto m_data = element->m_data;
+
+ if (m_data.color.a == 1.F || !m_data.blur)
+ g_pHyprOpenGL->renderRect(m_data.box, m_data.color, {.damage = &damage, .round = m_data.round, .roundingPower = m_data.roundingPower});
+ else
+ g_pHyprOpenGL->renderRect(m_data.box, m_data.color,
+ {.round = m_data.round, .roundingPower = m_data.roundingPower, .blur = true, .blurA = m_data.blurA, .xray = m_data.xray});
+};
+
+void CHyprGLRenderer::draw(CShadowPassElement* element, const CRegion& damage) {
+ const auto m_data = element->m_data;
+ m_data.deco->render(g_pHyprRenderer->m_renderData.pMonitor.lock(), m_data.a);
+};
+
+void CHyprGLRenderer::draw(CTexPassElement* element, const CRegion& damage) {
+ const auto m_data = element->m_data;
+
+ g_pHyprOpenGL->renderTexture( //
+ m_data.tex, m_data.box,
+ {
+ // blur settings for m_data.blur == true
+ .blur = m_data.blur,
+ .blurA = m_data.blurA,
+ .overallA = m_data.overallA,
+ .blockBlurOptimization = m_data.blockBlurOptimization.value_or(false),
+ .blurredBG = m_data.blurredBG,
+
+ // common settings
+ .damage = m_data.damage.empty() ? &damage : &m_data.damage,
+ .surface = m_data.surface,
+ .a = m_data.a,
+ .round = m_data.round,
+ .roundingPower = m_data.roundingPower,
+ .discardActive = m_data.discardActive,
+ .allowCustomUV = m_data.allowCustomUV,
+ .cmBackToSRGB = m_data.cmBackToSRGB,
+ .cmBackToSRGBSource = m_data.cmBackToSRGBSource,
+ .discardMode = m_data.ignoreAlpha.has_value() ? sc<uint32_t>(DISCARD_ALPHA) : m_data.discardMode,
+ .discardOpacity = m_data.ignoreAlpha.has_value() ? *m_data.ignoreAlpha : m_data.discardOpacity,
+ .clipRegion = m_data.clipRegion,
+ .currentLS = m_data.currentLS,
+
+ .primarySurfaceUVTopLeft = g_pHyprRenderer->m_renderData.primarySurfaceUVTopLeft,
+ .primarySurfaceUVBottomRight = g_pHyprRenderer->m_renderData.primarySurfaceUVBottomRight,
+ });
+};
+
+void CHyprGLRenderer::draw(CTextureMatteElement* element, const CRegion& damage) {
+ const auto m_data = element->m_data;
+
+ g_pHyprOpenGL->renderTextureMatte(m_data.tex, m_data.box, m_data.fb);
+};
+
+SP<ITexture> CHyprGLRenderer::getBlurTexture(PHLMONITORREF pMonitor) {
+ return pMonitor->m_blurFB->getTexture();
+}
+
+void CHyprGLRenderer::unsetEGL() {
+ if (!g_pHyprOpenGL)
+ return;
+
+ eglMakeCurrent(g_pHyprOpenGL->m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+}
diff --git a/src/render/GLRenderer.hpp b/src/render/GLRenderer.hpp
new file mode 100644
index 00000000..1446e9b2
--- /dev/null
+++ b/src/render/GLRenderer.hpp
@@ -0,0 +1,52 @@
+#pragma once
+
+#include "Renderer.hpp"
+
+class CHyprGLRenderer : public IHyprRenderer {
+ public:
+ CHyprGLRenderer();
+
+ void endRender(const std::function<void()>& renderingDoneCallback = {}) override;
+ SP<ITexture> createStencilTexture(const int width, const int height) override;
+ SP<ITexture> createTexture(bool opaque = false) override;
+ SP<ITexture> createTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false, bool opaque = false) override;
+ SP<ITexture> createTexture(const Aquamarine::SDMABUFAttrs&, bool opaque = false) override;
+ SP<ITexture> createTexture(const int width, const int height, unsigned char* const data) override;
+ SP<ITexture> createTexture(cairo_surface_t* cairo) override;
+ SP<ITexture> createTexture(std::span<const float> lut3D, size_t N) override;
+ bool explicitSyncSupported() override;
+ std::vector<SDRMFormat> getDRMFormats() override;
+ std::vector<uint64_t> getDRMFormatModifiers(DRMFormat format) override;
+ SP<IFramebuffer> createFB(const std::string& name = "") override;
+ void disableScissor() override;
+ void blend(bool enabled) override;
+ void drawShadow(const CBox& box, int round, float roundingPower, int range, CHyprColor color, float a) override;
+ SP<ITexture> blurFramebuffer(SP<IFramebuffer> source, float a, CRegion* originalDamage) override;
+ void setViewport(int x, int y, int width, int height) override;
+ bool reloadShaders(const std::string& path = "") override;
+
+ void unsetEGL();
+
+ private:
+ void renderOffToMain(IFramebuffer* off) override;
+ SP<IRenderbuffer> getOrCreateRenderbufferInternal(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) override;
+ bool beginRenderInternal(PHLMONITOR pMonitor, CRegion& damage, bool simple = false) override;
+ bool beginFullFakeRenderInternal(PHLMONITOR pMonitor, CRegion& damage, SP<IFramebuffer> fb, bool simple = false) override;
+ void initRender() override;
+ bool initRenderBuffer(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) override;
+
+ void draw(CBorderPassElement* element, const CRegion& damage) override;
+ void draw(CClearPassElement* element, const CRegion& damage) override;
+ void draw(CFramebufferElement* element, const CRegion& damage) override;
+ void draw(CPreBlurElement* element, const CRegion& damage) override;
+ void draw(CRectPassElement* element, const CRegion& damage) override;
+ void draw(CShadowPassElement* element, const CRegion& damage) override;
+ void draw(CTexPassElement* element, const CRegion& damage) override;
+ void draw(CTextureMatteElement* element, const CRegion& damage) override;
+
+ SP<ITexture> getBlurTexture(PHLMONITORREF pMonitor) override;
+
+ SP<IRenderbuffer> m_currentRenderbuffer = nullptr;
+
+ friend class CHyprOpenGLImpl;
+};
diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp
index 97cefb48..9cee975b 100644
--- a/src/render/OpenGL.cpp
+++ b/src/render/OpenGL.cpp
@@ -1,6 +1,8 @@
#include <GLES3/gl32.h>
+#include <cstdint>
#include <hyprgraphics/color/Color.hpp>
-#include <hyprutils/math/Misc.hpp>
+#include <hyprutils/memory/SharedPtr.hpp>
+#include <hyprutils/memory/UniquePtr.hpp>
#include <hyprutils/string/String.hpp>
#include <hyprutils/path/Path.hpp>
#include <numbers>
@@ -37,6 +39,7 @@
#include "pass/RectPassElement.hpp"
#include "pass/PreBlurElement.hpp"
#include "pass/ClearPassElement.hpp"
+#include "render/GLRenderer.hpp"
#include "render/Shader.hpp"
#include "AsyncResourceGatherer.hpp"
#include <ranges>
@@ -46,10 +49,11 @@
#include <xf86drm.h>
#include <fcntl.h>
#include <gbm.h>
+#include <filesystem>
#include <cstring>
+#include "./shaders/Shaders.hpp"
#include "ShaderLoader.hpp"
#include "Texture.hpp"
-#include <filesystem>
#include "gl/GLFramebuffer.hpp"
#include "gl/GLTexture.hpp"
@@ -662,8 +666,6 @@ void CHyprOpenGLImpl::beginSimple(PHLMONITOR pMonitor, const CRegion& damage, SP
setViewport(0, 0, pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y);
- g_pHyprRenderer->setProjectionType(FBO->m_size);
-
if (!m_shadersInitialized)
initShaders();
@@ -710,42 +712,12 @@ void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, SP<IFra
TRACY_GPU_ZONE("RenderBegin");
setViewport(0, 0, pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y);
- g_pHyprRenderer->setProjectionType(RPT_MONITOR);
-
- if (pMonitor && (!pMonitor->m_offloadFB || pMonitor->m_offloadFB->m_size != pMonitor->m_pixelSize))
- destroyMonitorResources(pMonitor);
if (!m_shadersInitialized)
initShaders();
- const auto DRM_FORMAT = fb ? fb->m_drmFormat : pMonitor->m_output->state->state().drmFormat;
-
- // ensure a framebuffer for the monitor exists
- if (!g_pHyprRenderer->m_renderData.pMonitor->m_offloadFB || g_pHyprRenderer->m_renderData.pMonitor->m_offloadFB->m_size != pMonitor->m_pixelSize ||
- DRM_FORMAT != g_pHyprRenderer->m_renderData.pMonitor->m_offloadFB->m_drmFormat) {
- g_pHyprRenderer->m_renderData.pMonitor->m_stencilTex = g_pHyprRenderer->createStencilTexture(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y);
- g_pHyprRenderer->m_renderData.pMonitor->m_offloadFB = g_pHyprRenderer->createFB();
- g_pHyprRenderer->m_renderData.pMonitor->m_mirrorFB = g_pHyprRenderer->createFB();
- g_pHyprRenderer->m_renderData.pMonitor->m_mirrorSwapFB = g_pHyprRenderer->createFB();
-
- g_pHyprRenderer->m_renderData.pMonitor->m_offloadFB->addStencil(g_pHyprRenderer->m_renderData.pMonitor->m_stencilTex);
- g_pHyprRenderer->m_renderData.pMonitor->m_mirrorFB->addStencil(g_pHyprRenderer->m_renderData.pMonitor->m_stencilTex);
- g_pHyprRenderer->m_renderData.pMonitor->m_mirrorSwapFB->addStencil(g_pHyprRenderer->m_renderData.pMonitor->m_stencilTex);
-
- g_pHyprRenderer->m_renderData.pMonitor->m_offloadFB->alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, DRM_FORMAT);
- g_pHyprRenderer->m_renderData.pMonitor->m_mirrorFB->alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, DRM_FORMAT);
- g_pHyprRenderer->m_renderData.pMonitor->m_mirrorSwapFB->alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, DRM_FORMAT);
- }
-
const bool HAS_MIRROR_FB = g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB && g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB->isAllocated();
- const bool NEEDS_COPY_FB = needsACopyFB(g_pHyprRenderer->m_renderData.pMonitor.lock());
-
- if (HAS_MIRROR_FB && !NEEDS_COPY_FB)
- g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB->release();
- else if (!HAS_MIRROR_FB && NEEDS_COPY_FB && g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB)
- g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB->alloc(g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.x,
- g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.y,
- g_pHyprRenderer->m_renderData.pMonitor->m_output->state->state().drmFormat);
+ const bool NEEDS_COPY_FB = g_pHyprRenderer->needsACopyFB(g_pHyprRenderer->m_renderData.pMonitor.lock());
g_pHyprRenderer->m_renderData.transformDamage = true;
if (HAS_MIRROR_FB != NEEDS_COPY_FB) {
@@ -770,32 +742,30 @@ void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, SP<IFra
m_offloadedFramebuffer = true;
g_pHyprRenderer->m_renderData.mainFB = g_pHyprRenderer->m_renderData.currentFB;
- g_pHyprRenderer->m_renderData.outFB = fb ? fb : g_pHyprRenderer->getCurrentRBO()->getFB();
+ g_pHyprRenderer->m_renderData.outFB = fb ? fb : dc<CHyprGLRenderer*>(g_pHyprRenderer.get())->m_currentRenderbuffer->getFB();
g_pHyprRenderer->pushMonitorTransformEnabled(false);
}
void CHyprOpenGLImpl::end() {
static auto PZOOMDISABLEAA = CConfigValue<Hyprlang::INT>("cursor:zoom_disable_aa");
-
+ auto& m_renderData = g_pHyprRenderer->m_renderData;
TRACY_GPU_ZONE("RenderEnd");
g_pHyprRenderer->m_renderData.currentWindow.reset();
g_pHyprRenderer->m_renderData.surface.reset();
- g_pHyprRenderer->m_renderData.currentLS.reset();
g_pHyprRenderer->m_renderData.clipBox = {};
- g_pHyprRenderer->m_renderData.clipRegion.clear();
// end the render, copy the data to the main framebuffer
if LIKELY (m_offloadedFramebuffer) {
g_pHyprRenderer->m_renderData.damage = g_pHyprRenderer->m_renderData.finalDamage;
g_pHyprRenderer->pushMonitorTransformEnabled(true);
- CBox monbox = {0, 0, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.x, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.y};
+ CBox monbox = {0, 0, m_renderData.pMonitor->m_transformedSize.x, m_renderData.pMonitor->m_transformedSize.y};
if LIKELY (g_pHyprRenderer->m_renderMode == RENDER_MODE_NORMAL && g_pHyprRenderer->m_renderData.mouseZoomFactor == 1.0f)
- g_pHyprRenderer->m_renderData.pMonitor->m_zoomController.m_resetCameraState = true;
- g_pHyprRenderer->m_renderData.pMonitor->m_zoomController.applyZoomTransform(monbox, g_pHyprRenderer->m_renderData);
+ m_renderData.pMonitor->m_zoomController.m_resetCameraState = true;
+ m_renderData.pMonitor->m_zoomController.applyZoomTransform(monbox, m_renderData);
m_applyFinalShader = !g_pHyprRenderer->m_renderData.blockScreenShader;
if UNLIKELY (g_pHyprRenderer->m_renderData.mouseZoomFactor != 1.F && g_pHyprRenderer->m_renderData.mouseZoomUseMouse && *PZOOMDISABLEAA)
@@ -803,7 +773,7 @@ void CHyprOpenGLImpl::end() {
// copy the damaged areas into the mirror buffer
// we can't use the offloadFB for mirroring / ss, as it contains artifacts from blurring
- if UNLIKELY (needsACopyFB(g_pHyprRenderer->m_renderData.pMonitor.lock()) && !m_fakeFrame)
+ if UNLIKELY (g_pHyprRenderer->needsACopyFB(g_pHyprRenderer->m_renderData.pMonitor.lock()) && !m_fakeFrame)
saveBufferForMirror(monbox);
g_pHyprRenderer->m_renderData.outFB->bind();
@@ -825,25 +795,17 @@ void CHyprOpenGLImpl::end() {
}
// invalidate our render FBs to signal to the driver we don't need them anymore
- if (g_pHyprRenderer->m_renderData.pMonitor->m_mirrorFB) {
- g_pHyprRenderer->m_renderData.pMonitor->m_mirrorFB->bind();
- GLFB(g_pHyprRenderer->m_renderData.pMonitor->m_mirrorFB)->invalidate({GL_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0});
- }
- if (g_pHyprRenderer->m_renderData.pMonitor->m_mirrorSwapFB) {
- g_pHyprRenderer->m_renderData.pMonitor->m_mirrorSwapFB->bind();
- GLFB(g_pHyprRenderer->m_renderData.pMonitor->m_mirrorSwapFB)->invalidate({GL_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0});
- }
- if (g_pHyprRenderer->m_renderData.pMonitor->m_offloadFB) {
- g_pHyprRenderer->m_renderData.pMonitor->m_offloadFB->bind();
- GLFB(g_pHyprRenderer->m_renderData.pMonitor->m_offloadFB)->invalidate({GL_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0});
- }
- if (g_pHyprRenderer->m_renderData.pMonitor->m_offMainFB) {
- g_pHyprRenderer->m_renderData.pMonitor->m_offMainFB->bind();
- GLFB(g_pHyprRenderer->m_renderData.pMonitor->m_offMainFB)->invalidate({GL_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0});
- }
+ g_pHyprRenderer->m_renderData.pMonitor->m_mirrorFB->bind();
+ GLFB(g_pHyprRenderer->m_renderData.pMonitor->m_mirrorFB)->invalidate({GL_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0});
+ g_pHyprRenderer->m_renderData.pMonitor->m_mirrorSwapFB->bind();
+ GLFB(g_pHyprRenderer->m_renderData.pMonitor->m_mirrorSwapFB)->invalidate({GL_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0});
+ g_pHyprRenderer->m_renderData.pMonitor->m_offloadFB->bind();
+ GLFB(g_pHyprRenderer->m_renderData.pMonitor->m_offloadFB)->invalidate({GL_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0});
+ g_pHyprRenderer->m_renderData.pMonitor->m_offMainFB->bind();
+ GLFB(g_pHyprRenderer->m_renderData.pMonitor->m_offMainFB)->invalidate({GL_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0});
// reset our data
- g_pHyprRenderer->m_renderData.pMonitor.reset();
+ m_renderData.pMonitor.reset();
g_pHyprRenderer->m_renderData.mouseZoomFactor = 1.f;
g_pHyprRenderer->m_renderData.mouseZoomUseMouse = true;
g_pHyprRenderer->m_renderData.blockScreenShader = false;
@@ -870,15 +832,6 @@ void CHyprOpenGLImpl::end() {
}
}
-bool CHyprOpenGLImpl::needsACopyFB(PHLMONITOR mon) {
- return !mon->m_mirrors.empty() || Screenshare::mgr()->isOutputBeingSSd(mon);
-}
-
-void CHyprOpenGLImpl::setDamage(const CRegion& damage_, std::optional<CRegion> finalDamage) {
- g_pHyprRenderer->m_renderData.damage.set(damage_);
- g_pHyprRenderer->m_renderData.finalDamage.set(finalDamage.value_or(damage_));
-}
-
static const std::vector<std::string> SHADER_INCLUDES = {
"defines.h", "constants.h", "cm_helpers.glsl", "rounding.glsl", "CM.glsl", "tonemap.glsl", "gain.glsl",
"border.glsl", "shadow.glsl", "blurprepare.glsl", "blur1.glsl", "blur2.glsl", "blurFinish.glsl",
@@ -1005,15 +958,16 @@ void CHyprOpenGLImpl::blend(bool enabled) {
}
void CHyprOpenGLImpl::scissor(const CBox& originalBox, bool transform) {
- RASSERT(g_pHyprRenderer->m_renderData.pMonitor, "Tried to scissor without begin()!");
+ auto& m_renderData = g_pHyprRenderer->m_renderData;
+ RASSERT(m_renderData.pMonitor, "Tried to scissor without begin()!");
// only call glScissor if the box has changed
static CBox m_lastScissorBox = {};
if (transform) {
CBox box = originalBox;
- const auto TR = Math::wlTransformToHyprutils(Math::invertTransform(g_pHyprRenderer->m_renderData.pMonitor->m_transform));
- box.transform(TR, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.x, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.y);
+ const auto TR = Math::wlTransformToHyprutils(Math::invertTransform(m_renderData.pMonitor->m_transform));
+ box.transform(TR, m_renderData.pMonitor->m_transformedSize.x, m_renderData.pMonitor->m_transformedSize.y);
if (box != m_lastScissorBox) {
GLCALL(glScissor(box.x, box.y, box.width, box.height));
@@ -1067,7 +1021,7 @@ void CHyprOpenGLImpl::renderRectWithBlurInternal(const CBox& box, const CHyprCol
CRegion damage{g_pHyprRenderer->m_renderData.damage};
damage.intersect(box);
- auto POUTFB = data.xray ? g_pHyprRenderer->m_renderData.pMonitor->m_blurFB : blurMainFramebufferWithDamage(data.blurA, &damage);
+ auto POUTFB = data.xray ? g_pHyprRenderer->m_renderData.pMonitor->m_blurFB->getTexture() : g_pHyprRenderer->blurMainFramebuffer(data.blurA, &damage);
g_pHyprRenderer->m_renderData.currentFB->bind();
@@ -1075,7 +1029,7 @@ void CHyprOpenGLImpl::renderRectWithBlurInternal(const CBox& box, const CHyprCol
g_pHyprRenderer->pushMonitorTransformEnabled(true);
const auto SAVEDRENDERMODIF = g_pHyprRenderer->m_renderData.renderModif;
g_pHyprRenderer->m_renderData.renderModif = {}; // fix shit
- renderTexture(POUTFB->getTexture(), MONITORBOX,
+ renderTexture(POUTFB, MONITORBOX,
STextureRenderData{.damage = &damage, .a = data.blurA, .round = data.round, .roundingPower = 2.F, .allowCustomUV = false, .allowDim = false, .noAA = false});
g_pHyprRenderer->popMonitorTransformEnabled();
g_pHyprRenderer->m_renderData.renderModif = SAVEDRENDERMODIF;
@@ -1084,8 +1038,9 @@ void CHyprOpenGLImpl::renderRectWithBlurInternal(const CBox& box, const CHyprCol
}
void CHyprOpenGLImpl::renderRectWithDamageInternal(const CBox& box, const CHyprColor& col, const SRectRenderData& data) {
+ auto& m_renderData = g_pHyprRenderer->m_renderData;
RASSERT((box.width > 0 && box.height > 0), "Tried to render rect with width/height < 0!");
- RASSERT(g_pHyprRenderer->m_renderData.pMonitor, "Tried to render rect without begin()!");
+ RASSERT(m_renderData.pMonitor, "Tried to render rect without begin()!");
TRACY_GPU_ZONE("RenderRectWithDamage");
@@ -1101,8 +1056,8 @@ void CHyprOpenGLImpl::renderRectWithDamageInternal(const CBox& box, const CHyprC
shader->setUniformFloat4(SHADER_COLOR, col.r * col.a, col.g * col.a, col.b * col.a, col.a);
CBox transformedBox = box;
- transformedBox.transform(Math::wlTransformToHyprutils(Math::invertTransform(g_pHyprRenderer->m_renderData.pMonitor->m_transform)),
- g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.x, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.y);
+ transformedBox.transform(Math::wlTransformToHyprutils(Math::invertTransform(m_renderData.pMonitor->m_transform)), m_renderData.pMonitor->m_transformedSize.x,
+ m_renderData.pMonitor->m_transformedSize.y);
const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y);
const auto FULLSIZE = Vector2D(transformedBox.width, transformedBox.height);
@@ -1231,6 +1186,8 @@ WP<CShader> CHyprOpenGLImpl::renderToOutputInternal() {
static const auto PDT = CConfigValue<Hyprlang::INT>("debug:damage_tracking");
static const auto PCURSORTIMEOUT = CConfigValue<Hyprlang::FLOAT>("cursor:inactive_timeout");
+ auto& m_renderData = g_pHyprRenderer->m_renderData;
+
WP<CShader> shader =
g_pHyprRenderer->m_crashingInProgress ? getShaderVariant(SH_FRAG_GLITCH) : (m_finalScreenShader->program() ? m_finalScreenShader : getShaderVariant(SH_FRAG_PASSTHRURGBA));
@@ -1241,8 +1198,8 @@ WP<CShader> CHyprOpenGLImpl::renderToOutputInternal() {
else
shader->setUniformFloat(SHADER_TIME, 0.f);
- shader->setUniformInt(SHADER_WL_OUTPUT, g_pHyprRenderer->m_renderData.pMonitor->m_id);
- shader->setUniformFloat2(SHADER_FULL_SIZE, g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.x, g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.y);
+ shader->setUniformInt(SHADER_WL_OUTPUT, m_renderData.pMonitor->m_id);
+ shader->setUniformFloat2(SHADER_FULL_SIZE, m_renderData.pMonitor->m_pixelSize.x, m_renderData.pMonitor->m_pixelSize.y);
shader->setUniformFloat(SHADER_POINTER_INACTIVE_TIMEOUT, *PCURSORTIMEOUT);
shader->setUniformInt(SHADER_POINTER_HIDDEN, g_pHyprRenderer->m_cursorHiddenByCondition);
shader->setUniformInt(SHADER_POINTER_KILLING, g_pInputManager->getClickMode() == CLICKMODE_KILL);
@@ -1251,7 +1208,7 @@ WP<CShader> CHyprOpenGLImpl::renderToOutputInternal() {
shader->setUniformFloat(SHADER_POINTER_SIZE, g_pCursorManager->getScaledSize());
if (*PDT == 0) {
- PHLMONITORREF pMonitor = g_pHyprRenderer->m_renderData.pMonitor;
+ PHLMONITORREF pMonitor = m_renderData.pMonitor;
Vector2D p = ((g_pInputManager->getMouseCoordsInternal() - pMonitor->m_position) * pMonitor->m_scale);
p = p.transform(Math::wlTransformToHyprutils(pMonitor->m_transform), pMonitor->m_pixelSize);
shader->setUniformFloat2(SHADER_POINTER, p.x / pMonitor->m_pixelSize.x, p.y / pMonitor->m_pixelSize.y);
@@ -1292,7 +1249,7 @@ WP<CShader> CHyprOpenGLImpl::renderToOutputInternal() {
if (g_pHyprRenderer->m_crashingInProgress) {
shader->setUniformFloat(SHADER_DISTORT, g_pHyprRenderer->m_crashingDistort);
- shader->setUniformFloat2(SHADER_FULL_SIZE, g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.x, g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.y);
+ shader->setUniformFloat2(SHADER_FULL_SIZE, m_renderData.pMonitor->m_pixelSize.x, m_renderData.pMonitor->m_pixelSize.y);
}
return shader;
@@ -1303,6 +1260,8 @@ WP<CShader> CHyprOpenGLImpl::renderToFBInternal(const STextureRenderData& data,
static const auto PENABLECM = CConfigValue<Hyprlang::INT>("render:cm_enabled");
static auto PBLEND = CConfigValue<Hyprlang::INT>("render:use_shader_blur_blend");
+ auto& m_renderData = g_pHyprRenderer->m_renderData;
+
float alpha = std::clamp(data.a, 0.f, 1.f);
WP<CShader> shader;
@@ -1368,9 +1327,8 @@ WP<CShader> CHyprOpenGLImpl::renderToFBInternal(const STextureRenderData& data,
|| g_pHyprRenderer->m_renderData.pMonitor->doesNoShaderCM() /* no shader needed */
|| (SOURCE_IMAGE_DESCRIPTION->id() == TARGET_IMAGE_DESCRIPTION->id() && !CANT_CHECK_CM_EQUALITY) /* Source and target have the same image description */
|| (((*PPASS && canPassHDRSurface) ||
- (*PPASS == 1 && !isHDRSurface && g_pHyprRenderer->m_renderData.pMonitor->m_cmType != NCMType::CM_HDR &&
- g_pHyprRenderer->m_renderData.pMonitor->m_cmType != NCMType::CM_HDR_EDID)) &&
- g_pHyprRenderer->m_renderData.pMonitor->inFullscreenMode()) /* Fullscreen window with pass cm enabled */;
+ (*PPASS == 1 && !isHDRSurface && m_renderData.pMonitor->m_cmType != NCMType::CM_HDR && m_renderData.pMonitor->m_cmType != NCMType::CM_HDR_EDID)) &&
+ m_renderData.pMonitor->inFullscreenMode()) /* Fullscreen window with pass cm enabled */;
if (data.allowDim && g_pHyprRenderer->m_renderData.currentWindow &&
(g_pHyprRenderer->m_renderData.currentWindow->m_notRespondingTint->value() > 0 || g_pHyprRenderer->m_renderData.currentWindow->m_dimPercent->value() > 0))
@@ -1421,28 +1379,25 @@ WP<CShader> CHyprOpenGLImpl::renderToFBInternal(const STextureRenderData& data,
if (shaderFeatures & SH_FEAT_BLUR) {
shader->setUniformInt(SHADER_BLURRED_BG, 1);
- // shader->setUniformFloat2(SHADER_UV_OFFSET, 0, 0);
- shader->setUniformFloat2(SHADER_UV_OFFSET, newBox.x / g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.x,
- newBox.y / g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.y);
- shader->setUniformFloat2(SHADER_UV_SIZE, newBox.width / g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.x,
- newBox.height / g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.y);
+ shader->setUniformFloat2(SHADER_UV_OFFSET, newBox.x / data.blurredBG->m_size.x, newBox.y / data.blurredBG->m_size.y);
+ shader->setUniformFloat2(SHADER_UV_SIZE, newBox.width / data.blurredBG->m_size.x, newBox.height / data.blurredBG->m_size.y);
glActiveTexture(GL_TEXTURE0 + 1);
data.blurredBG->bind();
}
if (data.discardActive) {
- shader->setUniformInt(SHADER_DISCARD_OPAQUE, !!(g_pHyprRenderer->m_renderData.discardMode & DISCARD_OPAQUE));
- shader->setUniformInt(SHADER_DISCARD_ALPHA, !!(g_pHyprRenderer->m_renderData.discardMode & DISCARD_ALPHA));
- shader->setUniformFloat(SHADER_DISCARD_ALPHA_VALUE, g_pHyprRenderer->m_renderData.discardOpacity);
+ shader->setUniformInt(SHADER_DISCARD_OPAQUE, !!(data.discardMode & DISCARD_OPAQUE));
+ shader->setUniformInt(SHADER_DISCARD_ALPHA, !!(data.discardMode & DISCARD_ALPHA));
+ shader->setUniformFloat(SHADER_DISCARD_ALPHA_VALUE, data.discardOpacity);
} else {
shader->setUniformInt(SHADER_DISCARD_OPAQUE, 0);
shader->setUniformInt(SHADER_DISCARD_ALPHA, 0);
}
CBox transformedBox = newBox;
- transformedBox.transform(Math::wlTransformToHyprutils(Math::invertTransform(g_pHyprRenderer->m_renderData.pMonitor->m_transform)),
- g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.x, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.y);
+ transformedBox.transform(Math::wlTransformToHyprutils(Math::invertTransform(m_renderData.pMonitor->m_transform)), m_renderData.pMonitor->m_transformedSize.x,
+ m_renderData.pMonitor->m_transformedSize.y);
const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y);
const auto FULLSIZE = Vector2D(transformedBox.width, transformedBox.height);
@@ -1520,11 +1475,11 @@ void CHyprOpenGLImpl::renderTextureInternal(SP<ITexture> tex, const CBox& box, c
auto verts = fullVerts;
- if (data.allowCustomUV && g_pHyprRenderer->m_renderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) {
- const float u0 = g_pHyprRenderer->m_renderData.primarySurfaceUVTopLeft.x;
- const float v0 = g_pHyprRenderer->m_renderData.primarySurfaceUVTopLeft.y;
- const float u1 = g_pHyprRenderer->m_renderData.primarySurfaceUVBottomRight.x;
- const float v1 = g_pHyprRenderer->m_renderData.primarySurfaceUVBottomRight.y;
+ if (data.allowCustomUV && data.primarySurfaceUVTopLeft != Vector2D(-1, -1)) {
+ const float u0 = data.primarySurfaceUVTopLeft.x;
+ const float v0 = data.primarySurfaceUVTopLeft.y;
+ const float u1 = data.primarySurfaceUVBottomRight.x;
+ const float v1 = data.primarySurfaceUVBottomRight.y;
verts[0].u = u0;
verts[0].v = v0;
@@ -1538,14 +1493,14 @@ void CHyprOpenGLImpl::renderTextureInternal(SP<ITexture> tex, const CBox& box, c
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(verts), verts.data());
- if (!g_pHyprRenderer->m_renderData.clipBox.empty() || !g_pHyprRenderer->m_renderData.clipRegion.empty()) {
+ if (!g_pHyprRenderer->m_renderData.clipBox.empty() || !data.clipRegion.empty()) {
CRegion damageClip = g_pHyprRenderer->m_renderData.clipBox;
- if (!g_pHyprRenderer->m_renderData.clipRegion.empty()) {
+ if (!data.clipRegion.empty()) {
if (g_pHyprRenderer->m_renderData.clipBox.empty())
- damageClip = g_pHyprRenderer->m_renderData.clipRegion;
+ damageClip = data.clipRegion;
else
- damageClip.intersect(g_pHyprRenderer->m_renderData.clipRegion);
+ damageClip.intersect(data.clipRegion);
}
if (!damageClip.empty()) {
@@ -1615,9 +1570,6 @@ void CHyprOpenGLImpl::renderTextureMatte(SP<ITexture> tex, const CBox& box, SP<I
TRACY_GPU_ZONE("RenderTextureMatte");
- if (g_pHyprRenderer->m_renderData.damage.empty())
- return;
-
CBox newBox = box;
g_pHyprRenderer->m_renderData.renderModif.applyToBox(newBox);
@@ -1652,25 +1604,17 @@ void CHyprOpenGLImpl::renderTextureMatte(SP<ITexture> tex, const CBox& box, SP<I
// but it works... well, I guess?
//
// Dual (or more) kawase blur
-SP<IFramebuffer> CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* originalDamage) {
- if (!g_pHyprRenderer->m_renderData.currentFB->getTexture()) {
- Log::logger->log(Log::ERR, "BUG THIS: null fb texture while attempting to blur main fb?! (introspection off?!)");
- return g_pHyprRenderer->m_renderData.pMonitor->m_mirrorFB; // return something to sample from at least
- }
-
- return blurFramebufferWithDamage(a, originalDamage, *GLFB(g_pHyprRenderer->m_renderData.currentFB));
-}
-
SP<IFramebuffer> CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* originalDamage, CGLFramebuffer& source) {
TRACY_GPU_ZONE("RenderBlurFramebufferWithDamage");
+ auto& m_renderData = g_pHyprRenderer->m_renderData;
const auto BLENDBEFORE = m_blend;
blend(false);
setCapStatus(GL_STENCIL_TEST, false);
// get transforms for the full monitor
- const auto TRANSFORM = Math::wlTransformToHyprutils(Math::invertTransform(g_pHyprRenderer->m_renderData.pMonitor->m_transform));
- CBox MONITORBOX = {0, 0, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.x, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.y};
+ const auto TRANSFORM = Math::wlTransformToHyprutils(Math::invertTransform(m_renderData.pMonitor->m_transform));
+ CBox MONITORBOX = {0, 0, m_renderData.pMonitor->m_transformedSize.x, m_renderData.pMonitor->m_transformedSize.y};
const auto& glMatrix = g_pHyprRenderer->projectBoxToTarget(MONITORBOX, TRANSFORM);
@@ -1684,8 +1628,8 @@ SP<IFramebuffer> CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* or
// prep damage
CRegion damage{*originalDamage};
- damage.transform(Math::wlTransformToHyprutils(Math::invertTransform(g_pHyprRenderer->m_renderData.pMonitor->m_transform)),
- g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.x, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.y);
+ damage.transform(Math::wlTransformToHyprutils(Math::invertTransform(m_renderData.pMonitor->m_transform)), m_renderData.pMonitor->m_transformedSize.x,
+ m_renderData.pMonitor->m_transformedSize.y);
damage.expand(std::clamp(*PBLURSIZE, sc<int64_t>(1), sc<int64_t>(40)) * pow(2, BLUR_PASSES));
// helper
@@ -1716,18 +1660,16 @@ SP<IFramebuffer> CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* or
const bool skipCM = !m_cmSupported || g_pHyprRenderer->workBufferImageDescription()->id() == DEFAULT_IMAGE_DESCRIPTION->id();
if (!skipCM) {
shader = useShader(getShaderVariant(SH_FRAG_BLURPREPARE, SH_FEAT_CM));
- passCMUniforms(shader, g_pHyprRenderer->m_renderData.pMonitor->m_imageDescription, DEFAULT_IMAGE_DESCRIPTION);
+ passCMUniforms(shader, m_renderData.pMonitor->m_imageDescription, DEFAULT_IMAGE_DESCRIPTION);
shader->setUniformFloat(SHADER_SDR_SATURATION,
- g_pHyprRenderer->m_renderData.pMonitor->m_sdrSaturation > 0 &&
- g_pHyprRenderer->m_renderData.pMonitor->m_imageDescription->value().transferFunction ==
- NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ?
- g_pHyprRenderer->m_renderData.pMonitor->m_sdrSaturation :
+ m_renderData.pMonitor->m_sdrSaturation > 0 &&
+ m_renderData.pMonitor->m_imageDescription->value().transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ?
+ m_renderData.pMonitor->m_sdrSaturation :
1.0f);
shader->setUniformFloat(SHADER_SDR_BRIGHTNESS,
- g_pHyprRenderer->m_renderData.pMonitor->m_sdrBrightness > 0 &&
- g_pHyprRenderer->m_renderData.pMonitor->m_imageDescription->value().transferFunction ==
- NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ?
- g_pHyprRenderer->m_renderData.pMonitor->m_sdrBrightness :
+ m_renderData.pMonitor->m_sdrBrightness > 0 &&
+ m_renderData.pMonitor->m_imageDescription->value().transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ?
+ m_renderData.pMonitor->m_sdrBrightness :
1.0f);
} else
shader = useShader(getShaderVariant(SH_FRAG_BLURPREPARE));
@@ -1770,14 +1712,12 @@ SP<IFramebuffer> CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* or
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
shader->setUniformFloat(SHADER_RADIUS, *PBLURSIZE * a); // this makes the blursize change with a
if (frag == SH_FRAG_BLUR1) {
- shader->setUniformFloat2(SHADER_HALFPIXEL, 0.5f / (g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.x / 2.f),
- 0.5f / (g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.y / 2.f));
+ shader->setUniformFloat2(SHADER_HALFPIXEL, 0.5f / (m_renderData.pMonitor->m_pixelSize.x / 2.f), 0.5f / (m_renderData.pMonitor->m_pixelSize.y / 2.f));
shader->setUniformInt(SHADER_PASSES, BLUR_PASSES);
shader->setUniformFloat(SHADER_VIBRANCY, *PBLURVIBRANCY);
shader->setUniformFloat(SHADER_VIBRANCY_DARKNESS, *PBLURVIBRANCYDARKNESS);
} else
- shader->setUniformFloat2(SHADER_HALFPIXEL, 0.5f / (g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.x * 2.f),
- 0.5f / (g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.y * 2.f));
+ shader->setUniformFloat2(SHADER_HALFPIXEL, 0.5f / (m_renderData.pMonitor->m_pixelSize.x * 2.f), 0.5f / (m_renderData.pMonitor->m_pixelSize.y * 2.f));
shader->setUniformInt(SHADER_TEX, 0);
glBindVertexArray(shader->getUniformLocation(SHADER_SHADER_VAO));
@@ -1951,114 +1891,14 @@ void CHyprOpenGLImpl::preRender(PHLMONITOR pMonitor) {
pMonitor->m_blurFBShouldRender = true;
}
-void CHyprOpenGLImpl::preBlurForCurrentMonitor() {
-
- TRACY_GPU_ZONE("RenderPreBlurForCurrentMonitor");
-
- const auto SAVEDRENDERMODIF = g_pHyprRenderer->m_renderData.renderModif;
- g_pHyprRenderer->m_renderData.renderModif = {}; // fix shit
-
- // make the fake dmg
- CRegion fakeDamage{0, 0, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.x, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.y};
- const auto POUTFB = blurMainFramebufferWithDamage(1, &fakeDamage);
-
- // render onto blurFB
- if (!g_pHyprRenderer->m_renderData.pMonitor->m_blurFB)
- g_pHyprRenderer->m_renderData.pMonitor->m_blurFB = g_pHyprRenderer->createFB();
-
- g_pHyprRenderer->m_renderData.pMonitor->m_blurFB->alloc(g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.x, g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.y,
- g_pHyprRenderer->m_renderData.pMonitor->m_output->state->state().drmFormat);
- g_pHyprRenderer->m_renderData.pMonitor->m_blurFB->bind();
-
- clear(CHyprColor(0, 0, 0, 0));
-
- g_pHyprRenderer->pushMonitorTransformEnabled(true);
- renderTextureInternal(POUTFB->getTexture(),
- CBox{0, 0, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.x, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.y},
- STextureRenderData{.damage = &fakeDamage, .a = 1, .round = 0, .roundingPower = 2.F, .discardActive = false, .allowCustomUV = false, .noAA = true});
- g_pHyprRenderer->popMonitorTransformEnabled();
-
- g_pHyprRenderer->m_renderData.currentFB->bind();
-
- g_pHyprRenderer->m_renderData.pMonitor->m_blurFBDirty = false;
-
- g_pHyprRenderer->m_renderData.renderModif = SAVEDRENDERMODIF;
-
- g_pHyprRenderer->m_renderData.pMonitor->m_blurFBShouldRender = false;
-}
-
-void CHyprOpenGLImpl::preWindowPass() {
- if (!preBlurQueued())
- return;
-
- g_pHyprRenderer->m_renderPass.add(makeUnique<CPreBlurElement>());
-}
-
-bool CHyprOpenGLImpl::preBlurQueued() {
- static auto PBLURNEWOPTIMIZE = CConfigValue<Hyprlang::INT>("decoration:blur:new_optimizations");
- static auto PBLUR = CConfigValue<Hyprlang::INT>("decoration:blur:enabled");
-
- return g_pHyprRenderer->m_renderData.pMonitor->m_blurFBDirty && *PBLURNEWOPTIMIZE && *PBLUR && g_pHyprRenderer->m_renderData.pMonitor->m_blurFBShouldRender;
-}
-
void CHyprOpenGLImpl::renderTextureWithBlurInternal(SP<ITexture> tex, const CBox& box, const STextureRenderData& data) {
- RASSERT(g_pHyprRenderer->m_renderData.pMonitor, "Tried to render texture with blur without begin()!");
+ auto& m_renderData = g_pHyprRenderer->m_renderData;
+ RASSERT(m_renderData.pMonitor, "Tried to render texture with blur without begin()!");
TRACY_GPU_ZONE("RenderTextureWithBlur");
- static auto PBLEND = CConfigValue<Hyprlang::INT>("render:use_shader_blur_blend");
-
- // make a damage region for this window
- CRegion texDamage{g_pHyprRenderer->m_renderData.damage};
- texDamage.intersect(box.x, box.y, box.width, box.height);
-
- // While renderTextureInternalWithDamage will clip the blur as well,
- // clipping texDamage here allows blur generation to be optimized.
- if (!g_pHyprRenderer->m_renderData.clipRegion.empty())
- texDamage.intersect(g_pHyprRenderer->m_renderData.clipRegion);
-
- if (texDamage.empty())
- return;
-
- g_pHyprRenderer->m_renderData.renderModif.applyToRegion(texDamage);
-
- // amazing hack: the surface has an opaque region!
- CRegion inverseOpaque;
- if (data.a >= 1.f && data.surface && std::round(data.surface->m_current.size.x * g_pHyprRenderer->m_renderData.pMonitor->m_scale) == box.w &&
- std::round(data.surface->m_current.size.y * g_pHyprRenderer->m_renderData.pMonitor->m_scale) == box.h) {
- pixman_box32_t surfbox = {0, 0, data.surface->m_current.size.x * data.surface->m_current.scale, data.surface->m_current.size.y * data.surface->m_current.scale};
- inverseOpaque = data.surface->m_current.opaque;
- inverseOpaque.invert(&surfbox).intersect(0, 0, data.surface->m_current.size.x * data.surface->m_current.scale,
- data.surface->m_current.size.y * data.surface->m_current.scale);
-
- if (inverseOpaque.empty()) {
- renderTextureInternal(tex, box, data);
- return;
- }
- } else
- inverseOpaque = {0, 0, box.width, box.height};
-
- inverseOpaque.scale(g_pHyprRenderer->m_renderData.pMonitor->m_scale);
-
- // vvv TODO: layered blur fbs?
- const bool USENEWOPTIMIZE =
- g_pHyprRenderer->shouldUseNewBlurOptimizations(g_pHyprRenderer->m_renderData.currentLS.lock(), g_pHyprRenderer->m_renderData.currentWindow.lock()) &&
- !data.blockBlurOptimization;
-
- SP<IFramebuffer> POUTFB = nullptr;
- if (!USENEWOPTIMIZE) {
- inverseOpaque.translate(box.pos());
- g_pHyprRenderer->m_renderData.renderModif.applyToRegion(inverseOpaque);
- inverseOpaque.intersect(texDamage);
- POUTFB = blurMainFramebufferWithDamage(data.a, &inverseOpaque);
- } else
- POUTFB = g_pHyprRenderer->m_renderData.pMonitor->m_blurFB;
-
- g_pHyprRenderer->m_renderData.currentFB->bind();
-
- auto blurredBG = POUTFB->getTexture();
-
- const auto NEEDS_STENCIL = g_pHyprRenderer->m_renderData.discardMode != 0 && (!data.blockBlurOptimization || (g_pHyprRenderer->m_renderData.discardMode & DISCARD_ALPHA));
+ static auto PBLEND = CConfigValue<Hyprlang::INT>("render:use_shader_blur_blend");
+ const auto NEEDS_STENCIL = data.discardMode != 0 && (!data.blockBlurOptimization || (data.discardMode & DISCARD_ALPHA));
if (!*PBLEND) {
if (NEEDS_STENCIL) {
@@ -2072,14 +1912,24 @@ void CHyprOpenGLImpl::renderTextureWithBlurInternal(SP<ITexture> tex, const CBox
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+
renderTexture(tex, box,
- STextureRenderData{.a = data.a,
- .round = data.round,
- .roundingPower = data.roundingPower,
- .discardActive = true,
- .allowCustomUV = true,
- .wrapX = data.wrapX,
- .wrapY = data.wrapY}); // discard opaque and alpha < discardOpacity
+ STextureRenderData{
+ .damage = &g_pHyprRenderer->m_renderData.damage,
+ .a = data.a,
+ .round = data.round,
+ .roundingPower = data.roundingPower,
+ .discardActive = true,
+ .allowCustomUV = true,
+ .wrapX = data.wrapX,
+ .wrapY = data.wrapY,
+ .discardMode = data.discardMode,
+ .discardOpacity = data.discardOpacity,
+ .clipRegion = data.clipRegion,
+ .currentLS = data.currentLS,
+ .primarySurfaceUVTopLeft = g_pHyprRenderer->m_renderData.primarySurfaceUVTopLeft,
+ .primarySurfaceUVBottomRight = g_pHyprRenderer->m_renderData.primarySurfaceUVBottomRight,
+ }); // discard opaque and alpha < discardOpacity
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
@@ -2088,64 +1938,71 @@ void CHyprOpenGLImpl::renderTextureWithBlurInternal(SP<ITexture> tex, const CBox
}
// stencil done. Render everything.
- const auto LASTTL = g_pHyprRenderer->m_renderData.primarySurfaceUVTopLeft;
- const auto LASTBR = g_pHyprRenderer->m_renderData.primarySurfaceUVBottomRight;
-
- CBox transformedBox = box;
- transformedBox.transform(Math::wlTransformToHyprutils(Math::invertTransform(g_pHyprRenderer->m_renderData.pMonitor->m_transform)),
- g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.x, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.y);
-
- CBox monitorSpaceBox = {transformedBox.pos().x / g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.x * g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.x,
- transformedBox.pos().y / g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.y * g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.y,
- transformedBox.width / g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.x * g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.x,
- transformedBox.height / g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.y * g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.y};
+ CBox transformedBox = box;
+ transformedBox.transform(Math::wlTransformToHyprutils(Math::invertTransform(m_renderData.pMonitor->m_transform)), m_renderData.pMonitor->m_transformedSize.x,
+ m_renderData.pMonitor->m_transformedSize.y);
- g_pHyprRenderer->m_renderData.primarySurfaceUVTopLeft = monitorSpaceBox.pos() / g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize;
- g_pHyprRenderer->m_renderData.primarySurfaceUVBottomRight = (monitorSpaceBox.pos() + monitorSpaceBox.size()) / g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize;
+ CBox monitorSpaceBox = {transformedBox.pos().x / m_renderData.pMonitor->m_pixelSize.x * m_renderData.pMonitor->m_transformedSize.x,
+ transformedBox.pos().y / m_renderData.pMonitor->m_pixelSize.y * m_renderData.pMonitor->m_transformedSize.y,
+ transformedBox.width / m_renderData.pMonitor->m_pixelSize.x * m_renderData.pMonitor->m_transformedSize.x,
+ transformedBox.height / m_renderData.pMonitor->m_pixelSize.y * m_renderData.pMonitor->m_transformedSize.y};
static auto PBLURIGNOREOPACITY = CConfigValue<Hyprlang::INT>("decoration:blur:ignore_opacity");
+
g_pHyprRenderer->pushMonitorTransformEnabled(true);
bool renderModif = g_pHyprRenderer->m_renderData.renderModif.enabled;
- if (!USENEWOPTIMIZE)
- setRenderModifEnabled(false);
- renderTextureInternal(blurredBG, box,
+ if (!data.blockBlurOptimization)
+ g_pHyprRenderer->m_renderData.renderModif.enabled = false;
+
+ renderTextureInternal(data.blurredBG, box,
STextureRenderData{
- .damage = &texDamage,
- .a = (*PBLURIGNOREOPACITY ? data.blurA : data.a * data.blurA) * data.overallA,
- .round = data.round,
- .roundingPower = data.roundingPower,
- .discardActive = false,
- .allowCustomUV = true,
- .noAA = false,
- .wrapX = data.wrapX,
- .wrapY = data.wrapY,
+ .damage = data.damage,
+ .a = (*PBLURIGNOREOPACITY ? data.blurA : data.a * data.blurA) * data.overallA,
+ .round = data.round,
+ .roundingPower = data.roundingPower,
+ .discardActive = false,
+ .allowCustomUV = true,
+ .noAA = false,
+ .wrapX = data.wrapX,
+ .wrapY = data.wrapY,
+ .discardMode = data.discardMode,
+ .discardOpacity = data.discardOpacity,
+ .clipRegion = data.clipRegion,
+ .currentLS = data.currentLS,
+
+ .primarySurfaceUVTopLeft = monitorSpaceBox.pos() / m_renderData.pMonitor->m_transformedSize,
+ .primarySurfaceUVBottomRight = (monitorSpaceBox.pos() + monitorSpaceBox.size()) / m_renderData.pMonitor->m_transformedSize,
});
- if (!USENEWOPTIMIZE)
- setRenderModifEnabled(renderModif);
+
+ g_pHyprRenderer->m_renderData.renderModif.enabled = renderModif;
g_pHyprRenderer->popMonitorTransformEnabled();
if (NEEDS_STENCIL)
setCapStatus(GL_STENCIL_TEST, false);
-
- g_pHyprRenderer->m_renderData.primarySurfaceUVTopLeft = LASTTL;
- g_pHyprRenderer->m_renderData.primarySurfaceUVBottomRight = LASTBR;
}
// draw window
renderTextureInternal(tex, box,
STextureRenderData{
- .damage = &texDamage,
- .a = data.a * data.overallA,
- .blur = *PBLEND,
- .round = data.round,
- .roundingPower = data.roundingPower,
- .discardActive = *PBLEND && NEEDS_STENCIL,
- .allowCustomUV = true,
- .allowDim = true,
- .noAA = false,
- .wrapX = data.wrapX,
- .wrapY = data.wrapY,
- .blurredBG = blurredBG,
+ .blur = *PBLEND,
+ .blurredBG = data.blurredBG,
+ .damage = data.damage,
+ .a = data.a * data.overallA,
+ .round = data.round,
+ .roundingPower = data.roundingPower,
+ .discardActive = *PBLEND && NEEDS_STENCIL,
+ .allowCustomUV = true,
+ .allowDim = true,
+ .noAA = false,
+ .wrapX = data.wrapX,
+ .wrapY = data.wrapY,
+ .discardMode = data.discardMode,
+ .discardOpacity = data.discardOpacity,
+ .clipRegion = data.clipRegion,
+ .currentLS = data.currentLS,
+
+ .primarySurfaceUVTopLeft = g_pHyprRenderer->m_renderData.primarySurfaceUVTopLeft,
+ .primarySurfaceUVBottomRight = g_pHyprRenderer->m_renderData.primarySurfaceUVBottomRight,
});
GLFB(g_pHyprRenderer->m_renderData.currentFB)->invalidate({GL_STENCIL_ATTACHMENT});
@@ -2153,8 +2010,9 @@ void CHyprOpenGLImpl::renderTextureWithBlurInternal(SP<ITexture> tex, const CBox
}
void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& grad, SBorderRenderData data) {
+ auto& m_renderData = g_pHyprRenderer->m_renderData;
RASSERT((box.width > 0 && box.height > 0), "Tried to render rect with width/height < 0!");
- RASSERT(g_pHyprRenderer->m_renderData.pMonitor, "Tried to render rect without begin()!");
+ RASSERT(m_renderData.pMonitor, "Tried to render rect without begin()!");
TRACY_GPU_ZONE("RenderBorder");
@@ -2167,7 +2025,7 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& gr
if (data.borderSize < 1)
return;
- int scaledBorderSize = std::round(data.borderSize * g_pHyprRenderer->m_renderData.pMonitor->m_scale);
+ int scaledBorderSize = std::round(data.borderSize * m_renderData.pMonitor->m_scale);
scaledBorderSize = std::round(scaledBorderSize * g_pHyprRenderer->m_renderData.renderModif.combinedScale());
// adjust box
@@ -2201,8 +2059,8 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& gr
shader->setUniformInt(SHADER_GRADIENT2_LENGTH, 0);
CBox transformedBox = newBox;
- transformedBox.transform(Math::wlTransformToHyprutils(Math::invertTransform(g_pHyprRenderer->m_renderData.pMonitor->m_transform)),
- g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.x, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.y);
+ transformedBox.transform(Math::wlTransformToHyprutils(Math::invertTransform(m_renderData.pMonitor->m_transform)), m_renderData.pMonitor->m_transformedSize.x,
+ m_renderData.pMonitor->m_transformedSize.y);
const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y);
const auto FULLSIZE = Vector2D(transformedBox.width, transformedBox.height);
@@ -2238,8 +2096,9 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& gr
}
void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& grad1, const CGradientValueData& grad2, float lerp, SBorderRenderData data) {
+ auto& m_renderData = g_pHyprRenderer->m_renderData;
RASSERT((box.width > 0 && box.height > 0), "Tried to render rect with width/height < 0!");
- RASSERT(g_pHyprRenderer->m_renderData.pMonitor, "Tried to render rect without begin()!");
+ RASSERT(m_renderData.pMonitor, "Tried to render rect without begin()!");
TRACY_GPU_ZONE("RenderBorder2");
@@ -2252,7 +2111,7 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& gr
if (data.borderSize < 1)
return;
- int scaledBorderSize = std::round(data.borderSize * g_pHyprRenderer->m_renderData.pMonitor->m_scale);
+ int scaledBorderSize = std::round(data.borderSize * m_renderData.pMonitor->m_scale);
scaledBorderSize = std::round(scaledBorderSize * g_pHyprRenderer->m_renderData.renderModif.combinedScale());
// adjust box
@@ -2289,8 +2148,8 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& gr
shader->setUniformFloat(SHADER_GRADIENT_LERP, lerp);
CBox transformedBox = newBox;
- transformedBox.transform(Math::wlTransformToHyprutils(Math::invertTransform(g_pHyprRenderer->m_renderData.pMonitor->m_transform)),
- g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.x, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.y);
+ transformedBox.transform(Math::wlTransformToHyprutils(Math::invertTransform(m_renderData.pMonitor->m_transform)), m_renderData.pMonitor->m_transformedSize.x,
+ m_renderData.pMonitor->m_transformedSize.y);
const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y);
const auto FULLSIZE = Vector2D(transformedBox.width, transformedBox.height);
@@ -2325,7 +2184,8 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& gr
}
void CHyprOpenGLImpl::renderRoundedShadow(const CBox& box, int round, float roundingPower, int range, const CHyprColor& color, float a) {
- RASSERT(g_pHyprRenderer->m_renderData.pMonitor, "Tried to render shadow without begin()!");
+ auto& m_renderData = g_pHyprRenderer->m_renderData;
+ RASSERT(m_renderData.pMonitor, "Tried to render shadow without begin()!");
RASSERT((box.width > 0 && box.height > 0), "Tried to render shadow with width/height < 0!");
if (g_pHyprRenderer->m_renderData.damage.empty())
@@ -2392,13 +2252,10 @@ void CHyprOpenGLImpl::renderRoundedShadow(const CBox& box, int round, float roun
}
void CHyprOpenGLImpl::saveBufferForMirror(const CBox& box) {
- if (!g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB)
- g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB = g_pHyprRenderer->createFB();
-
+ auto& m_renderData = g_pHyprRenderer->m_renderData;
if (!g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB->isAllocated())
- g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB->alloc(g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.x,
- g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.y,
- g_pHyprRenderer->m_renderData.pMonitor->m_output->state->state().drmFormat);
+ g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB->alloc(m_renderData.pMonitor->m_pixelSize.x, m_renderData.pMonitor->m_pixelSize.y,
+ m_renderData.pMonitor->m_output->state->state().drmFormat);
g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB->bind();
@@ -2419,94 +2276,6 @@ void CHyprOpenGLImpl::saveBufferForMirror(const CBox& box) {
g_pHyprRenderer->m_renderData.currentFB->bind();
}
-void CHyprOpenGLImpl::renderMirrored() {
-
- auto monitor = g_pHyprRenderer->m_renderData.pMonitor;
- auto mirrored = monitor->m_mirrorOf;
-
- const double scale = std::min(monitor->m_transformedSize.x / mirrored->m_transformedSize.x, monitor->m_transformedSize.y / mirrored->m_transformedSize.y);
- CBox monbox = {0, 0, mirrored->m_transformedSize.x * scale, mirrored->m_transformedSize.y * scale};
-
- // transform box as it will be drawn on a transformed projection
- monbox.transform(Math::wlTransformToHyprutils(mirrored->m_transform), mirrored->m_transformedSize.x * scale, mirrored->m_transformedSize.y * scale);
-
- monbox.x = (monitor->m_transformedSize.x - monbox.w) / 2;
- monbox.y = (monitor->m_transformedSize.y - monbox.h) / 2;
-
- auto PFB = mirrored->m_monitorMirrorFB;
- if (!PFB->isAllocated() || !PFB->getTexture())
- return;
-
- g_pHyprRenderer->m_renderPass.add(makeUnique<CClearPassElement>(CClearPassElement::SClearData{CHyprColor(0, 0, 0, 0)}));
-
- CTexPassElement::SRenderData data;
- data.tex = PFB->getTexture();
- data.box = monbox;
- data.useMirrorProjection = true;
-
- g_pHyprRenderer->m_renderPass.add(makeUnique<CTexPassElement>(std::move(data)));
-}
-
-void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const CAIROSURFACE, double offsetY, const Vector2D& size) {
- static auto PSPLASHCOLOR = CConfigValue<Hyprlang::INT>("misc:col.splash");
- static auto PSPLASHFONT = CConfigValue<std::string>("misc:splash_font_family");
- static auto FALLBACKFONT = CConfigValue<std::string>("misc:font_family");
-
- const auto FONTFAMILY = *PSPLASHFONT != STRVAL_EMPTY ? *PSPLASHFONT : *FALLBACKFONT;
- const auto FONTSIZE = sc<int>(size.y / 76);
- const auto COLOR = CHyprColor(*PSPLASHCOLOR);
-
- PangoLayout* layoutText = pango_cairo_create_layout(CAIRO);
- PangoFontDescription* pangoFD = pango_font_description_new();
-
- pango_font_description_set_family_static(pangoFD, FONTFAMILY.c_str());
- pango_font_description_set_absolute_size(pangoFD, FONTSIZE * PANGO_SCALE);
- pango_font_description_set_style(pangoFD, PANGO_STYLE_NORMAL);
- pango_font_description_set_weight(pangoFD, PANGO_WEIGHT_NORMAL);
- pango_layout_set_font_description(layoutText, pangoFD);
-
- cairo_set_source_rgba(CAIRO, COLOR.r, COLOR.g, COLOR.b, COLOR.a);
-
- int textW = 0, textH = 0;
- pango_layout_set_text(layoutText, g_pCompositor->m_currentSplash.c_str(), -1);
- pango_layout_get_size(layoutText, &textW, &textH);
- textW /= PANGO_SCALE;
- textH /= PANGO_SCALE;
-
- cairo_move_to(CAIRO, (size.x - textW) / 2.0, size.y - textH - offsetY);
- pango_cairo_show_layout(CAIRO, layoutText);
-
- pango_font_description_free(pangoFD);
- g_object_unref(layoutText);
-
- cairo_surface_flush(CAIROSURFACE);
-}
-
-SP<ITexture> CHyprOpenGLImpl::texFromCairo(cairo_surface_t* cairo) {
- const auto CAIROFORMAT = cairo_image_surface_get_format(cairo);
- auto tex = makeShared<CGLTexture>();
-
- 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;
-}
-
WP<CShader> CHyprOpenGLImpl::useShader(WP<CShader> prog) {
if (m_currentProgram == prog->program())
return prog;
@@ -2517,140 +2286,6 @@ WP<CShader> CHyprOpenGLImpl::useShader(WP<CShader> prog) {
return prog;
}
-void CHyprOpenGLImpl::createBGTextureForMonitor(PHLMONITOR pMonitor) {
- RASSERT(g_pHyprRenderer->m_renderData.pMonitor, "Tried to createBGTex without begin()!");
-
- Log::logger->log(Log::DEBUG, "Creating a texture for BGTex");
-
- static auto PRENDERTEX = CConfigValue<Hyprlang::INT>("misc:disable_hyprland_logo");
- static auto PNOSPLASH = CConfigValue<Hyprlang::INT>("misc:disable_splash_rendering");
-
- if (*PRENDERTEX || g_pHyprRenderer->m_backgroundResourceFailed)
- return;
-
- if (!g_pHyprRenderer->m_backgroundResource) {
- // queue the asset to be created
- g_pHyprRenderer->requestBackgroundResource();
- return;
- }
-
- if (!g_pHyprRenderer->m_backgroundResource->m_ready)
- return;
-
- if (!m_monitorBGFBs.contains(pMonitor))
- m_monitorBGFBs[pMonitor] = g_pHyprRenderer->createFB();
-
- // release the last tex if exists
- 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<ITexture> tex = makeShared<CGLTexture>();
-
- 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);
-
- cairo_set_antialias(CAIRO, CAIRO_ANTIALIAS_GOOD);
- cairo_save(CAIRO);
- cairo_set_source_rgba(CAIRO, 0, 0, 0, 0);
- cairo_set_operator(CAIRO, CAIRO_OPERATOR_SOURCE);
- cairo_paint(CAIRO);
- cairo_restore(CAIRO);
-
- if (!*PNOSPLASH)
- renderSplash(CAIRO, CAIROSURFACE, 0.02 * pMonitor->m_pixelSize.y, pMonitor->m_pixelSize);
-
- cairo_surface_flush(CAIROSURFACE);
-
- tex->m_size = pMonitor->m_pixelSize;
-
- // copy the data to an OpenGL texture we have
- const GLint glFormat = GL_RGBA;
- const GLint glType = GL_UNSIGNED_BYTE;
-
- const auto DATA = cairo_image_surface_get_data(CAIROSURFACE);
- 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);
-
- cairo_surface_destroy(CAIROSURFACE);
- cairo_destroy(CAIRO);
-
- // render the texture to our fb
- PFB->bind();
- CRegion fakeDamage{0, 0, INT16_MAX, INT16_MAX};
-
- blend(true);
- clear(CHyprColor{0, 0, 0, 1});
-
- SP<ITexture> backgroundTexture = texFromCairo(g_pHyprRenderer->m_backgroundResource->m_asset.cairoSurface->cairo());
-
- // first render the background
- if (backgroundTexture) {
- const double MONRATIO = g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.x / g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.y;
- const double WPRATIO = backgroundTexture->m_size.x / backgroundTexture->m_size.y;
- Vector2D origin;
- double scale = 1.0;
-
- if (MONRATIO > WPRATIO) {
- scale = g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.x / backgroundTexture->m_size.x;
- origin.y = (g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.y - backgroundTexture->m_size.y * scale) / 2.0;
- } else {
- scale = g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.y / backgroundTexture->m_size.y;
- origin.x = (g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.x - backgroundTexture->m_size.x * scale) / 2.0;
- }
-
- CBox texbox = CBox{origin, backgroundTexture->m_size * scale};
- renderTextureInternal(backgroundTexture, texbox, {.damage = &fakeDamage, .a = 1.0});
- }
-
- CBox monbox = {{}, pMonitor->m_pixelSize};
- renderTextureInternal(tex, monbox, {.damage = &fakeDamage, .a = 1.0});
-
- // bind back
- if (g_pHyprRenderer->m_renderData.currentFB)
- g_pHyprRenderer->m_renderData.currentFB->bind();
-
- Log::logger->log(Log::DEBUG, "Background created for monitor {}", pMonitor->m_name);
-
- // clear the resource after we're done using it
- g_pEventLoopManager->doLater([] { g_pHyprRenderer->m_backgroundResource.reset(); });
-
- // set the animation to start for fading this background in nicely
- pMonitor->m_backgroundOpacity->setValueAndWarp(0.F);
- *pMonitor->m_backgroundOpacity = 1.F;
-}
-
-void CHyprOpenGLImpl::clearWithTex() {
- RASSERT(g_pHyprRenderer->m_renderData.pMonitor, "Tried to render BGtex without begin()!");
-
- static auto PBACKGROUNDCOLOR = CConfigValue<Hyprlang::INT>("misc:background_color");
-
- auto TEXIT = m_monitorBGFBs.find(g_pHyprRenderer->m_renderData.pMonitor);
-
- if (TEXIT == m_monitorBGFBs.end()) {
- createBGTextureForMonitor(g_pHyprRenderer->m_renderData.pMonitor.lock());
- g_pHyprRenderer->m_renderPass.add(makeUnique<CClearPassElement>(CClearPassElement::SClearData{CHyprColor(*PBACKGROUNDCOLOR)}));
- }
-
- if (TEXIT != m_monitorBGFBs.end()) {
- CTexPassElement::SRenderData data;
- data.box = {0, 0, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.x, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.y};
- data.a = g_pHyprRenderer->m_renderData.pMonitor->m_backgroundOpacity->value();
- data.flipEndFrame = true;
- data.tex = TEXIT->second->getTexture();
- g_pHyprRenderer->m_renderPass.add(makeUnique<CTexPassElement>(std::move(data)));
- }
-}
-
void CHyprOpenGLImpl::destroyMonitorResources(PHLMONITORREF pMonitor) {
makeEGLCurrent();
@@ -2667,35 +2302,11 @@ void CHyprOpenGLImpl::destroyMonitorResources(PHLMONITORREF pMonitor) {
Log::logger->log(Log::DEBUG, "Monitor {} -> destroyed all render data", pMonitor->m_name);
}
-void CHyprOpenGLImpl::bindOffMain() {
- if (!g_pHyprRenderer->m_renderData.pMonitor->m_offMainFB)
- g_pHyprRenderer->m_renderData.pMonitor->m_offMainFB = g_pHyprRenderer->createFB();
-
- if (!g_pHyprRenderer->m_renderData.pMonitor->m_offMainFB->isAllocated()) {
- g_pHyprRenderer->m_renderData.pMonitor->m_offMainFB->addStencil(g_pHyprRenderer->m_renderData.pMonitor->m_stencilTex);
- g_pHyprRenderer->m_renderData.pMonitor->m_offMainFB->alloc(g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.x, g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.y,
- g_pHyprRenderer->m_renderData.pMonitor->m_output->state->state().drmFormat);
- }
-
- g_pHyprRenderer->m_renderData.pMonitor->m_offMainFB->bind();
- clear(CHyprColor(0, 0, 0, 0));
- g_pHyprRenderer->m_renderData.currentFB = g_pHyprRenderer->m_renderData.pMonitor->m_offMainFB;
-}
-
-void CHyprOpenGLImpl::renderOffToMain(CGLFramebuffer* off) {
+void CHyprOpenGLImpl::renderOffToMain(IFramebuffer* off) {
CBox monbox = {0, 0, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.x, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.y};
renderTexturePrimitive(off->getTexture(), monbox);
}
-void CHyprOpenGLImpl::bindBackOnMain() {
- g_pHyprRenderer->m_renderData.mainFB->bind();
- g_pHyprRenderer->m_renderData.currentFB = g_pHyprRenderer->m_renderData.mainFB;
-}
-
-void CHyprOpenGLImpl::setRenderModifEnabled(bool enabled) {
- g_pHyprRenderer->m_renderData.renderModif.enabled = enabled;
-}
-
void CHyprOpenGLImpl::setViewport(GLint x, GLint y, GLsizei width, GLsizei height) {
if (m_lastViewport.x == x && m_lastViewport.y == y && m_lastViewport.width == width && m_lastViewport.height == height)
return;
diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp
index b11c1efb..51c89e1e 100644
--- a/src/render/OpenGL.hpp
+++ b/src/render/OpenGL.hpp
@@ -35,7 +35,7 @@
#include "render/ShaderLoader.hpp"
#include "render/gl/GLFramebuffer.hpp"
#include "render/gl/GLRenderbuffer.hpp"
-#include "render/gl/GLTexture.hpp"
+#include "render/pass/TexPassElement.hpp"
#define GLFB(ifb) dc<CGLFramebuffer*>(ifb.get())
@@ -56,11 +56,6 @@ constexpr std::array<SVertex, 4> fullVerts = {{
inline const float fanVertsFull[] = {-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f};
-enum eDiscardMode : uint8_t {
- DISCARD_OPAQUE = 1,
- DISCARD_ALPHA = 1 << 1
-};
-
struct SRenderModifData {
enum eRenderModifType : uint8_t {
RMOD_TYPE_SCALE, /* scale by a float */
@@ -186,24 +181,33 @@ class CHyprOpenGLImpl {
};
struct STextureRenderData {
- const CRegion* damage = nullptr;
- SP<CWLSurfaceResource> surface = nullptr;
- float a = 1.F;
- bool blur = false;
+ bool blur = false;
float blurA = 1.F, overallA = 1.F;
- int round = 0;
- float roundingPower = 2.F;
- bool discardActive = false;
- bool allowCustomUV = false;
- bool allowDim = true;
- bool noAA = false;
bool blockBlurOptimization = false;
+ SP<ITexture> blurredBG;
+
+ const CRegion* damage = nullptr;
+ SP<CWLSurfaceResource> surface = nullptr;
+ float a = 1.F;
+ int round = 0;
+ float roundingPower = 2.F;
+ bool discardActive = false;
+ bool allowCustomUV = false;
+ bool allowDim = true;
+ bool noAA = false; // unused
GLenum wrapX = GL_CLAMP_TO_EDGE, wrapY = GL_CLAMP_TO_EDGE;
bool cmBackToSRGB = false;
- bool noCM = false;
bool finalMonitorCM = false;
SP<CMonitor> cmBackToSRGBSource;
- SP<ITexture> blurredBG;
+
+ uint32_t discardMode = DISCARD_OPAQUE;
+ float discardOpacity = 0.f;
+
+ CRegion clipRegion;
+ PHLLSREF currentLS;
+
+ Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1);
+ Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
};
struct SBorderRenderData {
@@ -227,37 +231,25 @@ class CHyprOpenGLImpl {
void renderTextureMatte(SP<ITexture> tex, const CBox& pBox, SP<IFramebuffer> matte);
void renderTexturePrimitive(SP<ITexture> tex, const CBox& box);
- void setRenderModifEnabled(bool enabled);
void setViewport(GLint x, GLint y, GLsizei width, GLsizei height);
void setCapStatus(int cap, bool status);
void blend(bool enabled);
void clear(const CHyprColor&);
- void clearWithTex();
void scissor(const CBox&, bool transform = true);
void scissor(const pixman_box32*, bool transform = true);
void scissor(const int x, const int y, const int w, const int h, bool transform = true);
void destroyMonitorResources(PHLMONITORREF);
- void preWindowPass();
- bool preBlurQueued();
void preRender(PHLMONITOR);
void saveBufferForMirror(const CBox&);
- void renderMirrored();
void applyScreenShader(const std::string& path);
- void bindOffMain();
- void renderOffToMain(CGLFramebuffer* off);
- void bindBackOnMain();
-
- SP<ITexture> texFromCairo(cairo_surface_t* cairo);
-
- bool needsACopyFB(PHLMONITOR mon);
- void setDamage(const CRegion& damage, std::optional<CRegion> finalDamage = {});
+ void renderOffToMain(IFramebuffer* off);
std::vector<SDRMFormat> getDRMFormats();
std::vector<uint64_t> getDRMFormatModifiers(DRMFormat format);
@@ -350,7 +342,6 @@ class CHyprOpenGLImpl {
SP<CShader> m_finalScreenShader;
GLuint m_currentProgram;
- void createBGTextureForMonitor(PHLMONITOR);
void initDRMFormats();
void initEGL(bool gbm);
EGLDeviceEXT eglDeviceFromDRMFD(int drmFD);
@@ -365,13 +356,11 @@ class CHyprOpenGLImpl {
std::optional<std::vector<uint64_t>> getModsForFormat(EGLint format);
// returns the out FB, can be either Mirror or MirrorSwap
- SP<IFramebuffer> blurMainFramebufferWithDamage(float a, CRegion* damage);
SP<IFramebuffer> blurFramebufferWithDamage(float a, CRegion* damage, CGLFramebuffer& source);
void passCMUniforms(WP<CShader>, const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1);
void passCMUniforms(WP<CShader>, const NColorManagement::PImageDescription imageDescription);
- void 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);
@@ -380,9 +369,8 @@ class CHyprOpenGLImpl {
void renderTextureInternal(SP<ITexture>, const CBox&, const STextureRenderData& data);
void renderTextureWithBlurInternal(SP<ITexture>, const CBox&, const STextureRenderData& data);
- void preBlurForCurrentMonitor();
-
- friend class CHyprRenderer;
+ friend class IHyprRenderer;
+ friend class CHyprGLRenderer;
friend class CTexPassElement;
friend class CPreBlurElement;
friend class CSurfacePassElement;
diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp
index 8dc2d82c..9872b83e 100644
--- a/src/render/Renderer.cpp
+++ b/src/render/Renderer.cpp
@@ -36,6 +36,7 @@
#include "helpers/MainLoopExecutor.hpp"
#include "helpers/Monitor.hpp"
#include "macros.hpp"
+#include "../managers/screenshare/ScreenshareManager.hpp"
#include "pass/TexPassElement.hpp"
#include "pass/ClearPassElement.hpp"
#include "pass/RectPassElement.hpp"
@@ -49,9 +50,8 @@
#include "render/Framebuffer.hpp"
#include "render/OpenGL.hpp"
#include "render/Texture.hpp"
-#include "render/decorations/CHyprDropShadowDecoration.hpp"
-#include "render/gl/GLFramebuffer.hpp"
-#include "render/gl/GLTexture.hpp"
+#include "render/pass/BorderPassElement.hpp"
+#include "render/pass/PreBlurElement.hpp"
#include <hyprutils/math/Mat3x3.hpp>
#include <hyprutils/math/Region.hpp>
#include <hyprutils/math/Vector2D.hpp>
@@ -76,10 +76,9 @@ static int cursorTicker(void* data) {
return 0;
}
-CHyprRenderer::CHyprRenderer() {
+IHyprRenderer::IHyprRenderer() {
m_globalTimer.reset();
pushMonitorTransformEnabled(false);
- initAssets();
if (g_pCompositor->m_aqBackend->hasSession()) {
size_t drmDevices = 0;
@@ -208,16 +207,16 @@ CHyprRenderer::CHyprRenderer() {
g_pEventLoopManager->addTimer(m_renderUnfocusedTimer);
}
-CHyprRenderer::~CHyprRenderer() {
+IHyprRenderer::~IHyprRenderer() {
if (m_cursorTicker)
wl_event_source_remove(m_cursorTicker);
}
-WP<CHyprOpenGLImpl> CHyprRenderer::glBackend() {
+WP<CHyprOpenGLImpl> IHyprRenderer::glBackend() {
return g_pHyprOpenGL;
}
-bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor) {
+bool IHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor) {
if (!pWindow->visibleOnMonitor(pMonitor))
return false;
@@ -283,7 +282,7 @@ bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor) {
return false;
}
-bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow) {
+bool IHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow) {
if (!validMapped(pWindow))
return false;
@@ -310,7 +309,7 @@ bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow) {
return false;
}
-void CHyprRenderer::renderWorkspaceWindowsFullscreen(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& time) {
+void IHyprRenderer::renderWorkspaceWindowsFullscreen(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& time) {
PHLWINDOW pWorkspaceWindow = nullptr;
Event::bus()->m_events.render.stage.emit(RENDER_PRE_WINDOWS);
@@ -401,7 +400,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(PHLMONITOR pMonitor, PHLWOR
}
}
-void CHyprRenderer::renderWorkspaceWindows(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& time) {
+void IHyprRenderer::renderWorkspaceWindows(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& time) {
PHLWINDOW lastWindow;
Event::bus()->m_events.render.stage.emit(RENDER_PRE_WINDOWS);
@@ -499,7 +498,20 @@ void CHyprRenderer::renderWorkspaceWindows(PHLMONITOR pMonitor, PHLWORKSPACE pWo
}
}
-void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, const Time::steady_tp& time, bool decorate, eRenderPassMode mode, bool ignorePosition, bool standalone) {
+void IHyprRenderer::bindOffMain() {
+ RASSERT(m_renderData.pMonitor->m_offMainFB->isAllocated(), "IHyprRenderer::beginRender should allocate monitor FBs")
+
+ m_renderData.pMonitor->m_offMainFB->bind();
+ draw(makeUnique<CClearPassElement>(CClearPassElement::SClearData{{0, 0, 0, 0}}), {});
+ m_renderData.currentFB = m_renderData.pMonitor->m_offMainFB;
+}
+
+void IHyprRenderer::bindBackOnMain() {
+ m_renderData.mainFB->bind();
+ m_renderData.currentFB = m_renderData.mainFB;
+}
+
+void IHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, const Time::steady_tp& time, bool decorate, eRenderPassMode mode, bool ignorePosition, bool standalone) {
if (pWindow->isHidden() && !standalone)
return;
@@ -596,7 +608,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, const T
const bool TRANSFORMERSPRESENT = !pWindow->m_transformers.empty();
if (TRANSFORMERSPRESENT) {
- g_pHyprOpenGL->bindOffMain();
+ bindOffMain();
for (auto const& t : pWindow->m_transformers) {
t->preWindowRender(&renderdata);
@@ -672,8 +684,8 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, const T
last = t->transform(last);
}
- g_pHyprOpenGL->bindBackOnMain();
- g_pHyprOpenGL->renderOffToMain(dc<CGLFramebuffer*>(last));
+ bindBackOnMain();
+ renderOffToMain(last);
}
}
@@ -757,134 +769,68 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, const T
m_renderData.currentWindow.reset();
}
-void CHyprRenderer::draw(WP<IPassElement> element, const CRegion& damage) {
- if (!element)
- return;
+void IHyprRenderer::drawRect(CRectPassElement* element, const CRegion& damage) {
+ auto& data = element->m_data;
- switch (element->type()) {
- case EK_BORDER: draw(dc<CBorderPassElement*>(element.get()), damage); break;
- case EK_CLEAR: draw(dc<CClearPassElement*>(element.get()), damage); break;
- case EK_FRAMEBUFFER: draw(dc<CFramebufferElement*>(element.get()), damage); break;
- case EK_PRE_BLUR: draw(dc<CPreBlurElement*>(element.get()), damage); break;
- case EK_RECT: draw(dc<CRectPassElement*>(element.get()), damage); break;
- case EK_HINTS: draw(dc<CRendererHintsPassElement*>(element.get()), damage); break;
- case EK_SHADOW: draw(dc<CShadowPassElement*>(element.get()), damage); break;
- case EK_SURFACE: draw(dc<CSurfacePassElement*>(element.get()), damage); break;
- case EK_TEXTURE: draw(dc<CTexPassElement*>(element.get()), damage); break;
- case EK_TEXTURE_MATTE: draw(dc<CTextureMatteElement*>(element.get()), damage); break;
- default: Log::logger->log(Log::WARN, "Unimplimented draw for {}", element->passName());
- }
-}
-
-void CHyprRenderer::draw(CBorderPassElement* element, const CRegion& damage) {
- const auto& m_data = element->m_data;
- if (m_data.hasGrad2)
- g_pHyprOpenGL->renderBorder(
- m_data.box, m_data.grad1, m_data.grad2, m_data.lerp,
- {.round = m_data.round, .roundingPower = m_data.roundingPower, .borderSize = m_data.borderSize, .a = m_data.a, .outerRound = m_data.outerRound});
- else
- g_pHyprOpenGL->renderBorder(
- m_data.box, m_data.grad1,
- {.round = m_data.round, .roundingPower = m_data.roundingPower, .borderSize = m_data.borderSize, .a = m_data.a, .outerRound = m_data.outerRound});
-}
+ if (data.box.w <= 0 || data.box.h <= 0)
+ return;
-void CHyprRenderer::draw(CClearPassElement* element, const CRegion& damage) {
- const auto& m_data = element->m_data;
- g_pHyprOpenGL->clear(m_data.color);
-};
+ if (!data.clipBox.empty())
+ m_renderData.clipBox = data.clipBox;
-void CHyprRenderer::draw(CFramebufferElement* element, const CRegion& damage) {
- const auto& m_data = element->m_data;
- SP<IFramebuffer> fb = nullptr;
+ data.modifiedBox = data.box;
+ m_renderData.renderModif.applyToBox(data.modifiedBox);
- if (m_data.main) {
- switch (m_data.framebufferID) {
- case FB_MONITOR_RENDER_MAIN: fb = m_renderData.mainFB; break;
- case FB_MONITOR_RENDER_CURRENT: fb = m_renderData.currentFB; break;
- case FB_MONITOR_RENDER_OUT: fb = m_renderData.outFB; break;
- }
+ CBox transformedBox = data.box;
+ transformedBox.transform(Math::wlTransformToHyprutils(Math::invertTransform(m_renderData.pMonitor->m_transform)), m_renderData.pMonitor->m_transformedSize.x,
+ m_renderData.pMonitor->m_transformedSize.y);
- if (!fb) {
- Log::logger->log(Log::ERR, "BUG THIS: CFramebufferElement::draw: main but null");
- return;
- }
+ data.TOPLEFT[0] = sc<float>(transformedBox.x);
+ data.TOPLEFT[1] = sc<float>(transformedBox.y);
+ data.FULLSIZE[0] = sc<float>(transformedBox.width);
+ data.FULLSIZE[1] = sc<float>(transformedBox.height);
- } else {
- switch (m_data.framebufferID) {
- case FB_MONITOR_RENDER_EXTRA_OFFLOAD: fb = m_renderData.pMonitor->m_offloadFB; break;
- case FB_MONITOR_RENDER_EXTRA_MIRROR: fb = m_renderData.pMonitor->m_mirrorFB; break;
- case FB_MONITOR_RENDER_EXTRA_MIRROR_SWAP: fb = m_renderData.pMonitor->m_mirrorSwapFB; break;
- case FB_MONITOR_RENDER_EXTRA_OFF_MAIN: fb = m_renderData.pMonitor->m_offMainFB; break;
- case FB_MONITOR_RENDER_EXTRA_MONITOR_MIRROR: fb = m_renderData.pMonitor->m_monitorMirrorFB; break;
- case FB_MONITOR_RENDER_EXTRA_BLUR: fb = m_renderData.pMonitor->m_blurFB; break;
- }
+ data.drawRegion = data.color.a == 1.F || !data.blur ? damage : m_renderData.damage;
- if (!fb) {
- Log::logger->log(Log::ERR, "BUG THIS: CFramebufferElement::draw: not main but null");
- return;
- }
+ if (m_renderData.clipBox.width != 0 && m_renderData.clipBox.height != 0) {
+ CRegion damageClip{m_renderData.clipBox.x, m_renderData.clipBox.y, m_renderData.clipBox.width, m_renderData.clipBox.height};
+ data.drawRegion = damageClip.intersect(data.drawRegion);
}
- fb->bind();
-};
+ draw(element, damage);
-void CHyprRenderer::draw(CPreBlurElement* element, const CRegion& damage) {
- g_pHyprOpenGL->preBlurForCurrentMonitor();
-};
+ m_renderData.clipBox = {};
+}
-void CHyprRenderer::draw(CRectPassElement* element, const CRegion& damage) {
- const auto& m_data = element->m_data;
- if (m_data.box.w <= 0 || m_data.box.h <= 0)
- return;
+void IHyprRenderer::drawHints(CRendererHintsPassElement* element, const CRegion& damage) {
+ const auto m_data = element->m_data;
+ if (m_data.renderModif.has_value())
+ m_renderData.renderModif = *m_data.renderModif;
+}
- if (!m_data.clipBox.empty())
- m_renderData.clipBox = m_data.clipBox;
+void IHyprRenderer::drawPreBlur(CPreBlurElement* element, const CRegion& damage) {
+ TRACY_GPU_ZONE("RenderPreBlurForCurrentMonitor");
- if (m_data.color.a == 1.F || !m_data.blur)
- g_pHyprOpenGL->renderRect(m_data.box, m_data.color, {.damage = &damage, .round = m_data.round, .roundingPower = m_data.roundingPower});
- else
- g_pHyprOpenGL->renderRect(m_data.box, m_data.color,
- {.round = m_data.round, .roundingPower = m_data.roundingPower, .blur = true, .blurA = m_data.blurA, .xray = m_data.xray});
+ const auto SAVEDRENDERMODIF = m_renderData.renderModif;
+ m_renderData.renderModif = {}; // fix shit
- m_renderData.clipBox = {};
-};
+ // make the fake dmg
+ CRegion fakeDamage{0, 0, m_renderData.pMonitor->m_transformedSize.x, m_renderData.pMonitor->m_transformedSize.y};
-void CHyprRenderer::draw(CRendererHintsPassElement* element, const CRegion& damage) {
- const auto& m_data = element->m_data;
- if (m_data.renderModif.has_value())
- m_renderData.renderModif = *m_data.renderModif;
-};
+ draw(element, fakeDamage);
-void CHyprRenderer::draw(CShadowPassElement* element, const CRegion& damage) {
- const auto& m_data = element->m_data;
- m_data.deco->render(m_renderData.pMonitor.lock(), m_data.a);
-};
+ m_renderData.pMonitor->m_blurFBDirty = false;
+ m_renderData.pMonitor->m_blurFBShouldRender = false;
-void CHyprRenderer::draw(CSurfacePassElement* element, const CRegion& damage) {
- const auto& m_data = element->m_data;
+ m_renderData.renderModif = SAVEDRENDERMODIF;
+}
- m_renderData.currentWindow = m_data.pWindow;
- m_renderData.surface = m_data.surface;
- m_renderData.currentLS = m_data.pLS;
- m_renderData.clipBox = m_data.clipBox;
- m_renderData.discardMode = m_data.discardMode;
- m_renderData.discardOpacity = m_data.discardOpacity;
- m_renderData.useNearestNeighbor = m_data.useNearestNeighbor;
- pushMonitorTransformEnabled(m_data.flipEndFrame);
+void IHyprRenderer::drawSurface(CSurfacePassElement* element, const CRegion& damage) {
+ const auto m_data = element->m_data;
- CScopeGuard x = {[&]() {
- m_renderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
- m_renderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
- m_renderData.useNearestNeighbor = false;
- m_renderData.clipBox = {};
- m_renderData.clipRegion = {};
- m_renderData.discardMode = 0;
- m_renderData.discardOpacity = 0;
- m_renderData.useNearestNeighbor = false;
- g_pHyprRenderer->popMonitorTransformEnabled();
- m_renderData.currentWindow.reset();
- m_renderData.surface.reset();
- m_renderData.currentLS.reset();
+ CScopeGuard x = {[]() {
+ g_pHyprRenderer->m_renderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
+ g_pHyprRenderer->m_renderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
}};
if (!m_data.texture)
@@ -926,8 +872,8 @@ void CHyprRenderer::draw(CSurfacePassElement* element, const CRegion& damage) {
calculateUVForSurface(m_data.pWindow, m_data.surface, m_data.pMonitor->m_self.lock(), m_data.mainSurface, windowBox.size(), PROJSIZEUNSCALED, MISALIGNEDFSV1);
- auto cancelRender = false;
- m_renderData.clipRegion = element->visibleRegion(cancelRender);
+ auto cancelRender = false;
+ auto clipRegion = element->visibleRegion(cancelRender);
if (cancelRender)
return;
@@ -952,129 +898,244 @@ void CHyprRenderer::draw(CSurfacePassElement* element, const CRegion& damage) {
const bool CANDISABLEBLEND = ALPHA >= 1.f && OVERALL_ALPHA >= 1.f && rounding <= 0 && WINDOWOPAQUE;
if (CANDISABLEBLEND)
- g_pHyprOpenGL->blend(false);
+ blend(false);
else
- g_pHyprOpenGL->blend(true);
+ blend(true);
// FIXME: This is wrong and will bug the blur out as shit if the first surface
// is a subsurface that does NOT cover the entire frame. In such cases, we probably should fall back
// to what we do for misaligned surfaces (blur the entire thing and then render shit without blur)
if (m_data.surfaceCounter == 0 && !m_data.popup) {
if (BLUR)
- g_pHyprOpenGL->renderTexture(TEXTURE, windowBox,
- {
- .surface = m_data.surface,
- .a = ALPHA,
- .blur = true,
- .blurA = m_data.fadeAlpha,
- .overallA = OVERALL_ALPHA,
- .round = rounding,
- .roundingPower = roundingPower,
- .allowCustomUV = true,
- .blockBlurOptimization = m_data.blockBlurOptimization,
- });
+ draw(makeUnique<CTexPassElement>(CTexPassElement::SRenderData{
+ .tex = TEXTURE,
+ .box = windowBox,
+ .a = ALPHA,
+ .blurA = m_data.fadeAlpha,
+ .overallA = OVERALL_ALPHA,
+ .round = rounding,
+ .roundingPower = roundingPower,
+ .blur = true,
+ .blockBlurOptimization = m_data.blockBlurOptimization,
+ .allowCustomUV = true,
+ .surface = m_data.surface,
+ .discardMode = m_data.discardMode,
+ .discardOpacity = m_data.discardOpacity,
+ .clipRegion = clipRegion,
+ .currentLS = m_data.pLS,
+ }),
+ m_renderData.damage.copy().intersect(windowBox));
else
- g_pHyprOpenGL->renderTexture(TEXTURE, windowBox,
- {.a = ALPHA * OVERALL_ALPHA, .round = rounding, .roundingPower = roundingPower, .discardActive = false, .allowCustomUV = true});
+ draw(makeUnique<CTexPassElement>(CTexPassElement::SRenderData{
+ .tex = TEXTURE,
+ .box = windowBox,
+ .a = ALPHA * OVERALL_ALPHA,
+ .round = rounding,
+ .roundingPower = roundingPower,
+ .discardActive = false,
+ .allowCustomUV = true,
+ .surface = m_data.surface,
+ .discardMode = m_data.discardMode,
+ .discardOpacity = m_data.discardOpacity,
+ .clipRegion = clipRegion,
+ .currentLS = m_data.pLS,
+ }),
+ m_renderData.damage.copy().intersect(windowBox));
} else {
if (BLUR && m_data.popup)
- g_pHyprOpenGL->renderTexture(TEXTURE, windowBox,
- {
- .surface = m_data.surface,
- .a = ALPHA,
- .blur = true,
- .blurA = m_data.fadeAlpha,
- .overallA = OVERALL_ALPHA,
- .round = rounding,
- .roundingPower = roundingPower,
- .allowCustomUV = true,
- .blockBlurOptimization = true,
- });
+ draw(makeUnique<CTexPassElement>(CTexPassElement::SRenderData{
+ .tex = TEXTURE,
+ .box = windowBox,
+ .a = ALPHA,
+ .blurA = m_data.fadeAlpha,
+ .overallA = OVERALL_ALPHA,
+ .round = rounding,
+ .roundingPower = roundingPower,
+ .blur = true,
+ .blockBlurOptimization = true,
+ .allowCustomUV = true,
+ .surface = m_data.surface,
+ .discardMode = m_data.discardMode,
+ .discardOpacity = m_data.discardOpacity,
+ .clipRegion = clipRegion,
+ .currentLS = m_data.pLS,
+ }),
+ m_renderData.damage.copy().intersect(windowBox));
else
- g_pHyprOpenGL->renderTexture(TEXTURE, windowBox,
- {.a = ALPHA * OVERALL_ALPHA, .round = rounding, .roundingPower = roundingPower, .discardActive = false, .allowCustomUV = true});
- }
+ draw(makeUnique<CTexPassElement>(CTexPassElement::SRenderData{
+ .tex = TEXTURE,
+ .box = windowBox,
+ .a = ALPHA * OVERALL_ALPHA,
+ .round = rounding,
+ .roundingPower = roundingPower,
+ .discardActive = false,
+ .allowCustomUV = true,
+ .surface = m_data.surface,
+ .discardMode = m_data.discardMode,
+ .discardOpacity = m_data.discardOpacity,
+ .clipRegion = clipRegion,
+ .currentLS = m_data.pLS,
+ }),
+ m_renderData.damage.copy().intersect(windowBox));
+ }
+
+ blend(true);
+};
- if (!g_pHyprRenderer->m_bBlockSurfaceFeedback)
- m_data.surface->presentFeedback(m_data.when, m_data.pMonitor->m_self.lock());
+void IHyprRenderer::preDrawSurface(CSurfacePassElement* element, const CRegion& damage) {
+ m_renderData.clipBox = element->m_data.clipBox;
+ m_renderData.useNearestNeighbor = element->m_data.useNearestNeighbor;
+ pushMonitorTransformEnabled(element->m_data.flipEndFrame);
+ m_renderData.currentWindow = element->m_data.pWindow;
+
+ drawSurface(element, damage);
+
+ if (!m_bBlockSurfaceFeedback)
+ element->m_data.surface->presentFeedback(element->m_data.when, element->m_data.pMonitor->m_self.lock());
// add async (dmabuf) buffers to usedBuffers so we can handle release later
// sync (shm) buffers will be released in commitState, so no need to track them here
- if (m_data.surface->m_current.buffer && !m_data.surface->m_current.buffer->isSynchronous())
- g_pHyprRenderer->m_usedAsyncBuffers.emplace_back(m_data.surface->m_current.buffer);
+ if (element->m_data.surface->m_current.buffer && !element->m_data.surface->m_current.buffer->isSynchronous())
+ m_usedAsyncBuffers.emplace_back(element->m_data.surface->m_current.buffer);
- g_pHyprOpenGL->blend(true);
-};
+ m_renderData.clipBox = {};
+ m_renderData.useNearestNeighbor = false;
+ popMonitorTransformEnabled();
+ m_renderData.currentWindow.reset();
+}
-void CHyprRenderer::draw(CTexPassElement* element, const CRegion& damage) {
- const auto& m_data = element->m_data;
- pushMonitorTransformEnabled(m_data.flipEndFrame);
+void IHyprRenderer::drawTex(CTexPassElement* element, const CRegion& damage) {
+ if (!element->m_data.clipBox.empty())
+ m_renderData.clipBox = element->m_data.clipBox;
- CScopeGuard x = {[&]() {
- //
+ pushMonitorTransformEnabled(element->m_data.flipEndFrame);
+ if (element->m_data.useMirrorProjection)
+ setProjectionType(RPT_MIRROR);
+
+ m_renderData.surface = element->m_data.surface;
+
+ CScopeGuard x = {[useMirrorProjection = element->m_data.useMirrorProjection]() {
g_pHyprRenderer->popMonitorTransformEnabled();
- m_renderData.clipBox = {};
- if (m_data.useMirrorProjection)
- setProjectionType(RPT_MONITOR);
- if (m_data.ignoreAlpha.has_value())
- m_renderData.discardMode = 0;
+ if (useMirrorProjection)
+ g_pHyprRenderer->setProjectionType(RPT_MONITOR);
+ g_pHyprRenderer->m_renderData.surface.reset();
}};
- if (!m_data.clipBox.empty())
- m_renderData.clipBox = m_data.clipBox;
+ if (element->m_data.blur) {
+ // make a damage region for this window
+ CRegion texDamage{m_renderData.damage};
+ texDamage.intersect(element->m_data.box.x, element->m_data.box.y, element->m_data.box.width, element->m_data.box.height);
- if (m_data.useMirrorProjection)
- setProjectionType(RPT_MIRROR);
+ // While renderTextureInternalWithDamage will clip the blur as well,
+ // clipping texDamage here allows blur generation to be optimized.
+ if (!element->m_data.clipRegion.empty())
+ texDamage.intersect(element->m_data.clipRegion);
- if (m_data.ignoreAlpha.has_value()) {
- m_renderData.discardMode = DISCARD_ALPHA;
- m_renderData.discardOpacity = *m_data.ignoreAlpha;
- }
-
- if (m_data.blur) {
- g_pHyprOpenGL->renderTexture(m_data.tex, m_data.box,
- {
- .a = m_data.a,
- .blur = true,
- .blurA = m_data.blurA,
- .overallA = 1.F,
- .round = m_data.round,
- .roundingPower = m_data.roundingPower,
- .blockBlurOptimization = m_data.blockBlurOptimization.value_or(false),
- });
- } else {
- g_pHyprOpenGL->renderTexture(m_data.tex, m_data.box,
- {.damage = m_data.damage.empty() ? &damage : &m_data.damage, .a = m_data.a, .round = m_data.round, .roundingPower = m_data.roundingPower});
- }
-};
+ if (texDamage.empty())
+ return;
+
+ m_renderData.renderModif.applyToRegion(texDamage);
+
+ element->m_data.damage = texDamage;
+
+ // amazing hack: the surface has an opaque region!
+ const auto& surface = element->m_data.surface;
+ const auto& box = element->m_data.box;
+ CRegion inverseOpaque;
+ if (element->m_data.a >= 1.f && surface && std::round(surface->m_current.size.x * m_renderData.pMonitor->m_scale) == box.w &&
+ std::round(surface->m_current.size.y * m_renderData.pMonitor->m_scale) == box.h) {
+ pixman_box32_t surfbox = {0, 0, surface->m_current.size.x * surface->m_current.scale, surface->m_current.size.y * surface->m_current.scale};
+ inverseOpaque = surface->m_current.opaque;
+ inverseOpaque.invert(&surfbox).intersect(0, 0, surface->m_current.size.x * surface->m_current.scale, surface->m_current.size.y * surface->m_current.scale);
+
+ if (inverseOpaque.empty()) {
+ element->m_data.blur = false;
+ draw(element, damage);
+ m_renderData.clipBox = {};
+ return;
+ }
+ } else
+ inverseOpaque = {0, 0, element->m_data.box.width, element->m_data.box.height};
+
+ inverseOpaque.scale(m_renderData.pMonitor->m_scale);
+ element->m_data.blockBlurOptimization =
+ element->m_data.blockBlurOptimization.value_or(false) || !shouldUseNewBlurOptimizations(element->m_data.currentLS.lock(), m_renderData.currentWindow.lock());
+
+ // vvv TODO: layered blur fbs?
+ if (element->m_data.blockBlurOptimization) {
+ inverseOpaque.translate(box.pos());
+ m_renderData.renderModif.applyToRegion(inverseOpaque);
+ inverseOpaque.intersect(element->m_data.damage);
+ element->m_data.blurredBG = blurMainFramebuffer(element->m_data.a, &inverseOpaque);
+ m_renderData.currentFB->bind();
+ } else
+ element->m_data.blurredBG = m_renderData.pMonitor->m_blurFB->getTexture();
+
+ draw(element, damage);
+ } else
+ draw(element, damage);
-void CHyprRenderer::draw(CTextureMatteElement* element, const CRegion& damage) {
- const auto& m_data = element->m_data;
+ m_renderData.clipBox = {};
+}
+
+void IHyprRenderer::drawTexMatte(CTextureMatteElement* element, const CRegion& damage) {
+ if (m_renderData.damage.empty())
+ return;
+
+ const auto m_data = element->m_data;
if (m_data.disableTransformAndModify) {
pushMonitorTransformEnabled(true);
- g_pHyprOpenGL->setRenderModifEnabled(false);
- g_pHyprOpenGL->renderTextureMatte(m_data.tex, m_data.box, m_data.fb);
- g_pHyprOpenGL->setRenderModifEnabled(true);
+ m_renderData.renderModif.enabled = false;
+ draw(element, damage);
+ m_renderData.renderModif.enabled = true;
popMonitorTransformEnabled();
} else
- g_pHyprOpenGL->renderTextureMatte(m_data.tex, m_data.box, m_data.fb);
-};
+ draw(element, damage);
+}
+
+void IHyprRenderer::draw(WP<IPassElement> element, const CRegion& damage) {
+ if (!element)
+ return;
-void CHyprRenderer::pushMonitorTransformEnabled(bool enabled) {
+ switch (element->type()) {
+ case EK_BORDER: draw(dc<CBorderPassElement*>(element.get()), damage); break;
+ case EK_CLEAR: draw(dc<CClearPassElement*>(element.get()), damage); break;
+ case EK_FRAMEBUFFER: draw(dc<CFramebufferElement*>(element.get()), damage); break;
+ case EK_PRE_BLUR: drawPreBlur(dc<CPreBlurElement*>(element.get()), damage); break;
+ case EK_RECT: drawRect(dc<CRectPassElement*>(element.get()), damage); break;
+ case EK_HINTS: drawHints(dc<CRendererHintsPassElement*>(element.get()), damage); break;
+ case EK_SHADOW: draw(dc<CShadowPassElement*>(element.get()), damage); break;
+ case EK_SURFACE: preDrawSurface(dc<CSurfacePassElement*>(element.get()), damage); break;
+ case EK_TEXTURE: drawTex(dc<CTexPassElement*>(element.get()), damage); break;
+ case EK_TEXTURE_MATTE: drawTexMatte(dc<CTextureMatteElement*>(element.get()), damage); break;
+ default: Log::logger->log(Log::WARN, "Unimplimented draw for {}", element->passName());
+ }
+}
+
+bool IHyprRenderer::preBlurQueued(PHLMONITORREF pMonitor) {
+ static auto PBLURNEWOPTIMIZE = CConfigValue<Hyprlang::INT>("decoration:blur:new_optimizations");
+ static auto PBLUR = CConfigValue<Hyprlang::INT>("decoration:blur:enabled");
+
+ if (!pMonitor)
+ return false;
+ return m_renderData.pMonitor->m_blurFBDirty && *PBLURNEWOPTIMIZE && *PBLUR && m_renderData.pMonitor->m_blurFBShouldRender;
+}
+
+void IHyprRenderer::pushMonitorTransformEnabled(bool enabled) {
m_monitorTransformStack.push(enabled);
m_monitorTransformEnabled = enabled;
}
-void CHyprRenderer::popMonitorTransformEnabled() {
+void IHyprRenderer::popMonitorTransformEnabled() {
m_monitorTransformStack.pop();
m_monitorTransformEnabled = m_monitorTransformStack.top();
}
-bool CHyprRenderer::monitorTransformEnabled() {
+bool IHyprRenderer::monitorTransformEnabled() {
return m_monitorTransformEnabled;
}
-SP<ITexture> CHyprRenderer::createTexture(const SP<Aquamarine::IBuffer> buffer, bool keepDataCopy) {
+SP<ITexture> IHyprRenderer::createTexture(const SP<Aquamarine::IBuffer> buffer, bool keepDataCopy) {
if (!buffer)
return createTexture();
@@ -1104,7 +1165,7 @@ SP<ITexture> CHyprRenderer::createTexture(const SP<Aquamarine::IBuffer> buffer,
return tex;
}
-void CHyprRenderer::renderLayer(PHLLS pLayer, PHLMONITOR pMonitor, const Time::steady_tp& time, bool popups, bool lockscreen) {
+void IHyprRenderer::renderLayer(PHLLS pLayer, PHLMONITOR pMonitor, const Time::steady_tp& time, bool popups, bool lockscreen) {
if (!pLayer)
return;
@@ -1117,7 +1178,7 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, PHLMONITOR pMonitor, const Time::s
if (*PDIMAROUND && pLayer->m_ruleApplicator->dimAround().valueOrDefault() && !m_bRenderingSnapshot && !popups) {
CRectPassElement::SRectData data;
- data.box = {0, 0, m_renderData.pMonitor->m_transformedSize.x, m_renderData.pMonitor->m_transformedSize.y};
+ data.box = {0, 0, pMonitor->m_transformedSize.x, pMonitor->m_transformedSize.y};
data.color = CHyprColor(0, 0, 0, *PDIMAROUND * pLayer->m_alpha->value());
m_renderPass.add(makeUnique<CRectPassElement>(data));
}
@@ -1199,7 +1260,7 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, PHLMONITOR pMonitor, const Time::s
}
}
-void CHyprRenderer::renderIMEPopup(CInputPopup* pPopup, PHLMONITOR pMonitor, const Time::steady_tp& time) {
+void IHyprRenderer::renderIMEPopup(CInputPopup* pPopup, PHLMONITOR pMonitor, const Time::steady_tp& time) {
const auto POS = pPopup->globalBox().pos();
CSurfacePassElement::SRenderData renderdata = {pMonitor, time, POS};
@@ -1239,7 +1300,7 @@ void CHyprRenderer::renderIMEPopup(CInputPopup* pPopup, PHLMONITOR pMonitor, con
&renderdata);
}
-void CHyprRenderer::renderSessionLockSurface(WP<SSessionLockSurface> pSurface, PHLMONITOR pMonitor, const Time::steady_tp& time) {
+void IHyprRenderer::renderSessionLockSurface(WP<SSessionLockSurface> pSurface, PHLMONITOR pMonitor, const Time::steady_tp& time) {
CSurfacePassElement::SRenderData renderdata = {pMonitor, time, pMonitor->m_position, pMonitor->m_position};
renderdata.blur = false;
@@ -1266,7 +1327,7 @@ void CHyprRenderer::renderSessionLockSurface(WP<SSessionLockSurface> pSurface, P
&renderdata);
}
-void CHyprRenderer::renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& time, const Vector2D& translate, const float& scale) {
+void IHyprRenderer::renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& time, const Vector2D& translate, const float& scale) {
static auto PDIMSPECIAL = CConfigValue<Hyprlang::FLOAT>("decoration:dim_special");
static auto PBLURSPECIAL = CConfigValue<Hyprlang::INT>("decoration:blur:special");
static auto PBLUR = CConfigValue<Hyprlang::INT>("decoration:blur:enabled");
@@ -1283,10 +1344,6 @@ void CHyprRenderer::renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPA
return;
}
- // todo: matrices are buggy atm for some reason, but probably would be preferable in the long run
- // g_pHyprOpenGL->saveMatrix();
- // g_pHyprOpenGL->setMatrixScaleTranslate(translate, scale);
-
SRenderModifData RENDERMODIFDATA;
if (translate != Vector2D{0, 0})
RENDERMODIFDATA.modifs.emplace_back(std::make_pair<>(SRenderModifData::eRenderModifType::RMOD_TYPE_TRANSLATE, translate));
@@ -1343,7 +1400,8 @@ void CHyprRenderer::renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPA
}
// pre window pass
- g_pHyprOpenGL->preWindowPass();
+ if (preBlurQueued(pMonitor))
+ m_renderPass.add(makeUnique<CPreBlurElement>());
if UNLIKELY /* subjective? */ (pWorkspace->m_hasFullscreenWindow)
renderWorkspaceWindowsFullscreen(pMonitor, pWorkspace, time);
@@ -1423,22 +1481,95 @@ void CHyprRenderer::renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPA
}
renderDragIcon(pMonitor, time);
+}
+
+SP<ITexture> IHyprRenderer::getBackground(PHLMONITOR pMonitor) {
+
+ if (m_backgroundResourceFailed)
+ return nullptr;
+
+ if (!m_backgroundResource) {
+ // queue the asset to be created
+ requestBackgroundResource();
+ return nullptr;
+ }
- //g_pHyprOpenGL->restoreMatrix();
+ if (!m_backgroundResource->m_ready)
+ return nullptr;
+
+ Log::logger->log(Log::DEBUG, "Creating a texture for BGTex");
+ SP<ITexture> backgroundTexture = createTexture(m_backgroundResource->m_asset.cairoSurface->cairo());
+ if (!backgroundTexture->ok())
+ return nullptr;
+ Log::logger->log(Log::DEBUG, "Background created for monitor {}", pMonitor->m_name);
+
+ // clear the resource after we're done using it
+ g_pEventLoopManager->doLater([this] { m_backgroundResource.reset(); });
+
+ // set the animation to start for fading this background in nicely
+ pMonitor->m_backgroundOpacity->setValueAndWarp(0.F);
+ *pMonitor->m_backgroundOpacity = 1.F;
+
+ return backgroundTexture;
}
-void CHyprRenderer::renderBackground(PHLMONITOR pMonitor) {
+void IHyprRenderer::renderBackground(PHLMONITOR pMonitor) {
static auto PRENDERTEX = CConfigValue<Hyprlang::INT>("misc:disable_hyprland_logo");
static auto PBACKGROUNDCOLOR = CConfigValue<Hyprlang::INT>("misc:background_color");
+ static auto PNOSPLASH = CConfigValue<Hyprlang::INT>("misc:disable_splash_rendering");
if (*PRENDERTEX /* inverted cfg flag */ || pMonitor->m_backgroundOpacity->isBeingAnimated())
m_renderPass.add(makeUnique<CClearPassElement>(CClearPassElement::SClearData{CHyprColor(*PBACKGROUNDCOLOR)}));
- if (!*PRENDERTEX)
- g_pHyprOpenGL->clearWithTex(); // will apply the hypr "wallpaper"
+ if (!*PRENDERTEX) {
+ static auto PBACKGROUNDCOLOR = CConfigValue<Hyprlang::INT>("misc:background_color");
+
+ if (!pMonitor->m_background)
+ pMonitor->m_background = getBackground(pMonitor);
+
+ if (!pMonitor->m_background)
+ m_renderPass.add(makeUnique<CClearPassElement>(CClearPassElement::SClearData{CHyprColor(*PBACKGROUNDCOLOR)}));
+ else {
+ CTexPassElement::SRenderData data;
+ const double MONRATIO = m_renderData.pMonitor->m_transformedSize.x / m_renderData.pMonitor->m_transformedSize.y;
+ const double WPRATIO = pMonitor->m_background->m_size.x / pMonitor->m_background->m_size.y;
+ Vector2D origin;
+ double scale = 1.0;
+
+ if (MONRATIO > WPRATIO) {
+ scale = m_renderData.pMonitor->m_transformedSize.x / pMonitor->m_background->m_size.x;
+ origin.y = (m_renderData.pMonitor->m_transformedSize.y - pMonitor->m_background->m_size.y * scale) / 2.0;
+ } else {
+ scale = m_renderData.pMonitor->m_transformedSize.y / pMonitor->m_background->m_size.y;
+ origin.x = (m_renderData.pMonitor->m_transformedSize.x - pMonitor->m_background->m_size.x * scale) / 2.0;
+ }
+
+ if (MONRATIO != WPRATIO)
+ m_renderPass.add(makeUnique<CClearPassElement>(CClearPassElement::SClearData{CHyprColor(*PBACKGROUNDCOLOR)}));
+
+ data.box = {origin, pMonitor->m_background->m_size * scale};
+ data.a = m_renderData.pMonitor->m_backgroundOpacity->value();
+ data.tex = pMonitor->m_background;
+ m_renderPass.add(makeUnique<CTexPassElement>(std::move(data)));
+ }
+ }
+
+ if (!*PNOSPLASH) {
+ auto monitorSize = pMonitor->m_transformedSize;
+ if (!pMonitor->m_splash)
+ pMonitor->m_splash = renderSplash([this, pMonitor](auto width, auto height, const auto DATA) { return createTexture(width, height, DATA); }, monitorSize.y / 76,
+ monitorSize.x, monitorSize.y);
+
+ if (pMonitor->m_splash) {
+ CTexPassElement::SRenderData data;
+ data.box = {{(monitorSize.x - pMonitor->m_splash->m_size.x) / 2.0, monitorSize.y * 0.98 - pMonitor->m_splash->m_size.y}, pMonitor->m_splash->m_size};
+ data.tex = pMonitor->m_splash;
+ m_renderPass.add(makeUnique<CTexPassElement>(std::move(data)));
+ }
+ }
}
-void CHyprRenderer::requestBackgroundResource() {
+void IHyprRenderer::requestBackgroundResource() {
if (m_backgroundResource)
return;
@@ -1492,7 +1623,7 @@ void CHyprRenderer::requestBackgroundResource() {
g_pAsyncResourceGatherer->enqueue(m_backgroundResource);
}
-std::string CHyprRenderer::resolveAssetPath(const std::string& filename) {
+std::string IHyprRenderer::resolveAssetPath(const std::string& filename) {
std::string fullPath;
for (auto& e : ASSET_PATHS) {
std::string p = std::string{e} + "/hypr/" + filename;
@@ -1513,7 +1644,7 @@ std::string CHyprRenderer::resolveAssetPath(const std::string& filename) {
return fullPath;
}
-SP<ITexture> CHyprRenderer::loadAsset(const std::string& filename) {
+SP<ITexture> IHyprRenderer::loadAsset(const std::string& filename) {
const std::string fullPath = resolveAssetPath(filename);
@@ -1535,11 +1666,15 @@ SP<ITexture> CHyprRenderer::loadAsset(const std::string& filename) {
return tex;
}
-bool CHyprRenderer::shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindow) {
+SP<ITexture> IHyprRenderer::getBlurTexture(PHLMONITORREF pMonitor) {
+ return pMonitor->m_blurFB->getTexture();
+}
+
+bool IHyprRenderer::shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindow) {
static auto PBLURNEWOPTIMIZE = CConfigValue<Hyprlang::INT>("decoration:blur:new_optimizations");
static auto PBLURXRAY = CConfigValue<Hyprlang::INT>("decoration:blur:xray");
- if (!m_renderData.pMonitor || !m_renderData.pMonitor->m_blurFB || !m_renderData.pMonitor->m_blurFB->getTexture())
+ if (!getBlurTexture(m_renderData.pMonitor))
return false;
if (pWindow && pWindow->m_ruleApplicator->xray().hasValue() && !pWindow->m_ruleApplicator->xray().valueOrDefault())
@@ -1557,7 +1692,7 @@ bool CHyprRenderer::shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindo
return false;
}
-void CHyprRenderer::initMissingAssetTexture() {
+void IHyprRenderer::initMissingAssetTexture() {
const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 512, 512);
const auto CAIRO = cairo_create(CAIROSURFACE);
@@ -1584,13 +1719,13 @@ void CHyprRenderer::initMissingAssetTexture() {
m_missingAssetTexture = tex;
}
-void CHyprRenderer::initAssets() {
+void IHyprRenderer::initAssets() {
initMissingAssetTexture();
m_screencopyDeniedTexture = renderText("Permission denied to share screen", Colors::WHITE, 20);
}
-SP<ITexture> CHyprRenderer::renderText(const std::string& text, CHyprColor col, int pt, bool italic, const std::string& fontFamily, int maxWidth, int weight) {
+SP<ITexture> IHyprRenderer::renderText(const std::string& text, CHyprColor col, int pt, bool italic, const std::string& fontFamily, int maxWidth, int weight) {
static auto FONT = CConfigValue<std::string>("misc:font_family");
const auto FONTFAMILY = fontFamily.empty() ? *FONT : fontFamily;
@@ -1659,7 +1794,7 @@ SP<ITexture> CHyprRenderer::renderText(const std::string& text, CHyprColor col,
return tex;
}
-void CHyprRenderer::ensureLockTexturesRendered(bool load) {
+void IHyprRenderer::ensureLockTexturesRendered(bool load) {
static bool loaded = false;
if (loaded == load)
@@ -1682,7 +1817,7 @@ void CHyprRenderer::ensureLockTexturesRendered(bool load) {
}
}
-void CHyprRenderer::renderLockscreen(PHLMONITOR pMonitor, const Time::steady_tp& now, const CBox& geometry) {
+void IHyprRenderer::renderLockscreen(PHLMONITOR pMonitor, const Time::steady_tp& now, const CBox& geometry) {
TRACY_GPU_ZONE("RenderLockscreen");
const bool LOCKED = g_pSessionLockManager->isSessionLocked();
@@ -1720,7 +1855,7 @@ void CHyprRenderer::renderLockscreen(PHLMONITOR pMonitor, const Time::steady_tp&
}
}
-void CHyprRenderer::renderSessionLockPrimer(PHLMONITOR pMonitor) {
+void IHyprRenderer::renderSessionLockPrimer(PHLMONITOR pMonitor) {
static auto PSESSIONLOCKXRAY = CConfigValue<Hyprlang::INT>("misc:session_lock_xray");
if (*PSESSIONLOCKXRAY)
return;
@@ -1732,7 +1867,7 @@ void CHyprRenderer::renderSessionLockPrimer(PHLMONITOR pMonitor) {
m_renderPass.add(makeUnique<CRectPassElement>(data));
}
-void CHyprRenderer::renderSessionLockMissing(PHLMONITOR pMonitor) {
+void IHyprRenderer::renderSessionLockMissing(PHLMONITOR pMonitor) {
const bool ANY_PRESENT = g_pSessionLockManager->anySessionLockSurfacesPresent();
// ANY_PRESENT: render image2, without instructions. Lock still "alive", unless texture dead
@@ -1774,7 +1909,7 @@ static std::optional<Vector2D> getSurfaceExpectedSize(PHLWINDOW pWindow, SP<CWLS
return std::nullopt;
}
-void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface, PHLMONITOR pMonitor, bool main, const Vector2D& projSize,
+void IHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface, PHLMONITOR pMonitor, bool main, const Vector2D& projSize,
const Vector2D& projSizeUnscaled, bool fixMisalignedFSV1) {
if (!pWindow || !pWindow->m_isX11) {
static auto PEXPANDEDGES = CConfigValue<Hyprlang::INT>("render:expand_undersized_textures");
@@ -1875,6 +2010,96 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResour
}
}
+bool IHyprRenderer::beginRender(PHLMONITOR pMonitor, CRegion& damage, eRenderMode mode, SP<IHLBuffer> buffer, SP<IFramebuffer> fb, bool simple) {
+ m_renderPass.clear();
+ m_renderMode = mode;
+ m_renderData.pMonitor = pMonitor;
+
+ if (simple)
+ setProjectionType(fb ? fb->m_size : buffer->m_texture->m_size);
+ else
+ setProjectionType(RPT_MONITOR);
+
+ if (!simple) {
+ const auto DRM_FORMAT = fb ? fb->m_drmFormat : pMonitor->m_output->state->state().drmFormat;
+
+ // ensure a framebuffer for the monitor exists
+ if (!m_renderData.pMonitor->m_offloadFB || m_renderData.pMonitor->m_offloadFB->m_size != pMonitor->m_pixelSize ||
+ DRM_FORMAT != m_renderData.pMonitor->m_offloadFB->m_drmFormat) {
+ if (!m_renderData.pMonitor->m_stencilTex || m_renderData.pMonitor->m_stencilTex->m_size != pMonitor->m_pixelSize)
+ m_renderData.pMonitor->m_stencilTex = createStencilTexture(m_renderData.pMonitor->m_pixelSize.x, m_renderData.pMonitor->m_pixelSize.y);
+
+ m_renderData.pMonitor->m_offloadFB = createFB("offload");
+ m_renderData.pMonitor->m_mirrorFB = createFB("mirror");
+ m_renderData.pMonitor->m_mirrorSwapFB = createFB("mirrorSwap");
+ m_renderData.pMonitor->m_offMainFB = createFB("offMain");
+ m_renderData.pMonitor->m_monitorMirrorFB = createFB("monitorMirror");
+ m_renderData.pMonitor->m_blurFB = createFB("blur");
+
+ // add stencil before FB allocation to avoid reallocs
+ m_renderData.pMonitor->m_offloadFB->addStencil(m_renderData.pMonitor->m_stencilTex);
+ m_renderData.pMonitor->m_mirrorFB->addStencil(m_renderData.pMonitor->m_stencilTex);
+ m_renderData.pMonitor->m_mirrorSwapFB->addStencil(m_renderData.pMonitor->m_stencilTex);
+ m_renderData.pMonitor->m_offMainFB->addStencil(m_renderData.pMonitor->m_stencilTex);
+
+ m_renderData.pMonitor->m_offloadFB->alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, DRM_FORMAT);
+ m_renderData.pMonitor->m_mirrorFB->alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, DRM_FORMAT);
+ m_renderData.pMonitor->m_mirrorSwapFB->alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, DRM_FORMAT);
+ m_renderData.pMonitor->m_offMainFB->alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, DRM_FORMAT);
+ }
+ }
+
+ const bool HAS_MIRROR_FB = g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB && g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB->isAllocated();
+ const bool NEEDS_COPY_FB = needsACopyFB(g_pHyprRenderer->m_renderData.pMonitor.lock());
+
+ if (HAS_MIRROR_FB && !NEEDS_COPY_FB)
+ g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB->release();
+ else if (!HAS_MIRROR_FB && NEEDS_COPY_FB && g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB)
+ g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB->alloc(g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.x,
+ g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.y,
+ g_pHyprRenderer->m_renderData.pMonitor->m_output->state->state().drmFormat);
+
+ if (m_renderMode == RENDER_MODE_FULL_FAKE)
+ return beginFullFakeRenderInternal(pMonitor, damage, fb, simple);
+
+ int bufferAge = 0;
+
+ if (!buffer) {
+ m_currentBuffer = pMonitor->m_output->swapchain->next(&bufferAge);
+ if (!m_currentBuffer) {
+ Log::logger->log(Log::ERR, "Failed to acquire swapchain buffer for {}", pMonitor->m_name);
+ return false;
+ }
+ } else
+ m_currentBuffer = buffer;
+
+ initRender();
+
+ if (!initRenderBuffer(m_currentBuffer, pMonitor->m_output->state->state().drmFormat)) {
+ Log::logger->log(Log::ERR, "failed to start a render pass for output {}, no RBO could be obtained", pMonitor->m_name);
+ return false;
+ }
+
+ if (m_renderMode == RENDER_MODE_NORMAL) {
+ damage = pMonitor->m_damage.getBufferDamage(bufferAge);
+ pMonitor->m_damage.rotate();
+ }
+
+ const auto res = beginRenderInternal(pMonitor, damage, simple);
+ static bool initial = true;
+ if (initial) {
+ initAssets();
+ initial = false;
+ }
+
+ return res;
+}
+
+void IHyprRenderer::setDamage(const CRegion& damage_, std::optional<CRegion> finalDamage) {
+ m_renderData.damage.set(damage_);
+ m_renderData.finalDamage.set(finalDamage.value_or(damage_));
+}
+
static Mat3x3 getMirrorProjection(PHLMONITORREF monitor) {
return Mat3x3::identity()
.translate(monitor->m_pixelSize / 2.0)
@@ -1891,12 +2116,12 @@ static Mat3x3 getFBProjection(PHLMONITORREF pMonitor, const Vector2D& size) {
return Mat3x3::identity().translate(size / 2.0).transform(Math::wlTransformToHyprutils(pMonitor->m_transform)).translate(-tfmd / 2.0);
}
-void CHyprRenderer::setProjectionType(const Vector2D& fbSize) {
+void IHyprRenderer::setProjectionType(const Vector2D& fbSize) {
m_renderData.fbSize = fbSize;
setProjectionType(RPT_FB);
}
-void CHyprRenderer::setProjectionType(eRenderProjectionType projectionType) {
+void IHyprRenderer::setProjectionType(eRenderProjectionType projectionType) {
m_renderData.projectionType = projectionType;
switch (projectionType) {
case RPT_MONITOR: m_renderData.targetProjection = m_renderData.pMonitor->getTransformMatrix(); break;
@@ -1906,16 +2131,49 @@ void CHyprRenderer::setProjectionType(eRenderProjectionType projectionType) {
}
}
-Mat3x3 CHyprRenderer::getBoxProjection(const CBox& box, std::optional<eTransform> transform) {
+Mat3x3 IHyprRenderer::getBoxProjection(const CBox& box, std::optional<eTransform> transform) {
return m_renderData.targetProjection.projectBox(
box, transform.value_or(Math::wlTransformToHyprutils(Math::invertTransform(!monitorTransformEnabled() ? WL_OUTPUT_TRANSFORM_NORMAL : m_renderData.pMonitor->m_transform))),
box.rot);
}
-Mat3x3 CHyprRenderer::projectBoxToTarget(const CBox& box, std::optional<eTransform> transform) {
+Mat3x3 IHyprRenderer::projectBoxToTarget(const CBox& box, std::optional<eTransform> transform) {
return m_renderData.pMonitor->getScaleMatrix().copy().multiply(getBoxProjection(box, transform));
}
+SP<ITexture> IHyprRenderer::blurMainFramebuffer(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.pMonitor->m_mirrorFB->getTexture(); // return something to sample from at least
+ }
+
+ return blurFramebuffer(m_renderData.currentFB, a, originalDamage);
+}
+
+void IHyprRenderer::preBlurForCurrentMonitor(CRegion* fakeDamage) {
+
+ const auto blurredTex = blurMainFramebuffer(1, fakeDamage);
+
+ // render onto blurFB
+ m_renderData.pMonitor->m_blurFB->alloc(m_renderData.pMonitor->m_pixelSize.x, m_renderData.pMonitor->m_pixelSize.y, m_renderData.pMonitor->m_output->state->state().drmFormat);
+ m_renderData.pMonitor->m_blurFB->bind();
+
+ draw(makeUnique<CClearPassElement>(CClearPassElement::SClearData{{0, 0, 0, 0}}), {});
+
+ pushMonitorTransformEnabled(true);
+
+ draw(makeUnique<CTexPassElement>(CTexPassElement::SRenderData{
+ .tex = blurredTex,
+ .box = CBox{0, 0, m_renderData.pMonitor->m_transformedSize.x, m_renderData.pMonitor->m_transformedSize.y},
+ .damage = *fakeDamage,
+ }),
+ *fakeDamage); // .noAA = true
+
+ popMonitorTransformEnabled();
+
+ m_renderData.currentFB->bind();
+}
+
static bool isSDR2HDR(const NColorManagement::SImageDescription& imageDescription, const NColorManagement::SImageDescription& targetImageDescription) {
// might be too strict
return (imageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_SRGB ||
@@ -1932,7 +2190,7 @@ static bool isHDR2SDR(const NColorManagement::SImageDescription& imageDescriptio
targetImageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22);
}
-SCMSettings CHyprRenderer::getCMSettings(const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
+SCMSettings IHyprRenderer::getCMSettings(const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
SP<CWLSurfaceResource> surface, bool modifySDR, float sdrMinLuminance, int sdrMaxLuminance) {
const auto sdrEOTF = NTransferFunction::fromConfig();
NColorManagement::eTransferFunction srcTF;
@@ -1988,7 +2246,37 @@ SCMSettings CHyprRenderer::getCMSettings(const NColorManagement::PImageDescripti
};
}
-void CHyprRenderer::renderMonitor(PHLMONITOR pMonitor, bool commit) {
+void IHyprRenderer::renderMirrored() {
+ auto monitor = m_renderData.pMonitor;
+ auto mirrored = monitor->m_mirrorOf;
+
+ const double scale = std::min(monitor->m_transformedSize.x / mirrored->m_transformedSize.x, monitor->m_transformedSize.y / mirrored->m_transformedSize.y);
+ CBox monbox = {0, 0, mirrored->m_transformedSize.x * scale, mirrored->m_transformedSize.y * scale};
+
+ // transform box as it will be drawn on a transformed projection
+ monbox.transform(Math::wlTransformToHyprutils(mirrored->m_transform), mirrored->m_transformedSize.x * scale, mirrored->m_transformedSize.y * scale);
+
+ monbox.x = (monitor->m_transformedSize.x - monbox.w) / 2;
+ monbox.y = (monitor->m_transformedSize.y - monbox.h) / 2;
+
+ if (!monitor->m_monitorMirrorFB)
+ monitor->m_monitorMirrorFB = createFB("monitorMirror");
+
+ const auto PFB = mirrored->m_monitorMirrorFB;
+ if (!PFB || !PFB->isAllocated() || !PFB->getTexture())
+ return;
+
+ m_renderPass.add(makeUnique<CClearPassElement>(CClearPassElement::SClearData{CHyprColor(0, 0, 0, 0)}));
+
+ CTexPassElement::SRenderData data;
+ data.tex = PFB->getTexture();
+ data.box = monbox;
+ data.useMirrorProjection = true;
+
+ m_renderPass.add(makeUnique<CTexPassElement>(std::move(data)));
+}
+
+void IHyprRenderer::renderMonitor(PHLMONITOR pMonitor, bool commit) {
static std::chrono::high_resolution_clock::time_point renderStart = std::chrono::high_resolution_clock::now();
static std::chrono::high_resolution_clock::time_point renderStartOverlay = std::chrono::high_resolution_clock::now();
static std::chrono::high_resolution_clock::time_point endRenderOverlay = std::chrono::high_resolution_clock::now();
@@ -2118,7 +2406,7 @@ void CHyprRenderer::renderMonitor(PHLMONITOR pMonitor, bool commit) {
finalDamage = damage;
// update damage in renderdata as we modified it
- g_pHyprOpenGL->setDamage(damage, finalDamage);
+ setDamage(damage, finalDamage);
if (pMonitor->m_forceFullFrames > 0) {
pMonitor->m_forceFullFrames -= 1;
@@ -2134,9 +2422,9 @@ void CHyprRenderer::renderMonitor(PHLMONITOR pMonitor, bool commit) {
renderWindow(pMonitor->m_solitaryClient.lock(), pMonitor, NOW, false, RENDER_PASS_MAIN /* solitary = no popups */);
else if (!finalDamage.empty()) {
if (pMonitor->isMirror()) {
- g_pHyprOpenGL->blend(false);
- g_pHyprOpenGL->renderMirrored();
- g_pHyprOpenGL->blend(true);
+ blend(false);
+ renderMirrored();
+ blend(true);
Event::bus()->m_events.render.stage.emit(RENDER_POST_MIRROR);
renderCursor = false;
} else {
@@ -2289,7 +2577,7 @@ static hdr_output_metadata createHDRMetadata(SImageDescription settings, S
};
}
-bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
+bool IHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
static auto PCT = CConfigValue<Hyprlang::INT>("render:send_content_type");
static auto PPASS = CConfigValue<Hyprlang::INT>("render:cm_fs_passthrough");
static auto PAUTOHDR = CConfigValue<Hyprlang::INT>("render:cm_auto_hdr");
@@ -2429,7 +2717,7 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
return ok;
}
-void CHyprRenderer::renderWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now, const CBox& geometry) {
+void IHyprRenderer::renderWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now, const CBox& geometry) {
Vector2D translate = {geometry.x, geometry.y};
float scale = sc<float>(geometry.width) / pMonitor->m_pixelSize.x;
@@ -2444,7 +2732,7 @@ void CHyprRenderer::renderWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace
renderAllClientsForWorkspace(pMonitor, pWorkspace, now, translate, scale);
}
-void CHyprRenderer::sendFrameEventsToWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now) {
+void IHyprRenderer::sendFrameEventsToWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now) {
for (const auto& view : Desktop::View::getViewsForWorkspace(pWorkspace)) {
if (!view->aliveAndVisible())
continue;
@@ -2453,7 +2741,7 @@ void CHyprRenderer::sendFrameEventsToWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE
}
}
-void CHyprRenderer::setSurfaceScanoutMode(SP<CWLSurfaceResource> surface, PHLMONITOR monitor) {
+void IHyprRenderer::setSurfaceScanoutMode(SP<CWLSurfaceResource> surface, PHLMONITOR monitor) {
if (!PROTO::linuxDma)
return;
@@ -2520,7 +2808,7 @@ static void applyExclusive(CBox& usableArea, uint32_t anchor, int32_t exclusive,
}
}
-void CHyprRenderer::arrangeLayerArray(PHLMONITOR pMonitor, const std::vector<PHLLSREF>& layerSurfaces, bool exclusiveZone, CBox* usableArea) {
+void IHyprRenderer::arrangeLayerArray(PHLMONITOR pMonitor, const std::vector<PHLLSREF>& layerSurfaces, bool exclusiveZone, CBox* usableArea) {
CBox full_area = {pMonitor->m_position.x, pMonitor->m_position.y, pMonitor->m_size.x, pMonitor->m_size.y};
for (auto const& ls : layerSurfaces) {
@@ -2607,7 +2895,7 @@ void CHyprRenderer::arrangeLayerArray(PHLMONITOR pMonitor, const std::vector<PHL
}
}
-void CHyprRenderer::arrangeLayersForMonitor(const MONITORID& monitor) {
+void IHyprRenderer::arrangeLayersForMonitor(const MONITORID& monitor) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitor);
if (!PMONITOR || PMONITOR->m_size.x <= 0 || PMONITOR->m_size.y <= 0)
@@ -2638,7 +2926,7 @@ void CHyprRenderer::arrangeLayersForMonitor(const MONITORID& monitor) {
g_layoutManager->invalidateMonitorGeometries(PMONITOR);
}
-void CHyprRenderer::damageSurface(SP<CWLSurfaceResource> pSurface, double x, double y, double scale) {
+void IHyprRenderer::damageSurface(SP<CWLSurfaceResource> pSurface, double x, double y, double scale) {
if (!pSurface)
return; // wut?
@@ -2693,7 +2981,7 @@ void CHyprRenderer::damageSurface(SP<CWLSurfaceResource> pSurface, double x, dou
damageBox.pixman()->extents.x2 - damageBox.pixman()->extents.x1, damageBox.pixman()->extents.y2 - damageBox.pixman()->extents.y1);
}
-void CHyprRenderer::damageWindow(PHLWINDOW pWindow, bool forceFull) {
+void IHyprRenderer::damageWindow(PHLWINDOW pWindow, bool forceFull) {
if (g_pCompositor->m_unsafeState)
return;
@@ -2720,7 +3008,7 @@ void CHyprRenderer::damageWindow(PHLWINDOW pWindow, bool forceFull) {
Log::logger->log(Log::DEBUG, "Damage: Window ({}): xy: {}, {} wh: {}, {}", pWindow->m_title, windowBox.x, windowBox.y, windowBox.width, windowBox.height);
}
-void CHyprRenderer::damageMonitor(PHLMONITOR pMonitor) {
+void IHyprRenderer::damageMonitor(PHLMONITOR pMonitor) {
if (g_pCompositor->m_unsafeState || pMonitor->isMirror())
return;
@@ -2733,7 +3021,7 @@ void CHyprRenderer::damageMonitor(PHLMONITOR pMonitor) {
Log::logger->log(Log::DEBUG, "Damage: Monitor {}", pMonitor->m_name);
}
-void CHyprRenderer::damageBox(const CBox& box, bool skipFrameSchedule) {
+void IHyprRenderer::damageBox(const CBox& box, bool skipFrameSchedule) {
if (g_pCompositor->m_unsafeState)
return;
@@ -2753,16 +3041,16 @@ void CHyprRenderer::damageBox(const CBox& box, bool skipFrameSchedule) {
Log::logger->log(Log::DEBUG, "Damage: Box: xy: {}, {} wh: {}, {}", box.x, box.y, box.w, box.h);
}
-void CHyprRenderer::damageBox(const int& x, const int& y, const int& w, const int& h) {
+void IHyprRenderer::damageBox(const int& x, const int& y, const int& w, const int& h) {
CBox box = {x, y, w, h};
damageBox(box);
}
-void CHyprRenderer::damageRegion(const CRegion& rg) {
+void IHyprRenderer::damageRegion(const CRegion& rg) {
rg.forEachRect([this](const auto& RECT) { damageBox(RECT.x1, RECT.y1, RECT.x2 - RECT.x1, RECT.y2 - RECT.y1); });
}
-void CHyprRenderer::damageMirrorsWith(PHLMONITOR pMonitor, const CRegion& pRegion) {
+void IHyprRenderer::damageMirrorsWith(PHLMONITOR pMonitor, const CRegion& pRegion) {
for (auto const& mirror : pMonitor->m_mirrors) {
// transform the damage here, so it won't get clipped by the monitor damage ring
@@ -2786,11 +3074,11 @@ void CHyprRenderer::damageMirrorsWith(PHLMONITOR pMonitor, const CRegion& pRegio
}
}
-void CHyprRenderer::renderDragIcon(PHLMONITOR pMonitor, const Time::steady_tp& time) {
+void IHyprRenderer::renderDragIcon(PHLMONITOR pMonitor, const Time::steady_tp& time) {
PROTO::data->renderDND(pMonitor, time);
}
-void CHyprRenderer::setCursorSurface(SP<Desktop::View::CWLSurface> surf, int hotspotX, int hotspotY, bool force) {
+void IHyprRenderer::setCursorSurface(SP<Desktop::View::CWLSurface> surf, int hotspotX, int hotspotY, bool force) {
m_cursorHasSurface = surf && surf->resource();
m_lastCursorData.name = "";
@@ -2804,7 +3092,7 @@ void CHyprRenderer::setCursorSurface(SP<Desktop::View::CWLSurface> surf, int hot
g_pCursorManager->setCursorSurface(surf, {hotspotX, hotspotY});
}
-void CHyprRenderer::setCursorFromName(const std::string& name, bool force) {
+void IHyprRenderer::setCursorFromName(const std::string& name, bool force) {
m_cursorHasSurface = true;
if (name == m_lastCursorData.name && !force)
@@ -2855,7 +3143,7 @@ void CHyprRenderer::setCursorFromName(const std::string& name, bool force) {
g_pCursorManager->setCursorFromName(name);
}
-void CHyprRenderer::ensureCursorRenderingMode() {
+void IHyprRenderer::ensureCursorRenderingMode() {
static auto PINVISIBLE = CConfigValue<Hyprlang::INT>("cursor:invisible");
static auto PCURSORTIMEOUT = CConfigValue<Hyprlang::FLOAT>("cursor:inactive_timeout");
static auto PHIDEONTOUCH = CConfigValue<Hyprlang::INT>("cursor:hide_on_touch");
@@ -2897,7 +3185,7 @@ void CHyprRenderer::ensureCursorRenderingMode() {
setCursorHidden(HIDE);
}
-void CHyprRenderer::setCursorHidden(bool hide) {
+void IHyprRenderer::setCursorHidden(bool hide) {
if (hide == m_cursorHidden)
return;
@@ -2917,11 +3205,11 @@ void CHyprRenderer::setCursorHidden(bool hide) {
setCursorFromName("left_ptr", true);
}
-bool CHyprRenderer::shouldRenderCursor() {
+bool IHyprRenderer::shouldRenderCursor() {
return !m_cursorHidden && m_cursorHasSurface;
}
-std::tuple<float, float, float> CHyprRenderer::getRenderTimes(PHLMONITOR pMonitor) {
+std::tuple<float, float, float> IHyprRenderer::getRenderTimes(PHLMONITOR pMonitor) {
const auto POVERLAY = &g_pDebugOverlay->m_monitorOverlays[pMonitor];
float avgRenderTime = 0;
@@ -2952,7 +3240,7 @@ static int handleCrashLoop(void* data) {
return 1;
}
-void CHyprRenderer::initiateManualCrash() {
+void IHyprRenderer::initiateManualCrash() {
g_pHyprNotificationOverlay->addNotification("Manual crash initiated. Farewell...", CHyprColor(0), 5000, ICON_INFO);
m_crashingLoop = wl_event_loop_add_timer(g_pCompositor->m_wlEventLoop, handleCrashLoop, nullptr);
@@ -2968,11 +3256,11 @@ void CHyprRenderer::initiateManualCrash() {
**PDT = 0;
}
-const SRenderData& CHyprRenderer::renderData() {
+const SRenderData& IHyprRenderer::renderData() {
return m_renderData;
}
-SP<IRenderbuffer> CHyprRenderer::getOrCreateRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) {
+SP<IRenderbuffer> IHyprRenderer::getOrCreateRenderbuffer(SP<Aquamarine::IBuffer> 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())
@@ -2987,163 +3275,35 @@ SP<IRenderbuffer> CHyprRenderer::getOrCreateRenderbuffer(SP<Aquamarine::IBuffer>
return buf;
}
-bool CHyprRenderer::beginRender(PHLMONITOR pMonitor, CRegion& damage, eRenderMode mode, SP<IHLBuffer> buffer, SP<IFramebuffer> fb, bool simple) {
-
- g_pHyprOpenGL->makeEGLCurrent();
-
- m_renderPass.clear();
-
- m_renderMode = mode;
-
- m_renderData.pMonitor = pMonitor; // has to be set cuz allocs
-
- if (mode == RENDER_MODE_FULL_FAKE) {
- RASSERT(fb, "Cannot render FULL_FAKE without a provided fb!");
- fb->bind();
- if (simple)
- g_pHyprOpenGL->beginSimple(pMonitor, damage, nullptr, fb);
- else
- g_pHyprOpenGL->begin(pMonitor, damage, fb);
- return true;
- }
-
- int bufferAge = 0;
-
- if (!buffer) {
- m_currentBuffer = pMonitor->m_output->swapchain->next(&bufferAge);
- if (!m_currentBuffer) {
- Log::logger->log(Log::ERR, "Failed to acquire swapchain buffer for {}", pMonitor->m_name);
- return false;
- }
- } else
- m_currentBuffer = buffer;
-
- try {
- m_currentRenderbuffer = getOrCreateRenderbuffer(m_currentBuffer, pMonitor->m_output->state->state().drmFormat);
- } catch (std::exception& e) {
- Log::logger->log(Log::ERR, "getOrCreateRenderbuffer failed for {}", pMonitor->m_name);
- return false;
- }
-
- if (!m_currentRenderbuffer) {
- Log::logger->log(Log::ERR, "failed to start a render pass for output {}, no RBO could be obtained", pMonitor->m_name);
- return false;
- }
-
- if (mode == RENDER_MODE_NORMAL) {
- damage = pMonitor->m_damage.getBufferDamage(bufferAge);
- pMonitor->m_damage.rotate();
- }
-
- m_currentRenderbuffer->bind();
- if (simple)
- g_pHyprOpenGL->beginSimple(pMonitor, damage, m_currentRenderbuffer);
- else
- g_pHyprOpenGL->begin(pMonitor, damage);
-
- return true;
+bool IHyprRenderer::beginFullFakeRender(PHLMONITOR pMonitor, CRegion& damage, SP<IFramebuffer> fb) {
+ return beginRender(pMonitor, damage, RENDER_MODE_FULL_FAKE, nullptr, fb, true);
}
-void CHyprRenderer::endRender(const std::function<void()>& renderingDoneCallback) {
- const auto PMONITOR = m_renderData.pMonitor;
- static auto PNVIDIAANTIFLICKER = CConfigValue<Hyprlang::INT>("opengl:nvidia_anti_flicker");
-
- m_renderData.damage = m_renderPass.render(m_renderData.damage);
-
- auto cleanup = CScopeGuard([this]() {
- if (m_currentRenderbuffer)
- m_currentRenderbuffer->unbind();
- m_currentRenderbuffer = nullptr;
- m_currentBuffer = nullptr;
- });
-
- if (m_renderMode != RENDER_MODE_TO_BUFFER_READ_ONLY)
- g_pHyprOpenGL->end();
- else {
- m_renderData.pMonitor.reset();
- m_renderData.mouseZoomFactor = 1.f;
- m_renderData.mouseZoomUseMouse = true;
- }
-
- if (m_renderMode == RENDER_MODE_FULL_FAKE)
- return;
-
- if (m_renderMode == RENDER_MODE_NORMAL)
- PMONITOR->m_output->state->setBuffer(m_currentBuffer);
-
- if (!g_pHyprOpenGL->explicitSyncSupported()) {
- Log::logger->log(Log::TRACE, "renderer: Explicit sync unsupported, falling back to implicit in endRender");
-
- // nvidia doesn't have implicit sync, so we have to explicitly wait here, llvmpipe and other software renderer seems to bug out aswell.
- if ((isNvidia() && *PNVIDIAANTIFLICKER) || isSoftware())
- glFinish();
- else
- glFlush(); // mark an implicit sync point
-
- m_usedAsyncBuffers.clear(); // release all buffer refs and hope implicit sync works
- if (renderingDoneCallback)
- renderingDoneCallback();
-
- return;
- }
-
- UP<CEGLSync> eglSync = CEGLSync::create();
- if LIKELY (eglSync && eglSync->isValid()) {
- for (auto const& buf : m_usedAsyncBuffers) {
- for (const auto& releaser : buf->m_syncReleasers) {
- releaser->addSyncFileFd(eglSync->fd());
- }
- }
-
- // release buffer refs with release points now, since syncReleaser handles actual buffer release based on EGLSync
- std::erase_if(m_usedAsyncBuffers, [](const auto& buf) { return !buf->m_syncReleasers.empty(); });
-
- // release buffer refs without release points when EGLSync sync_file/fence is signalled
- g_pEventLoopManager->doOnReadable(eglSync->fd().duplicate(), [renderingDoneCallback, prevbfs = std::move(m_usedAsyncBuffers)]() mutable {
- prevbfs.clear();
- if (renderingDoneCallback)
- renderingDoneCallback();
- });
- m_usedAsyncBuffers.clear();
-
- if (m_renderMode == RENDER_MODE_NORMAL) {
- PMONITOR->m_inFence = eglSync->takeFd();
- PMONITOR->m_output->state->setExplicitInFence(PMONITOR->m_inFence.get());
- }
- } else {
- Log::logger->log(Log::ERR, "renderer: Explicit sync failed, releasing resources");
-
- m_usedAsyncBuffers.clear(); // release all buffer refs and hope implicit sync works
- if (renderingDoneCallback)
- renderingDoneCallback();
- }
+bool IHyprRenderer::beginRenderToBuffer(PHLMONITOR pMonitor, CRegion& damage, SP<IHLBuffer> buffer, bool simple) {
+ return beginRender(pMonitor, damage, RENDER_MODE_TO_BUFFER, buffer, nullptr, simple);
}
-void CHyprRenderer::onRenderbufferDestroy(IRenderbuffer* rb) {
+void IHyprRenderer::onRenderbufferDestroy(IRenderbuffer* rb) {
std::erase_if(m_renderbuffers, [&](const auto& rbo) { return rbo.get() == rb; });
}
-SP<IRenderbuffer> CHyprRenderer::getCurrentRBO() {
- return m_currentRenderbuffer;
-}
-
-bool CHyprRenderer::isNvidia() {
+bool IHyprRenderer::isNvidia() {
return m_nvidia;
}
-bool CHyprRenderer::isIntel() {
+bool IHyprRenderer::isIntel() {
return m_intel;
}
-bool CHyprRenderer::isSoftware() {
+bool IHyprRenderer::isSoftware() {
return m_software;
}
-bool CHyprRenderer::isMgpu() {
+bool IHyprRenderer::isMgpu() {
return m_mgpu;
}
-void CHyprRenderer::addWindowToRenderUnfocused(PHLWINDOW window) {
+void IHyprRenderer::addWindowToRenderUnfocused(PHLWINDOW window) {
static auto PFPS = CConfigValue<Hyprlang::INT>("misc:render_unfocused_fps");
if (std::ranges::find(m_renderUnfocused, window) != m_renderUnfocused.end())
@@ -3155,7 +3315,7 @@ void CHyprRenderer::addWindowToRenderUnfocused(PHLWINDOW window) {
m_renderUnfocusedTimer->updateTimeout(std::chrono::milliseconds(1000 / *PFPS));
}
-void CHyprRenderer::makeSnapshot(PHLWINDOW pWindow) {
+void IHyprRenderer::makeSnapshot(PHLWINDOW pWindow) {
// we trust the window is valid.
const auto PMONITOR = pWindow->m_monitor.lock();
@@ -3181,20 +3341,27 @@ void CHyprRenderer::makeSnapshot(PHLWINDOW pWindow) {
PFRAMEBUFFER->alloc(PMONITOR->m_pixelSize.x, PMONITOR->m_pixelSize.y, DRM_FORMAT_ABGR8888);
- beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, PFRAMEBUFFER);
+ beginFullFakeRender(PMONITOR, fakeDamage, PFRAMEBUFFER);
m_bRenderingSnapshot = true;
- g_pHyprOpenGL->clear(CHyprColor(0, 0, 0, 0)); // JIC
+ draw(makeUnique<CClearPassElement>(CClearPassElement::SClearData{CHyprColor(0, 0, 0, 0)}), {});
+ startRenderPass();
+
+ Log::logger->log(Log::DEBUG, "renderer: cleared a snapshot of {:x}", rc<uintptr_t>(pWindow.get()));
renderWindow(pWindow, PMONITOR, Time::steadyNow(), !pWindow->m_X11DoesntWantBorders, RENDER_PASS_ALL);
+ Log::logger->log(Log::DEBUG, "renderer: rendered a snapshot of {:x}", rc<uintptr_t>(pWindow.get()));
+
endRender();
+ Log::logger->log(Log::DEBUG, "renderer: made a snapshot of {:x}", rc<uintptr_t>(pWindow.get()));
+
m_bRenderingSnapshot = false;
}
-void CHyprRenderer::makeSnapshot(PHLLS pLayer) {
+void IHyprRenderer::makeSnapshot(PHLLS pLayer) {
// we trust the window is valid.
const auto PMONITOR = pLayer->m_monitor.lock();
@@ -3215,21 +3382,28 @@ void CHyprRenderer::makeSnapshot(PHLLS pLayer) {
PFRAMEBUFFER->alloc(PMONITOR->m_pixelSize.x, PMONITOR->m_pixelSize.y, DRM_FORMAT_ABGR8888);
- beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, PFRAMEBUFFER);
+ beginFullFakeRender(PMONITOR, fakeDamage, PFRAMEBUFFER);
m_bRenderingSnapshot = true;
- g_pHyprOpenGL->clear(CHyprColor(0, 0, 0, 0)); // JIC
+ draw(makeUnique<CClearPassElement>(CClearPassElement::SClearData{CHyprColor(0, 0, 0, 0)}), {});
+ startRenderPass();
+
+ Log::logger->log(Log::DEBUG, "renderer: cleared a snapshot of layer {:x}", rc<uintptr_t>(pLayer.get()));
// draw the layer
renderLayer(pLayer, PMONITOR, Time::steadyNow());
+ Log::logger->log(Log::DEBUG, "renderer: rendered a snapshot of layer {:x}", rc<uintptr_t>(pLayer.get()));
+
endRender();
+ Log::logger->log(Log::DEBUG, "renderer: made a snapshot of layer {:x}", rc<uintptr_t>(pLayer.get()));
+
m_bRenderingSnapshot = false;
}
-void CHyprRenderer::makeSnapshot(WP<Desktop::View::CPopup> popup) {
+void IHyprRenderer::makeSnapshot(WP<Desktop::View::CPopup> popup) {
// we trust the window is valid.
const auto PMONITOR = popup->getMonitor();
@@ -3250,11 +3424,11 @@ void CHyprRenderer::makeSnapshot(WP<Desktop::View::CPopup> popup) {
PFRAMEBUFFER->alloc(PMONITOR->m_pixelSize.x, PMONITOR->m_pixelSize.y, DRM_FORMAT_ABGR8888);
- beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, PFRAMEBUFFER);
+ beginFullFakeRender(PMONITOR, fakeDamage, PFRAMEBUFFER);
m_bRenderingSnapshot = true;
- g_pHyprOpenGL->clear(CHyprColor(0, 0, 0, 0)); // JIC
+ draw(makeUnique<CClearPassElement>(CClearPassElement::SClearData{CHyprColor(0, 0, 0, 0)}), {});
CSurfacePassElement::SRenderData renderdata;
renderdata.pos = popup->coordsGlobal();
@@ -3287,7 +3461,7 @@ void CHyprRenderer::makeSnapshot(WP<Desktop::View::CPopup> popup) {
m_bRenderingSnapshot = false;
}
-void CHyprRenderer::renderSnapshot(PHLWINDOW pWindow) {
+void IHyprRenderer::renderSnapshot(PHLWINDOW pWindow) {
static auto PDIMAROUND = CConfigValue<Hyprlang::FLOAT>("decoration:dim_around");
PHLWINDOWREF ref{pWindow};
@@ -3334,7 +3508,7 @@ void CHyprRenderer::renderSnapshot(PHLWINDOW pWindow) {
data.roundingPower = pWindow->roundingPower();
data.xray = pWindow->m_ruleApplicator->xray().valueOr(false);
- m_renderPass.add(makeUnique<CRectPassElement>(std::move(data)));
+ m_renderPass.add(makeUnique<CRectPassElement>(data));
}
CTexPassElement::SRenderData data;
@@ -3347,7 +3521,7 @@ void CHyprRenderer::renderSnapshot(PHLWINDOW pWindow) {
m_renderPass.add(makeUnique<CTexPassElement>(std::move(data)));
}
-void CHyprRenderer::renderSnapshot(PHLLS pLayer) {
+void IHyprRenderer::renderSnapshot(PHLLS pLayer) {
if (!pLayer->m_snapshotFB)
return;
@@ -3389,7 +3563,7 @@ void CHyprRenderer::renderSnapshot(PHLLS pLayer) {
m_renderPass.add(makeUnique<CTexPassElement>(std::move(data)));
}
-void CHyprRenderer::renderSnapshot(WP<Desktop::View::CPopup> popup) {
+void IHyprRenderer::renderSnapshot(WP<Desktop::View::CPopup> popup) {
if (!popup->m_snapshotFB)
return;
@@ -3424,7 +3598,7 @@ void CHyprRenderer::renderSnapshot(WP<Desktop::View::CPopup> popup) {
m_renderPass.add(makeUnique<CTexPassElement>(std::move(data)));
}
-NColorManagement::PImageDescription CHyprRenderer::workBufferImageDescription() {
+NColorManagement::PImageDescription IHyprRenderer::workBufferImageDescription() {
// TODO
// const bool IS_MONITOR_ICC = m_renderData.pMonitor->m_imageDescription.valid() && m_renderData.pMonitor->m_imageDescription->value().icc.present;
// const auto sdrEOTF = NTransferFunction::fromConfig(IS_MONITOR_ICC);
@@ -3433,7 +3607,7 @@ NColorManagement::PImageDescription CHyprRenderer::workBufferImageDescription()
return m_renderData.pMonitor->m_imageDescription; //CImageDescription::from(NColorManagement::SImageDescription{.transferFunction = CHOSEN_SDR_EOTF});
}
-bool CHyprRenderer::shouldBlur(PHLLS ls) {
+bool IHyprRenderer::shouldBlur(PHLLS ls) {
if (m_bRenderingSnapshot)
return false;
@@ -3441,7 +3615,7 @@ bool CHyprRenderer::shouldBlur(PHLLS ls) {
return *PBLUR && ls->m_ruleApplicator->blur().valueOrDefault();
}
-bool CHyprRenderer::shouldBlur(PHLWINDOW w) {
+bool IHyprRenderer::shouldBlur(PHLWINDOW w) {
if (m_bRenderingSnapshot)
return false;
@@ -3450,115 +3624,74 @@ bool CHyprRenderer::shouldBlur(PHLWINDOW w) {
return *PBLUR && !DONT_BLUR;
}
-bool CHyprRenderer::shouldBlur(WP<Desktop::View::CPopup> p) {
+bool IHyprRenderer::shouldBlur(WP<Desktop::View::CPopup> p) {
static CConfigValue PBLURPOPUPS = CConfigValue<Hyprlang::INT>("decoration:blur:popups");
static CConfigValue PBLUR = CConfigValue<Hyprlang::INT>("decoration:blur:enabled");
return *PBLURPOPUPS && *PBLUR;
}
-bool CHyprRenderer::reloadShaders(const std::string& path) {
- return g_pHyprOpenGL->initShaders(path);
-}
-
-SP<ITexture> CHyprRenderer::createStencilTexture(const int width, const int height) {
- g_pHyprOpenGL->makeEGLCurrent();
- auto tex = makeShared<CGLTexture>();
- tex->allocate({width, height});
-
- return tex;
-}
-
-SP<ITexture> CHyprRenderer::createTexture(bool opaque) {
- g_pHyprOpenGL->makeEGLCurrent();
- return makeShared<CGLTexture>(opaque);
-}
-
-SP<ITexture> CHyprRenderer::createTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy, bool opaque) {
- g_pHyprOpenGL->makeEGLCurrent();
- return makeShared<CGLTexture>(drmFormat, pixels, stride, size, keepDataCopy, opaque);
-}
-
-SP<ITexture> CHyprRenderer::createTexture(const Aquamarine::SDMABUFAttrs& attrs, bool opaque) {
- g_pHyprOpenGL->makeEGLCurrent();
- const auto image = g_pHyprOpenGL->createEGLImage(attrs);
- if (!image)
- return nullptr;
- return makeShared<CGLTexture>(attrs, image, opaque);
-}
+SP<ITexture> IHyprRenderer::renderSplash(const std::function<SP<ITexture>(const int, const int, unsigned char* const)>& handleData, const int fontSize, const int maxWidth,
+ const int maxHeight) {
+ static auto PSPLASHCOLOR = CConfigValue<Hyprlang::INT>("misc:col.splash");
+ static auto PSPLASHFONT = CConfigValue<std::string>("misc:splash_font_family");
+ static auto FALLBACKFONT = CConfigValue<std::string>("misc:font_family");
-SP<ITexture> CHyprRenderer::createTexture(const int width, const int height, unsigned char* const data) {
- g_pHyprOpenGL->makeEGLCurrent();
- SP<ITexture> tex = makeShared<CGLTexture>();
+ const auto FONTFAMILY = *PSPLASHFONT != STRVAL_EMPTY ? *PSPLASHFONT : *FALLBACKFONT;
+ const auto COLOR = CHyprColor(*PSPLASHCOLOR);
- tex->allocate({width, height});
+ const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, maxWidth, maxHeight);
+ const auto CAIRO = cairo_create(CAIROSURFACE);
- 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;
+ cairo_set_antialias(CAIRO, CAIRO_ANTIALIAS_GOOD);
+ cairo_save(CAIRO);
+ cairo_set_source_rgba(CAIRO, 0, 0, 0, 0);
+ cairo_set_operator(CAIRO, CAIRO_OPERATOR_SOURCE);
+ cairo_paint(CAIRO);
+ cairo_restore(CAIRO);
- 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);
+ PangoLayout* layoutText = pango_cairo_create_layout(CAIRO);
+ PangoFontDescription* pangoFD = pango_font_description_new();
- glTexImage2D(GL_TEXTURE_2D, 0, glFormat, tex->m_size.x, tex->m_size.y, 0, glFormat, glType, data);
- tex->unbind();
+ pango_font_description_set_family_static(pangoFD, FONTFAMILY.c_str());
+ pango_font_description_set_absolute_size(pangoFD, fontSize * PANGO_SCALE);
+ pango_font_description_set_style(pangoFD, PANGO_STYLE_NORMAL);
+ pango_font_description_set_weight(pangoFD, PANGO_WEIGHT_NORMAL);
+ pango_layout_set_font_description(layoutText, pangoFD);
- return tex;
-}
+ cairo_set_source_rgba(CAIRO, COLOR.r, COLOR.g, COLOR.b, COLOR.a);
+ int textW = 0, textH = 0;
+ pango_layout_set_text(layoutText, g_pCompositor->m_currentSplash.c_str(), -1);
+ pango_layout_get_size(layoutText, &textW, &textH);
+ textW = std::ceil((float)textW / PANGO_SCALE + fontSize / 10.f);
+ textH = std::ceil((float)textH / PANGO_SCALE + fontSize / 10.f);
-SP<ITexture> CHyprRenderer::createTexture(cairo_surface_t* cairo) {
- g_pHyprOpenGL->makeEGLCurrent();
- const auto CAIROFORMAT = cairo_image_surface_get_format(cairo);
- auto tex = makeShared<CGLTexture>();
+ cairo_move_to(CAIRO, 0, 0);
+ pango_cairo_show_layout(CAIRO, layoutText);
- tex->allocate({cairo_image_surface_get_width(cairo), cairo_image_surface_get_height(cairo)});
+ pango_font_description_free(pangoFD);
+ g_object_unref(layoutText);
- 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;
+ cairo_surface_flush(CAIROSURFACE);
- 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);
+ const auto smallSurf = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, textW, textH);
+ const auto small = cairo_create(smallSurf);
+ cairo_set_source_surface(small, CAIROSURFACE, 0, 0);
+ cairo_rectangle(small, 0, 0, textW, textH);
+ cairo_set_operator(small, CAIRO_OPERATOR_SOURCE);
+ cairo_fill(small);
+ cairo_surface_flush(smallSurf);
- if (CAIROFORMAT != CAIRO_FORMAT_RGB96F) {
- tex->setTexParameter(GL_TEXTURE_SWIZZLE_R, GL_BLUE);
- tex->setTexParameter(GL_TEXTURE_SWIZZLE_B, GL_RED);
- }
+ auto tex = handleData(textW, textH, cairo_image_surface_get_data(smallSurf));
- glTexImage2D(GL_TEXTURE_2D, 0, glIFormat, tex->m_size.x, tex->m_size.y, 0, glFormat, glType, DATA);
+ cairo_surface_destroy(smallSurf);
+ cairo_destroy(small);
+ cairo_surface_destroy(CAIROSURFACE);
+ cairo_destroy(CAIRO);
return tex;
}
-SP<ITexture> CHyprRenderer::createTexture(std::span<const float> lut3D, size_t N) {
- g_pHyprOpenGL->makeEGLCurrent();
- return makeShared<CGLTexture>(lut3D, N);
+bool IHyprRenderer::needsACopyFB(PHLMONITOR mon) {
+ return !mon->m_mirrors.empty() || Screenshare::mgr()->isOutputBeingSSd(mon);
}
-
-SP<IFramebuffer> CHyprRenderer::createFB(const std::string& name) {
- g_pHyprOpenGL->makeEGLCurrent();
- return makeShared<CGLFramebuffer>(name);
-}
-
-bool CHyprRenderer::explicitSyncSupported() {
- return g_pHyprOpenGL->explicitSyncSupported();
-}
-
-std::vector<SDRMFormat> CHyprRenderer::getDRMFormats() {
- return g_pHyprOpenGL->getDRMFormats();
-}
-
-std::vector<uint64_t> CHyprRenderer::getDRMFormatModifiers(DRMFormat format) {
- return g_pHyprOpenGL->getDRMFormatModifiers(format);
-}
-
-SP<IRenderbuffer> CHyprRenderer::getOrCreateRenderbufferInternal(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) {
- g_pHyprOpenGL->makeEGLCurrent();
- return makeShared<CGLRenderbuffer>(buffer, fmt);
-} \ No newline at end of file
diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp
index 441a603c..1d099ee3 100644
--- a/src/render/Renderer.hpp
+++ b/src/render/Renderer.hpp
@@ -109,12 +109,6 @@ struct SRenderData {
// TODO remove and pass directly
CBox clipBox = {}; // scaled coordinates
- CRegion clipRegion;
-
- uint32_t discardMode = DISCARD_OPAQUE;
- float discardOpacity = 0.f;
-
- PHLLSREF currentLS;
PHLWINDOWREF currentWindow;
WP<CWLSurfaceResource> surface;
@@ -145,10 +139,10 @@ struct SCMSettings {
float sdrBrightnessMultiplier = 1.0;
};
-class CHyprRenderer {
+class IHyprRenderer {
public:
- CHyprRenderer();
- ~CHyprRenderer();
+ IHyprRenderer();
+ virtual ~IHyprRenderer();
WP<CHyprOpenGLImpl> glBackend();
@@ -168,49 +162,45 @@ class CHyprRenderer {
void setCursorHidden(bool hide);
void calculateUVForSurface(PHLWINDOW, SP<CWLSurfaceResource>, PHLMONITOR pMonitor, bool main = false, const Vector2D& projSize = {}, const Vector2D& projSizeUnscaled = {},
bool fixMisalignedFSV1 = false);
- std::tuple<float, float, float> getRenderTimes(PHLMONITOR pMonitor); // avg max min
- void ensureLockTexturesRendered(bool load);
- void renderLockscreen(PHLMONITOR pMonitor, const Time::steady_tp& now, const CBox& geometry);
- void setCursorSurface(SP<Desktop::View::CWLSurface> surf, int hotspotX, int hotspotY, bool force = false);
- void setCursorFromName(const std::string& name, bool force = false);
- void onRenderbufferDestroy(IRenderbuffer* rb);
- SP<IRenderbuffer> getCurrentRBO();
- bool isNvidia();
- bool isIntel();
- bool isSoftware();
- bool isMgpu();
- void addWindowToRenderUnfocused(PHLWINDOW window);
- void makeSnapshot(PHLWINDOW);
- void makeSnapshot(PHLLS);
- void makeSnapshot(WP<Desktop::View::CPopup>);
- void renderSnapshot(PHLWINDOW);
- void renderSnapshot(PHLLS);
- void renderSnapshot(WP<Desktop::View::CPopup>);
-
- //
- NColorManagement::PImageDescription workBufferImageDescription();
-
- // 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<IHLBuffer> buffer = {}, SP<IFramebuffer> fb = nullptr, bool simple = false);
- void endRender(const std::function<void()>& renderingDoneCallback = {});
+ std::tuple<float, float, float> getRenderTimes(PHLMONITOR pMonitor); // avg max min
+ void ensureLockTexturesRendered(bool load);
+ void renderLockscreen(PHLMONITOR pMonitor, const Time::steady_tp& now, const CBox& geometry);
+ void setCursorSurface(SP<Desktop::View::CWLSurface> surf, int hotspotX, int hotspotY, bool force = false);
+ void setCursorFromName(const std::string& name, bool force = false);
+ void onRenderbufferDestroy(IRenderbuffer* rb);
+ bool isNvidia();
+ bool isIntel();
+ bool isSoftware();
+ bool isMgpu();
+ void addWindowToRenderUnfocused(PHLWINDOW window);
+ void makeSnapshot(PHLWINDOW);
+ void makeSnapshot(PHLLS);
+ void makeSnapshot(WP<Desktop::View::CPopup>);
+ void renderSnapshot(PHLWINDOW);
+ void renderSnapshot(PHLLS);
+ void renderSnapshot(WP<Desktop::View::CPopup>);
+ bool beginFullFakeRender(PHLMONITOR pMonitor, CRegion& damage, SP<IFramebuffer> fb);
+ bool beginRenderToBuffer(PHLMONITOR pMonitor, CRegion& damage, SP<IHLBuffer> buffer, bool simple = false);
+ virtual void startRenderPass() {};
+ virtual void endRender(const std::function<void()>& renderingDoneCallback = {}) = 0;
- bool m_bBlockSurfaceFeedback = false;
- bool m_bRenderingSnapshot = false;
- PHLMONITORREF m_mostHzMonitor;
- bool m_directScanoutBlocked = false;
+ NColorManagement::PImageDescription workBufferImageDescription();
+ bool m_bBlockSurfaceFeedback = false;
+ bool m_bRenderingSnapshot = false;
+ PHLMONITORREF m_mostHzMonitor;
+ bool m_directScanoutBlocked = false;
- void setSurfaceScanoutMode(SP<CWLSurfaceResource> surface, PHLMONITOR monitor); // nullptr monitor resets
+ void setSurfaceScanoutMode(SP<CWLSurfaceResource> surface, PHLMONITOR monitor); // nullptr monitor resets
- void initiateManualCrash();
- const SRenderData& renderData();
+ void initiateManualCrash();
+ const SRenderData& renderData();
- bool m_crashingInProgress = false;
- float m_crashingDistort = 0.5f;
- wl_event_source* m_crashingLoop = nullptr;
- wl_event_source* m_cursorTicker = nullptr;
+ bool m_crashingInProgress = false;
+ float m_crashingDistort = 0.5f;
+ wl_event_source* m_crashingLoop = nullptr;
+ wl_event_source* m_cursorTicker = nullptr;
- std::vector<CHLBufferReference> m_usedAsyncBuffers;
+ std::vector<CHLBufferReference> m_usedAsyncBuffers;
struct {
int hotspotX = 0;
@@ -222,62 +212,97 @@ class CHyprRenderer {
std::string name;
} m_lastCursorData;
- CRenderPass m_renderPass = {};
-
- SP<IRenderbuffer> getOrCreateRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t fmt); // TODO? move to protected and fix CPointerManager::renderHWCursorBuffer
- SRenderData m_renderData; // TODO? move to protected and fix CRenderPass
- SP<ITexture> m_screencopyDeniedTexture; // TODO? make readonly
- uint m_failedAssetsNo = 0; // TODO? make readonly
- bool m_reloadScreenShader = true; // at launch it can be set
- CTimer m_globalTimer;
-
- SP<ITexture> createStencilTexture(const int width, const int height);
- SP<ITexture> createTexture(bool opaque = false);
- SP<ITexture> createTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false, bool opaque = false);
- SP<ITexture> createTexture(const Aquamarine::SDMABUFAttrs&, bool opaque = false);
- SP<ITexture> createTexture(const int width, const int height, unsigned char* const);
- SP<ITexture> createTexture(cairo_surface_t* cairo);
- SP<ITexture> createTexture(const SP<Aquamarine::IBuffer> buffer, bool keepDataCopy = false);
- SP<ITexture> createTexture(std::span<const float> lut3D, size_t N);
- SP<ITexture> renderText(const std::string& text, CHyprColor col, int pt, bool italic = false, const std::string& fontFamily = "", int maxWidth = 0, int weight = 400);
- SP<ITexture> loadAsset(const std::string& filename);
- bool shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindow);
- bool explicitSyncSupported();
- std::vector<SDRMFormat> getDRMFormats();
- std::vector<uint64_t> getDRMFormatModifiers(DRMFormat format);
- SP<IFramebuffer> createFB(const std::string& name = "");
- void pushMonitorTransformEnabled(bool enabled);
- void popMonitorTransformEnabled();
- bool monitorTransformEnabled();
-
- void setProjectionType(const Vector2D& fbSize);
- void setProjectionType(eRenderProjectionType projectionType);
- Mat3x3 getBoxProjection(const CBox& box, std::optional<eTransform> transform = std::nullopt);
- Mat3x3 projectBoxToTarget(const CBox& box, std::optional<eTransform> transform = std::nullopt);
-
- SCMSettings getCMSettings(const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
- SP<CWLSurfaceResource> surface = nullptr, bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1);
- bool reloadShaders(const std::string& path = "");
-
- void draw(CBorderPassElement* element, const CRegion& damage);
- void draw(CClearPassElement* element, const CRegion& damage);
- void draw(CFramebufferElement* element, const CRegion& damage);
- void draw(CPreBlurElement* element, const CRegion& damage);
- void draw(CRectPassElement* element, const CRegion& damage);
- void draw(CRendererHintsPassElement* element, const CRegion& damage);
- void draw(CShadowPassElement* element, const CRegion& damage);
- void draw(CSurfacePassElement* element, const CRegion& damage);
- void draw(CTexPassElement* element, const CRegion& damage);
- void draw(CTextureMatteElement* element, const CRegion& damage);
- void draw(WP<IPassElement> element, const CRegion& damage);
-
- SP<ITexture> m_lockDeadTexture;
- SP<ITexture> m_lockDead2Texture;
- SP<ITexture> m_lockTtyTextTexture;
- bool m_monitorTransformEnabled = false; // do not modify directly
- std::stack<bool> m_monitorTransformStack;
+ CRenderPass m_renderPass;
+
+ SP<ITexture> renderSplash(const std::function<SP<ITexture>(const int, const int, unsigned char* const)>& handleData, const int fontSize, const int maxWidth = 1024,
+ const int maxHeight = 1024);
+
+ virtual SP<IRenderbuffer> getOrCreateRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t fmt); // TODO? move to protected and fix CPointerManager::renderHWCursorBuffer
+ bool commitPendingAndDoExplicitSync(PHLMONITOR pMonitor); // TODO? move to protected and fix CMonitorFrameScheduler::onPresented
+ SRenderData m_renderData; // TODO? move to protected and fix CRenderPass
+ SP<ITexture> m_screencopyDeniedTexture; // TODO? make readonly
+ uint m_failedAssetsNo = 0; // TODO? make readonly
+ bool m_reloadScreenShader = true; // at launch it can be set
+ CTimer m_globalTimer;
+
+ void draw(WP<IPassElement> element, const CRegion& damage);
+ virtual SP<ITexture> createStencilTexture(const int width, const int height) = 0;
+ virtual SP<ITexture> createTexture(bool opaque = false) = 0;
+ virtual SP<ITexture> createTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false, bool opaque = false) = 0;
+ virtual SP<ITexture> createTexture(const Aquamarine::SDMABUFAttrs&, bool opaque = false) = 0;
+ virtual SP<ITexture> createTexture(const int width, const int height, unsigned char* const) = 0;
+ virtual SP<ITexture> createTexture(cairo_surface_t* cairo) = 0;
+ virtual SP<ITexture> createTexture(std::span<const float> lut3D, size_t N) = 0;
+ virtual SP<ITexture> createTexture(const SP<Aquamarine::IBuffer> buffer, bool keepDataCopy = false);
+ virtual SP<ITexture> renderText(const std::string& text, CHyprColor col, int pt, bool italic = false, const std::string& fontFamily = "", int maxWidth = 0, int weight = 400);
+ SP<ITexture> loadAsset(const std::string& filename);
+ virtual bool shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindow);
+ virtual bool explicitSyncSupported() = 0;
+ virtual std::vector<SDRMFormat> getDRMFormats() = 0;
+ virtual std::vector<uint64_t> getDRMFormatModifiers(DRMFormat format) = 0;
+ virtual SP<IFramebuffer> createFB(const std::string& name = "") = 0;
+ virtual void disableScissor() = 0;
+ virtual void blend(bool enabled) = 0;
+ virtual void drawShadow(const CBox& box, int round, float roundingPower, int range, CHyprColor color, float a) = 0;
+ virtual void setViewport(int x, int y, int width, int height) = 0;
+
+ bool preBlurQueued(PHLMONITORREF pMonitor);
+ void pushMonitorTransformEnabled(bool enabled);
+ void popMonitorTransformEnabled();
+ bool monitorTransformEnabled();
+
+ void setProjectionType(const Vector2D& fbSize);
+ void setProjectionType(eRenderProjectionType projectionType);
+ Mat3x3 getBoxProjection(const CBox& box, std::optional<eTransform> transform = std::nullopt);
+ Mat3x3 projectBoxToTarget(const CBox& box, std::optional<eTransform> transform = std::nullopt);
+
+ SP<ITexture> blurMainFramebuffer(float a, CRegion* originalDamage);
+ virtual SP<ITexture> blurFramebuffer(SP<IFramebuffer> source, float a, CRegion* originalDamage) = 0;
+ void preBlurForCurrentMonitor(CRegion* fakeDamage);
+
+ SCMSettings getCMSettings(const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
+ SP<CWLSurfaceResource> surface = nullptr, bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1);
+ virtual bool reloadShaders(const std::string& path = "") = 0;
+
+ bool needsACopyFB(PHLMONITOR mon);
+
+ protected:
+ virtual void renderOffToMain(IFramebuffer* off) = 0;
+ virtual SP<IRenderbuffer> getOrCreateRenderbufferInternal(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) = 0;
+ void renderMirrored();
+ void setDamage(const CRegion& damage_, std::optional<CRegion> finalDamage);
+ // 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<IHLBuffer> buffer = {}, SP<IFramebuffer> fb = nullptr, bool simple = false);
- private:
+ virtual bool beginRenderInternal(PHLMONITOR pMonitor, CRegion& damage, bool simple = false) {
+ return false;
+ };
+ virtual bool beginFullFakeRenderInternal(PHLMONITOR pMonitor, CRegion& damage, SP<IFramebuffer> fb, bool simple = false) {
+ return false;
+ };
+ virtual void initRender() {};
+ virtual bool initRenderBuffer(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) {
+ return false;
+ };
+
+ SP<ITexture> getBackground(PHLMONITOR pMonitor);
+ virtual void draw(CBorderPassElement* element, const CRegion& damage) = 0;
+ virtual void draw(CClearPassElement* element, const CRegion& damage) = 0;
+ virtual void draw(CFramebufferElement* element, const CRegion& damage) = 0;
+ virtual void draw(CPreBlurElement* element, const CRegion& damage) = 0;
+ virtual void draw(CRectPassElement* element, const CRegion& damage) = 0;
+ virtual void draw(CShadowPassElement* element, const CRegion& damage) = 0;
+ virtual void draw(CTexPassElement* element, const CRegion& damage) = 0;
+ virtual void draw(CTextureMatteElement* element, const CRegion& damage) = 0;
+ virtual SP<ITexture> getBlurTexture(PHLMONITORREF pMonitor);
+ SP<ITexture> m_lockDeadTexture;
+ SP<ITexture> m_lockDead2Texture;
+ SP<ITexture> m_lockTtyTextTexture;
+ bool m_monitorTransformEnabled = false; // do not modify directly
+ std::stack<bool> m_monitorTransformStack;
+
+ // old private:
void arrangeLayerArray(PHLMONITOR, const std::vector<PHLLSREF>&, bool, CBox*);
void renderWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now, const CBox& geometry);
void renderWorkspaceWindowsFullscreen(PHLMONITOR, PHLWORKSPACE, const Time::steady_tp&); // renders workspace windows (fullscreen) (tiled, floating, pinned, but no special)
@@ -292,12 +317,7 @@ class CHyprRenderer {
void renderSessionLockPrimer(PHLMONITOR pMonitor);
void renderSessionLockMissing(PHLMONITOR pMonitor);
void renderBackground(PHLMONITOR pMonitor);
-
- bool commitPendingAndDoExplicitSync(PHLMONITOR pMonitor);
-
void requestBackgroundResource();
- //
- SP<IRenderbuffer> getOrCreateRenderbufferInternal(SP<Aquamarine::IBuffer> buffer, uint32_t fmt);
std::string resolveAssetPath(const std::string& file);
void initMissingAssetTexture();
void initAssets();
@@ -312,7 +332,6 @@ class CHyprRenderer {
bool m_cursorHidden = false;
bool m_cursorHiddenByCondition = false;
bool m_cursorHasSurface = false;
- SP<IRenderbuffer> m_currentRenderbuffer = nullptr;
SP<Aquamarine::IBuffer> m_currentBuffer = nullptr;
eRenderMode m_renderMode = RENDER_MODE_NORMAL;
bool m_nvidia = false;
@@ -339,6 +358,18 @@ class CHyprRenderer {
friend class CPointerManager;
friend class CMonitor;
friend class CMonitorFrameScheduler;
+
+ private:
+ void bindOffMain();
+ void bindBackOnMain();
+
+ void drawRect(CRectPassElement* element, const CRegion& damage);
+ void drawHints(CRendererHintsPassElement* element, const CRegion& damage);
+ void drawPreBlur(CPreBlurElement* element, const CRegion& damage);
+ void drawSurface(CSurfacePassElement* element, const CRegion& damage);
+ void preDrawSurface(CSurfacePassElement* element, const CRegion& damage);
+ void drawTex(CTexPassElement* element, const CRegion& damage);
+ void drawTexMatte(CTextureMatteElement* element, const CRegion& damage);
};
-inline UP<CHyprRenderer> g_pHyprRenderer;
+inline UP<IHyprRenderer> g_pHyprRenderer;
diff --git a/src/render/decorations/CHyprBorderDecoration.cpp b/src/render/decorations/CHyprBorderDecoration.cpp
index 64dde4ff..2785a956 100644
--- a/src/render/decorations/CHyprBorderDecoration.cpp
+++ b/src/render/decorations/CHyprBorderDecoration.cpp
@@ -84,6 +84,7 @@ void CHyprBorderDecoration::draw(PHLMONITOR pMonitor, float const& a) {
data.roundingPower = ROUNDINGPOWER;
data.a = a;
data.borderSize = borderSize;
+ data.window = m_window;
if (ANIMATED) {
data.hasGrad2 = true;
diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp
index 69caa2cd..000e1d0f 100644
--- a/src/render/decorations/CHyprDropShadowDecoration.cpp
+++ b/src/render/decorations/CHyprDropShadowDecoration.cpp
@@ -4,6 +4,7 @@
#include "../../config/ConfigValue.hpp"
#include "../pass/ShadowPassElement.hpp"
#include "../Renderer.hpp"
+#include "render/pass/TextureMatteElement.hpp"
CHyprDropShadowDecoration::CHyprDropShadowDecoration(PHLWINDOW pWindow) : IHyprWindowDecoration(pWindow), m_window(pWindow) {
;
@@ -95,37 +96,46 @@ void CHyprDropShadowDecoration::draw(PHLMONITOR pMonitor, float const& a) {
g_pHyprRenderer->m_renderPass.add(makeUnique<CShadowPassElement>(data));
}
-void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) {
+bool CHyprDropShadowDecoration::canRender(PHLMONITOR pMonitor) {
+ static auto PSHADOWS = CConfigValue<Hyprlang::INT>("decoration:shadow:enabled");
+ if (*PSHADOWS != 1)
+ return false; // disabled
+
const auto PWINDOW = m_window.lock();
if (!validMapped(PWINDOW))
- return;
+ return false;
if (PWINDOW->m_realShadowColor->value() == CHyprColor(0, 0, 0, 0))
- return; // don't draw invisible shadows
+ return false; // don't draw invisible shadows
if (!PWINDOW->m_ruleApplicator->decorate().valueOrDefault())
- return;
+ return false;
if (PWINDOW->m_ruleApplicator->noShadow().valueOrDefault())
- return;
+ return false;
+
+ return true;
+}
+
+SShadowRenderData CHyprDropShadowDecoration::getRenderData(PHLMONITOR pMonitor, float const& a) {
+ if (!canRender(pMonitor))
+ return {};
+
+ const auto PWINDOW = m_window.lock();
- static auto PSHADOWS = CConfigValue<Hyprlang::INT>("decoration:shadow:enabled");
static auto PSHADOWSIZE = CConfigValue<Hyprlang::INT>("decoration:shadow:range");
static auto PSHADOWIGNOREWINDOW = CConfigValue<Hyprlang::INT>("decoration:shadow:ignore_window");
static auto PSHADOWSCALE = CConfigValue<Hyprlang::FLOAT>("decoration:shadow:scale");
static auto PSHADOWOFFSET = CConfigValue<Hyprlang::VEC2>("decoration:shadow:offset");
- if (*PSHADOWS != 1)
- return; // disabled
-
- const auto BORDERSIZE = PWINDOW->getRealBorderSize();
- const auto ROUNDINGBASE = PWINDOW->rounding();
- const auto ROUNDINGPOWER = PWINDOW->roundingPower();
- const auto CORRECTIONOFFSET = (BORDERSIZE * (M_SQRT2 - 1) * std::max(2.0 - ROUNDINGPOWER, 0.0));
- const auto ROUNDING = ROUNDINGBASE > 0 ? (ROUNDINGBASE + BORDERSIZE) - CORRECTIONOFFSET : 0;
- const auto PWORKSPACE = PWINDOW->m_workspace;
- const auto WORKSPACEOFFSET = PWORKSPACE && !PWINDOW->m_pinned ? PWORKSPACE->m_renderOffset->value() : Vector2D();
+ const auto BORDERSIZE = PWINDOW->getRealBorderSize();
+ const auto ROUNDINGBASE = PWINDOW->rounding();
+ const auto ROUNDINGPOWER = PWINDOW->roundingPower();
+ const auto CORRECTIONOFFSET = (BORDERSIZE * (M_SQRT2 - 1) * std::max(2.0 - ROUNDINGPOWER, 0.0));
+ const auto ROUNDING = ROUNDINGBASE > 0 ? (ROUNDINGBASE + BORDERSIZE) - CORRECTIONOFFSET : 0;
+ const auto PWORKSPACE = PWINDOW->m_workspace;
+ const auto WORKSPACEOFFSET = PWORKSPACE && !PWINDOW->m_pinned ? PWORKSPACE->m_renderOffset->value() : Vector2D();
// draw the shadow
CBox fullBox = m_lastWindowBoxWithDecos;
@@ -142,27 +152,31 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) {
updateWindow(PWINDOW);
m_lastWindowPos += WORKSPACEOFFSET;
- m_extents = {{m_lastWindowPos.x - fullBox.x - pMonitor->m_position.x + 2, m_lastWindowPos.y - fullBox.y - pMonitor->m_position.y + 2},
- {fullBox.x + fullBox.width + pMonitor->m_position.x - m_lastWindowPos.x - m_lastWindowSize.x + 2,
- fullBox.y + fullBox.height + pMonitor->m_position.y - m_lastWindowPos.y - m_lastWindowSize.y + 2}};
+ m_extents = {
+ .topLeft =
+ {
+ m_lastWindowPos.x - fullBox.x - pMonitor->m_position.x + 2,
+ m_lastWindowPos.y - fullBox.y - pMonitor->m_position.y + 2,
+ },
+ .bottomRight =
+ {
+ fullBox.x + fullBox.width + pMonitor->m_position.x - m_lastWindowPos.x - m_lastWindowSize.x + 2,
+ fullBox.y + fullBox.height + pMonitor->m_position.y - m_lastWindowPos.y - m_lastWindowSize.y + 2,
+ },
+ };
fullBox.translate(PWINDOW->m_floatingOffset);
if (fullBox.width < 1 || fullBox.height < 1)
- return; // don't draw invisible shadows
+ return {}; // don't draw invisible shadows
- g_pHyprOpenGL->scissor(nullptr);
g_pHyprRenderer->m_renderData.currentWindow = m_window;
- // we'll take the liberty of using this as it should not be used rn
- auto alphaFB = g_pHyprRenderer->m_renderData.pMonitor->m_mirrorFB;
- auto alphaSwapFB = g_pHyprRenderer->m_renderData.pMonitor->m_mirrorSwapFB;
- auto LASTFB = g_pHyprRenderer->m_renderData.currentFB;
-
+ CBox windowBox;
+ CRegion saveDamage;
fullBox.scale(pMonitor->m_scale).round();
-
if (*PSHADOWIGNOREWINDOW) {
- CBox windowBox = m_lastWindowBox;
+ windowBox = m_lastWindowBox;
CBox withDecos = m_lastWindowBoxWithDecos;
// get window box
@@ -180,51 +194,98 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) {
windowBox.scale(pMonitor->m_scale).round().addExtents(scaledExtentss);
if (windowBox.width < 1 || windowBox.height < 1)
- return; // prevent assert failed
+ return {}; // prevent assert failed
- CRegion saveDamage = g_pHyprRenderer->m_renderData.damage;
+ saveDamage = g_pHyprRenderer->m_renderData.damage;
g_pHyprRenderer->m_renderData.damage = fullBox;
g_pHyprRenderer->m_renderData.damage.subtract(windowBox.copy().expand(-ROUNDING * pMonitor->m_scale)).intersect(saveDamage);
g_pHyprRenderer->m_renderData.renderModif.applyToRegion(g_pHyprRenderer->m_renderData.damage);
+ }
+
+ return {
+ .ignoreWindow = *PSHADOWIGNOREWINDOW,
+ .valid = true,
+ .fullBox = fullBox,
+ .windowBox = windowBox,
+ .saveDamage = saveDamage,
+ .rounding = ROUNDING,
+ .roundingPower = ROUNDINGPOWER,
+ .size = *PSHADOWSIZE,
+ };
+}
+
+void CHyprDropShadowDecoration::reposition() {
+ if (m_extents != m_reportedExtents)
+ g_pDecorationPositioner->repositionDeco(this);
+
+ g_pHyprRenderer->m_renderData.currentWindow.reset();
+}
+
+// TODO remove
+void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) {
+ auto data = getRenderData(pMonitor, a);
+ if (!data.valid)
+ return;
+
+ const auto PWINDOW = m_window.lock();
+
+ g_pHyprRenderer->disableScissor();
+
+ if (data.ignoreWindow) {
+ // we'll take the liberty of using this as it should not be used rn
+ const auto alphaFB = g_pHyprRenderer->m_renderData.pMonitor->m_mirrorFB;
+ const auto alphaSwapFB = g_pHyprRenderer->m_renderData.pMonitor->m_mirrorSwapFB;
+ const auto LASTFB = g_pHyprRenderer->m_renderData.currentFB;
+
+ CBox monbox = {0, 0, pMonitor->m_transformedSize.x, pMonitor->m_transformedSize.y};
alphaFB->bind();
// build the matte
// 10-bit formats have dogshit alpha channels, so we have to use the matte to its fullest.
// first, clear region of interest with black (fully transparent)
- g_pHyprOpenGL->renderRect(fullBox, CHyprColor(0, 0, 0, 1), {.round = 0});
+ g_pHyprRenderer->draw(makeUnique<CRectPassElement>(CRectPassElement::SRectData{.box = data.fullBox, .color = CHyprColor(0, 0, 0, 1), .round = 0}), monbox);
// render white shadow with the alpha of the shadow color (otherwise we clear with alpha later and shit it to 2 bit)
- drawShadowInternal(fullBox, ROUNDING * pMonitor->m_scale, ROUNDINGPOWER, *PSHADOWSIZE * pMonitor->m_scale, CHyprColor(1, 1, 1, PWINDOW->m_realShadowColor->value().a), a);
+ drawShadowInternal(data.fullBox, data.rounding * pMonitor->m_scale, data.roundingPower, data.size * pMonitor->m_scale,
+ CHyprColor(1, 1, 1, PWINDOW->m_realShadowColor->value().a), a);
// render black window box ("clip")
- g_pHyprOpenGL->renderRect(windowBox, CHyprColor(0, 0, 0, 1.0),
- {.round = (ROUNDING + 1 /* This fixes small pixel gaps. */) * pMonitor->m_scale, .roundingPower = ROUNDINGPOWER});
+ g_pHyprRenderer->draw(makeUnique<CRectPassElement>(CRectPassElement::SRectData{
+ .box = data.windowBox,
+ .color = CHyprColor(0, 0, 0, 1),
+ .round = (data.rounding + 1 /* This fixes small pixel gaps. */) * pMonitor->m_scale,
+ .roundingPower = data.roundingPower,
+ }),
+ monbox);
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});
+ g_pHyprRenderer->draw(makeUnique<CRectPassElement>(CRectPassElement::SRectData{.box = data.fullBox, .color = PWINDOW->m_realShadowColor->value().stripA(), .round = 0}),
+ monbox);
LASTFB->bind();
- CBox monbox = {0, 0, pMonitor->m_transformedSize.x, pMonitor->m_transformedSize.y};
-
g_pHyprRenderer->pushMonitorTransformEnabled(true);
- g_pHyprOpenGL->setRenderModifEnabled(false);
- g_pHyprOpenGL->renderTextureMatte(alphaSwapFB->getTexture(), monbox, alphaFB);
- g_pHyprOpenGL->setRenderModifEnabled(true);
+ g_pHyprRenderer->m_renderData.renderModif.enabled = false;
+
+ g_pHyprRenderer->draw(makeUnique<CTextureMatteElement>(CTextureMatteElement::STextureMatteData{
+ .box = monbox,
+ .tex = alphaSwapFB->getTexture(),
+ .fb = alphaFB,
+ }),
+ {});
+
+ g_pHyprRenderer->m_renderData.renderModif.enabled = true;
g_pHyprRenderer->popMonitorTransformEnabled();
- g_pHyprRenderer->m_renderData.damage = saveDamage;
+ g_pHyprRenderer->m_renderData.damage = data.saveDamage;
} else
- drawShadowInternal(fullBox, ROUNDING * pMonitor->m_scale, ROUNDINGPOWER, *PSHADOWSIZE * pMonitor->m_scale, PWINDOW->m_realShadowColor->value(), a);
+ drawShadowInternal(data.fullBox, data.rounding * pMonitor->m_scale, data.roundingPower, data.size * pMonitor->m_scale, PWINDOW->m_realShadowColor->value(), a);
- if (m_extents != m_reportedExtents)
- g_pDecorationPositioner->repositionDeco(this);
-
- g_pHyprRenderer->m_renderData.currentWindow.reset();
+ reposition();
}
eDecorationLayer CHyprDropShadowDecoration::getDecorationLayer() {
@@ -237,12 +298,18 @@ void CHyprDropShadowDecoration::drawShadowInternal(const CBox& box, int round, f
if (box.w < 1 || box.h < 1)
return;
- g_pHyprOpenGL->blend(true);
+ g_pHyprRenderer->blend(true);
color.a *= a;
if (*PSHADOWSHARP)
- g_pHyprOpenGL->renderRect(box, color, {.round = round, .roundingPower = roundingPower});
+ g_pHyprRenderer->draw(makeUnique<CRectPassElement>(CRectPassElement::SRectData{
+ .box = box,
+ .color = color,
+ .round = round,
+ .roundingPower = roundingPower,
+ }),
+ {});
else
- g_pHyprOpenGL->renderRoundedShadow(box, round, roundingPower, range, color, 1.F);
+ g_pHyprRenderer->drawShadow(box, round, roundingPower, range, color, 1.F);
}
diff --git a/src/render/decorations/CHyprDropShadowDecoration.hpp b/src/render/decorations/CHyprDropShadowDecoration.hpp
index 22887a52..d8a01edb 100644
--- a/src/render/decorations/CHyprDropShadowDecoration.hpp
+++ b/src/render/decorations/CHyprDropShadowDecoration.hpp
@@ -2,6 +2,17 @@
#include "IHyprWindowDecoration.hpp"
+struct SShadowRenderData {
+ bool ignoreWindow = false;
+ bool valid = false;
+ CBox fullBox;
+ CBox windowBox;
+ CRegion saveDamage;
+ float rounding = 0;
+ float roundingPower = 0;
+ int size = 0;
+};
+
class CHyprDropShadowDecoration : public IHyprWindowDecoration {
public:
CHyprDropShadowDecoration(PHLWINDOW);
@@ -25,7 +36,12 @@ class CHyprDropShadowDecoration : public IHyprWindowDecoration {
virtual std::string getDisplayName();
- void render(PHLMONITOR, float const& a);
+ bool canRender(PHLMONITOR);
+ SShadowRenderData getRenderData(PHLMONITOR, float const& a);
+ void reposition();
+
+ // TODO remove
+ void render(PHLMONITOR, float const& a);
private:
SBoxExtents m_extents;
diff --git a/src/render/gl/GLFramebuffer.cpp b/src/render/gl/GLFramebuffer.cpp
index f3952556..27ad4a1b 100644
--- a/src/render/gl/GLFramebuffer.cpp
+++ b/src/render/gl/GLFramebuffer.cpp
@@ -2,7 +2,7 @@
#include "../OpenGL.hpp"
#include "../Renderer.hpp"
#include "macros.hpp"
-#include "render/Framebuffer.hpp"
+#include "../Framebuffer.hpp"
CGLFramebuffer::CGLFramebuffer() : IFramebuffer() {}
CGLFramebuffer::CGLFramebuffer(const std::string& name) : IFramebuffer(name) {}
@@ -71,9 +71,10 @@ void CGLFramebuffer::addStencil(SP<ITexture> tex) {
void CGLFramebuffer::bind() {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fb);
- if (g_pHyprOpenGL)
- g_pHyprOpenGL->setViewport(0, 0, g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.x, g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.y);
- else
+ if (g_pHyprOpenGL) {
+ const auto& size = g_pHyprRenderer->m_renderData.pMonitor ? g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize : m_size;
+ g_pHyprOpenGL->setViewport(0, 0, size.x, size.y);
+ } else
glViewport(0, 0, m_size.x, m_size.y);
}
diff --git a/src/render/pass/BorderPassElement.hpp b/src/render/pass/BorderPassElement.hpp
index 1a458fd5..6513b74a 100644
--- a/src/render/pass/BorderPassElement.hpp
+++ b/src/render/pass/BorderPassElement.hpp
@@ -13,6 +13,7 @@ class CBorderPassElement : public IPassElement {
float lerp = 0.F, a = 1.F;
int round = 0, borderSize = 1, outerRound = -1;
float roundingPower = 2.F;
+ PHLWINDOWREF window;
};
CBorderPassElement(const SBorderData& data_);
diff --git a/src/render/pass/Pass.cpp b/src/render/pass/Pass.cpp
index 901b4770..b7923a66 100644
--- a/src/render/pass/Pass.cpp
+++ b/src/render/pass/Pass.cpp
@@ -213,9 +213,15 @@ void CRenderPass::renderDebugData() {
const auto pMonitor = g_pHyprRenderer->m_renderData.pMonitor;
CBox box = {{}, pMonitor->m_transformedSize};
for (const auto& rg : m_occludedRegions) {
- g_pHyprOpenGL->renderRect(box, Colors::RED.modifyA(0.1F), {.damage = &rg});
+ CRectPassElement::SRectData data;
+ data.box = box;
+ data.color = Colors::RED.modifyA(0.1F);
+ g_pHyprRenderer->draw(makeUnique<CRectPassElement>(data), rg);
}
- g_pHyprOpenGL->renderRect(box, Colors::GREEN.modifyA(0.1F), {.damage = &m_totalLiveBlurRegion});
+ CRectPassElement::SRectData data;
+ data.box = box;
+ data.color = Colors::GREEN.modifyA(0.1F);
+ g_pHyprRenderer->draw(makeUnique<CRectPassElement>(data), m_totalLiveBlurRegion);
std::unordered_map<CWLSurfaceResource*, float> offsets;
@@ -238,9 +244,12 @@ void CRenderPass::renderDebugData() {
if (box.intersection(CBox{{}, pMonitor->m_size}).empty())
return;
- static const auto FULL_REGION = CRegion{0, 0, INT32_MAX, INT32_MAX};
+ static const auto FULL_REGION = CRegion{0, 0, INT32_MAX, INT32_MAX};
- g_pHyprOpenGL->renderRect(box, color, {.damage = &FULL_REGION});
+ CRectPassElement::SRectData data;
+ data.box = box;
+ data.color = color;
+ g_pHyprRenderer->draw(makeUnique<CRectPassElement>(data), FULL_REGION);
if (offsets.contains(surface.get()))
box.translate(Vector2D{0.F, offsets[surface.get()]});
@@ -248,8 +257,16 @@ void CRenderPass::renderDebugData() {
offsets[surface.get()] = 0;
box = {box.pos(), texture->m_size};
- g_pHyprOpenGL->renderRect(box, CHyprColor{0.F, 0.F, 0.F, 0.2F}, {.damage = &FULL_REGION, .round = std::min(5.0, box.size().y)});
- g_pHyprOpenGL->renderTexture(texture, box, {});
+ CRectPassElement::SRectData data2;
+ data.box = box;
+ data.color = color;
+ data.round = std::min(5.0, box.size().y);
+ g_pHyprRenderer->draw(makeUnique<CRectPassElement>(data2), FULL_REGION);
+
+ CTexPassElement::SRenderData texData;
+ texData.tex = texture;
+ texData.box = box;
+ g_pHyprRenderer->draw(makeUnique<CTexPassElement>(texData), {});
offsets[surface.get()] += texture->m_size.y;
};
@@ -267,7 +284,10 @@ void CRenderPass::renderDebugData() {
auto BOX = hlSurface->getSurfaceBoxGlobal();
if (BOX) {
auto region = g_pSeatManager->m_state.pointerFocus->m_current.input.copy().scale(pMonitor->m_scale).translate(BOX->pos() - pMonitor->m_position);
- g_pHyprOpenGL->renderRect(box, CHyprColor{0.8F, 0.8F, 0.2F, 0.4F}, {.damage = &region});
+ CRectPassElement::SRectData data;
+ data.box = box;
+ data.color = CHyprColor{0.8F, 0.8F, 0.2F, 0.4F};
+ g_pHyprRenderer->draw(makeUnique<CRectPassElement>(data), region);
}
}
}
@@ -280,7 +300,10 @@ void CRenderPass::renderDebugData() {
if (tex) {
box = CBox{{0.F, pMonitor->m_size.y - tex->m_size.y}, tex->m_size}.scale(pMonitor->m_scale);
- g_pHyprOpenGL->renderTexture(tex, box, {});
+ CTexPassElement::SRenderData texData;
+ texData.tex = tex;
+ texData.box = box;
+ g_pHyprRenderer->draw(makeUnique<CTexPassElement>(texData), {});
}
std::string passStructure;
@@ -297,7 +320,10 @@ void CRenderPass::renderDebugData() {
tex = g_pHyprRenderer->renderText(passStructure, Colors::WHITE, 12);
if (tex) {
box = CBox{{pMonitor->m_size.x - tex->m_size.x, pMonitor->m_size.y - tex->m_size.y}, tex->m_size}.scale(pMonitor->m_scale);
- g_pHyprOpenGL->renderTexture(tex, box, {});
+ CTexPassElement::SRenderData texData;
+ texData.tex = tex;
+ texData.box = box;
+ g_pHyprRenderer->draw(makeUnique<CTexPassElement>(texData), {});
}
}
diff --git a/src/render/pass/RectPassElement.hpp b/src/render/pass/RectPassElement.hpp
index b6d310ad..a61ab155 100644
--- a/src/render/pass/RectPassElement.hpp
+++ b/src/render/pass/RectPassElement.hpp
@@ -12,6 +12,12 @@ class CRectPassElement : public IPassElement {
bool blur = false, xray = false;
float blurA = 1.F;
CBox clipBox;
+
+ // internal
+ CBox modifiedBox;
+ float TOPLEFT[2];
+ float FULLSIZE[2];
+ CRegion drawRegion;
};
CRectPassElement(const SRectData& data);
diff --git a/src/render/pass/SurfacePassElement.hpp b/src/render/pass/SurfacePassElement.hpp
index bd02417d..c76b475d 100644
--- a/src/render/pass/SurfacePassElement.hpp
+++ b/src/render/pass/SurfacePassElement.hpp
@@ -1,5 +1,6 @@
#pragma once
#include "PassElement.hpp"
+#include "TexPassElement.hpp"
#include <optional>
#include "../../helpers/time/Time.hpp"
@@ -41,7 +42,7 @@ class CSurfacePassElement : public IPassElement {
CBox clipBox = {}; // scaled coordinates
- uint32_t discardMode = 0;
+ uint32_t discardMode = DISCARD_OPAQUE;
float discardOpacity = 0.f;
bool useNearestNeighbor = false;
diff --git a/src/render/pass/TexPassElement.hpp b/src/render/pass/TexPassElement.hpp
index 1ac3db0c..5b8c9757 100644
--- a/src/render/pass/TexPassElement.hpp
+++ b/src/render/pass/TexPassElement.hpp
@@ -6,22 +6,42 @@ class CWLSurfaceResource;
class ITexture;
class CSyncTimeline;
+enum eDiscardMode : uint8_t {
+ DISCARD_OPAQUE = 1,
+ DISCARD_ALPHA = 1 << 1
+};
+
class CTexPassElement : public IPassElement {
public:
struct SRenderData {
- SP<ITexture> tex;
- CBox box;
- float a = 1.F;
- float blurA = 1.F;
- CRegion damage;
- int round = 0;
- float roundingPower = 2.0f;
- bool flipEndFrame = false;
- bool useMirrorProjection = false;
- CBox clipBox;
- bool blur = false;
- std::optional<float> ignoreAlpha;
- std::optional<bool> blockBlurOptimization;
+ SP<ITexture> tex;
+ CBox box;
+ float a = 1.F;
+ float blurA = 1.F;
+ float overallA = 1.F;
+ CRegion damage;
+ int round = 0;
+ float roundingPower = 2.0f;
+ bool flipEndFrame = false;
+ bool useMirrorProjection = false;
+ CBox clipBox;
+ bool blur = false;
+ std::optional<float> ignoreAlpha;
+ std::optional<bool> blockBlurOptimization;
+ bool cmBackToSRGB = false;
+ SP<CMonitor> cmBackToSRGBSource;
+
+ bool discardActive = false;
+ bool allowCustomUV = false;
+ SP<CWLSurfaceResource> surface = nullptr;
+
+ uint32_t discardMode = DISCARD_OPAQUE;
+ float discardOpacity = 0.f;
+
+ CRegion clipRegion;
+ PHLLSREF currentLS;
+
+ SP<ITexture> blurredBG;
};
CTexPassElement(const SRenderData& data);