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
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:
parent
a5858018d8
commit
4152ac76d0
46 changed files with 1154 additions and 843 deletions
|
|
@ -8,7 +8,7 @@
|
||||||
#include "../desktop/state/FocusState.hpp"
|
#include "../desktop/state/FocusState.hpp"
|
||||||
|
|
||||||
CHyprDebugOverlay::CHyprDebugOverlay() {
|
CHyprDebugOverlay::CHyprDebugOverlay() {
|
||||||
m_texture = makeShared<CTexture>();
|
m_texture = g_pHyprRenderer->createTexture();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHyprMonitorDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs) {
|
void CHyprMonitorDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs) {
|
||||||
|
|
@ -259,15 +259,7 @@ void CHyprDebugOverlay::draw() {
|
||||||
cairo_surface_flush(m_cairoSurface);
|
cairo_surface_flush(m_cairoSurface);
|
||||||
|
|
||||||
// copy the data to an OpenGL texture we have
|
// copy the data to an OpenGL texture we have
|
||||||
const auto DATA = cairo_image_surface_get_data(m_cairoSurface);
|
m_texture = g_pHyprRenderer->createTexture(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);
|
|
||||||
|
|
||||||
CTexPassElement::SRenderData data;
|
CTexPassElement::SRenderData data;
|
||||||
data.tex = m_texture;
|
data.tex = m_texture;
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ class CHyprDebugOverlay {
|
||||||
cairo_surface_t* m_cairoSurface = nullptr;
|
cairo_surface_t* m_cairoSurface = nullptr;
|
||||||
cairo_t* m_cairo = nullptr;
|
cairo_t* m_cairo = nullptr;
|
||||||
|
|
||||||
SP<CTexture> m_texture;
|
SP<ITexture> m_texture;
|
||||||
|
|
||||||
friend class CHyprMonitorDebugOverlay;
|
friend class CHyprMonitorDebugOverlay;
|
||||||
friend class CHyprRenderer;
|
friend class CHyprRenderer;
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,6 @@ CHyprNotificationOverlay::CHyprNotificationOverlay() {
|
||||||
|
|
||||||
g_pHyprRenderer->damageBox(m_lastDamage);
|
g_pHyprRenderer->damageBox(m_lastDamage);
|
||||||
});
|
});
|
||||||
|
|
||||||
m_texture = makeShared<CTexture>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CHyprNotificationOverlay::~CHyprNotificationOverlay() {
|
CHyprNotificationOverlay::~CHyprNotificationOverlay() {
|
||||||
|
|
@ -232,16 +230,7 @@ void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) {
|
||||||
|
|
||||||
m_lastDamage = damage;
|
m_lastDamage = damage;
|
||||||
|
|
||||||
// copy the data to an OpenGL texture we have
|
m_texture = g_pHyprRenderer->createTexture(m_cairoSurface);
|
||||||
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);
|
|
||||||
|
|
||||||
CTexPassElement::SRenderData data;
|
CTexPassElement::SRenderData data;
|
||||||
data.tex = m_texture;
|
data.tex = m_texture;
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ enum eIconBackend : uint8_t {
|
||||||
static const std::array<std::array<std::string, ICON_NONE + 1>, 3 /* backends */> ICONS_ARRAY = {
|
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>{"[!]", "[i]", "[Hint]", "[Err]", "[?]", "[ok]", ""},
|
||||||
std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", "", ""}, std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", ""}};
|
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{128 / 255.0, 255 / 255.0, 255 / 255.0, 1.0},
|
||||||
CHyprColor{179 / 255.0, 255 / 255.0, 204 / 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},
|
CHyprColor{255 / 255.0, 77 / 255.0, 77 / 255.0, 1.0},
|
||||||
|
|
@ -57,7 +57,7 @@ class CHyprNotificationOverlay {
|
||||||
PHLMONITORREF m_lastMonitor;
|
PHLMONITORREF m_lastMonitor;
|
||||||
Vector2D m_lastSize = Vector2D(-1, -1);
|
Vector2D m_lastSize = Vector2D(-1, -1);
|
||||||
|
|
||||||
SP<CTexture> m_texture;
|
SP<ITexture> m_texture;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline UP<CHyprNotificationOverlay> g_pHyprNotificationOverlay;
|
inline UP<CHyprNotificationOverlay> g_pHyprNotificationOverlay;
|
||||||
|
|
|
||||||
|
|
@ -1879,7 +1879,7 @@ uint16_t CMonitor::isDSBlocked(bool full) {
|
||||||
|
|
||||||
// we can't scanout shm buffers.
|
// we can't scanout shm buffers.
|
||||||
const auto params = PSURFACE->m_current.buffer->dmabuf();
|
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;
|
reasons |= DS_BLOCK_DMA;
|
||||||
if (!full)
|
if (!full)
|
||||||
return reasons;
|
return reasons;
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
#define HDR_REF_LUMINANCE 203.0
|
#define HDR_REF_LUMINANCE 203.0
|
||||||
#define HLG_MAX_LUMINANCE 1000.0
|
#define HLG_MAX_LUMINANCE 1000.0
|
||||||
|
|
||||||
class CTexture;
|
class ITexture;
|
||||||
|
|
||||||
namespace NColorManagement {
|
namespace NColorManagement {
|
||||||
enum eNoShader : uint8_t {
|
enum eNoShader : uint8_t {
|
||||||
|
|
@ -219,7 +219,7 @@ namespace NColorManagement {
|
||||||
bool present = false;
|
bool present = false;
|
||||||
size_t lutSize = 33;
|
size_t lutSize = 33;
|
||||||
std::vector<float> lutDataPacked;
|
std::vector<float> lutDataPacked;
|
||||||
SP<CTexture> lutTexture;
|
SP<ITexture> lutTexture;
|
||||||
std::optional<SVCGTTable16> vcgt;
|
std::optional<SVCGTTable16> vcgt;
|
||||||
} icc;
|
} icc;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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());
|
Log::logger->log(Log::DEBUG, "3D LUT constructed, size {}", image.icc.lutDataPacked.size());
|
||||||
|
|
||||||
// upload
|
// 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 {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,6 @@ CHyprError::CHyprError() {
|
||||||
if (m_fadeOpacity->isBeingAnimated() || m_monitorChanged)
|
if (m_fadeOpacity->isBeingAnimated() || m_monitorChanged)
|
||||||
g_pHyprRenderer->damageBox(m_damageBox);
|
g_pHyprRenderer->damageBox(m_damageBox);
|
||||||
});
|
});
|
||||||
|
|
||||||
m_texture = makeShared<CTexture>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHyprError::queueCreate(std::string message, const CHyprColor& color) {
|
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() {
|
void CHyprError::createQueued() {
|
||||||
if (m_isCreated)
|
if (m_isCreated && m_texture)
|
||||||
m_texture->destroyTexture();
|
m_texture.reset();
|
||||||
|
|
||||||
m_fadeOpacity->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn"));
|
m_fadeOpacity->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn"));
|
||||||
|
|
||||||
|
|
@ -145,12 +143,13 @@ void CHyprError::createQueued() {
|
||||||
|
|
||||||
// copy the data to an OpenGL texture we have
|
// copy the data to an OpenGL texture we have
|
||||||
const auto DATA = cairo_image_surface_get_data(CAIROSURFACE);
|
const auto DATA = cairo_image_surface_get_data(CAIROSURFACE);
|
||||||
m_texture->allocate();
|
auto tex = texture();
|
||||||
m_texture->bind();
|
tex->allocate(PMONITOR->m_pixelSize);
|
||||||
m_texture->setTexParameter(GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
tex->bind();
|
||||||
m_texture->setTexParameter(GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
tex->setTexParameter(GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
m_texture->setTexParameter(GL_TEXTURE_SWIZZLE_R, GL_BLUE);
|
tex->setTexParameter(GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
m_texture->setTexParameter(GL_TEXTURE_SWIZZLE_B, GL_RED);
|
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);
|
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->isBeingAnimated()) {
|
||||||
if (m_fadeOpacity->value() == 0.f) {
|
if (m_fadeOpacity->value() == 0.f) {
|
||||||
m_queuedDestroy = false;
|
m_queuedDestroy = false;
|
||||||
m_texture->destroyTexture();
|
if (m_texture)
|
||||||
|
m_texture.reset();
|
||||||
m_isCreated = false;
|
m_isCreated = false;
|
||||||
m_queued = "";
|
m_queued = "";
|
||||||
|
|
||||||
|
|
@ -218,7 +218,7 @@ void CHyprError::draw() {
|
||||||
m_monitorChanged = false;
|
m_monitorChanged = false;
|
||||||
|
|
||||||
CTexPassElement::SRenderData data;
|
CTexPassElement::SRenderData data;
|
||||||
data.tex = m_texture;
|
data.tex = texture();
|
||||||
data.box = monbox;
|
data.box = monbox;
|
||||||
data.a = m_fadeOpacity->value();
|
data.a = m_fadeOpacity->value();
|
||||||
|
|
||||||
|
|
@ -239,3 +239,9 @@ bool CHyprError::active() {
|
||||||
float CHyprError::height() {
|
float CHyprError::height() {
|
||||||
return m_lastHeight;
|
return m_lastHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SP<ITexture> CHyprError::texture() {
|
||||||
|
if (!m_texture)
|
||||||
|
m_texture = g_pHyprRenderer->createTexture();
|
||||||
|
return m_texture;
|
||||||
|
}
|
||||||
|
|
@ -18,13 +18,16 @@ class CHyprError {
|
||||||
bool active();
|
bool active();
|
||||||
float height(); // logical
|
float height(); // logical
|
||||||
|
|
||||||
|
//
|
||||||
|
SP<ITexture> texture();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createQueued();
|
void createQueued();
|
||||||
std::string m_queued = "";
|
std::string m_queued = "";
|
||||||
CHyprColor m_queuedColor;
|
CHyprColor m_queuedColor;
|
||||||
bool m_queuedDestroy = false;
|
bool m_queuedDestroy = false;
|
||||||
bool m_isCreated = false;
|
bool m_isCreated = false;
|
||||||
SP<CTexture> m_texture;
|
SP<ITexture> m_texture;
|
||||||
PHLANIMVAR<float> m_fadeOpacity;
|
PHLANIMVAR<float> m_fadeOpacity;
|
||||||
CBox m_damageBox = {0, 0, 0, 0};
|
CBox m_damageBox = {0, 0, 0, 0};
|
||||||
float m_lastHeight = 0.F;
|
float m_lastHeight = 0.F;
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#include "../protocols/IdleNotify.hpp"
|
#include "../protocols/IdleNotify.hpp"
|
||||||
#include "../protocols/core/Compositor.hpp"
|
#include "../protocols/core/Compositor.hpp"
|
||||||
#include "../protocols/core/Seat.hpp"
|
#include "../protocols/core/Seat.hpp"
|
||||||
|
#include "debug/log/Logger.hpp"
|
||||||
#include "eventLoop/EventLoopManager.hpp"
|
#include "eventLoop/EventLoopManager.hpp"
|
||||||
#include "../render/pass/TexPassElement.hpp"
|
#include "../render/pass/TexPassElement.hpp"
|
||||||
#include "../managers/input/InputManager.hpp"
|
#include "../managers/input/InputManager.hpp"
|
||||||
|
|
@ -22,6 +23,8 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <gbm.h>
|
#include <gbm.h>
|
||||||
#include <cairo/cairo.h>
|
#include <cairo/cairo.h>
|
||||||
|
#include <hyprutils/math/Region.hpp>
|
||||||
|
#include <hyprutils/math/Vector2D.hpp>
|
||||||
#include <hyprutils/utils/ScopeGuard.hpp>
|
#include <hyprutils/utils/ScopeGuard.hpp>
|
||||||
|
|
||||||
using namespace Hyprutils::Utils;
|
using namespace Hyprutils::Utils;
|
||||||
|
|
@ -407,7 +410,7 @@ bool CPointerManager::setHWCursorBuffer(SP<SMonitorPointerState> state, SP<Aquam
|
||||||
return true;
|
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 maxSize = state->monitor->m_output->cursorPlaneSize();
|
||||||
auto const& cursorSize = m_currentCursorImage.size;
|
auto const& cursorSize = m_currentCursorImage.size;
|
||||||
|
|
||||||
|
|
@ -900,13 +903,13 @@ const CPointerManager::SCursorImage& CPointerManager::currentCursorImage() {
|
||||||
return m_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))
|
if (!m_currentCursorImage.pBuffer && (!m_currentCursorImage.surface || !m_currentCursorImage.surface->resource()->m_current.texture))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (m_currentCursorImage.pBuffer) {
|
if (m_currentCursorImage.pBuffer) {
|
||||||
if (!m_currentCursorImage.bufferTex)
|
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;
|
return m_currentCursorImage.bufferTex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
class CMonitor;
|
class CMonitor;
|
||||||
class IHID;
|
class IHID;
|
||||||
class CTexture;
|
class ITexture;
|
||||||
|
|
||||||
AQUAMARINE_FORWARD(IBuffer);
|
AQUAMARINE_FORWARD(IBuffer);
|
||||||
|
|
||||||
|
|
@ -71,7 +71,7 @@ class CPointerManager {
|
||||||
|
|
||||||
struct SCursorImage {
|
struct SCursorImage {
|
||||||
SP<Aquamarine::IBuffer> pBuffer;
|
SP<Aquamarine::IBuffer> pBuffer;
|
||||||
SP<CTexture> bufferTex;
|
SP<ITexture> bufferTex;
|
||||||
WP<Desktop::View::CWLSurface> surface;
|
WP<Desktop::View::CWLSurface> surface;
|
||||||
|
|
||||||
Vector2D hotspot;
|
Vector2D hotspot;
|
||||||
|
|
@ -83,7 +83,7 @@ class CPointerManager {
|
||||||
};
|
};
|
||||||
|
|
||||||
const SCursorImage& currentCursorImage();
|
const SCursorImage& currentCursorImage();
|
||||||
SP<CTexture> getCurrentCursorTexture();
|
SP<ITexture> getCurrentCursorTexture();
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
CSignalT<> cursorChanged;
|
CSignalT<> cursorChanged;
|
||||||
|
|
@ -181,7 +181,7 @@ class CPointerManager {
|
||||||
std::vector<SP<SMonitorPointerState>> m_monitorStates;
|
std::vector<SP<SMonitorPointerState>> m_monitorStates;
|
||||||
SP<SMonitorPointerState> stateFor(PHLMONITOR mon);
|
SP<SMonitorPointerState> stateFor(PHLMONITOR mon);
|
||||||
bool attemptHardwareCursor(SP<SMonitorPointerState> state);
|
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);
|
bool setHWCursorBuffer(SP<SMonitorPointerState> state, SP<Aquamarine::IBuffer> buf);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
|
|
||||||
|
|
@ -169,10 +169,10 @@ bool CCursorshareSession::copy() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CFramebuffer outFB;
|
auto outFB = g_pHyprRenderer->createFB();
|
||||||
outFB.alloc(m_bufferSize.x, m_bufferSize.y, m_format);
|
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");
|
LOGM(Log::ERR, "Can't copy: failed to begin rendering to shm");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -182,8 +182,8 @@ bool CCursorshareSession::copy() {
|
||||||
g_pHyprRenderer->endRender();
|
g_pHyprRenderer->endRender();
|
||||||
|
|
||||||
g_pHyprOpenGL->m_renderData.pMonitor = m_pendingFrame.monitor;
|
g_pHyprOpenGL->m_renderData.pMonitor = m_pendingFrame.monitor;
|
||||||
outFB.bind();
|
outFB->bind();
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, outFB.getFBID());
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, GLFB(outFB)->getFBID());
|
||||||
|
|
||||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||||
|
|
||||||
|
|
@ -212,7 +212,7 @@ bool CCursorshareSession::copy() {
|
||||||
g_pHyprOpenGL->m_renderData.pMonitor.reset();
|
g_pHyprOpenGL->m_renderData.pMonitor.reset();
|
||||||
|
|
||||||
m_pendingFrame.buffer->endDataPtr();
|
m_pendingFrame.buffer->endDataPtr();
|
||||||
outFB.unbind();
|
GLFB(outFB)->unbind();
|
||||||
glPixelStorei(GL_PACK_ALIGNMENT, 4);
|
glPixelStorei(GL_PACK_ALIGNMENT, 4);
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#include "../../helpers/Monitor.hpp"
|
#include "../../helpers/Monitor.hpp"
|
||||||
#include "../../desktop/view/Window.hpp"
|
#include "../../desktop/view/Window.hpp"
|
||||||
#include "../../desktop/state/FocusState.hpp"
|
#include "../../desktop/state/FocusState.hpp"
|
||||||
|
#include <hyprutils/math/Region.hpp>
|
||||||
|
|
||||||
using namespace Screenshare;
|
using namespace Screenshare;
|
||||||
|
|
||||||
|
|
@ -133,7 +134,7 @@ void CScreenshareFrame::copy() {
|
||||||
// store a snapshot before the permission popup so we don't break screenshots
|
// 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);
|
const auto PERM = g_pDynamicPermissionManager->clientPermissionMode(m_session->m_client, PERMISSION_TYPE_SCREENCOPY);
|
||||||
if (PERM == PERMISSION_RULE_ALLOW_MODE_PENDING) {
|
if (PERM == PERMISSION_RULE_ALLOW_MODE_PENDING) {
|
||||||
if (!m_session->m_tempFB.isAllocated())
|
if (!m_session->m_tempFB || !m_session->m_tempFB->isAllocated())
|
||||||
storeTempFB();
|
storeTempFB();
|
||||||
|
|
||||||
// don't copy a frame while allow is pending because screenshot tools will only take the first frame we give, which is empty
|
// 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();
|
const auto PMONITOR = m_session->monitor();
|
||||||
|
|
||||||
if (!g_pHyprOpenGL->m_monitorRenderResources.contains(PMONITOR))
|
auto TEXTURE = g_pHyprRenderer->createTexture(PMONITOR->m_output->state->state().buffer);
|
||||||
return; // wtf?
|
|
||||||
|
|
||||||
auto TEXTURE = g_pHyprOpenGL->m_monitorRenderResources[PMONITOR].monitorMirrorFB.getTexture();
|
|
||||||
|
|
||||||
const bool IS_CM_AWARE = PROTO::colorManagement && PROTO::colorManagement->isClientCMAware(m_session->m_client);
|
const bool IS_CM_AWARE = PROTO::colorManagement && PROTO::colorManagement->isClientCMAware(m_session->m_client);
|
||||||
g_pHyprOpenGL->m_renderData.transformDamage = false;
|
g_pHyprOpenGL->m_renderData.transformDamage = false;
|
||||||
|
|
@ -328,10 +326,10 @@ void CScreenshareFrame::render() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_session->m_tempFB.isAllocated()) {
|
if (m_session->m_tempFB && m_session->m_tempFB->isAllocated()) {
|
||||||
CBox texbox = {{}, m_bufferSize};
|
CBox texbox = {{}, m_bufferSize};
|
||||||
g_pHyprOpenGL->renderTexture(m_session->m_tempFB.getTexture(), texbox, {});
|
g_pHyprOpenGL->renderTexture(m_session->m_tempFB->getTexture(), texbox, {});
|
||||||
m_session->m_tempFB.release();
|
m_session->m_tempFB->release();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -384,12 +382,12 @@ bool CScreenshareFrame::copyShm() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto PMONITOR = m_session->monitor();
|
const auto PMONITOR = m_session->monitor();
|
||||||
|
|
||||||
CFramebuffer outFB;
|
auto outFB = g_pHyprRenderer->createFB();
|
||||||
outFB.alloc(m_bufferSize.x, m_bufferSize.y, shm.format);
|
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");
|
LOGM(Log::ERR, "Can't copy: failed to begin rendering");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -401,8 +399,8 @@ bool CScreenshareFrame::copyShm() {
|
||||||
g_pHyprRenderer->endRender();
|
g_pHyprRenderer->endRender();
|
||||||
|
|
||||||
g_pHyprOpenGL->m_renderData.pMonitor = PMONITOR;
|
g_pHyprOpenGL->m_renderData.pMonitor = PMONITOR;
|
||||||
outFB.bind();
|
outFB->bind();
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, outFB.getFBID());
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, GLFB(outFB)->getFBID());
|
||||||
|
|
||||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||||
|
|
||||||
|
|
@ -444,7 +442,7 @@ bool CScreenshareFrame::copyShm() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
outFB.unbind();
|
GLFB(outFB)->unbind();
|
||||||
glPixelStorei(GL_PACK_ALIGNMENT, 4);
|
glPixelStorei(GL_PACK_ALIGNMENT, 4);
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||||
|
|
||||||
|
|
@ -459,13 +457,13 @@ bool CScreenshareFrame::copyShm() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CScreenshareFrame::storeTempFB() {
|
void CScreenshareFrame::storeTempFB() {
|
||||||
g_pHyprRenderer->makeEGLCurrent();
|
if (!m_session->m_tempFB)
|
||||||
|
m_session->m_tempFB = g_pHyprRenderer->createFB();
|
||||||
m_session->m_tempFB.alloc(m_bufferSize.x, m_bufferSize.y);
|
m_session->m_tempFB->alloc(m_bufferSize.x, m_bufferSize.y);
|
||||||
|
|
||||||
CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX};
|
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");
|
LOGM(Log::ERR, "Can't copy: failed to begin rendering to temp fb");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ namespace Screenshare {
|
||||||
std::vector<DRMFormat> m_formats;
|
std::vector<DRMFormat> m_formats;
|
||||||
Vector2D m_bufferSize = Vector2D(0, 0);
|
Vector2D m_bufferSize = Vector2D(0, 0);
|
||||||
|
|
||||||
CFramebuffer m_tempFB;
|
SP<IFramebuffer> m_tempFB;
|
||||||
|
|
||||||
SP<CEventLoopTimer> m_shareStopTimer;
|
SP<CEventLoopTimer> m_shareStopTimer;
|
||||||
bool m_sharing = false;
|
bool m_sharing = false;
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,11 @@ CSinglePixelBuffer::CSinglePixelBuffer(uint32_t id, wl_client* client, CHyprColo
|
||||||
|
|
||||||
m_opaque = col_.a >= 1.F;
|
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_resource = CWLBufferResource::create(makeShared<CWlBuffer>(client, 1, id));
|
||||||
|
|
||||||
m_success = m_texture->m_texID;
|
m_success = m_texture->ok();
|
||||||
|
|
||||||
size = {1, 1};
|
size = {1, 1};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ class IHLBuffer : public Aquamarine::IBuffer {
|
||||||
void onBackendRelease(const std::function<void()>& fn);
|
void onBackendRelease(const std::function<void()>& fn);
|
||||||
void addReleasePoint(CDRMSyncPointState& point);
|
void addReleasePoint(CDRMSyncPointState& point);
|
||||||
|
|
||||||
SP<CTexture> m_texture;
|
SP<ITexture> m_texture;
|
||||||
bool m_opaque = false;
|
bool m_opaque = false;
|
||||||
SP<CWLBufferResource> m_resource;
|
SP<CWLBufferResource> m_resource;
|
||||||
std::vector<UP<CSyncReleaser>> m_syncReleasers;
|
std::vector<UP<CSyncReleaser>> m_syncReleasers;
|
||||||
|
|
|
||||||
|
|
@ -13,31 +13,28 @@
|
||||||
using namespace Hyprutils::OS;
|
using namespace Hyprutils::OS;
|
||||||
|
|
||||||
CDMABuffer::CDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs const& attrs_) : m_attrs(attrs_) {
|
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] {
|
m_listeners.resourceDestroy = events.destroy.listen([this] {
|
||||||
closeFDs();
|
closeFDs();
|
||||||
m_listeners.resourceDestroy.reset();
|
m_listeners.resourceDestroy.reset();
|
||||||
});
|
});
|
||||||
|
|
||||||
size = m_attrs.size;
|
size = m_attrs.size;
|
||||||
m_resource = CWLBufferResource::create(makeShared<CWlBuffer>(client, 1, id));
|
m_resource = CWLBufferResource::create(makeShared<CWlBuffer>(client, 1, id));
|
||||||
auto eglImage = g_pHyprOpenGL->createEGLImage(m_attrs);
|
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");
|
Log::logger->log(Log::ERR, "CDMABuffer: failed to import EGLImage, retrying as implicit");
|
||||||
m_attrs.modifier = DRM_FORMAT_MOD_INVALID;
|
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");
|
Log::logger->log(Log::ERR, "CDMABuffer: failed to import EGLImage");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_texture = makeShared<CTexture>(m_attrs, eglImage); // texture takes ownership of the eglImage
|
m_success = m_texture->ok();
|
||||||
m_opaque = NFormatUtils::isFormatOpaque(m_attrs.format);
|
|
||||||
m_success = m_texture->m_texID;
|
|
||||||
|
|
||||||
if UNLIKELY (!m_success)
|
if UNLIKELY (!m_success)
|
||||||
Log::logger->log(Log::ERR, "Failed to create a dmabuf: texture is null");
|
Log::logger->log(Log::ERR, "Failed to create a dmabuf: texture is null");
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include "SurfaceState.hpp"
|
#include "SurfaceState.hpp"
|
||||||
#include "helpers/Format.hpp"
|
#include "helpers/Format.hpp"
|
||||||
#include "protocols/types/Buffer.hpp"
|
#include "protocols/types/Buffer.hpp"
|
||||||
|
#include "render/Renderer.hpp"
|
||||||
#include "render/Texture.hpp"
|
#include "render/Texture.hpp"
|
||||||
|
|
||||||
Vector2D SSurfaceState::sourceSize() {
|
Vector2D SSurfaceState::sourceSize() {
|
||||||
|
|
@ -34,7 +35,7 @@ CRegion SSurfaceState::accumulateBufferDamage() {
|
||||||
return bufferDamage;
|
return bufferDamage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSurfaceState::updateSynchronousTexture(SP<CTexture> lastTexture) {
|
void SSurfaceState::updateSynchronousTexture(SP<ITexture> lastTexture) {
|
||||||
auto [dataPtr, fmt, size] = buffer->beginDataPtr(0);
|
auto [dataPtr, fmt, size] = buffer->beginDataPtr(0);
|
||||||
if (dataPtr) {
|
if (dataPtr) {
|
||||||
auto drmFmt = NFormatUtils::shmToDRM(fmt);
|
auto drmFmt = NFormatUtils::shmToDRM(fmt);
|
||||||
|
|
@ -43,7 +44,7 @@ void SSurfaceState::updateSynchronousTexture(SP<CTexture> lastTexture) {
|
||||||
texture = lastTexture;
|
texture = lastTexture;
|
||||||
texture->update(drmFmt, dataPtr, stride, accumulateBufferDamage());
|
texture->update(drmFmt, dataPtr, stride, accumulateBufferDamage());
|
||||||
} else
|
} else
|
||||||
texture = makeShared<CTexture>(drmFmt, dataPtr, stride, bufferSize);
|
texture = g_pHyprRenderer->createTexture(drmFmt, dataPtr, stride, bufferSize);
|
||||||
}
|
}
|
||||||
buffer->endDataPtr();
|
buffer->endDataPtr();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
#include "../WaylandProtocol.hpp"
|
#include "../WaylandProtocol.hpp"
|
||||||
#include "./Buffer.hpp"
|
#include "./Buffer.hpp"
|
||||||
|
|
||||||
class CTexture;
|
class ITexture;
|
||||||
class CDRMSyncPointState;
|
class CDRMSyncPointState;
|
||||||
class CWLCallbackResource;
|
class CWLCallbackResource;
|
||||||
|
|
||||||
|
|
@ -88,8 +88,8 @@ struct SSurfaceState {
|
||||||
eLockReason lockMask = LOCK_REASON_NONE;
|
eLockReason lockMask = LOCK_REASON_NONE;
|
||||||
|
|
||||||
// texture of surface content, used for rendering
|
// texture of surface content, used for rendering
|
||||||
SP<CTexture> texture;
|
SP<ITexture> texture;
|
||||||
void updateSynchronousTexture(SP<CTexture> lastTexture);
|
void updateSynchronousTexture(SP<ITexture> lastTexture);
|
||||||
|
|
||||||
// fifo
|
// fifo
|
||||||
bool barrierSet = false;
|
bool barrierSet = false;
|
||||||
|
|
|
||||||
|
|
@ -1,140 +1,30 @@
|
||||||
#include "Framebuffer.hpp"
|
#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 IFramebuffer::alloc(int w, int h, uint32_t format) {
|
||||||
bool firstAlloc = false;
|
|
||||||
RASSERT((w > 0 && h > 0), "cannot alloc a FB with negative / zero size! (attempted {}x{})", w, h);
|
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 sizeChanged = (m_size != Vector2D(w, h));
|
||||||
const bool formatChanged = (drmFormat != m_drmFormat);
|
const bool formatChanged = (format != m_drmFormat);
|
||||||
|
|
||||||
if (!m_tex) {
|
if (m_fbAllocated && !sizeChanged && !formatChanged)
|
||||||
m_tex = makeShared<CTexture>();
|
return true;
|
||||||
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) {
|
m_size = {w, h};
|
||||||
glGenFramebuffers(1, &m_fb);
|
m_drmFormat = format;
|
||||||
m_fbAllocated = true;
|
m_fbAllocated = internalAlloc(w, h, format);
|
||||||
firstAlloc = true;
|
return m_fbAllocated;
|
||||||
}
|
|
||||||
|
|
||||||
if (firstAlloc || sizeChanged || formatChanged) {
|
|
||||||
const auto format = NFormatUtils::getPixelFormatFromDRM(drmFormat);
|
|
||||||
m_tex->bind();
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, format->glInternalFormat ? format->glInternalFormat : format->glFormat, w, h, 0, format->glFormat, format->glType, nullptr);
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, m_fb);
|
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_tex->m_texID, 0);
|
|
||||||
|
|
||||||
if (m_stencilTex) {
|
|
||||||
m_stencilTex->bind();
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, w, h, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr);
|
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_stencilTex->m_texID, 0);
|
|
||||||
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
|
||||||
glDepthMask(GL_FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
||||||
RASSERT((status == GL_FRAMEBUFFER_COMPLETE), "Framebuffer incomplete, couldn't create! (FB status: {}, GL Error: 0x{:x})", status, sc<int>(glGetError()));
|
|
||||||
|
|
||||||
Log::logger->log(Log::DEBUG, "Framebuffer created, status {}", status);
|
|
||||||
}
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
||||||
|
|
||||||
m_drmFormat = drmFormat;
|
|
||||||
m_size = Vector2D(w, h);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFramebuffer::addStencil(SP<CTexture> tex) {
|
bool IFramebuffer::isAllocated() {
|
||||||
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() {
|
|
||||||
return m_fbAllocated && m_tex;
|
return m_fbAllocated && m_tex;
|
||||||
}
|
}
|
||||||
|
|
||||||
SP<CTexture> CFramebuffer::getTexture() {
|
SP<ITexture> IFramebuffer::getTexture() {
|
||||||
return m_tex;
|
return m_tex;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint CFramebuffer::getFBID() {
|
SP<ITexture> IFramebuffer::getStencilTex() {
|
||||||
return m_fbAllocated ? m_fb : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
SP<CTexture> CFramebuffer::getStencilTex() {
|
|
||||||
return m_stencilTex;
|
return m_stencilTex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFramebuffer::invalidate(const std::vector<GLenum>& attachments) {
|
|
||||||
if (!isAllocated())
|
|
||||||
return;
|
|
||||||
|
|
||||||
glInvalidateFramebuffer(GL_FRAMEBUFFER, attachments.size(), attachments.data());
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -3,34 +3,38 @@
|
||||||
#include "../defines.hpp"
|
#include "../defines.hpp"
|
||||||
#include "../helpers/Format.hpp"
|
#include "../helpers/Format.hpp"
|
||||||
#include "Texture.hpp"
|
#include "Texture.hpp"
|
||||||
|
#include <cstdint>
|
||||||
#include <drm_fourcc.h>
|
#include <drm_fourcc.h>
|
||||||
|
|
||||||
class CFramebuffer {
|
class CHLBufferReference;
|
||||||
public:
|
|
||||||
CFramebuffer();
|
class IFramebuffer {
|
||||||
~CFramebuffer();
|
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();
|
bool isAllocated();
|
||||||
SP<CTexture> getTexture();
|
SP<ITexture> getTexture();
|
||||||
SP<CTexture> getStencilTex();
|
SP<ITexture> getStencilTex();
|
||||||
GLuint getFBID();
|
|
||||||
void invalidate(const std::vector<GLenum>& attachments);
|
virtual void addStencil(SP<ITexture> tex) = 0;
|
||||||
|
|
||||||
Vector2D m_size;
|
Vector2D m_size;
|
||||||
DRMFormat m_drmFormat = 0 /* DRM_FORMAT_INVALID */;
|
DRMFormat m_drmFormat = DRM_FORMAT_INVALID;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
SP<CTexture> m_tex;
|
virtual bool internalAlloc(int w, int h, uint32_t format = DRM_FORMAT_ARGB8888) = 0;
|
||||||
GLuint m_fb = -1;
|
|
||||||
|
SP<ITexture> m_tex;
|
||||||
bool m_fbAllocated = false;
|
bool m_fbAllocated = false;
|
||||||
|
|
||||||
SP<CTexture> m_stencilTex;
|
SP<ITexture> m_stencilTex;
|
||||||
|
std::string m_name; // name for logging
|
||||||
friend class CRenderbuffer;
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,8 @@
|
||||||
#include "ShaderLoader.hpp"
|
#include "ShaderLoader.hpp"
|
||||||
#include "Texture.hpp"
|
#include "Texture.hpp"
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include "gl/GLFramebuffer.hpp"
|
||||||
|
#include "gl/GLTexture.hpp"
|
||||||
|
|
||||||
using namespace Hyprutils::OS;
|
using namespace Hyprutils::OS;
|
||||||
using namespace NColorManagement;
|
using namespace NColorManagement;
|
||||||
|
|
@ -644,7 +646,7 @@ EGLImageKHR CHyprOpenGLImpl::createEGLImage(const Aquamarine::SDMABUFAttrs& attr
|
||||||
return image;
|
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;
|
m_renderData.pMonitor = pMonitor;
|
||||||
|
|
||||||
const GLenum RESETSTATUS = glGetGraphicsResetStatus();
|
const GLenum RESETSTATUS = glGetGraphicsResetStatus();
|
||||||
|
|
@ -697,7 +699,7 @@ void CHyprOpenGLImpl::beginSimple(PHLMONITOR pMonitor, const CRegion& damage, SP
|
||||||
pushMonitorTransformEnabled(false);
|
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;
|
m_renderData.pMonitor = pMonitor;
|
||||||
|
|
||||||
const GLenum RESETSTATUS = glGetGraphicsResetStatus();
|
const GLenum RESETSTATUS = glGetGraphicsResetStatus();
|
||||||
|
|
@ -721,7 +723,8 @@ void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, CFrameb
|
||||||
|
|
||||||
m_renderData.monitorProjection = pMonitor->m_projMatrix;
|
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);
|
destroyMonitorResources(pMonitor);
|
||||||
|
|
||||||
m_renderData.pCurrentMonData = &m_monitorRenderResources[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;
|
const auto DRM_FORMAT = fb ? fb->m_drmFormat : pMonitor->m_output->state->state().drmFormat;
|
||||||
|
|
||||||
// ensure a framebuffer for the monitor exists
|
// 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) {
|
if (!m_renderData.pCurrentMonData->offloadFB || m_renderData.pCurrentMonData->offloadFB->m_size != pMonitor->m_pixelSize ||
|
||||||
m_renderData.pCurrentMonData->stencilTex->allocate();
|
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->offloadFB->addStencil(m_renderData.pCurrentMonData->stencilTex);
|
||||||
m_renderData.pCurrentMonData->mirrorFB.alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, DRM_FORMAT);
|
m_renderData.pCurrentMonData->mirrorFB->addStencil(m_renderData.pCurrentMonData->stencilTex);
|
||||||
m_renderData.pCurrentMonData->mirrorSwapFB.alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, DRM_FORMAT);
|
m_renderData.pCurrentMonData->mirrorSwapFB->addStencil(m_renderData.pCurrentMonData->stencilTex);
|
||||||
|
|
||||||
m_renderData.pCurrentMonData->offloadFB.addStencil(m_renderData.pCurrentMonData->stencilTex);
|
m_renderData.pCurrentMonData->offloadFB->alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, DRM_FORMAT);
|
||||||
m_renderData.pCurrentMonData->mirrorFB.addStencil(m_renderData.pCurrentMonData->stencilTex);
|
m_renderData.pCurrentMonData->mirrorFB->alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, DRM_FORMAT);
|
||||||
m_renderData.pCurrentMonData->mirrorSwapFB.addStencil(m_renderData.pCurrentMonData->stencilTex);
|
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());
|
const bool NEEDS_COPY_FB = needsACopyFB(m_renderData.pMonitor.lock());
|
||||||
|
|
||||||
if (HAS_MIRROR_FB && !NEEDS_COPY_FB)
|
if (HAS_MIRROR_FB && !NEEDS_COPY_FB)
|
||||||
m_renderData.pCurrentMonData->monitorMirrorFB.release();
|
m_renderData.pCurrentMonData->monitorMirrorFB->release();
|
||||||
else if (!HAS_MIRROR_FB && NEEDS_COPY_FB)
|
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.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.pMonitor->m_output->state->state().drmFormat);
|
||||||
|
|
||||||
m_renderData.transformDamage = true;
|
m_renderData.transformDamage = true;
|
||||||
if (HAS_MIRROR_FB != NEEDS_COPY_FB) {
|
if (HAS_MIRROR_FB != NEEDS_COPY_FB) {
|
||||||
|
|
@ -771,8 +778,8 @@ void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, CFrameb
|
||||||
applyScreenShader(*PSHADER);
|
applyScreenShader(*PSHADER);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_renderData.pCurrentMonData->offloadFB.bind();
|
m_renderData.pCurrentMonData->offloadFB->bind();
|
||||||
m_renderData.currentFB = &m_renderData.pCurrentMonData->offloadFB;
|
m_renderData.currentFB = m_renderData.pCurrentMonData->offloadFB;
|
||||||
m_offloadedFramebuffer = true;
|
m_offloadedFramebuffer = true;
|
||||||
|
|
||||||
m_renderData.mainFB = m_renderData.currentFB;
|
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{};
|
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)
|
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.
|
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);
|
blend(true);
|
||||||
|
|
||||||
|
|
@ -831,14 +838,22 @@ void CHyprOpenGLImpl::end() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// invalidate our render FBs to signal to the driver we don't need them anymore
|
// invalidate our render FBs to signal to the driver we don't need them anymore
|
||||||
m_renderData.pCurrentMonData->mirrorFB.bind();
|
if (m_renderData.pCurrentMonData->mirrorFB) {
|
||||||
m_renderData.pCurrentMonData->mirrorFB.invalidate({GL_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0});
|
m_renderData.pCurrentMonData->mirrorFB->bind();
|
||||||
m_renderData.pCurrentMonData->mirrorSwapFB.bind();
|
GLFB(m_renderData.pCurrentMonData->mirrorFB)->invalidate({GL_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0});
|
||||||
m_renderData.pCurrentMonData->mirrorSwapFB.invalidate({GL_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0});
|
}
|
||||||
m_renderData.pCurrentMonData->offloadFB.bind();
|
if (m_renderData.pCurrentMonData->mirrorSwapFB) {
|
||||||
m_renderData.pCurrentMonData->offloadFB.invalidate({GL_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0});
|
m_renderData.pCurrentMonData->mirrorSwapFB->bind();
|
||||||
m_renderData.pCurrentMonData->offMainFB.bind();
|
GLFB(m_renderData.pCurrentMonData->mirrorSwapFB)->invalidate({GL_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0});
|
||||||
m_renderData.pCurrentMonData->offMainFB.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
|
// reset our data
|
||||||
m_renderData.pMonitor.reset();
|
m_renderData.pMonitor.reset();
|
||||||
|
|
@ -853,8 +868,8 @@ void CHyprOpenGLImpl::end() {
|
||||||
// if we dropped to offMain, release it now.
|
// if we dropped to offMain, release it now.
|
||||||
// if there is a plugin constantly using it, this might be a bit slow,
|
// 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.
|
// 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())
|
if UNLIKELY (m_renderData.pCurrentMonData->offMainFB && m_renderData.pCurrentMonData->offMainFB->isAllocated())
|
||||||
m_renderData.pCurrentMonData->offMainFB.release();
|
m_renderData.pCurrentMonData->offMainFB->release();
|
||||||
|
|
||||||
static const auto GLDEBUG = CConfigValue<Hyprlang::INT>("debug:gl_debugging");
|
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};
|
CRegion damage{m_renderData.damage};
|
||||||
damage.intersect(box);
|
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();
|
m_renderData.currentFB->bind();
|
||||||
|
|
||||||
|
|
@ -1135,7 +1150,7 @@ void CHyprOpenGLImpl::renderRectWithDamageInternal(const CBox& box, const CHyprC
|
||||||
scissor(nullptr);
|
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()!");
|
RASSERT(m_renderData.pMonitor, "Tried to render texture without begin()!");
|
||||||
|
|
||||||
if (!data.damage) {
|
if (!data.damage) {
|
||||||
|
|
@ -1460,9 +1475,9 @@ WP<CShader> CHyprOpenGLImpl::renderToFBInternal(const STextureRenderData& data,
|
||||||
return shader;
|
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(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");
|
TRACY_GPU_ZONE("RenderTextureInternalWithDamage");
|
||||||
|
|
||||||
|
|
@ -1558,9 +1573,9 @@ void CHyprOpenGLImpl::renderTextureInternal(SP<CTexture> tex, const CBox& box, c
|
||||||
tex->unbind();
|
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(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");
|
TRACY_GPU_ZONE("RenderTexturePrimitive");
|
||||||
|
|
||||||
|
|
@ -1603,9 +1618,9 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP<CTexture> tex, const CBox& box)
|
||||||
tex->unbind();
|
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(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");
|
TRACY_GPU_ZONE("RenderTextureMatte");
|
||||||
|
|
||||||
|
|
@ -1629,7 +1644,7 @@ void CHyprOpenGLImpl::renderTextureMatte(SP<CTexture> tex, const CBox& box, CFra
|
||||||
tex->bind();
|
tex->bind();
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0 + 1);
|
glActiveTexture(GL_TEXTURE0 + 1);
|
||||||
auto matteTex = matte.getTexture();
|
auto matteTex = matte->getTexture();
|
||||||
matteTex->bind();
|
matteTex->bind();
|
||||||
|
|
||||||
glBindVertexArray(shader->getUniformLocation(SHADER_SHADER_VAO));
|
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?
|
// but it works... well, I guess?
|
||||||
//
|
//
|
||||||
// Dual (or more) kawase blur
|
// 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()) {
|
if (!m_renderData.currentFB->getTexture()) {
|
||||||
Log::logger->log(Log::ERR, "BUG THIS: null fb texture while attempting to blur main fb?! (introspection off?!)");
|
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");
|
TRACY_GPU_ZONE("RenderBlurFramebufferWithDamage");
|
||||||
|
|
||||||
const auto BLENDBEFORE = m_blend;
|
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));
|
damage.expand(std::clamp(*PBLURSIZE, sc<int64_t>(1), sc<int64_t>(40)) * pow(2, BLUR_PASSES));
|
||||||
|
|
||||||
// helper
|
// helper
|
||||||
const auto PMIRRORFB = &m_renderData.pCurrentMonData->mirrorFB;
|
const auto PMIRRORFB = m_renderData.pCurrentMonData->mirrorFB;
|
||||||
const auto PMIRRORSWAPFB = &m_renderData.pCurrentMonData->mirrorSwapFB;
|
const auto PMIRRORSWAPFB = m_renderData.pCurrentMonData->mirrorSwapFB;
|
||||||
|
|
||||||
CFramebuffer* currentRenderToFB = PMIRRORFB;
|
auto currentRenderToFB = PMIRRORFB;
|
||||||
|
|
||||||
// Begin with base color adjustments - global brightness and contrast
|
// Begin with base color adjustments - global brightness and contrast
|
||||||
// TODO: make this a part of the first pass maybe to save on a drawcall?
|
// 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);
|
const auto POUTFB = blurMainFramebufferWithDamage(1, &fakeDamage);
|
||||||
|
|
||||||
// render onto blurFB
|
// render onto blurFB
|
||||||
m_renderData.pCurrentMonData->blurFB.alloc(m_renderData.pMonitor->m_pixelSize.x, m_renderData.pMonitor->m_pixelSize.y,
|
if (!m_renderData.pCurrentMonData->blurFB)
|
||||||
m_renderData.pMonitor->m_output->state->state().drmFormat);
|
m_renderData.pCurrentMonData->blurFB = g_pHyprRenderer->createFB();
|
||||||
m_renderData.pCurrentMonData->blurFB.bind();
|
|
||||||
|
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));
|
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 PBLURNEWOPTIMIZE = CConfigValue<Hyprlang::INT>("decoration:blur:new_optimizations");
|
||||||
static auto PBLURXRAY = CConfigValue<Hyprlang::INT>("decoration:blur:xray");
|
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;
|
return false;
|
||||||
|
|
||||||
if (pWindow && pWindow->m_ruleApplicator->xray().hasValue() && !pWindow->m_ruleApplicator->xray().valueOrDefault())
|
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;
|
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()!");
|
RASSERT(m_renderData.pMonitor, "Tried to render texture with blur without begin()!");
|
||||||
|
|
||||||
TRACY_GPU_ZONE("RenderTextureWithBlur");
|
TRACY_GPU_ZONE("RenderTextureWithBlur");
|
||||||
|
|
@ -2056,16 +2074,16 @@ void CHyprOpenGLImpl::renderTextureWithBlurInternal(SP<CTexture> tex, const CBox
|
||||||
inverseOpaque.scale(m_renderData.pMonitor->m_scale);
|
inverseOpaque.scale(m_renderData.pMonitor->m_scale);
|
||||||
|
|
||||||
// vvv TODO: layered blur fbs?
|
// 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) {
|
if (!USENEWOPTIMIZE) {
|
||||||
inverseOpaque.translate(box.pos());
|
inverseOpaque.translate(box.pos());
|
||||||
m_renderData.renderModif.applyToRegion(inverseOpaque);
|
m_renderData.renderModif.applyToRegion(inverseOpaque);
|
||||||
inverseOpaque.intersect(texDamage);
|
inverseOpaque.intersect(texDamage);
|
||||||
POUTFB = blurMainFramebufferWithDamage(data.a, &inverseOpaque);
|
POUTFB = blurMainFramebufferWithDamage(data.a, &inverseOpaque);
|
||||||
} else
|
} else
|
||||||
POUTFB = &m_renderData.pCurrentMonData->blurFB;
|
POUTFB = m_renderData.pCurrentMonData->blurFB;
|
||||||
|
|
||||||
m_renderData.currentFB->bind();
|
m_renderData.currentFB->bind();
|
||||||
|
|
||||||
|
|
@ -2161,7 +2179,7 @@ void CHyprOpenGLImpl::renderTextureWithBlurInternal(SP<CTexture> tex, const CBox
|
||||||
.blurredBG = blurredBG,
|
.blurredBG = blurredBG,
|
||||||
});
|
});
|
||||||
|
|
||||||
m_renderData.currentFB->invalidate({GL_STENCIL_ATTACHMENT});
|
GLFB(m_renderData.currentFB)->invalidate({GL_STENCIL_ATTACHMENT});
|
||||||
scissor(nullptr);
|
scissor(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2410,7 +2428,14 @@ void CHyprOpenGLImpl::renderRoundedShadow(const CBox& box, int round, float roun
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHyprOpenGLImpl::saveBufferForMirror(const CBox& box) {
|
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);
|
blend(false);
|
||||||
|
|
||||||
|
|
@ -2443,7 +2468,7 @@ void CHyprOpenGLImpl::renderMirrored() {
|
||||||
monbox.x = (monitor->m_transformedSize.x - monbox.w) / 2;
|
monbox.x = (monitor->m_transformedSize.x - monbox.w) / 2;
|
||||||
monbox.y = (monitor->m_transformedSize.y - monbox.h) / 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())
|
if (!PFB->isAllocated() || !PFB->getTexture())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -2517,7 +2542,7 @@ std::string CHyprOpenGLImpl::resolveAssetPath(const std::string& filename) {
|
||||||
return fullPath;
|
return fullPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
SP<CTexture> CHyprOpenGLImpl::loadAsset(const std::string& filename) {
|
SP<ITexture> CHyprOpenGLImpl::loadAsset(const std::string& filename) {
|
||||||
|
|
||||||
const std::string fullPath = resolveAssetPath(filename);
|
const std::string fullPath = resolveAssetPath(filename);
|
||||||
|
|
||||||
|
|
@ -2539,12 +2564,11 @@ SP<CTexture> CHyprOpenGLImpl::loadAsset(const std::string& filename) {
|
||||||
return tex;
|
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);
|
const auto CAIROFORMAT = cairo_image_surface_get_format(cairo);
|
||||||
auto tex = makeShared<CTexture>();
|
auto tex = makeShared<CGLTexture>();
|
||||||
|
|
||||||
tex->allocate();
|
tex->allocate({cairo_image_surface_get_width(cairo), cairo_image_surface_get_height(cairo)});
|
||||||
tex->m_size = {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 glIFormat = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_RGB32F : GL_RGBA;
|
||||||
const GLint glFormat = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_RGB : 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;
|
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<ITexture> 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> tex = makeShared<CGLTexture>();
|
||||||
|
|
||||||
static auto FONT = CConfigValue<std::string>("misc:font_family");
|
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);
|
cairo_surface_flush(CAIROSURFACE);
|
||||||
|
|
||||||
tex->allocate();
|
tex->allocate({cairo_image_surface_get_width(CAIROSURFACE), cairo_image_surface_get_height(CAIROSURFACE)});
|
||||||
tex->m_size = {cairo_image_surface_get_width(CAIROSURFACE), cairo_image_surface_get_height(CAIROSURFACE)};
|
|
||||||
|
|
||||||
const auto DATA = cairo_image_surface_get_data(CAIROSURFACE);
|
const auto DATA = cairo_image_surface_get_data(CAIROSURFACE);
|
||||||
tex->bind();
|
tex->bind();
|
||||||
|
|
@ -2646,8 +2669,8 @@ SP<CTexture> CHyprOpenGLImpl::renderText(const std::string& text, CHyprColor col
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHyprOpenGLImpl::initMissingAssetTexture() {
|
void CHyprOpenGLImpl::initMissingAssetTexture() {
|
||||||
SP<CTexture> tex = makeShared<CTexture>();
|
SP<ITexture> tex = makeShared<CGLTexture>();
|
||||||
tex->allocate();
|
tex->allocate({512, 512});
|
||||||
|
|
||||||
const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 512, 512);
|
const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 512, 512);
|
||||||
const auto CAIRO = cairo_create(CAIROSURFACE);
|
const auto CAIRO = cairo_create(CAIROSURFACE);
|
||||||
|
|
@ -2799,16 +2822,19 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(PHLMONITOR pMonitor) {
|
||||||
if (!m_backgroundResource->m_ready)
|
if (!m_backgroundResource->m_ready)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!m_monitorBGFBs.contains(pMonitor))
|
||||||
|
m_monitorBGFBs[pMonitor] = g_pHyprRenderer->createFB();
|
||||||
|
|
||||||
// release the last tex if exists
|
// release the last tex if exists
|
||||||
const auto PFB = &m_monitorBGFBs[pMonitor];
|
auto PFB = m_monitorBGFBs[pMonitor];
|
||||||
PFB->release();
|
PFB->release();
|
||||||
|
|
||||||
PFB->alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, pMonitor->m_output->state->state().drmFormat);
|
PFB->alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, pMonitor->m_output->state->state().drmFormat);
|
||||||
|
|
||||||
// create a new one with cairo
|
// 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 CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y);
|
||||||
const auto CAIRO = cairo_create(CAIROSURFACE);
|
const auto CAIRO = cairo_create(CAIROSURFACE);
|
||||||
|
|
@ -2850,7 +2876,7 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(PHLMONITOR pMonitor) {
|
||||||
blend(true);
|
blend(true);
|
||||||
clear(CHyprColor{0, 0, 0, 1});
|
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
|
// first render the background
|
||||||
if (backgroundTexture) {
|
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.box = {0, 0, m_renderData.pMonitor->m_transformedSize.x, m_renderData.pMonitor->m_transformedSize.y};
|
||||||
data.a = m_renderData.pMonitor->m_backgroundOpacity->value();
|
data.a = m_renderData.pMonitor->m_backgroundOpacity->value();
|
||||||
data.flipEndFrame = true;
|
data.flipEndFrame = true;
|
||||||
data.tex = TEXIT->second.getTexture();
|
data.tex = TEXIT->second->getTexture();
|
||||||
g_pHyprRenderer->m_renderPass.add(makeUnique<CTexPassElement>(std::move(data)));
|
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);
|
auto RESIT = g_pHyprOpenGL->m_monitorRenderResources.find(pMonitor);
|
||||||
if (RESIT != g_pHyprOpenGL->m_monitorRenderResources.end()) {
|
if (RESIT != g_pHyprOpenGL->m_monitorRenderResources.end()) {
|
||||||
RESIT->second.mirrorFB.release();
|
RESIT->second.mirrorFB.reset();
|
||||||
RESIT->second.offloadFB.release();
|
RESIT->second.offloadFB.reset();
|
||||||
RESIT->second.mirrorSwapFB.release();
|
RESIT->second.mirrorSwapFB.reset();
|
||||||
RESIT->second.monitorMirrorFB.release();
|
RESIT->second.monitorMirrorFB.reset();
|
||||||
RESIT->second.blurFB.release();
|
RESIT->second.blurFB.reset();
|
||||||
RESIT->second.offMainFB.release();
|
RESIT->second.offMainFB.reset();
|
||||||
RESIT->second.stencilTex->destroyTexture();
|
RESIT->second.stencilTex.reset();
|
||||||
g_pHyprOpenGL->m_monitorRenderResources.erase(RESIT);
|
g_pHyprOpenGL->m_monitorRenderResources.erase(RESIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto TEXIT = g_pHyprOpenGL->m_monitorBGFBs.find(pMonitor);
|
auto TEXIT = g_pHyprOpenGL->m_monitorBGFBs.find(pMonitor);
|
||||||
if (TEXIT != g_pHyprOpenGL->m_monitorBGFBs.end()) {
|
if (TEXIT != g_pHyprOpenGL->m_monitorBGFBs.end()) {
|
||||||
TEXIT->second.release();
|
TEXIT->second.reset();
|
||||||
g_pHyprOpenGL->m_monitorBGFBs.erase(TEXIT);
|
g_pHyprOpenGL->m_monitorBGFBs.erase(TEXIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2951,19 +2977,21 @@ void CHyprOpenGLImpl::restoreMatrix() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHyprOpenGLImpl::bindOffMain() {
|
void CHyprOpenGLImpl::bindOffMain() {
|
||||||
if (!m_renderData.pCurrentMonData->offMainFB.isAllocated()) {
|
if (!m_renderData.pCurrentMonData->offMainFB)
|
||||||
m_renderData.pCurrentMonData->offMainFB.alloc(m_renderData.pMonitor->m_pixelSize.x, m_renderData.pMonitor->m_pixelSize.y,
|
m_renderData.pCurrentMonData->offMainFB = g_pHyprRenderer->createFB();
|
||||||
m_renderData.pMonitor->m_output->state->state().drmFormat);
|
|
||||||
|
|
||||||
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));
|
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};
|
CBox monbox = {0, 0, m_renderData.pMonitor->m_transformedSize.x, m_renderData.pMonitor->m_transformedSize.y};
|
||||||
renderTexturePrimitive(off->getTexture(), monbox);
|
renderTexturePrimitive(off->getTexture(), monbox);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
#include "Texture.hpp"
|
#include "Texture.hpp"
|
||||||
#include "Framebuffer.hpp"
|
#include "Framebuffer.hpp"
|
||||||
#include "Renderbuffer.hpp"
|
#include "Renderbuffer.hpp"
|
||||||
|
#include "desktop/DesktopTypes.hpp"
|
||||||
#include "pass/Pass.hpp"
|
#include "pass/Pass.hpp"
|
||||||
|
|
||||||
#include <EGL/egl.h>
|
#include <EGL/egl.h>
|
||||||
|
|
@ -32,9 +33,14 @@
|
||||||
#include "../debug/TracyDefines.hpp"
|
#include "../debug/TracyDefines.hpp"
|
||||||
#include "../protocols/core/Compositor.hpp"
|
#include "../protocols/core/Compositor.hpp"
|
||||||
#include "render/ShaderLoader.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;
|
struct gbm_device;
|
||||||
class CHyprRenderer;
|
class IHyprRenderer;
|
||||||
|
|
||||||
struct SVertex {
|
struct SVertex {
|
||||||
float x, y; // position
|
float x, y; // position
|
||||||
|
|
@ -108,17 +114,17 @@ struct SPreparedShaders {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SMonitorRenderData {
|
struct SMonitorRenderData {
|
||||||
CFramebuffer offloadFB;
|
SP<IFramebuffer> offloadFB;
|
||||||
CFramebuffer mirrorFB; // these are used for some effects,
|
SP<IFramebuffer> mirrorFB; // these are used for some effects,
|
||||||
CFramebuffer mirrorSwapFB; // etc
|
SP<IFramebuffer> mirrorSwapFB; // etc
|
||||||
CFramebuffer offMainFB;
|
SP<IFramebuffer> offMainFB;
|
||||||
CFramebuffer monitorMirrorFB; // used for mirroring outputs / screencopy, does not contain artifacts like offloadFB and is in sRGB
|
SP<IFramebuffer> monitorMirrorFB; // used for mirroring outputs, does not contain artifacts like offloadFB
|
||||||
CFramebuffer blurFB;
|
SP<IFramebuffer> blurFB;
|
||||||
|
|
||||||
SP<CTexture> stencilTex = makeShared<CTexture>();
|
SP<ITexture> stencilTex = makeShared<CGLTexture>();
|
||||||
|
|
||||||
bool blurFBDirty = true;
|
bool blurFBDirty = true;
|
||||||
bool blurFBShouldRender = false;
|
bool blurFBShouldRender = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SCurrentRenderData {
|
struct SCurrentRenderData {
|
||||||
|
|
@ -129,9 +135,9 @@ struct SCurrentRenderData {
|
||||||
|
|
||||||
// FIXME: raw pointer galore!
|
// FIXME: raw pointer galore!
|
||||||
SMonitorRenderData* pCurrentMonData = nullptr;
|
SMonitorRenderData* pCurrentMonData = nullptr;
|
||||||
CFramebuffer* currentFB = nullptr; // current rendering to
|
SP<IFramebuffer> currentFB = nullptr; // current rendering to
|
||||||
CFramebuffer* mainFB = nullptr; // main to render to
|
SP<IFramebuffer> mainFB = nullptr; // main to render to
|
||||||
CFramebuffer* outFB = nullptr; // out to render to (if offloaded, etc)
|
SP<IFramebuffer> outFB = nullptr; // out to render to (if offloaded, etc)
|
||||||
|
|
||||||
CRegion damage;
|
CRegion damage;
|
||||||
CRegion finalDamage; // damage used for funal off -> main
|
CRegion finalDamage; // damage used for funal off -> main
|
||||||
|
|
@ -213,7 +219,7 @@ class CHyprOpenGLImpl {
|
||||||
bool noCM = false;
|
bool noCM = false;
|
||||||
bool finalMonitorCM = false;
|
bool finalMonitorCM = false;
|
||||||
SP<CMonitor> cmBackToSRGBSource;
|
SP<CMonitor> cmBackToSRGBSource;
|
||||||
SP<CTexture> blurredBG;
|
SP<ITexture> blurredBG;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SBorderRenderData {
|
struct SBorderRenderData {
|
||||||
|
|
@ -224,17 +230,17 @@ class CHyprOpenGLImpl {
|
||||||
int outerRound = -1; /* use round */
|
int outerRound = -1; /* use round */
|
||||||
};
|
};
|
||||||
|
|
||||||
void begin(PHLMONITOR, const CRegion& damage, CFramebuffer* fb = nullptr, std::optional<CRegion> finalDamage = {});
|
void begin(PHLMONITOR, const CRegion& damage, SP<IFramebuffer> fb = nullptr, std::optional<CRegion> finalDamage = {});
|
||||||
void beginSimple(PHLMONITOR, const CRegion& damage, SP<CRenderbuffer> rb = nullptr, CFramebuffer* fb = nullptr);
|
void beginSimple(PHLMONITOR, const CRegion& damage, SP<IRenderbuffer> rb = nullptr, SP<IFramebuffer> fb = nullptr);
|
||||||
void end();
|
void end();
|
||||||
|
|
||||||
void renderRect(const CBox&, const CHyprColor&, SRectRenderData data);
|
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 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&, SBorderRenderData data);
|
||||||
void renderBorder(const CBox&, const CGradientValueData&, const CGradientValueData&, float lerp, 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 renderTextureMatte(SP<ITexture> tex, const CBox& pBox, SP<IFramebuffer> matte);
|
||||||
void renderTexturePrimitive(SP<CTexture> tex, const CBox& box);
|
void renderTexturePrimitive(SP<ITexture> tex, const CBox& box);
|
||||||
|
|
||||||
void pushMonitorTransformEnabled(bool enabled);
|
void pushMonitorTransformEnabled(bool enabled);
|
||||||
void popMonitorTransformEnabled();
|
void popMonitorTransformEnabled();
|
||||||
|
|
@ -271,49 +277,49 @@ class CHyprOpenGLImpl {
|
||||||
void applyScreenShader(const std::string& path);
|
void applyScreenShader(const std::string& path);
|
||||||
|
|
||||||
void bindOffMain();
|
void bindOffMain();
|
||||||
void renderOffToMain(CFramebuffer* off);
|
void renderOffToMain(CGLFramebuffer* off);
|
||||||
void bindBackOnMain();
|
void bindBackOnMain();
|
||||||
|
|
||||||
bool needsACopyFB(PHLMONITOR mon);
|
bool needsACopyFB(PHLMONITOR mon);
|
||||||
|
|
||||||
std::string resolveAssetPath(const std::string& file);
|
std::string resolveAssetPath(const std::string& file);
|
||||||
SP<CTexture> loadAsset(const std::string& file);
|
SP<ITexture> loadAsset(const std::string& file);
|
||||||
SP<CTexture> texFromCairo(cairo_surface_t* cairo);
|
SP<ITexture> 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> 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 = {});
|
void setDamage(const CRegion& damage, std::optional<CRegion> finalDamage = {});
|
||||||
|
|
||||||
DRMFormat getPreferredReadFormat(PHLMONITOR pMonitor);
|
DRMFormat getPreferredReadFormat(PHLMONITOR pMonitor);
|
||||||
std::vector<SDRMFormat> getDRMFormats();
|
std::vector<SDRMFormat> getDRMFormats();
|
||||||
std::vector<uint64_t> getDRMFormatModifiers(DRMFormat format);
|
std::vector<uint64_t> getDRMFormatModifiers(DRMFormat format);
|
||||||
EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs);
|
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();
|
bool explicitSyncSupported();
|
||||||
WP<CShader> getShaderVariant(Render::ePreparedFragmentShader frag, Render::ShaderFeatureFlags features = 0);
|
WP<CShader> getShaderVariant(Render::ePreparedFragmentShader frag, Render::ShaderFeatureFlags features = 0);
|
||||||
|
|
||||||
bool m_shadersInitialized = false;
|
bool m_shadersInitialized = false;
|
||||||
SP<SPreparedShaders> m_shaders;
|
SP<SPreparedShaders> m_shaders;
|
||||||
|
|
||||||
SCurrentRenderData m_renderData;
|
SCurrentRenderData m_renderData;
|
||||||
|
|
||||||
Hyprutils::OS::CFileDescriptor m_gbmFD;
|
Hyprutils::OS::CFileDescriptor m_gbmFD;
|
||||||
gbm_device* m_gbmDevice = nullptr;
|
gbm_device* m_gbmDevice = nullptr;
|
||||||
EGLContext m_eglContext = nullptr;
|
EGLContext m_eglContext = nullptr;
|
||||||
EGLDisplay m_eglDisplay = nullptr;
|
EGLDisplay m_eglDisplay = nullptr;
|
||||||
EGLDeviceEXT m_eglDevice = nullptr;
|
EGLDeviceEXT m_eglDevice = nullptr;
|
||||||
uint m_failedAssetsNo = 0;
|
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<PHLWINDOWREF, SP<IFramebuffer>> m_windowFramebuffers;
|
||||||
std::map<PHLLSREF, CFramebuffer> m_layerFramebuffers;
|
std::map<PHLLSREF, SP<IFramebuffer>> m_layerFramebuffers;
|
||||||
std::map<WP<Desktop::View::CPopup>, CFramebuffer> m_popupFramebuffers;
|
std::map<WP<Desktop::View::CPopup>, SP<IFramebuffer>> m_popupFramebuffers;
|
||||||
std::map<PHLMONITORREF, SMonitorRenderData> m_monitorRenderResources;
|
std::map<PHLMONITORREF, SMonitorRenderData> m_monitorRenderResources;
|
||||||
std::map<PHLMONITORREF, CFramebuffer> m_monitorBGFBs;
|
std::map<PHLMONITORREF, SP<IFramebuffer>> m_monitorBGFBs;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES = nullptr;
|
PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES = nullptr;
|
||||||
|
|
@ -344,7 +350,7 @@ class CHyprOpenGLImpl {
|
||||||
bool EGL_ANDROID_native_fence_sync_ext = false;
|
bool EGL_ANDROID_native_fence_sync_ext = false;
|
||||||
} m_exts;
|
} m_exts;
|
||||||
|
|
||||||
SP<CTexture> m_screencopyDeniedTexture;
|
SP<ITexture> m_screencopyDeniedTexture;
|
||||||
|
|
||||||
enum eEGLContextVersion : uint8_t {
|
enum eEGLContextVersion : uint8_t {
|
||||||
EGL_CONTEXT_GLES_2_0 = 0,
|
EGL_CONTEXT_GLES_2_0 = 0,
|
||||||
|
|
@ -385,10 +391,10 @@ class CHyprOpenGLImpl {
|
||||||
|
|
||||||
bool m_monitorTransformEnabled = false; // do not modify directly
|
bool m_monitorTransformEnabled = false; // do not modify directly
|
||||||
std::stack<bool> m_monitorTransformStack;
|
std::stack<bool> m_monitorTransformStack;
|
||||||
SP<CTexture> m_missingAssetTexture;
|
SP<ITexture> m_missingAssetTexture;
|
||||||
SP<CTexture> m_lockDeadTexture;
|
SP<ITexture> m_lockDeadTexture;
|
||||||
SP<CTexture> m_lockDead2Texture;
|
SP<ITexture> m_lockDead2Texture;
|
||||||
SP<CTexture> m_lockTtyTextTexture;
|
SP<ITexture> m_lockTtyTextTexture;
|
||||||
SP<CShader> m_finalScreenShader;
|
SP<CShader> m_finalScreenShader;
|
||||||
CTimer m_globalTimer;
|
CTimer m_globalTimer;
|
||||||
GLuint m_currentProgram;
|
GLuint m_currentProgram;
|
||||||
|
|
@ -414,22 +420,22 @@ class CHyprOpenGLImpl {
|
||||||
std::optional<std::vector<uint64_t>> getModsForFormat(EGLint format);
|
std::optional<std::vector<uint64_t>> getModsForFormat(EGLint format);
|
||||||
|
|
||||||
// returns the out FB, can be either Mirror or MirrorSwap
|
// returns the out FB, can be either Mirror or MirrorSwap
|
||||||
CFramebuffer* blurMainFramebufferWithDamage(float a, CRegion* damage);
|
SP<IFramebuffer> blurMainFramebufferWithDamage(float a, CRegion* damage);
|
||||||
CFramebuffer* blurFramebufferWithDamage(float a, CRegion* damage, CFramebuffer& source);
|
SP<IFramebuffer> blurFramebufferWithDamage(float a, CRegion* damage, CGLFramebuffer& source);
|
||||||
|
|
||||||
void passCMUniforms(WP<CShader>, const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
|
void passCMUniforms(WP<CShader>, const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
|
||||||
bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1);
|
bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1);
|
||||||
void passCMUniforms(WP<CShader>, const NColorManagement::PImageDescription imageDescription);
|
void passCMUniforms(WP<CShader>, const NColorManagement::PImageDescription imageDescription);
|
||||||
void renderSplash(cairo_t* const, cairo_surface_t* const, double offset, const Vector2D& size);
|
void renderSplash(cairo_t* const, cairo_surface_t* const, double offset, const Vector2D& size);
|
||||||
void renderRectInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
|
void renderRectInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
|
||||||
void renderRectWithBlurInternal(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);
|
void renderRectWithDamageInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
|
||||||
WP<CShader> renderToOutputInternal();
|
WP<CShader> renderToOutputInternal();
|
||||||
WP<CShader> renderToFBInternal(const STextureRenderData& data, eTextureType texType, const CBox& newBox);
|
WP<CShader> renderToFBInternal(const STextureRenderData& data, eTextureType texType, const CBox& newBox);
|
||||||
void renderTextureInternal(SP<CTexture>, const CBox&, const STextureRenderData& data);
|
void renderTextureInternal(SP<ITexture>, const CBox&, const STextureRenderData& data);
|
||||||
void renderTextureWithBlurInternal(SP<CTexture>, const CBox&, const STextureRenderData& data);
|
void renderTextureWithBlurInternal(SP<ITexture>, const CBox&, const STextureRenderData& data);
|
||||||
|
|
||||||
void preBlurForCurrentMonitor();
|
void preBlurForCurrentMonitor();
|
||||||
|
|
||||||
friend class CHyprRenderer;
|
friend class CHyprRenderer;
|
||||||
friend class CTexPassElement;
|
friend class CTexPassElement;
|
||||||
|
|
|
||||||
|
|
@ -1,74 +1,21 @@
|
||||||
#include "Renderbuffer.hpp"
|
#include "Renderbuffer.hpp"
|
||||||
#include "Renderer.hpp"
|
#include "Framebuffer.hpp"
|
||||||
#include "OpenGL.hpp"
|
#include "render/Renderer.hpp"
|
||||||
#include "../Compositor.hpp"
|
#include "render/gl/GLRenderbuffer.hpp"
|
||||||
#include "../protocols/types/Buffer.hpp"
|
#include <hyprutils/memory/SharedPtr.hpp>
|
||||||
#include <hyprutils/signal/Listener.hpp>
|
#include <hyprutils/signal/Listener.hpp>
|
||||||
#include <hyprutils/signal/Signal.hpp>
|
#include <hyprutils/signal/Signal.hpp>
|
||||||
|
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
||||||
CRenderbuffer::~CRenderbuffer() {
|
IRenderbuffer::IRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t format) : m_hlBuffer(buffer) {
|
||||||
if (!g_pCompositor || g_pCompositor->m_isShuttingDown || !g_pHyprRenderer)
|
m_listeners.destroyBuffer = buffer->events.destroy.listen([this] { g_pHyprRenderer->onRenderbufferDestroy(dc<CGLRenderbuffer*>(this)); });
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CRenderbuffer::CRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t format) : m_hlBuffer(buffer), m_drmFormat(format) {
|
bool IRenderbuffer::good() {
|
||||||
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() {
|
|
||||||
return m_good;
|
return m_good;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CRenderbuffer::bind() {
|
SP<IFramebuffer> IRenderbuffer::getFB() {
|
||||||
m_framebuffer.bind();
|
return m_framebuffer;
|
||||||
}
|
|
||||||
|
|
||||||
void CRenderbuffer::unbind() {
|
|
||||||
m_framebuffer.unbind();
|
|
||||||
}
|
|
||||||
|
|
||||||
CFramebuffer* CRenderbuffer::getFB() {
|
|
||||||
return &m_framebuffer;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,27 +5,22 @@
|
||||||
#include "Framebuffer.hpp"
|
#include "Framebuffer.hpp"
|
||||||
#include <aquamarine/buffer/Buffer.hpp>
|
#include <aquamarine/buffer/Buffer.hpp>
|
||||||
|
|
||||||
class CMonitor;
|
class IRenderbuffer {
|
||||||
|
|
||||||
class CRenderbuffer {
|
|
||||||
public:
|
public:
|
||||||
CRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t format);
|
IRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t format);
|
||||||
~CRenderbuffer();
|
virtual ~IRenderbuffer() = default;
|
||||||
|
|
||||||
bool good();
|
bool good();
|
||||||
void bind();
|
SP<IFramebuffer> getFB();
|
||||||
void unbind();
|
|
||||||
CFramebuffer* getFB();
|
virtual void bind() = 0;
|
||||||
uint32_t getFormat();
|
virtual void unbind() = 0;
|
||||||
|
|
||||||
WP<Aquamarine::IBuffer> m_hlBuffer;
|
WP<Aquamarine::IBuffer> m_hlBuffer;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
void* m_image = nullptr;
|
SP<IFramebuffer> m_framebuffer;
|
||||||
GLuint m_rbo = 0;
|
bool m_good = false;
|
||||||
CFramebuffer m_framebuffer;
|
|
||||||
uint32_t m_drmFormat = 0;
|
|
||||||
bool m_good = false;
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
CHyprSignalListener destroyBuffer;
|
CHyprSignalListener destroyBuffer;
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#include "../helpers/math/Math.hpp"
|
#include "../helpers/math/Math.hpp"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <aquamarine/output/Output.hpp>
|
#include <aquamarine/output/Output.hpp>
|
||||||
|
#include <cmath>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include "../config/ConfigValue.hpp"
|
#include "../config/ConfigValue.hpp"
|
||||||
#include "../config/ConfigManager.hpp"
|
#include "../config/ConfigManager.hpp"
|
||||||
|
|
@ -29,10 +30,12 @@
|
||||||
#include "../layout/LayoutManager.hpp"
|
#include "../layout/LayoutManager.hpp"
|
||||||
#include "../layout/space/Space.hpp"
|
#include "../layout/space/Space.hpp"
|
||||||
#include "../i18n/Engine.hpp"
|
#include "../i18n/Engine.hpp"
|
||||||
|
#include "desktop/DesktopTypes.hpp"
|
||||||
#include "../event/EventBus.hpp"
|
#include "../event/EventBus.hpp"
|
||||||
#include "helpers/CursorShapes.hpp"
|
#include "helpers/CursorShapes.hpp"
|
||||||
|
#include "helpers/MainLoopExecutor.hpp"
|
||||||
#include "helpers/Monitor.hpp"
|
#include "helpers/Monitor.hpp"
|
||||||
#include "helpers/cm/ColorManagement.hpp"
|
#include "macros.hpp"
|
||||||
#include "pass/TexPassElement.hpp"
|
#include "pass/TexPassElement.hpp"
|
||||||
#include "pass/ClearPassElement.hpp"
|
#include "pass/ClearPassElement.hpp"
|
||||||
#include "pass/RectPassElement.hpp"
|
#include "pass/RectPassElement.hpp"
|
||||||
|
|
@ -42,7 +45,18 @@
|
||||||
#include "../protocols/ColorManagement.hpp"
|
#include "../protocols/ColorManagement.hpp"
|
||||||
#include "../protocols/types/ContentType.hpp"
|
#include "../protocols/types/ContentType.hpp"
|
||||||
#include "../helpers/MiscFunctions.hpp"
|
#include "../helpers/MiscFunctions.hpp"
|
||||||
|
#include "render/AsyncResourceGatherer.hpp"
|
||||||
|
#include "render/Framebuffer.hpp"
|
||||||
#include "render/OpenGL.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>
|
#include <hyprutils/utils/ScopeGuard.hpp>
|
||||||
using namespace Hyprutils::Utils;
|
using namespace Hyprutils::Utils;
|
||||||
|
|
@ -643,13 +657,13 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, const T
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TRANSFORMERSPRESENT) {
|
if (TRANSFORMERSPRESENT) {
|
||||||
CFramebuffer* last = g_pHyprOpenGL->m_renderData.currentFB;
|
IFramebuffer* last = g_pHyprOpenGL->m_renderData.currentFB.get();
|
||||||
for (auto const& t : pWindow->m_transformers) {
|
for (auto const& t : pWindow->m_transformers) {
|
||||||
last = t->transform(last);
|
last = t->transform(last);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_pHyprOpenGL->bindBackOnMain();
|
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();
|
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) {
|
void CHyprRenderer::renderLayer(PHLLS pLayer, PHLMONITOR pMonitor, const Time::steady_tp& time, bool popups, bool lockscreen) {
|
||||||
if (!pLayer)
|
if (!pLayer)
|
||||||
return;
|
return;
|
||||||
|
|
@ -2313,13 +2357,13 @@ void CHyprRenderer::initiateManualCrash() {
|
||||||
**PDT = 0;
|
**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; });
|
auto it = std::ranges::find_if(m_renderbuffers, [&](const auto& other) { return other->m_hlBuffer == buffer; });
|
||||||
|
|
||||||
if (it != m_renderbuffers.end())
|
if (it != m_renderbuffers.end())
|
||||||
return *it;
|
return *it;
|
||||||
|
|
||||||
auto buf = makeShared<CRenderbuffer>(buffer, fmt);
|
auto buf = makeShared<CGLRenderbuffer>(buffer, fmt);
|
||||||
|
|
||||||
if (!buf->good())
|
if (!buf->good())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
@ -2343,7 +2387,7 @@ void CHyprRenderer::unsetEGL() {
|
||||||
eglMakeCurrent(g_pHyprOpenGL->m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
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();
|
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; });
|
std::erase_if(m_renderbuffers, [&](const auto& rbo) { return rbo.get() == rb; });
|
||||||
}
|
}
|
||||||
|
|
||||||
SP<CRenderbuffer> CHyprRenderer::getCurrentRBO() {
|
SP<IRenderbuffer> CHyprRenderer::getCurrentRBO() {
|
||||||
return m_currentRenderbuffer;
|
return m_currentRenderbuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2532,7 +2576,10 @@ void CHyprRenderer::makeSnapshot(PHLWINDOW pWindow) {
|
||||||
|
|
||||||
makeEGLCurrent();
|
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);
|
PFRAMEBUFFER->alloc(PMONITOR->m_pixelSize.x, PMONITOR->m_pixelSize.y, DRM_FORMAT_ABGR8888);
|
||||||
|
|
||||||
|
|
@ -2565,7 +2612,10 @@ void CHyprRenderer::makeSnapshot(PHLLS pLayer) {
|
||||||
|
|
||||||
makeEGLCurrent();
|
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);
|
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();
|
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);
|
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))
|
if (!g_pHyprOpenGL->m_windowFramebuffers.contains(ref))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto FBDATA = &g_pHyprOpenGL->m_windowFramebuffers.at(ref);
|
const auto FBDATA = g_pHyprOpenGL->m_windowFramebuffers.at(ref);
|
||||||
|
|
||||||
if (!FBDATA->getTexture())
|
if (!FBDATA->getTexture())
|
||||||
return;
|
return;
|
||||||
|
|
@ -2704,7 +2757,7 @@ void CHyprRenderer::renderSnapshot(PHLLS pLayer) {
|
||||||
if (!g_pHyprOpenGL->m_layerFramebuffers.contains(pLayer))
|
if (!g_pHyprOpenGL->m_layerFramebuffers.contains(pLayer))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto FBDATA = &g_pHyprOpenGL->m_layerFramebuffers.at(pLayer);
|
const auto FBDATA = g_pHyprOpenGL->m_layerFramebuffers.at(pLayer);
|
||||||
|
|
||||||
if (!FBDATA->getTexture())
|
if (!FBDATA->getTexture())
|
||||||
return;
|
return;
|
||||||
|
|
@ -2748,7 +2801,7 @@ void CHyprRenderer::renderSnapshot(WP<Desktop::View::CPopup> popup) {
|
||||||
|
|
||||||
static CConfigValue PBLURIGNOREA = CConfigValue<Hyprlang::FLOAT>("decoration:blur:popups_ignorealpha");
|
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())
|
if (!FBDATA->getTexture())
|
||||||
return;
|
return;
|
||||||
|
|
@ -2813,4 +2866,89 @@ bool CHyprRenderer::shouldBlur(WP<Desktop::View::CPopup> p) {
|
||||||
|
|
||||||
bool CHyprRenderer::reloadShaders(const std::string& path) {
|
bool CHyprRenderer::reloadShaders(const std::string& path) {
|
||||||
return g_pHyprOpenGL->initShaders(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);
|
||||||
}
|
}
|
||||||
|
|
@ -13,7 +13,8 @@
|
||||||
#include "../helpers/math/Math.hpp"
|
#include "../helpers/math/Math.hpp"
|
||||||
#include "../helpers/time/Time.hpp"
|
#include "../helpers/time/Time.hpp"
|
||||||
#include "../../protocols/cursor-shape-v1.hpp"
|
#include "../../protocols/cursor-shape-v1.hpp"
|
||||||
#include "helpers/cm/ColorManagement.hpp"
|
#include "render/Framebuffer.hpp"
|
||||||
|
#include "render/Texture.hpp"
|
||||||
|
|
||||||
struct SMonitorRule;
|
struct SMonitorRule;
|
||||||
class CWorkspace;
|
class CWorkspace;
|
||||||
|
|
@ -108,8 +109,8 @@ class CHyprRenderer {
|
||||||
void renderLockscreen(PHLMONITOR pMonitor, const Time::steady_tp& now, const CBox& geometry);
|
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 setCursorSurface(SP<Desktop::View::CWLSurface> surf, int hotspotX, int hotspotY, bool force = false);
|
||||||
void setCursorFromName(const std::string& name, bool force = false);
|
void setCursorFromName(const std::string& name, bool force = false);
|
||||||
void onRenderbufferDestroy(CRenderbuffer* rb);
|
void onRenderbufferDestroy(CGLRenderbuffer* rb);
|
||||||
SP<CRenderbuffer> getCurrentRBO();
|
SP<IRenderbuffer> getCurrentRBO();
|
||||||
bool isNvidia();
|
bool isNvidia();
|
||||||
bool isIntel();
|
bool isIntel();
|
||||||
bool isSoftware();
|
bool isSoftware();
|
||||||
|
|
@ -129,7 +130,7 @@ class CHyprRenderer {
|
||||||
|
|
||||||
// if RENDER_MODE_NORMAL, provided damage will be written to.
|
// if RENDER_MODE_NORMAL, provided damage will be written to.
|
||||||
// otherwise, it will be the one used.
|
// 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 = {});
|
void endRender(const std::function<void()>& renderingDoneCallback = {});
|
||||||
|
|
||||||
bool m_bBlockSurfaceFeedback = false;
|
bool m_bBlockSurfaceFeedback = false;
|
||||||
|
|
@ -157,11 +158,21 @@ class CHyprRenderer {
|
||||||
std::string name;
|
std::string name;
|
||||||
} m_lastCursorData;
|
} m_lastCursorData;
|
||||||
|
|
||||||
CRenderPass m_renderPass = {};
|
CRenderPass m_renderPass = {};
|
||||||
|
|
||||||
SCMSettings getCMSettings(const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
|
SP<ITexture> createStencilTexture(const int width, const int height);
|
||||||
SP<CWLSurfaceResource> surface = nullptr, bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1);
|
SP<ITexture> createTexture(bool opaque = false);
|
||||||
bool reloadShaders(const std::string& path = "");
|
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:
|
private:
|
||||||
void arrangeLayerArray(PHLMONITOR, const std::vector<PHLLSREF>&, bool, CBox*);
|
void arrangeLayerArray(PHLMONITOR, const std::vector<PHLLSREF>&, bool, CBox*);
|
||||||
|
|
@ -188,7 +199,7 @@ class CHyprRenderer {
|
||||||
bool m_cursorHidden = false;
|
bool m_cursorHidden = false;
|
||||||
bool m_cursorHiddenByCondition = false;
|
bool m_cursorHiddenByCondition = false;
|
||||||
bool m_cursorHasSurface = false;
|
bool m_cursorHasSurface = false;
|
||||||
SP<CRenderbuffer> m_currentRenderbuffer = nullptr;
|
SP<IRenderbuffer> m_currentRenderbuffer = nullptr;
|
||||||
SP<Aquamarine::IBuffer> m_currentBuffer = nullptr;
|
SP<Aquamarine::IBuffer> m_currentBuffer = nullptr;
|
||||||
eRenderMode m_renderMode = RENDER_MODE_NORMAL;
|
eRenderMode m_renderMode = RENDER_MODE_NORMAL;
|
||||||
bool m_nvidia = false;
|
bool m_nvidia = false;
|
||||||
|
|
@ -203,8 +214,8 @@ class CHyprRenderer {
|
||||||
bool hiddenOnKeyboard = false;
|
bool hiddenOnKeyboard = false;
|
||||||
} m_cursorHiddenConditions;
|
} m_cursorHiddenConditions;
|
||||||
|
|
||||||
SP<CRenderbuffer> getOrCreateRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t fmt);
|
SP<IRenderbuffer> getOrCreateRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t fmt);
|
||||||
std::vector<SP<CRenderbuffer>> m_renderbuffers;
|
std::vector<SP<IRenderbuffer>> m_renderbuffers;
|
||||||
std::vector<PHLWINDOWREF> m_renderUnfocused;
|
std::vector<PHLWINDOWREF> m_renderUnfocused;
|
||||||
SP<CEventLoopTimer> m_renderUnfocusedTimer;
|
SP<CEventLoopTimer> m_renderUnfocusedTimer;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,265 +1,24 @@
|
||||||
#include "Texture.hpp"
|
#include "Texture.hpp"
|
||||||
#include "Renderer.hpp"
|
|
||||||
#include "../Compositor.hpp"
|
|
||||||
#include "../protocols/types/Buffer.hpp"
|
|
||||||
#include "../helpers/Format.hpp"
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
CTexture::CTexture() = default;
|
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) {
|
||||||
CTexture::~CTexture() {
|
if (m_keepDataCopy && stride && pixels) {
|
||||||
if (!g_pCompositor || g_pCompositor->m_isShuttingDown || !g_pHyprRenderer)
|
m_dataCopy.resize(stride * size.y);
|
||||||
return;
|
memcpy(m_dataCopy.data(), pixels, stride * size.y);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CTexture::createFromDma(const Aquamarine::SDMABUFAttrs& attrs, void* image) {
|
ITexture::ITexture(std::span<const float> lut3D, size_t N) : m_type(TEXTURE_3D_LUT), m_size(lut3D.size() / 3, 1), m_isSynchronous(true) {}
|
||||||
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);
|
bool ITexture::ok() {
|
||||||
|
return false;
|
||||||
// #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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CTexture::update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage) {
|
bool ITexture::isDMA() {
|
||||||
if (damage.empty())
|
return false;
|
||||||
return;
|
|
||||||
|
|
||||||
g_pHyprRenderer->makeEGLCurrent();
|
|
||||||
|
|
||||||
const auto format = NFormatUtils::getPixelFormatFromDRM(drmFormat);
|
|
||||||
ASSERT(format);
|
|
||||||
|
|
||||||
bind();
|
|
||||||
|
|
||||||
if (format->swizzle.has_value())
|
|
||||||
swizzle(format->swizzle.value());
|
|
||||||
|
|
||||||
bool alignmentChanged = false;
|
|
||||||
if (format->bytesPerBlock != 4) {
|
|
||||||
const GLint alignment = (stride % 4 == 0) ? 4 : 1;
|
|
||||||
GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, alignment));
|
|
||||||
alignmentChanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / format->bytesPerBlock));
|
|
||||||
|
|
||||||
damage.copy().intersect(CBox{{}, m_size}).forEachRect([&format, &pixels](const auto& rect) {
|
|
||||||
GLCALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, rect.x1));
|
|
||||||
GLCALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, rect.y1));
|
|
||||||
|
|
||||||
int width = rect.x2 - rect.x1;
|
|
||||||
int height = rect.y2 - rect.y1;
|
|
||||||
GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x1, rect.y1, width, height, format->glFormat, format->glType, pixels));
|
|
||||||
});
|
|
||||||
|
|
||||||
if (alignmentChanged)
|
|
||||||
GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 4));
|
|
||||||
|
|
||||||
GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0));
|
|
||||||
GLCALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0));
|
|
||||||
GLCALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0));
|
|
||||||
|
|
||||||
unbind();
|
|
||||||
|
|
||||||
if (m_keepDataCopy) {
|
|
||||||
m_dataCopy.resize(stride * m_size.y);
|
|
||||||
memcpy(m_dataCopy.data(), pixels, stride * m_size.y);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CTexture::destroyTexture() {
|
const std::vector<uint8_t>& ITexture::dataCopy() {
|
||||||
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() {
|
|
||||||
return m_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));
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -16,61 +16,43 @@ enum eTextureType : int8_t {
|
||||||
TEXTURE_EXTERNAL, // EGLImage
|
TEXTURE_EXTERNAL, // EGLImage
|
||||||
};
|
};
|
||||||
|
|
||||||
class CTexture {
|
class ITexture {
|
||||||
public:
|
public:
|
||||||
CTexture();
|
ITexture(ITexture&) = delete;
|
||||||
|
ITexture(ITexture&&) = delete;
|
||||||
|
ITexture(const ITexture&&) = delete;
|
||||||
|
ITexture(const ITexture&) = delete;
|
||||||
|
|
||||||
CTexture(CTexture&) = delete;
|
virtual ~ITexture() = default;
|
||||||
CTexture(CTexture&&) = delete;
|
|
||||||
CTexture(const CTexture&&) = delete;
|
|
||||||
CTexture(const CTexture&) = delete;
|
|
||||||
|
|
||||||
CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false);
|
virtual void setTexParameter(GLenum pname, GLint param) = 0;
|
||||||
CTexture(std::span<const float> lut3D, size_t N);
|
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();
|
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;
|
eTextureType m_type = TEXTURE_RGBA;
|
||||||
GLenum m_target = GL_TEXTURE_2D;
|
Vector2D m_size = {};
|
||||||
GLuint m_texID = 0;
|
eTransform m_transform = HYPRUTILS_TRANSFORM_NORMAL;
|
||||||
Vector2D m_size = {};
|
bool m_opaque = false;
|
||||||
void* m_eglImage = nullptr;
|
|
||||||
eTransform m_transform = HYPRUTILS_TRANSFORM_NORMAL;
|
|
||||||
bool m_opaque = false;
|
|
||||||
uint32_t m_drmFormat = 0; // for shm
|
uint32_t m_drmFormat = 0; // for shm
|
||||||
bool m_isSynchronous = false;
|
bool m_isSynchronous = false;
|
||||||
|
|
||||||
GLenum magFilter = GL_LINEAR; // useNearestNeighbor overwrites these
|
// TODO move to GLTexture
|
||||||
GLenum minFilter = GL_LINEAR;
|
GLuint m_texID = 0;
|
||||||
|
GLenum magFilter = GL_LINEAR; // useNearestNeighbor overwrites these
|
||||||
|
GLenum minFilter = GL_LINEAR;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
enum eTextureParam : uint8_t {
|
ITexture() = default;
|
||||||
TEXTURE_PAR_WRAP_S = 0,
|
ITexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false, bool opaque = false);
|
||||||
TEXTURE_PAR_WRAP_T,
|
ITexture(std::span<const float> lut3D, size_t N);
|
||||||
TEXTURE_PAR_MAG_FILTER,
|
|
||||||
TEXTURE_PAR_MIN_FILTER,
|
|
||||||
TEXTURE_PAR_SWIZZLE_R,
|
|
||||||
TEXTURE_PAR_SWIZZLE_B,
|
|
||||||
TEXTURE_PAR_LAST,
|
|
||||||
};
|
|
||||||
|
|
||||||
void createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size);
|
bool m_keepDataCopy = false;
|
||||||
void createFromDma(const Aquamarine::SDMABUFAttrs&, void* image);
|
std::vector<uint8_t> m_dataCopy;
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ class IWindowTransformer {
|
||||||
|
|
||||||
// called by Hyprland. For more data about what is being rendered, inspect render data.
|
// called by Hyprland. For more data about what is being rendered, inspect render data.
|
||||||
// returns the out fb.
|
// 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.
|
// called by Hyprland before a window main pass is started.
|
||||||
virtual void preWindowRender(CSurfacePassElement::SRenderData* pRenderData);
|
virtual void preWindowRender(CSurfacePassElement::SRenderData* pRenderData);
|
||||||
|
|
|
||||||
|
|
@ -155,9 +155,9 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) {
|
||||||
g_pHyprOpenGL->m_renderData.currentWindow = m_window;
|
g_pHyprOpenGL->m_renderData.currentWindow = m_window;
|
||||||
|
|
||||||
// we'll take the liberty of using this as it should not be used rn
|
// we'll take the liberty of using this as it should not be used rn
|
||||||
CFramebuffer& alphaFB = g_pHyprOpenGL->m_renderData.pCurrentMonData->mirrorFB;
|
auto alphaFB = g_pHyprOpenGL->m_renderData.pCurrentMonData->mirrorFB;
|
||||||
CFramebuffer& alphaSwapFB = g_pHyprOpenGL->m_renderData.pCurrentMonData->mirrorSwapFB;
|
auto alphaSwapFB = g_pHyprOpenGL->m_renderData.pCurrentMonData->mirrorSwapFB;
|
||||||
auto* LASTFB = g_pHyprOpenGL->m_renderData.currentFB;
|
auto LASTFB = g_pHyprOpenGL->m_renderData.currentFB;
|
||||||
|
|
||||||
fullBox.scale(pMonitor->m_scale).round();
|
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.damage.subtract(windowBox.copy().expand(-ROUNDING * pMonitor->m_scale)).intersect(saveDamage);
|
||||||
g_pHyprOpenGL->m_renderData.renderModif.applyToRegion(g_pHyprOpenGL->m_renderData.damage);
|
g_pHyprOpenGL->m_renderData.renderModif.applyToRegion(g_pHyprOpenGL->m_renderData.damage);
|
||||||
|
|
||||||
alphaFB.bind();
|
alphaFB->bind();
|
||||||
|
|
||||||
// build the matte
|
// build the matte
|
||||||
// 10-bit formats have dogshit alpha channels, so we have to use the matte to its fullest.
|
// 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),
|
g_pHyprOpenGL->renderRect(windowBox, CHyprColor(0, 0, 0, 1.0),
|
||||||
{.round = (ROUNDING + 1 /* This fixes small pixel gaps. */) * pMonitor->m_scale, .roundingPower = ROUNDINGPOWER});
|
{.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.
|
// alpha swap just has the shadow color. It will be the "texture" to render.
|
||||||
g_pHyprOpenGL->renderRect(fullBox, PWINDOW->m_realShadowColor->value().stripA(), {.round = 0});
|
g_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->pushMonitorTransformEnabled(true);
|
||||||
g_pHyprOpenGL->setRenderModifEnabled(false);
|
g_pHyprOpenGL->setRenderModifEnabled(false);
|
||||||
g_pHyprOpenGL->renderTextureMatte(alphaSwapFB.getTexture(), monbox, alphaFB);
|
g_pHyprOpenGL->renderTextureMatte(alphaSwapFB->getTexture(), monbox, alphaFB);
|
||||||
g_pHyprOpenGL->setRenderModifEnabled(true);
|
g_pHyprOpenGL->setRenderModifEnabled(true);
|
||||||
g_pHyprOpenGL->popMonitorTransformEnabled();
|
g_pHyprOpenGL->popMonitorTransformEnabled();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,10 @@
|
||||||
#include "../../layout/supplementary/DragController.hpp"
|
#include "../../layout/supplementary/DragController.hpp"
|
||||||
|
|
||||||
// shared things to conserve VRAM
|
// shared things to conserve VRAM
|
||||||
static SP<CTexture> m_tGradientActive = makeShared<CTexture>();
|
static SP<ITexture> m_tGradientActive;
|
||||||
static SP<CTexture> m_tGradientInactive = makeShared<CTexture>();
|
static SP<ITexture> m_tGradientInactive;
|
||||||
static SP<CTexture> m_tGradientLockedActive = makeShared<CTexture>();
|
static SP<ITexture> m_tGradientLockedActive;
|
||||||
static SP<CTexture> m_tGradientLockedInactive = makeShared<CTexture>();
|
static SP<ITexture> m_tGradientLockedInactive;
|
||||||
|
|
||||||
constexpr int BAR_TEXT_PAD = 2;
|
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 PGRADIENTS = CConfigValue<Hyprlang::INT>("group:groupbar:enabled");
|
||||||
static auto PENABLED = CConfigValue<Hyprlang::INT>("group:groupbar:gradients");
|
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();
|
refreshGroupBarGradients();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -196,7 +205,7 @@ void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) {
|
||||||
if (*PGRADIENTS) {
|
if (*PGRADIENTS) {
|
||||||
const auto GRADIENTTEX = (m_dwGroupMembers[WINDOWINDEX] == Desktop::focusState()->window() ? (GROUPLOCKED ? m_tGradientLockedActive : m_tGradientActive) :
|
const auto GRADIENTTEX = (m_dwGroupMembers[WINDOWINDEX] == Desktop::focusState()->window() ? (GROUPLOCKED ? m_tGradientLockedActive : m_tGradientActive) :
|
||||||
(GROUPLOCKED ? m_tGradientLockedInactive : m_tGradientInactive));
|
(GROUPLOCKED ? m_tGradientLockedInactive : m_tGradientInactive));
|
||||||
if (GRADIENTTEX->m_texID) {
|
if (GRADIENTTEX->ok()) {
|
||||||
CTexPassElement::SRenderData data;
|
CTexPassElement::SRenderData data;
|
||||||
data.tex = GRADIENTTEX;
|
data.tex = GRADIENTTEX;
|
||||||
data.blur = blur;
|
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))
|
Vector2D{(m_barWidth - (*PTEXTPADDING * 2)) * pMonitor->m_scale, (*PTITLEFONTSIZE + 2L * BAR_TEXT_PAD) * pMonitor->m_scale}, pMonitor->m_scale))
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
SP<CTexture> titleTex;
|
SP<ITexture> titleTex;
|
||||||
if (m_dwGroupMembers[WINDOWINDEX] == Desktop::focusState()->window())
|
if (m_dwGroupMembers[WINDOWINDEX] == Desktop::focusState()->window())
|
||||||
titleTex = GROUPLOCKED ? pTitleTex->m_texLockedActive : pTitleTex->m_texActive;
|
titleTex = GROUPLOCKED ? pTitleTex->m_texLockedActive : pTitleTex->m_texActive;
|
||||||
else
|
else
|
||||||
|
|
@ -307,7 +316,7 @@ CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float
|
||||||
#undef RENDER_TEXT
|
#undef RENDER_TEXT
|
||||||
}
|
}
|
||||||
|
|
||||||
static void renderGradientTo(SP<CTexture> tex, CGradientValueData* grad) {
|
static void renderGradientTo(SP<ITexture> tex, CGradientValueData* grad) {
|
||||||
|
|
||||||
if (!Desktop::focusState()->monitor())
|
if (!Desktop::focusState()->monitor())
|
||||||
return;
|
return;
|
||||||
|
|
@ -339,15 +348,7 @@ static void renderGradientTo(SP<CTexture> tex, CGradientValueData* grad) {
|
||||||
cairo_surface_flush(CAIROSURFACE);
|
cairo_surface_flush(CAIROSURFACE);
|
||||||
|
|
||||||
// copy the data to an OpenGL texture we have
|
// copy the data to an OpenGL texture we have
|
||||||
const auto DATA = cairo_image_surface_get_data(CAIROSURFACE);
|
tex = g_pHyprRenderer->createTexture(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);
|
|
||||||
|
|
||||||
// delete cairo
|
// delete cairo
|
||||||
cairo_destroy(CAIRO);
|
cairo_destroy(CAIRO);
|
||||||
|
|
@ -367,13 +368,11 @@ void refreshGroupBarGradients() {
|
||||||
auto* const GROUPCOLACTIVELOCKED = sc<CGradientValueData*>((PGROUPCOLACTIVELOCKED.ptr())->getData());
|
auto* const GROUPCOLACTIVELOCKED = sc<CGradientValueData*>((PGROUPCOLACTIVELOCKED.ptr())->getData());
|
||||||
auto* const GROUPCOLINACTIVELOCKED = sc<CGradientValueData*>((PGROUPCOLINACTIVELOCKED.ptr())->getData());
|
auto* const GROUPCOLINACTIVELOCKED = sc<CGradientValueData*>((PGROUPCOLINACTIVELOCKED.ptr())->getData());
|
||||||
|
|
||||||
g_pHyprRenderer->makeEGLCurrent();
|
if (m_tGradientActive && m_tGradientActive->ok()) {
|
||||||
|
m_tGradientActive.reset();
|
||||||
if (m_tGradientActive->m_texID != 0) {
|
m_tGradientInactive.reset();
|
||||||
m_tGradientActive->destroyTexture();
|
m_tGradientLockedActive.reset();
|
||||||
m_tGradientInactive->destroyTexture();
|
m_tGradientLockedInactive.reset();
|
||||||
m_tGradientLockedActive->destroyTexture();
|
|
||||||
m_tGradientLockedInactive->destroyTexture();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!*PENABLED || !*PGRADIENTS)
|
if (!*PENABLED || !*PGRADIENTS)
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,10 @@ class CTitleTex {
|
||||||
CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float monitorScale);
|
CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float monitorScale);
|
||||||
~CTitleTex() = default;
|
~CTitleTex() = default;
|
||||||
|
|
||||||
SP<CTexture> m_texActive;
|
SP<ITexture> m_texActive;
|
||||||
SP<CTexture> m_texInactive;
|
SP<ITexture> m_texInactive;
|
||||||
SP<CTexture> m_texLockedActive;
|
SP<ITexture> m_texLockedActive;
|
||||||
SP<CTexture> m_texLockedInactive;
|
SP<ITexture> m_texLockedInactive;
|
||||||
std::string m_content;
|
std::string m_content;
|
||||||
|
|
||||||
PHLWINDOWREF m_windowOwner;
|
PHLWINDOWREF m_windowOwner;
|
||||||
|
|
|
||||||
170
src/render/gl/GLFramebuffer.cpp
Normal file
170
src/render/gl/GLFramebuffer.cpp
Normal 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());
|
||||||
|
}
|
||||||
30
src/render/gl/GLFramebuffer.hpp
Normal file
30
src/render/gl/GLFramebuffer.hpp
Normal 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;
|
||||||
|
};
|
||||||
71
src/render/gl/GLRenderbuffer.cpp
Normal file
71
src/render/gl/GLRenderbuffer.cpp
Normal 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();
|
||||||
|
}
|
||||||
20
src/render/gl/GLRenderbuffer.hpp
Normal file
20
src/render/gl/GLRenderbuffer.hpp
Normal 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
223
src/render/gl/GLTexture.cpp
Normal 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));
|
||||||
|
}
|
||||||
49
src/render/gl/GLTexture.hpp
Normal file
49
src/render/gl/GLTexture.hpp
Normal 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;
|
||||||
|
};
|
||||||
|
|
@ -6,7 +6,7 @@ CFramebufferElement::CFramebufferElement(const CFramebufferElement::SFramebuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFramebufferElement::draw(const CRegion& damage) {
|
void CFramebufferElement::draw(const CRegion& damage) {
|
||||||
CFramebuffer* fb = nullptr;
|
SP<IFramebuffer> fb = nullptr;
|
||||||
|
|
||||||
if (m_data.main) {
|
if (m_data.main) {
|
||||||
switch (m_data.framebufferID) {
|
switch (m_data.framebufferID) {
|
||||||
|
|
@ -22,12 +22,12 @@ void CFramebufferElement::draw(const CRegion& damage) {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
switch (m_data.framebufferID) {
|
switch (m_data.framebufferID) {
|
||||||
case FB_MONITOR_RENDER_EXTRA_OFFLOAD: fb = &g_pHyprOpenGL->m_renderData.pCurrentMonData->offloadFB; 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: 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_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_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_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_BLUR: fb = g_pHyprOpenGL->m_renderData.pCurrentMonData->blurFB; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fb) {
|
if (!fb) {
|
||||||
|
|
|
||||||
|
|
@ -216,7 +216,7 @@ void CRenderPass::renderDebugData() {
|
||||||
std::unordered_map<CWLSurfaceResource*, float> offsets;
|
std::unordered_map<CWLSurfaceResource*, float> offsets;
|
||||||
|
|
||||||
// render focus stuff
|
// 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)
|
if (!surface || !texture)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
#include "PassElement.hpp"
|
#include "PassElement.hpp"
|
||||||
|
|
||||||
class CGradientValueData;
|
class CGradientValueData;
|
||||||
class CTexture;
|
class ITexture;
|
||||||
|
|
||||||
class CRenderPass {
|
class CRenderPass {
|
||||||
public:
|
public:
|
||||||
|
|
@ -36,7 +36,7 @@ class CRenderPass {
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool present = false;
|
bool present = false;
|
||||||
SP<CTexture> keyboardFocusText, pointerFocusText, lastWindowText;
|
SP<ITexture> keyboardFocusText, pointerFocusText, lastWindowText;
|
||||||
} m_debugData;
|
} m_debugData;
|
||||||
|
|
||||||
friend class CHyprOpenGLImpl;
|
friend class CHyprOpenGLImpl;
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
#include "../../helpers/time/Time.hpp"
|
#include "../../helpers/time/Time.hpp"
|
||||||
|
|
||||||
class CWLSurfaceResource;
|
class CWLSurfaceResource;
|
||||||
class CTexture;
|
class ITexture;
|
||||||
class CSyncTimeline;
|
class CSyncTimeline;
|
||||||
|
|
||||||
class CSurfacePassElement : public IPassElement {
|
class CSurfacePassElement : public IPassElement {
|
||||||
|
|
@ -16,7 +16,7 @@ class CSurfacePassElement : public IPassElement {
|
||||||
|
|
||||||
void* data = nullptr;
|
void* data = nullptr;
|
||||||
SP<CWLSurfaceResource> surface = nullptr;
|
SP<CWLSurfaceResource> surface = nullptr;
|
||||||
SP<CTexture> texture = nullptr;
|
SP<ITexture> texture = nullptr;
|
||||||
bool mainSurface = true;
|
bool mainSurface = true;
|
||||||
double w = 0, h = 0;
|
double w = 0, h = 0;
|
||||||
int rounding = 0;
|
int rounding = 0;
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,13 @@
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
class CWLSurfaceResource;
|
class CWLSurfaceResource;
|
||||||
class CTexture;
|
class ITexture;
|
||||||
class CSyncTimeline;
|
class CSyncTimeline;
|
||||||
|
|
||||||
class CTexPassElement : public IPassElement {
|
class CTexPassElement : public IPassElement {
|
||||||
public:
|
public:
|
||||||
struct SRenderData {
|
struct SRenderData {
|
||||||
SP<CTexture> tex;
|
SP<ITexture> tex;
|
||||||
CBox box;
|
CBox box;
|
||||||
float a = 1.F;
|
float a = 1.F;
|
||||||
float blurA = 1.F;
|
float blurA = 1.F;
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,11 @@ void CTextureMatteElement::draw(const CRegion& damage) {
|
||||||
if (m_data.disableTransformAndModify) {
|
if (m_data.disableTransformAndModify) {
|
||||||
g_pHyprOpenGL->pushMonitorTransformEnabled(true);
|
g_pHyprOpenGL->pushMonitorTransformEnabled(true);
|
||||||
g_pHyprOpenGL->setRenderModifEnabled(false);
|
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->setRenderModifEnabled(true);
|
||||||
g_pHyprOpenGL->popMonitorTransformEnabled();
|
g_pHyprOpenGL->popMonitorTransformEnabled();
|
||||||
} else
|
} 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() {
|
bool CTextureMatteElement::needsLiveBlur() {
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,14 @@
|
||||||
#include "PassElement.hpp"
|
#include "PassElement.hpp"
|
||||||
#include "../Framebuffer.hpp"
|
#include "../Framebuffer.hpp"
|
||||||
|
|
||||||
class CTexture;
|
class ITexture;
|
||||||
|
|
||||||
class CTextureMatteElement : public IPassElement {
|
class CTextureMatteElement : public IPassElement {
|
||||||
public:
|
public:
|
||||||
struct STextureMatteData {
|
struct STextureMatteData {
|
||||||
CBox box;
|
CBox box;
|
||||||
SP<CTexture> tex;
|
SP<ITexture> tex;
|
||||||
SP<CFramebuffer> fb;
|
SP<IFramebuffer> fb;
|
||||||
bool disableTransformAndModify = false;
|
bool disableTransformAndModify = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue