renderer: refactor Texture, Framebuffer and Renderbuffer (#13437)
Some checks are pending
Build Hyprland / Build Hyprland (Arch) (push) Waiting to run
Build Hyprland / Code Style (push) Waiting to run
Nix / update-inputs (push) Waiting to run
Nix / hyprland (push) Waiting to run
Nix / xdph (push) Blocked by required conditions
Nix / test (push) Waiting to run
Security Checks / Flawfinder Checks (push) Waiting to run

Part 1 of the renderer refactors
This commit is contained in:
UjinT34 2026-03-07 00:44:10 +03:00 committed by GitHub
parent a5858018d8
commit 4152ac76d0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
46 changed files with 1154 additions and 843 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,140 +1,30 @@
#include "Framebuffer.hpp"
#include "OpenGL.hpp"
CFramebuffer::CFramebuffer() {
;
}
IFramebuffer::IFramebuffer(const std::string& name) : m_name(name) {}
bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) {
bool firstAlloc = false;
bool IFramebuffer::alloc(int w, int h, uint32_t format) {
RASSERT((w > 0 && h > 0), "cannot alloc a FB with negative / zero size! (attempted {}x{})", w, h);
const bool sizeChanged = (m_size != Vector2D(w, h));
const bool formatChanged = (drmFormat != m_drmFormat);
const bool formatChanged = (format != m_drmFormat);
if (!m_tex) {
m_tex = makeShared<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 && !sizeChanged && !formatChanged)
return true;
if (!m_fbAllocated) {
glGenFramebuffers(1, &m_fb);
m_fbAllocated = true;
firstAlloc = true;
}
if (firstAlloc || sizeChanged || formatChanged) {
const auto format = NFormatUtils::getPixelFormatFromDRM(drmFormat);
m_tex->bind();
glTexImage2D(GL_TEXTURE_2D, 0, format->glInternalFormat ? format->glInternalFormat : format->glFormat, w, h, 0, format->glFormat, format->glType, nullptr);
glBindFramebuffer(GL_FRAMEBUFFER, m_fb);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_tex->m_texID, 0);
if (m_stencilTex) {
m_stencilTex->bind();
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, w, h, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_stencilTex->m_texID, 0);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
}
auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
RASSERT((status == GL_FRAMEBUFFER_COMPLETE), "Framebuffer incomplete, couldn't create! (FB status: {}, GL Error: 0x{:x})", status, sc<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;
m_size = {w, h};
m_drmFormat = format;
m_fbAllocated = internalAlloc(w, h, format);
return m_fbAllocated;
}
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);
auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
RASSERT((status == GL_FRAMEBUFFER_COMPLETE), "Failed adding a stencil to fbo!", status);
m_stencilTex->unbind();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void CFramebuffer::bind() {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fb);
if (g_pHyprOpenGL)
g_pHyprOpenGL->setViewport(0, 0, g_pHyprOpenGL->m_renderData.pMonitor->m_pixelSize.x, g_pHyprOpenGL->m_renderData.pMonitor->m_pixelSize.y);
else
glViewport(0, 0, m_size.x, m_size.y);
}
void CFramebuffer::unbind() {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}
void CFramebuffer::release() {
if (m_fbAllocated) {
glBindFramebuffer(GL_FRAMEBUFFER, m_fb);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &m_fb);
m_fbAllocated = false;
m_fb = 0;
}
if (m_tex)
m_tex.reset();
m_size = Vector2D();
}
CFramebuffer::~CFramebuffer() {
release();
}
bool CFramebuffer::isAllocated() {
bool IFramebuffer::isAllocated() {
return m_fbAllocated && m_tex;
}
SP<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());
}

View file

@ -3,34 +3,38 @@
#include "../defines.hpp"
#include "../helpers/Format.hpp"
#include "Texture.hpp"
#include <cstdint>
#include <drm_fourcc.h>
class CFramebuffer {
public:
CFramebuffer();
~CFramebuffer();
class CHLBufferReference;
class IFramebuffer {
public:
IFramebuffer() = default;
IFramebuffer(const std::string& name);
virtual ~IFramebuffer() = default;
virtual bool alloc(int w, int h, uint32_t format = DRM_FORMAT_ARGB8888);
virtual void release() = 0;
virtual bool readPixels(CHLBufferReference buffer, uint32_t offsetX = 0, uint32_t offsetY = 0, uint32_t width = 0, uint32_t height = 0) = 0;
virtual void bind() = 0;
bool alloc(int w, int h, uint32_t format = DRM_FORMAT_ARGB8888);
void addStencil(SP<CTexture> tex);
void bind();
void unbind();
void release();
void reset();
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;
protected:
virtual bool internalAlloc(int w, int h, uint32_t format = DRM_FORMAT_ARGB8888) = 0;
SP<ITexture> m_tex;
bool m_fbAllocated = false;
SP<CTexture> m_stencilTex;
friend class CRenderbuffer;
SP<ITexture> m_stencilTex;
std::string m_name; // name for logging
};

View file

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

View file

@ -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);
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<CTexture>, const CBox&, const STextureRenderData& data);
void renderTextureWithBlurInternal(SP<CTexture>, const CBox&, const STextureRenderData& data);
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();
void preBlurForCurrentMonitor();
friend class CHyprRenderer;
friend class CTexPassElement;

View file

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

View file

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

View file

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

View file

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

View file

@ -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;
}
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);
// 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 CTexture::createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size_) {
g_pHyprRenderer->makeEGLCurrent();
const auto format = NFormatUtils::getPixelFormatFromDRM(drmFormat);
ASSERT(format);
m_type = format->withAlpha ? TEXTURE_RGBA : TEXTURE_RGBX;
m_size = size_;
m_isSynchronous = true;
m_target = GL_TEXTURE_2D;
allocate();
bind();
setTexParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
setTexParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (format->swizzle.has_value())
swizzle(format->swizzle.value());
bool alignmentChanged = false;
if (format->bytesPerBlock != 4) {
const GLint alignment = (stride % 4 == 0) ? 4 : 1;
GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, alignment));
alignmentChanged = true;
}
GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / format->bytesPerBlock));
GLCALL(glTexImage2D(GL_TEXTURE_2D, 0, format->glInternalFormat ? format->glInternalFormat : format->glFormat, size_.x, size_.y, 0, format->glFormat, format->glType, pixels));
GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0));
if (alignmentChanged)
GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 4));
unbind();
if (m_keepDataCopy) {
m_dataCopy.resize(stride * size_.y);
memcpy(m_dataCopy.data(), pixels, stride * size_.y);
ITexture::ITexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy, bool opaque) :
m_size(size), m_opaque(opaque), m_drmFormat(drmFormat), m_keepDataCopy(keepDataCopy) {
if (m_keepDataCopy && stride && pixels) {
m_dataCopy.resize(stride * size.y);
memcpy(m_dataCopy.data(), pixels, stride * size.y);
}
}
void CTexture::createFromDma(const Aquamarine::SDMABUFAttrs& attrs, void* image) {
if (!g_pHyprOpenGL->m_proc.glEGLImageTargetTexture2DOES) {
Log::logger->log(Log::ERR, "Cannot create a dmabuf texture: no glEGLImageTargetTexture2DOES");
return;
}
ITexture::ITexture(std::span<const float> lut3D, size_t N) : m_type(TEXTURE_3D_LUT), m_size(lut3D.size() / 3, 1), m_isSynchronous(true) {}
m_opaque = NFormatUtils::isFormatOpaque(attrs.format);
// #TODO external only formats should be external aswell.
// also needs a seperate color shader.
/*if (NFormatUtils::isFormatYUV(attrs.format)) {
m_target = GL_TEXTURE_EXTERNAL_OES;
m_type = TEXTURE_EXTERNAL;
} else {*/
m_target = GL_TEXTURE_2D;
m_type = NFormatUtils::isFormatOpaque(attrs.format) ? TEXTURE_RGBX : TEXTURE_RGBA;
//}
m_size = attrs.size;
allocate();
m_eglImage = image;
bind();
setTexParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
setTexParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
GLCALL(g_pHyprOpenGL->m_proc.glEGLImageTargetTexture2DOES(m_target, image));
unbind();
bool ITexture::ok() {
return false;
}
void CTexture::update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage) {
if (damage.empty())
return;
g_pHyprRenderer->makeEGLCurrent();
const auto format = NFormatUtils::getPixelFormatFromDRM(drmFormat);
ASSERT(format);
bind();
if (format->swizzle.has_value())
swizzle(format->swizzle.value());
bool alignmentChanged = false;
if (format->bytesPerBlock != 4) {
const GLint alignment = (stride % 4 == 0) ? 4 : 1;
GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, alignment));
alignmentChanged = true;
}
GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / format->bytesPerBlock));
damage.copy().intersect(CBox{{}, m_size}).forEachRect([&format, &pixels](const auto& rect) {
GLCALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, rect.x1));
GLCALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, rect.y1));
int width = rect.x2 - rect.x1;
int height = rect.y2 - rect.y1;
GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x1, rect.y1, width, height, format->glFormat, format->glType, pixels));
});
if (alignmentChanged)
GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 4));
GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0));
GLCALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0));
GLCALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0));
unbind();
if (m_keepDataCopy) {
m_dataCopy.resize(stride * m_size.y);
memcpy(m_dataCopy.data(), pixels, stride * m_size.y);
}
bool ITexture::isDMA() {
return false;
}
void CTexture::destroyTexture() {
if (m_texID) {
GLCALL(glDeleteTextures(1, &m_texID));
m_texID = 0;
}
if (m_eglImage)
g_pHyprOpenGL->m_proc.eglDestroyImageKHR(g_pHyprOpenGL->m_eglDisplay, m_eglImage);
m_eglImage = nullptr;
m_cachedStates.fill(std::nullopt);
}
void CTexture::allocate() {
if (!m_texID)
GLCALL(glGenTextures(1, &m_texID));
}
const std::vector<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));
}

View file

@ -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;
// TODO move to GLTexture
GLuint m_texID = 0;
GLenum magFilter = GL_LINEAR; // useNearestNeighbor overwrites these
GLenum minFilter = GL_LINEAR;
private:
enum eTextureParam : uint8_t {
TEXTURE_PAR_WRAP_S = 0,
TEXTURE_PAR_WRAP_T,
TEXTURE_PAR_MAG_FILTER,
TEXTURE_PAR_MIN_FILTER,
TEXTURE_PAR_SWIZZLE_R,
TEXTURE_PAR_SWIZZLE_B,
TEXTURE_PAR_LAST,
};
protected:
ITexture() = default;
ITexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false, bool opaque = false);
ITexture(std::span<const float> lut3D, size_t N);
void createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size);
void createFromDma(const Aquamarine::SDMABUFAttrs&, void* image);
inline constexpr std::optional<size_t> getCacheStateIndex(GLenum pname);
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;
};

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

223
src/render/gl/GLTexture.cpp Normal file
View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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() {

View file

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