renderer: refactor gl renderer (#13488)

This commit is contained in:
UjinT34 2026-03-07 21:21:23 +03:00 committed by GitHub
parent b227efc849
commit 02f30ea15b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 1733 additions and 1394 deletions

View file

@ -32,6 +32,7 @@
#include <unordered_set>
#include "debug/HyprCtl.hpp"
#include "debug/crash/CrashReporter.hpp"
#include "render/GLRenderer.hpp"
#include "render/ShaderLoader.hpp"
#ifdef USES_SYSTEMD
#include <helpers/SdDaemon.hpp> // for SdNotify
@ -658,6 +659,9 @@ void CCompositor::initManagers(eManagersInitStage stage) {
Log::logger->log(Log::DEBUG, "Creating the CHyprOpenGLImpl!");
g_pHyprOpenGL = makeUnique<CHyprOpenGLImpl>();
Log::logger->log(Log::DEBUG, "Creating the HyprRenderer!");
g_pHyprRenderer = makeUnique<CHyprGLRenderer>();
Log::logger->log(Log::DEBUG, "Creating the ProtocolManager!");
g_pProtocolManager = makeUnique<CProtocolManager>();
@ -676,9 +680,6 @@ void CCompositor::initManagers(eManagersInitStage stage) {
Log::logger->log(Log::DEBUG, "Creating the InputManager!");
g_pInputManager = makeUnique<CInputManager>();
Log::logger->log(Log::DEBUG, "Creating the HyprRenderer!");
g_pHyprRenderer = makeUnique<CHyprRenderer>();
Log::logger->log(Log::DEBUG, "Creating the XWaylandManager!");
g_pXWaylandManager = makeUnique<CHyprXWaylandManager>();

View file

@ -6,7 +6,7 @@
#include <map>
#include <deque>
class CHyprRenderer;
class IHyprRenderer;
class CHyprMonitorDebugOverlay {
public:
@ -25,7 +25,7 @@ class CHyprMonitorDebugOverlay {
PHLMONITORREF m_monitor;
CBox m_lastDrawnBox;
friend class CHyprRenderer;
friend class IHyprRenderer;
};
class CHyprDebugOverlay {
@ -45,7 +45,7 @@ class CHyprDebugOverlay {
SP<ITexture> m_texture;
friend class CHyprMonitorDebugOverlay;
friend class CHyprRenderer;
friend class IHyprRenderer;
};
inline UP<CHyprDebugOverlay> g_pDebugOverlay;

View file

@ -591,16 +591,21 @@ SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager
RBO->bind();
g_pHyprOpenGL->beginSimple(state->monitor.lock(), {0, 0, INT_MAX, INT_MAX}, RBO);
g_pHyprOpenGL->clear(CHyprColor{0.F, 0.F, 0.F, 0.F}); // ensure the RBO is zero initialized.
CRegion damageRegion = {0, 0, INT_MAX, INT_MAX};
g_pHyprRenderer->beginFullFakeRender(state->monitor.lock(), damageRegion, RBO->getFB());
g_pHyprRenderer->startRenderPass();
g_pHyprRenderer->draw(makeUnique<CClearPassElement>(CClearPassElement::SClearData{{0.F, 0.F, 0.F, 0.F}}), {});
CBox xbox = {{}, Vector2D{m_currentCursorImage.size / m_currentCursorImage.scale * state->monitor->m_scale}.round()};
Log::logger->log(Log::TRACE, "[pointer] monitor: {}, size: {}, hw buf: {}, scale: {:.2f}, monscale: {:.2f}, xbox: {}", state->monitor->m_name, m_currentCursorImage.size,
cursorSize, m_currentCursorImage.scale, state->monitor->m_scale, xbox.size());
g_pHyprOpenGL->renderTexture(texture, xbox, {.noCM = true});
CTexPassElement::SRenderData data;
data.tex = texture;
data.box = xbox;
g_pHyprRenderer->draw(makeUnique<CTexPassElement>(std::move(data)), {});
g_pHyprOpenGL->end();
g_pHyprRenderer->endRender();
g_pHyprRenderer->m_renderData.pMonitor.reset();
return buf;

View file

@ -9,7 +9,7 @@
#include <any>
class CInputManager;
class CHyprRenderer;
class IHyprRenderer;
class CTextInputV1;
class CInputMethodV2;
@ -54,9 +54,8 @@ class CInputMethodRelay {
CHyprSignalListener newPopup;
} m_listeners;
friend class CHyprRenderer;
friend class IHyprRenderer;
friend class CInputManager;
friend class CTextInputV1ProtocolManager;
friend class CTextInput;
friend class CHyprRenderer;
};

View file

@ -116,19 +116,24 @@ void CCursorshareSession::render() {
// TODO: implement a monitor independent render mode to buffer that does this in CHyprRenderer::begin() or something like that
g_pHyprRenderer->m_renderData.transformDamage = false;
g_pHyprOpenGL->setViewport(0, 0, m_bufferSize.x, m_bufferSize.y);
g_pHyprRenderer->setViewport(0, 0, m_bufferSize.x, m_bufferSize.y);
bool overlaps = g_pPointerManager->getCursorBoxGlobal().overlaps(m_pendingFrame.sourceBoxCallback());
g_pHyprRenderer->startRenderPass();
if (PERM != PERMISSION_RULE_ALLOW_MODE_ALLOW || !overlaps) {
// render black when not allowed
g_pHyprOpenGL->clear(Colors::BLACK);
g_pHyprRenderer->draw(makeUnique<CClearPassElement>(CClearPassElement::SClearData{Colors::BLACK}), {});
} else if (!cursorImage.pBuffer || !cursorImage.surface || !cursorImage.bufferTex) {
// render clear when cursor is probably hidden
g_pHyprOpenGL->clear(CHyprColor(0, 0, 0, 0));
g_pHyprRenderer->draw(makeUnique<CClearPassElement>(CClearPassElement::SClearData{{0, 0, 0, 0}}), {});
} else {
// render cursor
CBox texbox = {{}, cursorImage.bufferTex->m_size};
g_pHyprOpenGL->renderTexture(cursorImage.bufferTex, texbox, {});
g_pHyprRenderer->draw(makeUnique<CTexPassElement>(CTexPassElement::SRenderData{
.tex = cursorImage.bufferTex,
.box = texbox,
}),
{});
}
g_pHyprRenderer->m_renderData.blockScreenShader = true;
@ -141,8 +146,6 @@ bool CCursorshareSession::copy() {
// FIXME: this doesn't really make sense but just to be safe
m_pendingFrame.callback(RESULT_TIMESTAMP);
g_pHyprOpenGL->makeEGLCurrent();
CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX};
if (auto attrs = m_pendingFrame.buffer->dmabuf(); attrs.success) {
if (attrs.format != m_format) {
@ -150,7 +153,7 @@ bool CCursorshareSession::copy() {
return false;
}
if (!g_pHyprRenderer->beginRender(m_pendingFrame.monitor, fakeDamage, RENDER_MODE_TO_BUFFER, m_pendingFrame.buffer, nullptr, true)) {
if (!g_pHyprRenderer->beginRenderToBuffer(m_pendingFrame.monitor, fakeDamage, m_pendingFrame.buffer, true)) {
LOGM(Log::ERR, "Can't copy: failed to begin rendering to dmabuf");
return false;
}
@ -162,8 +165,7 @@ bool CCursorshareSession::copy() {
callback(RESULT_COPIED);
});
} else if (auto attrs = m_pendingFrame.buffer->shm(); attrs.success) {
auto [bufData, fmt, bufLen] = m_pendingFrame.buffer->beginDataPtr(0);
const auto PFORMAT = NFormatUtils::getPixelFormatFromDRM(m_format);
const auto PFORMAT = NFormatUtils::getPixelFormatFromDRM(m_format);
if (attrs.format != m_format || !PFORMAT) {
LOGM(Log::ERR, "Can't copy: invalid format");
@ -173,7 +175,7 @@ bool CCursorshareSession::copy() {
auto outFB = g_pHyprRenderer->createFB();
outFB->alloc(m_bufferSize.x, m_bufferSize.y, m_format);
if (!g_pHyprRenderer->beginRender(m_pendingFrame.monitor, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, outFB, true)) {
if (!g_pHyprRenderer->beginFullFakeRender(m_pendingFrame.monitor, fakeDamage, outFB)) {
LOGM(Log::ERR, "Can't copy: failed to begin rendering to shm");
return false;
}
@ -182,12 +184,6 @@ bool CCursorshareSession::copy() {
g_pHyprRenderer->endRender();
g_pHyprRenderer->m_renderData.pMonitor = m_pendingFrame.monitor;
outFB->bind();
glBindFramebuffer(GL_READ_FRAMEBUFFER, GLFB(outFB)->getFBID());
glPixelStorei(GL_PACK_ALIGNMENT, 1);
int glFormat = PFORMAT->glFormat;
if (glFormat == GL_RGBA)
@ -208,15 +204,10 @@ bool CCursorshareSession::copy() {
}
}
glReadPixels(0, 0, m_bufferSize.x, m_bufferSize.y, glFormat, PFORMAT->glType, bufData);
outFB->readPixels(m_pendingFrame.buffer, 0, 0, m_bufferSize.x, m_bufferSize.y);
g_pHyprRenderer->m_renderData.pMonitor.reset();
m_pendingFrame.buffer->endDataPtr();
GLFB(outFB)->unbind();
glPixelStorei(GL_PACK_ALIGNMENT, 4);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
m_pendingFrame.callback(RESULT_COPIED);
} else {
LOGM(Log::ERR, "Can't copy: invalid buffer type");

View file

@ -10,6 +10,7 @@
#include "../../helpers/Monitor.hpp"
#include "../../desktop/view/Window.hpp"
#include "../../desktop/state/FocusState.hpp"
#include "render/pass/RectPassElement.hpp"
#include <hyprutils/math/Region.hpp>
using namespace Screenshare;
@ -170,15 +171,19 @@ void CScreenshareFrame::renderMonitor() {
CBox monbox = CBox{{}, PMONITOR->m_pixelSize}
.transform(Math::wlTransformToHyprutils(Math::invertTransform(PMONITOR->m_transform)), PMONITOR->m_pixelSize.x, PMONITOR->m_pixelSize.y)
.translate(-m_session->m_captureBox.pos()); // vvvv kinda ass-backwards but that's how I designed the renderer... sigh.
g_pHyprRenderer->pushMonitorTransformEnabled(true);
g_pHyprOpenGL->setRenderModifEnabled(false);
g_pHyprOpenGL->renderTexture(TEXTURE, monbox,
{
.cmBackToSRGB = !IS_CM_AWARE,
.cmBackToSRGBSource = !IS_CM_AWARE ? PMONITOR : nullptr,
});
g_pHyprOpenGL->setRenderModifEnabled(true);
g_pHyprRenderer->popMonitorTransformEnabled();
const auto OLD = g_pHyprRenderer->m_renderData.renderModif.enabled;
g_pHyprRenderer->m_renderData.renderModif.enabled = false;
g_pHyprRenderer->startRenderPass();
g_pHyprRenderer->draw(makeUnique<CTexPassElement>(CTexPassElement::SRenderData{
.tex = TEXTURE,
.box = monbox,
.flipEndFrame = true,
.cmBackToSRGB = !IS_CM_AWARE,
.cmBackToSRGBSource = !IS_CM_AWARE ? PMONITOR : nullptr,
}),
monbox);
g_pHyprRenderer->m_renderData.renderModif.enabled = OLD;
// render black boxes for noscreenshare
auto hidePopups = [&](Vector2D popupBaseOffset) {
@ -194,7 +199,11 @@ void CScreenshareFrame::renderMonitor() {
CBox{popupBaseOffset + popRel + localOff, size}.translate(PMONITOR->m_position).scale(PMONITOR->m_scale).translate(-m_session->m_captureBox.pos());
if LIKELY (surfBox.w > 0 && surfBox.h > 0)
g_pHyprOpenGL->renderRect(surfBox, Colors::BLACK, {});
g_pHyprRenderer->draw(makeUnique<CRectPassElement>(CRectPassElement::SRectData{
.box = surfBox,
.color = Colors::BLACK,
}),
surfBox);
},
nullptr);
};
@ -215,7 +224,11 @@ void CScreenshareFrame::renderMonitor() {
.scale(PMONITOR->m_scale)
.translate(-m_session->m_captureBox.pos());
g_pHyprOpenGL->renderRect(noScreenShareBox, Colors::BLACK, {});
g_pHyprRenderer->draw(makeUnique<CRectPassElement>(CRectPassElement::SRectData{
.box = noScreenShareBox,
.color = Colors::BLACK,
}),
noScreenShareBox);
const auto geom = l->m_geometry;
const Vector2D popupBaseOffset = REALPOS - Vector2D{geom.pos().x, geom.pos().y};
@ -250,7 +263,13 @@ void CScreenshareFrame::renderMonitor() {
const auto rounding = dontRound ? 0 : w->rounding() * PMONITOR->m_scale;
const auto roundingPower = dontRound ? 2.0f : w->roundingPower();
g_pHyprOpenGL->renderRect(noScreenShareBox, Colors::BLACK, {.round = rounding, .roundingPower = roundingPower});
g_pHyprRenderer->draw(makeUnique<CRectPassElement>(CRectPassElement::SRectData{
.box = noScreenShareBox,
.color = Colors::BLACK,
.round = rounding,
.roundingPower = roundingPower,
}),
noScreenShareBox);
if (w->m_isX11 || !w->m_popupHead)
continue;
@ -281,7 +300,7 @@ void CScreenshareFrame::renderWindow() {
g_pHyprRenderer->m_renderData.fbSize = m_bufferSize;
g_pHyprRenderer->setProjectionType(RPT_FB);
g_pHyprRenderer->m_renderData.transformDamage = false;
g_pHyprOpenGL->setViewport(0, 0, m_bufferSize.x, m_bufferSize.y);
g_pHyprRenderer->setViewport(0, 0, m_bufferSize.x, m_bufferSize.y);
g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(PWINDOW); // block the feedback to avoid spamming the surface if it's visible
g_pHyprRenderer->renderWindow(PWINDOW, PMONITOR, NOW, false, RENDER_PASS_ALL, true, true);
@ -313,22 +332,32 @@ void CScreenshareFrame::renderWindow() {
void CScreenshareFrame::render() {
const auto PERM = g_pDynamicPermissionManager->clientPermissionMode(m_session->m_client, PERMISSION_TYPE_SCREENCOPY);
CRegion frameRegion = {0, 0, g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.x, g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.y};
if (PERM == PERMISSION_RULE_ALLOW_MODE_PENDING) {
g_pHyprOpenGL->clear(CHyprColor(0, 0, 0, 0));
g_pHyprRenderer->draw(makeUnique<CClearPassElement>(CClearPassElement::SClearData{{0, 0, 0, 0}}), frameRegion);
return;
}
bool windowShareDenied = m_session->m_type == SHARE_WINDOW && m_session->m_window->m_ruleApplicator && m_session->m_window->m_ruleApplicator->noScreenShare().valueOrDefault();
g_pHyprRenderer->startRenderPass();
if (PERM == PERMISSION_RULE_ALLOW_MODE_DENY || windowShareDenied) {
g_pHyprOpenGL->clear(CHyprColor(0, 0, 0, 0));
g_pHyprRenderer->draw(makeUnique<CClearPassElement>(CClearPassElement::SClearData{{0, 0, 0, 0}}), frameRegion);
CBox texbox = CBox{m_bufferSize / 2.F, g_pHyprRenderer->m_screencopyDeniedTexture->m_size}.translate(-g_pHyprRenderer->m_screencopyDeniedTexture->m_size / 2.F);
g_pHyprOpenGL->renderTexture(g_pHyprRenderer->m_screencopyDeniedTexture, texbox, {});
g_pHyprRenderer->draw(makeUnique<CTexPassElement>(CTexPassElement::SRenderData{
.tex = g_pHyprRenderer->m_screencopyDeniedTexture,
.box = texbox,
}),
texbox);
return;
}
if (m_session->m_tempFB && m_session->m_tempFB->isAllocated()) {
CBox texbox = {{}, m_bufferSize};
g_pHyprOpenGL->renderTexture(m_session->m_tempFB->getTexture(), texbox, {});
g_pHyprRenderer->draw(makeUnique<CTexPassElement>(CTexPassElement::SRenderData{
.tex = m_session->m_tempFB->getTexture(),
.box = texbox,
}),
texbox);
m_session->m_tempFB->release();
return;
}
@ -371,10 +400,7 @@ bool CScreenshareFrame::copyShm() {
if (done())
return false;
g_pHyprOpenGL->makeEGLCurrent();
auto shm = m_buffer->shm();
auto [pixelData, fmt, bufLen] = m_buffer->beginDataPtr(0); // no need for end, cuz it's shm
auto shm = m_buffer->shm();
const auto PFORMAT = NFormatUtils::getPixelFormatFromDRM(shm.format);
if (!PFORMAT) {
@ -387,7 +413,7 @@ bool CScreenshareFrame::copyShm() {
auto outFB = g_pHyprRenderer->createFB();
outFB->alloc(m_bufferSize.x, m_bufferSize.y, shm.format);
if (!g_pHyprRenderer->beginRender(PMONITOR, m_damage, RENDER_MODE_FULL_FAKE, nullptr, outFB, true)) {
if (!g_pHyprRenderer->beginFullFakeRender(PMONITOR, m_damage, outFB)) {
LOGM(Log::ERR, "Can't copy: failed to begin rendering");
return false;
}
@ -398,53 +424,11 @@ bool CScreenshareFrame::copyShm() {
g_pHyprRenderer->endRender();
g_pHyprRenderer->m_renderData.pMonitor = PMONITOR;
outFB->bind();
glBindFramebuffer(GL_READ_FRAMEBUFFER, GLFB(outFB)->getFBID());
glPixelStorei(GL_PACK_ALIGNMENT, 1);
uint32_t packStride = NFormatUtils::minStride(PFORMAT, m_bufferSize.x);
int glFormat = PFORMAT->glFormat;
if (glFormat == GL_RGBA)
glFormat = GL_BGRA_EXT;
if (glFormat != GL_BGRA_EXT && glFormat != GL_RGB) {
if (PFORMAT->swizzle.has_value()) {
std::array<GLint, 4> RGBA = SWIZZLE_RGBA;
std::array<GLint, 4> BGRA = SWIZZLE_BGRA;
if (PFORMAT->swizzle == RGBA)
glFormat = GL_RGBA;
else if (PFORMAT->swizzle == BGRA)
glFormat = GL_BGRA_EXT;
else {
LOGM(Log::ERR, "Copied frame via shm might be broken or color flipped");
glFormat = GL_RGBA;
}
}
}
// TODO: use pixel buffer object to not block cpu
if (packStride == sc<uint32_t>(shm.stride)) {
m_damage.forEachRect([&](const auto& rect) {
int width = rect.x2 - rect.x1;
int height = rect.y2 - rect.y1;
glReadPixels(rect.x1, rect.y1, width, height, glFormat, PFORMAT->glType, pixelData);
});
} else {
m_damage.forEachRect([&](const auto& rect) {
size_t width = rect.x2 - rect.x1;
size_t height = rect.y2 - rect.y1;
for (size_t i = rect.y1; i < height; ++i) {
glReadPixels(rect.x1, i, width, 1, glFormat, PFORMAT->glType, pixelData + (rect.x1 * PFORMAT->bytesPerBlock) + (i * shm.stride));
}
});
}
GLFB(outFB)->unbind();
glPixelStorei(GL_PACK_ALIGNMENT, 4);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
m_damage.forEachRect([&](const auto& rect) {
int width = rect.x2 - rect.x1;
int height = rect.y2 - rect.y1;
outFB->readPixels(m_buffer, rect.x1, rect.y1, width, height);
});
g_pHyprRenderer->m_renderData.pMonitor.reset();
@ -463,7 +447,7 @@ void CScreenshareFrame::storeTempFB() {
CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX};
if (!g_pHyprRenderer->beginRender(m_session->monitor(), fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, m_session->m_tempFB, true)) {
if (!g_pHyprRenderer->beginFullFakeRender(m_session->monitor(), fakeDamage, m_session->m_tempFB)) {
LOGM(Log::ERR, "Can't copy: failed to begin rendering to temp fb");
return;
}

405
src/render/GLRenderer.cpp Normal file
View file

@ -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);
}

52
src/render/GLRenderer.hpp Normal file
View file

@ -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;
};

File diff suppressed because it is too large Load diff

View file

@ -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;

File diff suppressed because it is too large Load diff

View file

@ -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>);
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;
//
NColorManagement::PImageDescription workBufferImageDescription();
bool m_bBlockSurfaceFeedback = false;
bool m_bRenderingSnapshot = false;
PHLMONITORREF m_mostHzMonitor;
bool m_directScanoutBlocked = false;
// 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 = {});
void setSurfaceScanoutMode(SP<CWLSurfaceResource> surface, PHLMONITOR monitor); // nullptr monitor resets
bool m_bBlockSurfaceFeedback = false;
bool m_bRenderingSnapshot = false;
PHLMONITORREF m_mostHzMonitor;
bool m_directScanoutBlocked = false;
void initiateManualCrash();
const SRenderData& renderData();
void setSurfaceScanoutMode(SP<CWLSurfaceResource> surface, PHLMONITOR monitor); // nullptr monitor resets
bool m_crashingInProgress = false;
float m_crashingDistort = 0.5f;
wl_event_source* m_crashingLoop = nullptr;
wl_event_source* m_cursorTicker = nullptr;
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;
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 = {};
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> 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);
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();
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 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);
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;
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 = "");
bool preBlurQueued(PHLMONITORREF pMonitor);
void pushMonitorTransformEnabled(bool enabled);
void popMonitorTransformEnabled();
bool monitorTransformEnabled();
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);
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> m_lockDeadTexture;
SP<ITexture> m_lockDead2Texture;
SP<ITexture> m_lockTtyTextTexture;
bool m_monitorTransformEnabled = false; // do not modify directly
std::stack<bool> m_monitorTransformStack;
SP<ITexture> blurMainFramebuffer(float a, CRegion* originalDamage);
virtual SP<ITexture> blurFramebuffer(SP<IFramebuffer> source, float a, CRegion* originalDamage) = 0;
void preBlurForCurrentMonitor(CRegion* fakeDamage);
private:
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);
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;

View file

@ -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;

View file

@ -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);
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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_);

View file

@ -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), {});
}
}

View file

@ -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);

View file

@ -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;

View file

@ -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);