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