namespaces & element renderer

This commit is contained in:
UjinT34 2026-03-07 13:28:45 +03:00
parent 8726a7363e
commit d071feb9b6
35 changed files with 1520 additions and 1377 deletions

View file

@ -98,6 +98,7 @@ using namespace Hyprutils::String;
using namespace Aquamarine;
using enum NContentType::eContentType;
using namespace NColorManagement;
using namespace Render::GL;
static int handleCritSignal(int signo, void* data) {
Log::logger->log(Log::DEBUG, "Hyprland received signal {}", signo);

View file

@ -71,6 +71,8 @@ using namespace Hyprutils::OS;
#include "../layout/algorithm/TiledAlgorithm.hpp"
#include "../layout/supplementary/WorkspaceAlgoMatcher.hpp"
using namespace Render::GL;
#if defined(__DragonFly__) || defined(__FreeBSD__)
#include <sys/ucred.h>
#define CRED_T xucred

View file

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

View file

@ -58,6 +58,7 @@ using namespace Hyprutils::Utils;
using namespace Hyprutils::OS;
using enum NContentType::eContentType;
using namespace NColorManagement;
using namespace Render::GL;
CMonitor::CMonitor(SP<Aquamarine::IOutput> output_) : m_state(this), m_output(output_), m_imageDescription(DEFAULT_IMAGE_DESCRIPTION) {
g_pAnimationManager->createAnimation(0.f, m_specialFade, Config::animationTree()->getAnimationPropertyConfig("specialWorkspaceIn"), AVARDAMAGE_NONE);

View file

@ -31,7 +31,9 @@
class CMonitorFrameScheduler;
class CMonitor;
class CSyncTimeline;
class CEGLSync;
namespace Render::GL {
class CEGLSync;
}
class CEventLoopTimer;
class CMonitorState {

View file

@ -4,6 +4,8 @@
#include "../render/Renderer.hpp"
#include "../managers/eventLoop/EventLoopManager.hpp"
using namespace Render::GL;
CMonitorFrameScheduler::CMonitorFrameScheduler(PHLMONITOR m) : m_monitor(m) {
;
}

View file

@ -4,7 +4,9 @@
#include <chrono>
class CEGLSync;
namespace Render::GL {
class CEGLSync;
}
class CMonitorFrameScheduler {
public:
@ -32,7 +34,7 @@ class CMonitorFrameScheduler {
PHLMONITORREF m_monitor;
UP<CEGLSync> m_sync;
UP<Render::GL::CEGLSync> m_sync;
WP<CMonitorFrameScheduler> m_self;

View file

@ -7,7 +7,7 @@
#include "desktop/DesktopTypes.hpp"
#include "render/Renderer.hpp"
void CMonitorZoomController::zoomWithDetachedCamera(CBox& result, const SRenderData& m_renderData) {
void CMonitorZoomController::zoomWithDetachedCamera(CBox& result, const Render::SRenderData& m_renderData) {
const auto m = m_renderData.pMonitor;
auto monbox = CBox(0, 0, m->m_size.x, m->m_size.y);
const auto ZOOM = g_pHyprRenderer->m_renderData.mouseZoomFactor;
@ -68,7 +68,7 @@ void CMonitorZoomController::zoomWithDetachedCamera(CBox& result, const SRenderD
result = monbox;
}
void CMonitorZoomController::applyZoomTransform(CBox& monbox, const SRenderData& m_renderData) {
void CMonitorZoomController::applyZoomTransform(CBox& monbox, const Render::SRenderData& m_renderData) {
static auto PZOOMRIGID = CConfigValue<Hyprlang::INT>("cursor:zoom_rigid");
static auto PZOOMDETACHEDCAMERA = CConfigValue<Hyprlang::INT>("cursor:zoom_detached_camera");
const auto ZOOM = g_pHyprRenderer->m_renderData.mouseZoomFactor;

View file

@ -2,16 +2,18 @@
#include "./math/Math.hpp"
struct SRenderData;
namespace Render {
struct SRenderData;
}
class CMonitorZoomController {
public:
bool m_resetCameraState = true;
void applyZoomTransform(CBox& monbox, const SRenderData& m_renderData);
void applyZoomTransform(CBox& monbox, const Render::SRenderData& m_renderData);
private:
void zoomWithDetachedCamera(CBox& result, const SRenderData& m_renderData);
void zoomWithDetachedCamera(CBox& result, const Render::SRenderData& m_renderData);
CBox m_camera;
float m_lastZoomLevel = 1.0f;

View file

@ -10,6 +10,7 @@
#include "../protocols/core/Seat.hpp"
#include "debug/log/Logger.hpp"
#include "eventLoop/EventLoopManager.hpp"
#include "../render/pass/ClearPassElement.hpp"
#include "../render/pass/TexPassElement.hpp"
#include "../managers/input/InputManager.hpp"
#include "../render/Renderer.hpp"
@ -594,7 +595,7 @@ SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager
CRegion damageRegion = {0, 0, INT_MAX, INT_MAX};
g_pHyprRenderer->beginFullFakeRender(state->monitor.lock(), damageRegion, RBO->getFB());
g_pHyprRenderer->startRenderPass();
g_pHyprRenderer->draw(makeUnique<CClearPassElement>(CClearPassElement::SClearData{{0.F, 0.F, 0.F, 0.F}}), {});
g_pHyprRenderer->draw(makeShared<CClearPassElement>(CClearPassElement::SClearData{{0.F, 0.F, 0.F, 0.F}}), {});
CBox xbox = {{}, Vector2D{m_currentCursorImage.size / m_currentCursorImage.scale * state->monitor->m_scale}.round()};
Log::logger->log(Log::TRACE, "[pointer] monitor: {}, size: {}, hw buf: {}, scale: {:.2f}, monscale: {:.2f}, xbox: {}", state->monitor->m_name, m_currentCursorImage.size,

View file

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

View file

@ -3,7 +3,8 @@
#include "../../protocols/core/Seat.hpp"
#include "../permissions/DynamicPermissionManager.hpp"
#include "../../render/Renderer.hpp"
#include "render/pass/TexPassElement.hpp"
#include "../../render/pass/ClearPassElement.hpp"
#include "../../render/pass/TexPassElement.hpp"
using namespace Screenshare;
@ -122,14 +123,14 @@ void CCursorshareSession::render() {
g_pHyprRenderer->startRenderPass();
if (PERM != PERMISSION_RULE_ALLOW_MODE_ALLOW || !overlaps) {
// render black when not allowed
g_pHyprRenderer->draw(makeUnique<CClearPassElement>(CClearPassElement::SClearData{Colors::BLACK}), {});
g_pHyprRenderer->draw(makeShared<CClearPassElement>(CClearPassElement::SClearData{Colors::BLACK}), {});
} else if (!cursorImage.pBuffer || !cursorImage.surface || !cursorImage.bufferTex) {
// render clear when cursor is probably hidden
g_pHyprRenderer->draw(makeUnique<CClearPassElement>(CClearPassElement::SClearData{{0, 0, 0, 0}}), {});
g_pHyprRenderer->draw(makeShared<CClearPassElement>(CClearPassElement::SClearData{{0, 0, 0, 0}}), {});
} else {
// render cursor
CBox texbox = {{}, cursorImage.bufferTex->m_size};
g_pHyprRenderer->draw(makeUnique<CTexPassElement>(CTexPassElement::SRenderData{
g_pHyprRenderer->draw(makeShared<CTexPassElement>(CTexPassElement::SRenderData{
.tex = cursorImage.bufferTex,
.box = texbox,
}),

View file

@ -10,7 +10,8 @@
#include "../../helpers/Monitor.hpp"
#include "../../desktop/view/Window.hpp"
#include "../../desktop/state/FocusState.hpp"
#include "render/pass/RectPassElement.hpp"
#include "../../render/pass/ClearPassElement.hpp"
#include "../../render/pass/RectPassElement.hpp"
#include <hyprutils/math/Region.hpp>
using namespace Screenshare;
@ -175,7 +176,7 @@ void CScreenshareFrame::renderMonitor() {
const auto OLD = g_pHyprRenderer->m_renderData.renderModif.enabled;
g_pHyprRenderer->m_renderData.renderModif.enabled = false;
g_pHyprRenderer->startRenderPass();
g_pHyprRenderer->draw(makeUnique<CTexPassElement>(CTexPassElement::SRenderData{
g_pHyprRenderer->draw(makeShared<CTexPassElement>(CTexPassElement::SRenderData{
.tex = TEXTURE,
.box = monbox,
.flipEndFrame = true,
@ -199,7 +200,7 @@ void CScreenshareFrame::renderMonitor() {
CBox{popupBaseOffset + popRel + localOff, size}.translate(PMONITOR->m_position).scale(PMONITOR->m_scale).translate(-m_session->m_captureBox.pos());
if LIKELY (surfBox.w > 0 && surfBox.h > 0)
g_pHyprRenderer->draw(makeUnique<CRectPassElement>(CRectPassElement::SRectData{
g_pHyprRenderer->draw(makeShared<CRectPassElement>(CRectPassElement::SRectData{
.box = surfBox,
.color = Colors::BLACK,
}),
@ -224,7 +225,7 @@ void CScreenshareFrame::renderMonitor() {
.scale(PMONITOR->m_scale)
.translate(-m_session->m_captureBox.pos());
g_pHyprRenderer->draw(makeUnique<CRectPassElement>(CRectPassElement::SRectData{
g_pHyprRenderer->draw(makeShared<CRectPassElement>(CRectPassElement::SRectData{
.box = noScreenShareBox,
.color = Colors::BLACK,
}),
@ -263,7 +264,7 @@ void CScreenshareFrame::renderMonitor() {
const auto rounding = dontRound ? 0 : w->rounding() * PMONITOR->m_scale;
const auto roundingPower = dontRound ? 2.0f : w->roundingPower();
g_pHyprRenderer->draw(makeUnique<CRectPassElement>(CRectPassElement::SRectData{
g_pHyprRenderer->draw(makeShared<CRectPassElement>(CRectPassElement::SRectData{
.box = noScreenShareBox,
.color = Colors::BLACK,
.round = rounding,
@ -298,12 +299,12 @@ void CScreenshareFrame::renderWindow() {
// TODO: implement a monitor independent render mode to buffer that does this in CHyprRenderer::begin() or something like that
g_pHyprRenderer->m_renderData.fbSize = m_bufferSize;
g_pHyprRenderer->setProjectionType(RPT_EXPORT);
g_pHyprRenderer->setProjectionType(Render::RPT_EXPORT);
g_pHyprRenderer->m_renderData.transformDamage = false;
g_pHyprRenderer->setViewport(0, 0, m_bufferSize.x, m_bufferSize.y);
g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(PWINDOW); // block the feedback to avoid spamming the surface if it's visible
g_pHyprRenderer->renderWindow(PWINDOW, PMONITOR, NOW, false, RENDER_PASS_ALL, true, true);
g_pHyprRenderer->renderWindow(PWINDOW, PMONITOR, NOW, false, Render::RENDER_PASS_ALL, true, true);
g_pHyprRenderer->m_bBlockSurfaceFeedback = false;
if (!m_overlayCursor)
@ -334,16 +335,16 @@ void CScreenshareFrame::render() {
CRegion frameRegion = {0, 0, g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.x, g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.y};
if (PERM == PERMISSION_RULE_ALLOW_MODE_PENDING) {
g_pHyprRenderer->draw(makeUnique<CClearPassElement>(CClearPassElement::SClearData{{0, 0, 0, 0}}), frameRegion);
g_pHyprRenderer->draw(makeShared<CClearPassElement>(CClearPassElement::SClearData{{0, 0, 0, 0}}), frameRegion);
return;
}
bool windowShareDenied = m_session->m_type == SHARE_WINDOW && m_session->m_window->m_ruleApplicator && m_session->m_window->m_ruleApplicator->noScreenShare().valueOrDefault();
g_pHyprRenderer->startRenderPass();
if (PERM == PERMISSION_RULE_ALLOW_MODE_DENY || windowShareDenied) {
g_pHyprRenderer->draw(makeUnique<CClearPassElement>(CClearPassElement::SClearData{{0, 0, 0, 0}}), frameRegion);
g_pHyprRenderer->draw(makeShared<CClearPassElement>(CClearPassElement::SClearData{{0, 0, 0, 0}}), frameRegion);
CBox texbox = CBox{m_bufferSize / 2.F, g_pHyprRenderer->m_screencopyDeniedTexture->m_size}.translate(-g_pHyprRenderer->m_screencopyDeniedTexture->m_size / 2.F);
g_pHyprRenderer->draw(makeUnique<CTexPassElement>(CTexPassElement::SRenderData{
g_pHyprRenderer->draw(makeShared<CTexPassElement>(CTexPassElement::SRenderData{
.tex = g_pHyprRenderer->m_screencopyDeniedTexture,
.box = texbox,
}),
@ -353,7 +354,7 @@ void CScreenshareFrame::render() {
if (m_session->m_tempFB && m_session->m_tempFB->isAllocated()) {
CBox texbox = {{}, m_bufferSize};
g_pHyprRenderer->draw(makeUnique<CTexPassElement>(CTexPassElement::SRenderData{
g_pHyprRenderer->draw(makeShared<CTexPassElement>(CTexPassElement::SRenderData{
.tex = m_session->m_tempFB->getTexture(),
.box = texbox,
}),
@ -375,7 +376,7 @@ bool CScreenshareFrame::copyDmabuf() {
if (done())
return false;
if (!g_pHyprRenderer->beginRender(m_session->monitor(), m_damage, RENDER_MODE_TO_BUFFER, m_buffer, nullptr, true)) {
if (!g_pHyprRenderer->beginRender(m_session->monitor(), m_damage, Render::RENDER_MODE_TO_BUFFER, m_buffer, nullptr, true)) {
LOGM(Log::ERR, "Can't copy: failed to begin rendering to dma frame");
return false;
}

View file

@ -0,0 +1,478 @@
#include "ElementRenderer.hpp"
#include "Renderer.hpp"
#include "../layout/LayoutManager.hpp"
#include "../desktop/view/Window.hpp"
#include <hyprutils/memory/SharedPtr.hpp>
#include <hyprutils/utils/ScopeGuard.hpp>
using namespace Render;
void IElementRenderer::drawElement(WP<IPassElement> element, const CRegion& damage) {
if (!element)
return;
switch (element->type()) {
case EK_BORDER: draw(dynamicPointerCast<CBorderPassElement>(element), damage); break;
case EK_CLEAR: draw(dynamicPointerCast<CClearPassElement>(element), damage); break;
case EK_FRAMEBUFFER: draw(dynamicPointerCast<CFramebufferElement>(element), damage); break;
case EK_PRE_BLUR: drawPreBlur(dynamicPointerCast<CPreBlurElement>(element), damage); break;
case EK_RECT: drawRect(dynamicPointerCast<CRectPassElement>(element), damage); break;
case EK_HINTS: drawHints(dynamicPointerCast<CRendererHintsPassElement>(element), damage); break;
case EK_SHADOW: draw(dynamicPointerCast<CShadowPassElement>(element), damage); break;
case EK_SURFACE: preDrawSurface(dynamicPointerCast<CSurfacePassElement>(element), damage); break;
case EK_TEXTURE: drawTex(dynamicPointerCast<CTexPassElement>(element), damage); break;
case EK_TEXTURE_MATTE: drawTexMatte(dynamicPointerCast<CTextureMatteElement>(element), damage); break;
default: Log::logger->log(Log::WARN, "Unimplimented draw for {}", element->passName());
}
}
static std::optional<Vector2D> getSurfaceExpectedSize(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface, PHLMONITOR pMonitor, bool main) {
const auto CAN_USE_WINDOW = pWindow && main;
const auto WINDOW_SIZE_MISALIGN = CAN_USE_WINDOW && pWindow->getReportedSize() != pWindow->wlSurface()->resource()->m_current.size;
if (pSurface->m_current.viewport.hasDestination)
return (pSurface->m_current.viewport.destination * pMonitor->m_scale).round();
if (pSurface->m_current.viewport.hasSource)
return (pSurface->m_current.viewport.source.size() * pMonitor->m_scale).round();
if (WINDOW_SIZE_MISALIGN)
return (pSurface->m_current.size * pMonitor->m_scale).round();
if (CAN_USE_WINDOW)
return (pWindow->getReportedSize() * pMonitor->m_scale).round();
return std::nullopt;
}
void IElementRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface, PHLMONITOR pMonitor, bool main, const Vector2D& projSize,
const Vector2D& projSizeUnscaled, bool fixMisalignedFSV1) {
auto& m_renderData = g_pHyprRenderer->m_renderData;
if (!pWindow || !pWindow->m_isX11) {
static auto PEXPANDEDGES = CConfigValue<Hyprlang::INT>("render:expand_undersized_textures");
Vector2D uvTL;
Vector2D uvBR = Vector2D(1, 1);
if (pSurface->m_current.viewport.hasSource) {
// we stretch it to dest. if no dest, to 1,1
Vector2D const& bufferSize = pSurface->m_current.bufferSize;
auto const& bufferSource = pSurface->m_current.viewport.source;
// calculate UV for the basic src_box. Assume dest == size. Scale to dest later
uvTL = Vector2D(bufferSource.x / bufferSize.x, bufferSource.y / bufferSize.y);
uvBR = Vector2D((bufferSource.x + bufferSource.width) / bufferSize.x, (bufferSource.y + bufferSource.height) / bufferSize.y);
if (uvBR.x < 0.01f || uvBR.y < 0.01f) {
uvTL = Vector2D();
uvBR = Vector2D(1, 1);
}
}
if (projSize != Vector2D{} && fixMisalignedFSV1) {
// instead of nearest_neighbor (we will repeat / skip)
// just cut off / expand surface
const Vector2D PIXELASUV = Vector2D{1, 1} / pSurface->m_current.bufferSize;
const auto& BUFFER_SIZE = pSurface->m_current.bufferSize;
// compute MISALIGN from the adjusted UV coordinates.
const Vector2D MISALIGNMENT = (uvBR - uvTL) * BUFFER_SIZE - projSize;
if (MISALIGNMENT != Vector2D{})
uvBR -= MISALIGNMENT * PIXELASUV;
} else {
// if the surface is smaller than our viewport, extend its edges.
// this will break if later on xdg geometry is hit, but we really try
// to let the apps know to NOT add CSD. Also if source is there.
// there is no way to fix this if that's the case
const auto MONITOR_WL_SCALE = std::ceil(pMonitor->m_scale);
const bool SCALE_UNAWARE = pMonitor->m_scale != 1.f && (MONITOR_WL_SCALE == pSurface->m_current.scale || !pSurface->m_current.viewport.hasDestination);
const auto EXPECTED_SIZE = getSurfaceExpectedSize(pWindow, pSurface, pMonitor, main).value_or((projSize * pMonitor->m_scale).round());
const auto RATIO = projSize / EXPECTED_SIZE;
if (!SCALE_UNAWARE || MONITOR_WL_SCALE == 1) {
if (*PEXPANDEDGES && !SCALE_UNAWARE && (RATIO.x > 1 || RATIO.y > 1)) {
const auto FIX = RATIO.clamp(Vector2D{1, 1}, Vector2D{1000000, 1000000});
uvBR = uvBR * FIX;
}
// FIXME: probably do this for in anims on all views...
const auto SHOULD_SKIP = !pWindow || pWindow->m_animatingIn;
if (!SHOULD_SKIP && (RATIO.x < 1 || RATIO.y < 1)) {
const auto FIX = RATIO.clamp(Vector2D{0.0001, 0.0001}, Vector2D{1, 1});
uvBR = uvBR * FIX;
}
}
}
m_renderData.primarySurfaceUVTopLeft = uvTL;
m_renderData.primarySurfaceUVBottomRight = uvBR;
if (m_renderData.primarySurfaceUVTopLeft == Vector2D() && m_renderData.primarySurfaceUVBottomRight == Vector2D(1, 1)) {
// No special UV mods needed
m_renderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
m_renderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
}
if (!main || !pWindow)
return;
// FIXME: this doesn't work. We always set MAXIMIZED anyways, so this doesn't need to work, but it's problematic.
// CBox geom = pWindow->m_xdgSurface->m_current.geometry;
// // Adjust UV based on the xdg_surface geometry
// if (geom.x != 0 || geom.y != 0 || geom.w != 0 || geom.h != 0) {
// const auto XPERC = geom.x / pSurface->m_current.size.x;
// const auto YPERC = geom.y / pSurface->m_current.size.y;
// const auto WPERC = (geom.x + geom.w ? geom.w : pSurface->m_current.size.x) / pSurface->m_current.size.x;
// const auto HPERC = (geom.y + geom.h ? geom.h : pSurface->m_current.size.y) / pSurface->m_current.size.y;
// const auto TOADDTL = Vector2D(XPERC * (uvBR.x - uvTL.x), YPERC * (uvBR.y - uvTL.y));
// uvBR = uvBR - Vector2D((1.0 - WPERC) * (uvBR.x - uvTL.x), (1.0 - HPERC) * (uvBR.y - uvTL.y));
// uvTL = uvTL + TOADDTL;
// }
m_renderData.primarySurfaceUVTopLeft = uvTL;
m_renderData.primarySurfaceUVBottomRight = uvBR;
if (m_renderData.primarySurfaceUVTopLeft == Vector2D() && m_renderData.primarySurfaceUVBottomRight == Vector2D(1, 1)) {
// No special UV mods needed
m_renderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
m_renderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
}
} else {
m_renderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
m_renderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
}
}
void IElementRenderer::drawRect(WP<CRectPassElement> element, const CRegion& damage) {
auto& data = element->m_data;
auto& m_renderData = g_pHyprRenderer->m_renderData;
if (data.box.w <= 0 || data.box.h <= 0)
return;
if (!data.clipBox.empty())
m_renderData.clipBox = data.clipBox;
data.modifiedBox = data.box;
m_renderData.renderModif.applyToBox(data.modifiedBox);
CBox transformedBox = data.box;
transformedBox.transform(Math::wlTransformToHyprutils(Math::invertTransform(m_renderData.pMonitor->m_transform)), m_renderData.pMonitor->m_transformedSize.x,
m_renderData.pMonitor->m_transformedSize.y);
data.TOPLEFT[0] = sc<float>(transformedBox.x);
data.TOPLEFT[1] = sc<float>(transformedBox.y);
data.FULLSIZE[0] = sc<float>(transformedBox.width);
data.FULLSIZE[1] = sc<float>(transformedBox.height);
data.drawRegion = data.color.a == 1.F || !data.blur ? damage : m_renderData.damage;
if (m_renderData.clipBox.width != 0 && m_renderData.clipBox.height != 0) {
CRegion damageClip{m_renderData.clipBox.x, m_renderData.clipBox.y, m_renderData.clipBox.width, m_renderData.clipBox.height};
data.drawRegion = damageClip.intersect(data.drawRegion);
}
draw(element, damage);
m_renderData.clipBox = {};
}
void IElementRenderer::drawHints(WP<CRendererHintsPassElement> element, const CRegion& damage) {
const auto m_data = element->m_data;
if (m_data.renderModif.has_value())
g_pHyprRenderer->m_renderData.renderModif = *m_data.renderModif;
}
void IElementRenderer::drawPreBlur(WP<CPreBlurElement> element, const CRegion& damage) {
TRACY_GPU_ZONE("RenderPreBlurForCurrentMonitor");
auto& m_renderData = g_pHyprRenderer->m_renderData;
const auto SAVEDRENDERMODIF = m_renderData.renderModif;
m_renderData.renderModif = {}; // fix shit
// make the fake dmg
CRegion fakeDamage{0, 0, m_renderData.pMonitor->m_transformedSize.x, m_renderData.pMonitor->m_transformedSize.y};
draw(element, fakeDamage);
m_renderData.pMonitor->m_blurFBDirty = false;
m_renderData.pMonitor->m_blurFBShouldRender = false;
m_renderData.renderModif = SAVEDRENDERMODIF;
}
void IElementRenderer::drawSurface(WP<CSurfacePassElement> element, const CRegion& damage) {
const auto m_data = element->m_data;
auto& m_renderData = g_pHyprRenderer->m_renderData;
Hyprutils::Utils::CScopeGuard x = {[]() {
g_pHyprRenderer->m_renderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
g_pHyprRenderer->m_renderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
}};
if (!m_data.texture)
return;
const auto& TEXTURE = m_data.texture;
// this is bad, probably has been logged elsewhere. Means the texture failed
// uploading to the GPU.
if (!TEXTURE->ok())
return;
const auto INTERACTIVERESIZEINPROGRESS = m_data.pWindow && g_layoutManager->dragController()->target() && g_layoutManager->dragController()->mode() == MBIND_RESIZE;
TRACY_GPU_ZONE("RenderSurface");
auto PSURFACE = Desktop::View::CWLSurface::fromResource(m_data.surface);
const float ALPHA = m_data.alpha * m_data.fadeAlpha * (PSURFACE ? PSURFACE->m_alphaModifier : 1.F);
const float OVERALL_ALPHA = PSURFACE ? PSURFACE->m_overallOpacity : 1.F;
const bool BLUR = m_data.blur && (!TEXTURE->m_opaque || ALPHA < 1.F || OVERALL_ALPHA < 1.F);
auto windowBox = element->getTexBox();
const auto PROJSIZEUNSCALED = windowBox.size();
windowBox.scale(m_data.pMonitor->m_scale);
windowBox.round();
if (windowBox.width <= 1 || windowBox.height <= 1) {
element->discard();
return;
}
const bool MISALIGNEDFSV1 = std::floor(m_data.pMonitor->m_scale) != m_data.pMonitor->m_scale /* Fractional */ && m_data.surface->m_current.scale == 1 /* fs protocol */ &&
windowBox.size() != m_data.surface->m_current.bufferSize /* misaligned */ && DELTALESSTHAN(windowBox.width, m_data.surface->m_current.bufferSize.x, 3) &&
DELTALESSTHAN(windowBox.height, m_data.surface->m_current.bufferSize.y, 3) /* off by one-or-two */ &&
(!m_data.pWindow || (!m_data.pWindow->m_realSize->isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */ &&
(!m_data.pLS || (!m_data.pLS->m_realSize->isBeingAnimated())); /* not LS or not animated */
calculateUVForSurface(m_data.pWindow, m_data.surface, m_data.pMonitor->m_self.lock(), m_data.mainSurface, windowBox.size(), PROJSIZEUNSCALED, MISALIGNEDFSV1);
auto cancelRender = false;
auto clipRegion = element->visibleRegion(cancelRender);
if (cancelRender)
return;
// check for fractional scale surfaces misaligning the buffer size
// in those cases it's better to just force nearest neighbor
// as long as the window is not animated. During those it'd look weird.
// UV will fixup it as well
if (MISALIGNEDFSV1)
m_renderData.useNearestNeighbor = true;
float rounding = m_data.rounding;
float roundingPower = m_data.roundingPower;
rounding -= 1; // to fix a border issue
if (m_data.dontRound) {
rounding = 0;
roundingPower = 2.0f;
}
const bool WINDOWOPAQUE = m_data.pWindow && m_data.pWindow->wlSurface()->resource() == m_data.surface ? m_data.pWindow->opaque() : false;
const bool CANDISABLEBLEND = ALPHA >= 1.f && OVERALL_ALPHA >= 1.f && rounding <= 0 && WINDOWOPAQUE;
if (CANDISABLEBLEND)
g_pHyprRenderer->blend(false);
else
g_pHyprRenderer->blend(true);
// FIXME: This is wrong and will bug the blur out as shit if the first surface
// is a subsurface that does NOT cover the entire frame. In such cases, we probably should fall back
// to what we do for misaligned surfaces (blur the entire thing and then render shit without blur)
if (m_data.surfaceCounter == 0 && !m_data.popup) {
if (BLUR)
drawElement(makeShared<CTexPassElement>(CTexPassElement::SRenderData{
.tex = TEXTURE,
.box = windowBox,
.a = ALPHA,
.blurA = m_data.fadeAlpha,
.overallA = OVERALL_ALPHA,
.round = rounding,
.roundingPower = roundingPower,
.blur = true,
.blockBlurOptimization = m_data.blockBlurOptimization,
.allowCustomUV = true,
.surface = m_data.surface,
.discardMode = m_data.discardMode,
.discardOpacity = m_data.discardOpacity,
.clipRegion = clipRegion,
.currentLS = m_data.pLS,
}),
m_renderData.damage.copy().intersect(windowBox));
else
drawElement(makeShared<CTexPassElement>(CTexPassElement::SRenderData{
.tex = TEXTURE,
.box = windowBox,
.a = ALPHA * OVERALL_ALPHA,
.round = rounding,
.roundingPower = roundingPower,
.discardActive = false,
.allowCustomUV = true,
.surface = m_data.surface,
.discardMode = m_data.discardMode,
.discardOpacity = m_data.discardOpacity,
.clipRegion = clipRegion,
.currentLS = m_data.pLS,
}),
m_renderData.damage.copy().intersect(windowBox));
} else {
if (BLUR && m_data.popup)
drawElement(makeShared<CTexPassElement>(CTexPassElement::SRenderData{
.tex = TEXTURE,
.box = windowBox,
.a = ALPHA,
.blurA = m_data.fadeAlpha,
.overallA = OVERALL_ALPHA,
.round = rounding,
.roundingPower = roundingPower,
.blur = true,
.blockBlurOptimization = true,
.allowCustomUV = true,
.surface = m_data.surface,
.discardMode = m_data.discardMode,
.discardOpacity = m_data.discardOpacity,
.clipRegion = clipRegion,
.currentLS = m_data.pLS,
}),
m_renderData.damage.copy().intersect(windowBox));
else
drawElement(makeShared<CTexPassElement>(CTexPassElement::SRenderData{
.tex = TEXTURE,
.box = windowBox,
.a = ALPHA * OVERALL_ALPHA,
.round = rounding,
.roundingPower = roundingPower,
.discardActive = false,
.allowCustomUV = true,
.surface = m_data.surface,
.discardMode = m_data.discardMode,
.discardOpacity = m_data.discardOpacity,
.clipRegion = clipRegion,
.currentLS = m_data.pLS,
}),
m_renderData.damage.copy().intersect(windowBox));
}
g_pHyprRenderer->blend(true);
};
void IElementRenderer::preDrawSurface(WP<CSurfacePassElement> element, const CRegion& damage) {
auto& m_renderData = g_pHyprRenderer->m_renderData;
m_renderData.clipBox = element->m_data.clipBox;
m_renderData.useNearestNeighbor = element->m_data.useNearestNeighbor;
g_pHyprRenderer->pushMonitorTransformEnabled(element->m_data.flipEndFrame);
m_renderData.currentWindow = element->m_data.pWindow;
drawSurface(element, damage);
if (!g_pHyprRenderer->m_bBlockSurfaceFeedback)
element->m_data.surface->presentFeedback(element->m_data.when, element->m_data.pMonitor->m_self.lock());
// add async (dmabuf) buffers to usedBuffers so we can handle release later
// sync (shm) buffers will be released in commitState, so no need to track them here
if (element->m_data.surface->m_current.buffer && !element->m_data.surface->m_current.buffer->isSynchronous())
g_pHyprRenderer->m_usedAsyncBuffers.emplace_back(element->m_data.surface->m_current.buffer);
m_renderData.clipBox = {};
m_renderData.useNearestNeighbor = false;
g_pHyprRenderer->popMonitorTransformEnabled();
m_renderData.currentWindow.reset();
}
void IElementRenderer::drawTex(WP<CTexPassElement> element, const CRegion& damage) {
auto& m_renderData = g_pHyprRenderer->m_renderData;
if (!element->m_data.clipBox.empty())
m_renderData.clipBox = element->m_data.clipBox;
g_pHyprRenderer->pushMonitorTransformEnabled(element->m_data.flipEndFrame);
if (element->m_data.useMirrorProjection)
g_pHyprRenderer->setProjectionType(RPT_MIRROR);
m_renderData.surface = element->m_data.surface;
Hyprutils::Utils::CScopeGuard x = {[useMirrorProjection = element->m_data.useMirrorProjection]() {
g_pHyprRenderer->popMonitorTransformEnabled();
if (useMirrorProjection)
g_pHyprRenderer->setProjectionType(RPT_MONITOR);
g_pHyprRenderer->m_renderData.surface.reset();
}};
if (element->m_data.blur) {
// make a damage region for this window
CRegion texDamage{m_renderData.damage};
texDamage.intersect(element->m_data.box.x, element->m_data.box.y, element->m_data.box.width, element->m_data.box.height);
// While renderTextureInternalWithDamage will clip the blur as well,
// clipping texDamage here allows blur generation to be optimized.
if (!element->m_data.clipRegion.empty())
texDamage.intersect(element->m_data.clipRegion);
if (texDamage.empty())
return;
m_renderData.renderModif.applyToRegion(texDamage);
element->m_data.damage = texDamage;
// amazing hack: the surface has an opaque region!
const auto& surface = element->m_data.surface;
const auto& box = element->m_data.box;
CRegion inverseOpaque;
if (element->m_data.a >= 1.f && surface && std::round(surface->m_current.size.x * m_renderData.pMonitor->m_scale) == box.w &&
std::round(surface->m_current.size.y * m_renderData.pMonitor->m_scale) == box.h) {
pixman_box32_t surfbox = {0, 0, surface->m_current.size.x * surface->m_current.scale, surface->m_current.size.y * surface->m_current.scale};
inverseOpaque = surface->m_current.opaque;
inverseOpaque.invert(&surfbox).intersect(0, 0, surface->m_current.size.x * surface->m_current.scale, surface->m_current.size.y * surface->m_current.scale);
if (inverseOpaque.empty()) {
element->m_data.blur = false;
draw(element, damage);
m_renderData.clipBox = {};
return;
}
} else
inverseOpaque = {0, 0, element->m_data.box.width, element->m_data.box.height};
inverseOpaque.scale(m_renderData.pMonitor->m_scale);
element->m_data.blockBlurOptimization = element->m_data.blockBlurOptimization.value_or(false) ||
!g_pHyprRenderer->shouldUseNewBlurOptimizations(element->m_data.currentLS.lock(), m_renderData.currentWindow.lock());
// vvv TODO: layered blur fbs?
if (element->m_data.blockBlurOptimization) {
inverseOpaque.translate(box.pos());
m_renderData.renderModif.applyToRegion(inverseOpaque);
inverseOpaque.intersect(element->m_data.damage);
element->m_data.blurredBG = g_pHyprRenderer->blurMainFramebuffer(element->m_data.a, &inverseOpaque);
m_renderData.currentFB->bind();
} else
element->m_data.blurredBG = m_renderData.pMonitor->m_blurFB ? m_renderData.pMonitor->m_blurFB->getTexture() : nullptr;
draw(element, damage);
} else
draw(element, damage);
m_renderData.clipBox = {};
}
void IElementRenderer::drawTexMatte(WP<CTextureMatteElement> element, const CRegion& damage) {
if (g_pHyprRenderer->m_renderData.damage.empty())
return;
const auto m_data = element->m_data;
if (m_data.disableTransformAndModify) {
g_pHyprRenderer->pushMonitorTransformEnabled(true);
g_pHyprRenderer->m_renderData.renderModif.enabled = false;
draw(element, damage);
g_pHyprRenderer->m_renderData.renderModif.enabled = true;
g_pHyprRenderer->popMonitorTransformEnabled();
} else
draw(element, damage);
}

View file

@ -0,0 +1,45 @@
#pragma once
#include "./pass/BorderPassElement.hpp"
#include "./pass/ClearPassElement.hpp"
#include "./pass/FramebufferElement.hpp"
#include "./pass/PreBlurElement.hpp"
#include "./pass/RectPassElement.hpp"
#include "./pass/RendererHintsPassElement.hpp"
#include "./pass/ShadowPassElement.hpp"
#include "./pass/SurfacePassElement.hpp"
#include "./pass/TexPassElement.hpp"
#include "./pass/TextureMatteElement.hpp"
#include <hyprutils/math/Region.hpp>
namespace Render {
class IElementRenderer {
public:
IElementRenderer() = default;
virtual ~IElementRenderer() = default;
void drawElement(WP<IPassElement> element, const CRegion& damage);
protected:
virtual void draw(WP<CBorderPassElement> element, const CRegion& damage) = 0;
virtual void draw(WP<CClearPassElement> element, const CRegion& damage) = 0;
virtual void draw(WP<CFramebufferElement> element, const CRegion& damage) = 0;
virtual void draw(WP<CPreBlurElement> element, const CRegion& damage) = 0;
virtual void draw(WP<CRectPassElement> element, const CRegion& damage) = 0;
virtual void draw(WP<CShadowPassElement> element, const CRegion& damage) = 0;
virtual void draw(WP<CTexPassElement> element, const CRegion& damage) = 0;
virtual void draw(WP<CTextureMatteElement> element, const CRegion& damage) = 0;
private:
void calculateUVForSurface(PHLWINDOW, SP<CWLSurfaceResource>, PHLMONITOR pMonitor, bool main = false, const Vector2D& projSize = {}, const Vector2D& projSizeUnscaled = {},
bool fixMisalignedFSV1 = false);
void drawRect(WP<CRectPassElement> element, const CRegion& damage);
void drawHints(WP<CRendererHintsPassElement> element, const CRegion& damage);
void drawPreBlur(WP<CPreBlurElement> element, const CRegion& damage);
void drawSurface(WP<CSurfacePassElement> element, const CRegion& damage);
void preDrawSurface(WP<CSurfacePassElement> element, const CRegion& damage);
void drawTex(WP<CTexPassElement> element, const CRegion& damage);
void drawTexMatte(WP<CTextureMatteElement> element, const CRegion& damage);
};
}

View file

@ -11,30 +11,37 @@
#include "../debug/HyprDebugOverlay.hpp"
#include "../helpers/Monitor.hpp"
#include "pass/TexPassElement.hpp"
#include "pass/ClearPassElement.hpp"
#include "pass/RectPassElement.hpp"
#include "pass/SurfacePassElement.hpp"
#include "../debug/log/Logger.hpp"
#include "../protocols/types/ContentType.hpp"
#include "OpenGL.hpp"
#include "Renderer.hpp"
#include "gl/GLFramebuffer.hpp"
#include "gl/GLTexture.hpp"
#include "decorations/CHyprDropShadowDecoration.hpp"
#include "./gl/GLElementRenderer.hpp"
#include "./gl/GLFramebuffer.hpp"
#include "./gl/GLTexture.hpp"
#include <cstdint>
#include <hyprutils/memory/SharedPtr.hpp>
#include <hyprutils/memory/UniquePtr.hpp>
#include <hyprutils/utils/ScopeGuard.hpp>
using namespace Hyprutils::Utils;
using namespace Hyprutils::OS;
using enum NContentType::eContentType;
using namespace NColorManagement;
using namespace Render;
using namespace Render::GL;
extern "C" {
#include <xf86drm.h>
}
CHyprGLRenderer::CHyprGLRenderer() : IHyprRenderer() {}
CHyprGLRenderer::CHyprGLRenderer() : IHyprRenderer() {
m_elementRenderer = makeUnique<CGLElementRenderer>();
}
CHyprGLRenderer::~CHyprGLRenderer() {
m_elementRenderer.reset();
}
void CHyprGLRenderer::initRender() {
g_pHyprOpenGL->makeEGLCurrent();
@ -281,118 +288,6 @@ bool CHyprGLRenderer::reloadShaders(const std::string& path) {
return g_pHyprOpenGL->initShaders(path);
}
void CHyprGLRenderer::draw(CBorderPassElement* element, const CRegion& damage) {
const auto m_data = element->m_data;
if (m_data.hasGrad2)
g_pHyprOpenGL->renderBorder(
m_data.box, m_data.grad1, m_data.grad2, m_data.lerp,
{.round = m_data.round, .roundingPower = m_data.roundingPower, .borderSize = m_data.borderSize, .a = m_data.a, .outerRound = m_data.outerRound});
else
g_pHyprOpenGL->renderBorder(
m_data.box, m_data.grad1,
{.round = m_data.round, .roundingPower = m_data.roundingPower, .borderSize = m_data.borderSize, .a = m_data.a, .outerRound = m_data.outerRound});
};
void CHyprGLRenderer::draw(CClearPassElement* element, const CRegion& damage) {
g_pHyprOpenGL->clear(element->m_data.color);
};
void CHyprGLRenderer::draw(CFramebufferElement* element, const CRegion& damage) {
const auto m_data = element->m_data;
SP<IFramebuffer> fb = nullptr;
if (m_data.main) {
switch (m_data.framebufferID) {
case FB_MONITOR_RENDER_MAIN: fb = g_pHyprRenderer->m_renderData.mainFB; break;
case FB_MONITOR_RENDER_CURRENT: fb = g_pHyprRenderer->m_renderData.currentFB; break;
case FB_MONITOR_RENDER_OUT: fb = g_pHyprRenderer->m_renderData.outFB; break;
default: fb = nullptr;
}
if (!fb) {
Log::logger->log(Log::ERR, "BUG THIS: CFramebufferElement::draw: main but null");
return;
}
} else {
switch (m_data.framebufferID) {
case FB_MONITOR_RENDER_EXTRA_OFFLOAD: fb = g_pHyprRenderer->m_renderData.pMonitor->m_offloadFB; break;
case FB_MONITOR_RENDER_EXTRA_MIRROR: fb = m_renderData.pMonitor->m_mirrorFB; break;
case FB_MONITOR_RENDER_EXTRA_MIRROR_SWAP: fb = m_renderData.pMonitor->m_mirrorSwapFB; break;
case FB_MONITOR_RENDER_EXTRA_OFF_MAIN: fb = g_pHyprRenderer->m_renderData.pMonitor->m_offMainFB; break;
case FB_MONITOR_RENDER_EXTRA_MONITOR_MIRROR: fb = g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB; break;
case FB_MONITOR_RENDER_EXTRA_BLUR: fb = g_pHyprRenderer->m_renderData.pMonitor->m_blurFB; break;
default: fb = nullptr;
}
if (!fb) {
Log::logger->log(Log::ERR, "BUG THIS: CFramebufferElement::draw: not main but null");
return;
}
}
fb->bind();
};
void CHyprGLRenderer::draw(CPreBlurElement* element, const CRegion& damage) {
auto dmg = damage;
g_pHyprRenderer->preBlurForCurrentMonitor(&dmg);
};
void CHyprGLRenderer::draw(CRectPassElement* element, const CRegion& damage) {
const auto m_data = element->m_data;
if (m_data.color.a == 1.F || !m_data.blur)
g_pHyprOpenGL->renderRect(m_data.box, m_data.color, {.damage = &damage, .round = m_data.round, .roundingPower = m_data.roundingPower});
else
g_pHyprOpenGL->renderRect(m_data.box, m_data.color,
{.round = m_data.round, .roundingPower = m_data.roundingPower, .blur = true, .blurA = m_data.blurA, .xray = m_data.xray});
};
void CHyprGLRenderer::draw(CShadowPassElement* element, const CRegion& damage) {
const auto m_data = element->m_data;
m_data.deco->render(g_pHyprRenderer->m_renderData.pMonitor.lock(), m_data.a);
};
void CHyprGLRenderer::draw(CTexPassElement* element, const CRegion& damage) {
const auto m_data = element->m_data;
g_pHyprOpenGL->renderTexture( //
m_data.tex, m_data.box,
{
// blur settings for m_data.blur == true
.blur = m_data.blur,
.blurA = m_data.blurA,
.overallA = m_data.overallA,
.blockBlurOptimization = m_data.blockBlurOptimization.value_or(false),
.blurredBG = m_data.blurredBG,
// common settings
.damage = m_data.damage.empty() ? &damage : &m_data.damage,
.surface = m_data.surface,
.a = m_data.a,
.round = m_data.round,
.roundingPower = m_data.roundingPower,
.discardActive = m_data.discardActive,
.allowCustomUV = m_data.allowCustomUV,
.cmBackToSRGB = m_data.cmBackToSRGB,
.cmBackToSRGBSource = m_data.cmBackToSRGBSource,
.discardMode = m_data.ignoreAlpha.has_value() ? sc<uint32_t>(DISCARD_ALPHA) : m_data.discardMode,
.discardOpacity = m_data.ignoreAlpha.has_value() ? *m_data.ignoreAlpha : m_data.discardOpacity,
.clipRegion = m_data.clipRegion,
.currentLS = m_data.currentLS,
.primarySurfaceUVTopLeft = g_pHyprRenderer->m_renderData.primarySurfaceUVTopLeft,
.primarySurfaceUVBottomRight = g_pHyprRenderer->m_renderData.primarySurfaceUVBottomRight,
});
};
void CHyprGLRenderer::draw(CTextureMatteElement* element, const CRegion& damage) {
const auto m_data = element->m_data;
g_pHyprOpenGL->renderTextureMatte(m_data.tex, m_data.box, m_data.fb);
};
SP<ITexture> CHyprGLRenderer::getBlurTexture(PHLMONITORREF pMonitor) {
if (!pMonitor->m_blurFB)
return nullptr;
@ -405,3 +300,7 @@ void CHyprGLRenderer::unsetEGL() {
eglMakeCurrent(g_pHyprOpenGL->m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
WP<IElementRenderer> CHyprGLRenderer::elementRenderer() {
return m_elementRenderer;
}

View file

@ -1,52 +1,49 @@
#pragma once
#include "Renderer.hpp"
#include "render/ElementRenderer.hpp"
class CHyprGLRenderer : public IHyprRenderer {
public:
CHyprGLRenderer();
namespace Render::GL {
class CHyprGLRenderer : public Render::IHyprRenderer {
public:
CHyprGLRenderer();
~CHyprGLRenderer();
void endRender(const std::function<void()>& renderingDoneCallback = {}) override;
SP<ITexture> createStencilTexture(const int width, const int height) override;
SP<ITexture> createTexture(bool opaque = false) override;
SP<ITexture> createTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false, bool opaque = false) override;
SP<ITexture> createTexture(const Aquamarine::SDMABUFAttrs&, bool opaque = false) override;
SP<ITexture> createTexture(const int width, const int height, unsigned char* const data) override;
SP<ITexture> createTexture(cairo_surface_t* cairo) override;
SP<ITexture> createTexture(std::span<const float> lut3D, size_t N) override;
bool explicitSyncSupported() override;
std::vector<SDRMFormat> getDRMFormats() override;
std::vector<uint64_t> getDRMFormatModifiers(DRMFormat format) override;
SP<IFramebuffer> createFB(const std::string& name = "") override;
void disableScissor() override;
void blend(bool enabled) override;
void drawShadow(const CBox& box, int round, float roundingPower, int range, CHyprColor color, float a) override;
SP<ITexture> blurFramebuffer(SP<IFramebuffer> source, float a, CRegion* originalDamage) override;
void setViewport(int x, int y, int width, int height) override;
bool reloadShaders(const std::string& path = "") override;
void endRender(const std::function<void()>& renderingDoneCallback = {}) override;
SP<ITexture> createStencilTexture(const int width, const int height) override;
SP<ITexture> createTexture(bool opaque = false) override;
SP<ITexture> createTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false, bool opaque = false) override;
SP<ITexture> createTexture(const Aquamarine::SDMABUFAttrs&, bool opaque = false) override;
SP<ITexture> createTexture(const int width, const int height, unsigned char* const data) override;
SP<ITexture> createTexture(cairo_surface_t* cairo) override;
SP<ITexture> createTexture(std::span<const float> lut3D, size_t N) override;
bool explicitSyncSupported() override;
std::vector<SDRMFormat> getDRMFormats() override;
std::vector<uint64_t> getDRMFormatModifiers(DRMFormat format) override;
SP<IFramebuffer> createFB(const std::string& name = "") override;
void disableScissor() override;
void blend(bool enabled) override;
void drawShadow(const CBox& box, int round, float roundingPower, int range, CHyprColor color, float a) override;
SP<ITexture> blurFramebuffer(SP<IFramebuffer> source, float a, CRegion* originalDamage) override;
void setViewport(int x, int y, int width, int height) override;
bool reloadShaders(const std::string& path = "") override;
void unsetEGL();
void unsetEGL();
WP<IElementRenderer> elementRenderer() override;
private:
void renderOffToMain(IFramebuffer* off) override;
SP<IRenderbuffer> getOrCreateRenderbufferInternal(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) override;
bool beginRenderInternal(PHLMONITOR pMonitor, CRegion& damage, bool simple = false) override;
bool beginFullFakeRenderInternal(PHLMONITOR pMonitor, CRegion& damage, SP<IFramebuffer> fb, bool simple = false) override;
void initRender() override;
bool initRenderBuffer(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) override;
private:
void renderOffToMain(IFramebuffer* off) override;
SP<IRenderbuffer> getOrCreateRenderbufferInternal(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) override;
bool beginRenderInternal(PHLMONITOR pMonitor, CRegion& damage, bool simple = false) override;
bool beginFullFakeRenderInternal(PHLMONITOR pMonitor, CRegion& damage, SP<IFramebuffer> fb, bool simple = false) override;
void initRender() override;
bool initRenderBuffer(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) override;
void draw(CBorderPassElement* element, const CRegion& damage) override;
void draw(CClearPassElement* element, const CRegion& damage) override;
void draw(CFramebufferElement* element, const CRegion& damage) override;
void draw(CPreBlurElement* element, const CRegion& damage) override;
void draw(CRectPassElement* element, const CRegion& damage) override;
void draw(CShadowPassElement* element, const CRegion& damage) override;
void draw(CTexPassElement* element, const CRegion& damage) override;
void draw(CTextureMatteElement* element, const CRegion& damage) override;
SP<ITexture> getBlurTexture(PHLMONITORREF pMonitor) override;
SP<ITexture> getBlurTexture(PHLMONITORREF pMonitor) override;
SP<IRenderbuffer> m_currentRenderbuffer;
UP<IElementRenderer> m_elementRenderer;
SP<IRenderbuffer> m_currentRenderbuffer = nullptr;
friend class CHyprOpenGLImpl;
};
friend class CHyprOpenGLImpl;
};
}

View file

@ -60,6 +60,7 @@
using namespace Hyprutils::OS;
using namespace NColorManagement;
using namespace Render;
using namespace Render::GL;
static inline void loadGLProc(void* pProc, const char* name) {
void* proc = rc<void*>(eglGetProcAddress(name));
@ -951,21 +952,6 @@ void CHyprOpenGLImpl::applyScreenShader(const std::string& path) {
uniformRequireNoDamage(SHADER_POINTER_SHAPE_PREVIOUS, "pointer_shape_previous");
}
void CHyprOpenGLImpl::clear(const CHyprColor& color) {
RASSERT(g_pHyprRenderer->m_renderData.pMonitor, "Tried to render without begin()!");
TRACY_GPU_ZONE("RenderClear");
GLCALL(glClearColor(color.r, color.g, color.b, color.a));
if (!g_pHyprRenderer->m_renderData.damage.empty()) {
g_pHyprRenderer->m_renderData.damage.forEachRect([this](const auto& RECT) {
scissor(&RECT, g_pHyprRenderer->m_renderData.transformDamage);
glClear(GL_COLOR_BUFFER_BIT);
});
}
}
void CHyprOpenGLImpl::blend(bool enabled) {
if (enabled) {
setCapStatus(GL_BLEND, true);
@ -1446,7 +1432,7 @@ WP<CShader> CHyprOpenGLImpl::renderToFBInternal(const STextureRenderData& data,
void CHyprOpenGLImpl::renderTextureInternal(SP<ITexture> tex, const CBox& box, const STextureRenderData& data) {
RASSERT(g_pHyprRenderer->m_renderData.pMonitor, "Tried to render texture without begin()!");
RASSERT((tex->ok()), "Attempted to draw nullptr texture!");
RASSERT((tex && tex->ok()), "Attempted to draw nullptr texture!");
TRACY_GPU_ZONE("RenderTextureInternalWithDamage");

View file

@ -16,6 +16,7 @@
#include <cairo/cairo.h>
#include "types.hpp"
#include "Shader.hpp"
#include "Texture.hpp"
#include "Framebuffer.hpp"
@ -40,342 +41,326 @@
#define GLFB(ifb) dc<CGLFramebuffer*>(ifb.get())
struct gbm_device;
class IHyprRenderer;
namespace Config {
class CGradientValueData;
namespace Render {
class IHyprRenderer;
}
class CGradientValueData;
struct SVertex {
float x, y; // position
float u, v; // uv
};
namespace Render::GL {
constexpr std::array<SVertex, 4> fullVerts = {{
{0.0f, 0.0f, 0.0f, 0.0f}, // top-left
{0.0f, 1.0f, 0.0f, 1.0f}, // bottom-left
{1.0f, 0.0f, 1.0f, 0.0f}, // top-right
{1.0f, 1.0f, 1.0f, 1.0f}, // bottom-right
}};
inline const float fanVertsFull[] = {-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f};
struct SRenderModifData {
enum eRenderModifType : uint8_t {
RMOD_TYPE_SCALE, /* scale by a float */
RMOD_TYPE_SCALECENTER, /* scale by a float from the center */
RMOD_TYPE_TRANSLATE, /* translate by a Vector2D */
RMOD_TYPE_ROTATE, /* rotate by a float in rad from top left */
RMOD_TYPE_ROTATECENTER, /* rotate by a float in rad from center */
struct SVertex {
float x, y; // position
float u, v; // uv
};
std::vector<std::pair<eRenderModifType, std::any>> modifs;
constexpr std::array<SVertex, 4> fullVerts = {{
{0.0f, 0.0f, 0.0f, 0.0f}, // top-left
{0.0f, 1.0f, 0.0f, 1.0f}, // bottom-left
{1.0f, 0.0f, 1.0f, 0.0f}, // top-right
{1.0f, 1.0f, 1.0f, 1.0f}, // bottom-right
}};
void applyToBox(CBox& box);
void applyToRegion(CRegion& rg);
float combinedScale();
inline const float fanVertsFull[] = {-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f};
bool enabled = true;
};
enum eMonitorRenderFBs : uint8_t {
FB_MONITOR_RENDER_MAIN = 0,
FB_MONITOR_RENDER_CURRENT = 1,
FB_MONITOR_RENDER_OUT = 2,
};
enum eMonitorExtraRenderFBs : uint8_t {
FB_MONITOR_RENDER_EXTRA_OFFLOAD = 0,
FB_MONITOR_RENDER_EXTRA_MIRROR,
FB_MONITOR_RENDER_EXTRA_MIRROR_SWAP,
FB_MONITOR_RENDER_EXTRA_OFF_MAIN,
FB_MONITOR_RENDER_EXTRA_MONITOR_MIRROR,
FB_MONITOR_RENDER_EXTRA_BLUR,
};
struct SFragShaderDesc {
Render::ePreparedFragmentShader id;
const char* file;
};
struct SPreparedShaders {
// SPreparedShaders() {
// for (auto& f : frag) {
// f = makeShared<CShader>();
// }
// }
std::string TEXVERTSRC;
std::string TEXVERTSRC320;
// std::array<SP<CShader>, SH_FRAG_LAST> frag;
// std::map<uint8_t, SP<CShader>> fragVariants;
std::array<std::map<Render::ShaderFeatureFlags, SP<CShader>>, Render::SH_FRAG_LAST> fragVariants;
};
struct SCurrentRenderData {
PHLMONITORREF pMonitor;
Mat3x3 projection;
Mat3x3 savedProjection;
Mat3x3 monitorProjection;
SP<IFramebuffer> currentFB = nullptr; // current rendering to
SP<IFramebuffer> mainFB = nullptr; // main to render to
SP<IFramebuffer> outFB = nullptr; // out to render to (if offloaded, etc)
CRegion damage;
CRegion finalDamage; // damage used for funal off -> main
SRenderModifData renderModif;
float mouseZoomFactor = 1.f;
bool mouseZoomUseMouse = true; // true by default
bool useNearestNeighbor = false;
bool blockScreenShader = false;
bool simplePass = false;
bool transformDamage = true;
bool noSimplify = false;
Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1);
Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
CBox clipBox = {}; // scaled coordinates
CRegion clipRegion;
uint32_t discardMode = DISCARD_OPAQUE;
float discardOpacity = 0.f;
PHLLSREF currentLS;
PHLWINDOWREF currentWindow;
WP<CWLSurfaceResource> surface;
};
class CEGLSync {
public:
static UP<CEGLSync> create();
~CEGLSync();
Hyprutils::OS::CFileDescriptor& fd();
Hyprutils::OS::CFileDescriptor&& takeFd();
bool isValid();
private:
CEGLSync() = default;
Hyprutils::OS::CFileDescriptor m_fd;
EGLSyncKHR m_sync = EGL_NO_SYNC_KHR;
bool m_valid = false;
friend class CHyprOpenGLImpl;
};
class CHyprOpenGLImpl {
public:
CHyprOpenGLImpl();
~CHyprOpenGLImpl();
struct SRectRenderData {
const CRegion* damage = nullptr;
int round = 0;
float roundingPower = 2.F;
bool blur = false;
float blurA = 1.F;
bool xray = false;
enum eMonitorRenderFBs : uint8_t {
FB_MONITOR_RENDER_MAIN = 0,
FB_MONITOR_RENDER_CURRENT = 1,
FB_MONITOR_RENDER_OUT = 2,
};
struct STextureRenderData {
bool blur = false;
float blurA = 1.F, overallA = 1.F;
bool blockBlurOptimization = false;
SP<ITexture> blurredBG;
const CRegion* damage = nullptr;
SP<CWLSurfaceResource> surface = nullptr;
float a = 1.F;
int round = 0;
float roundingPower = 2.F;
bool discardActive = false;
bool allowCustomUV = false;
bool allowDim = true;
bool noAA = false; // unused
GLenum wrapX = GL_CLAMP_TO_EDGE, wrapY = GL_CLAMP_TO_EDGE;
bool cmBackToSRGB = false;
bool finalMonitorCM = false;
SP<CMonitor> cmBackToSRGBSource;
uint32_t discardMode = DISCARD_OPAQUE;
float discardOpacity = 0.f;
CRegion clipRegion;
PHLLSREF currentLS;
Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1);
Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
enum eMonitorExtraRenderFBs : uint8_t {
FB_MONITOR_RENDER_EXTRA_OFFLOAD = 0,
FB_MONITOR_RENDER_EXTRA_MIRROR,
FB_MONITOR_RENDER_EXTRA_MIRROR_SWAP,
FB_MONITOR_RENDER_EXTRA_OFF_MAIN,
FB_MONITOR_RENDER_EXTRA_MONITOR_MIRROR,
FB_MONITOR_RENDER_EXTRA_BLUR,
};
struct SBorderRenderData {
int round = 0;
float roundingPower = 2.F;
int borderSize = 1;
float a = 1.0;
int outerRound = -1; /* use round */
struct SFragShaderDesc {
Render::ePreparedFragmentShader id;
const char* file;
};
void makeEGLCurrent();
void begin(PHLMONITOR, const CRegion& damage, SP<IFramebuffer> fb = nullptr, std::optional<CRegion> finalDamage = {});
void beginSimple(PHLMONITOR, const CRegion& damage, SP<IRenderbuffer> rb = nullptr, SP<IFramebuffer> fb = nullptr);
void end();
struct SPreparedShaders {
// SPreparedShaders() {
// for (auto& f : frag) {
// f = makeShared<CShader>();
// }
// }
void renderRect(const CBox&, const CHyprColor&, SRectRenderData data);
void renderTexture(SP<ITexture>, const CBox&, STextureRenderData data);
void renderRoundedShadow(const CBox&, int round, float roundingPower, int range, const CHyprColor& color, float a = 1.0);
void renderBorder(const CBox&, const Config::CGradientValueData&, SBorderRenderData data);
void renderBorder(const CBox&, const Config::CGradientValueData&, const Config::CGradientValueData&, float lerp, SBorderRenderData data);
void renderTextureMatte(SP<ITexture> tex, const CBox& pBox, SP<IFramebuffer> matte);
void renderTexturePrimitive(SP<ITexture> tex, const CBox& box);
void setViewport(GLint x, GLint y, GLsizei width, GLsizei height);
void setCapStatus(int cap, bool status);
void blend(bool enabled);
void clear(const CHyprColor&);
void scissor(const CBox&, bool transform = true);
void scissor(const pixman_box32*, bool transform = true);
void scissor(const int x, const int y, const int w, const int h, bool transform = true);
void destroyMonitorResources(PHLMONITORREF);
void preRender(PHLMONITOR);
void saveBufferForMirror(const CBox&);
void applyScreenShader(const std::string& path);
void renderOffToMain(IFramebuffer* off);
std::vector<SDRMFormat> getDRMFormats();
std::vector<uint64_t> getDRMFormatModifiers(DRMFormat format);
EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs);
bool initShaders(const std::string& path = "");
WP<CShader> useShader(WP<CShader> prog);
bool explicitSyncSupported();
WP<CShader> getShaderVariant(Render::ePreparedFragmentShader frag, Render::ShaderFeatureFlags features = 0);
bool m_shadersInitialized = false;
SP<SPreparedShaders> m_shaders;
Hyprutils::OS::CFileDescriptor m_gbmFD;
gbm_device* m_gbmDevice = nullptr;
EGLContext m_eglContext = nullptr;
EGLDisplay m_eglDisplay = nullptr;
EGLDeviceEXT m_eglDevice = nullptr;
std::map<PHLMONITORREF, SP<IFramebuffer>> m_monitorBGFBs;
struct {
PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES = nullptr;
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = nullptr;
PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR = nullptr;
PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = nullptr;
PFNEGLQUERYDMABUFFORMATSEXTPROC eglQueryDmaBufFormatsEXT = nullptr;
PFNEGLQUERYDMABUFMODIFIERSEXTPROC eglQueryDmaBufModifiersEXT = nullptr;
PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = nullptr;
PFNEGLDEBUGMESSAGECONTROLKHRPROC eglDebugMessageControlKHR = nullptr;
PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT = nullptr;
PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT = nullptr;
PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT = nullptr;
PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR = nullptr;
PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR = nullptr;
PFNEGLDUPNATIVEFENCEFDANDROIDPROC eglDupNativeFenceFDANDROID = nullptr;
PFNEGLWAITSYNCKHRPROC eglWaitSyncKHR = nullptr;
} m_proc;
struct {
bool EXT_read_format_bgra = false;
bool EXT_image_dma_buf_import = false;
bool EXT_image_dma_buf_import_modifiers = false;
bool KHR_context_flush_control = false;
bool KHR_display_reference = false;
bool IMG_context_priority = false;
bool EXT_create_context_robustness = false;
bool EGL_ANDROID_native_fence_sync_ext = false;
} m_exts;
enum eEGLContextVersion : uint8_t {
EGL_CONTEXT_GLES_2_0 = 0,
EGL_CONTEXT_GLES_3_0,
EGL_CONTEXT_GLES_3_2,
std::string TEXVERTSRC;
std::string TEXVERTSRC320;
// std::array<SP<CShader>, SH_FRAG_LAST> frag;
// std::map<uint8_t, SP<CShader>> fragVariants;
std::array<std::map<Render::ShaderFeatureFlags, SP<CShader>>, Render::SH_FRAG_LAST> fragVariants;
};
eEGLContextVersion m_eglContextVersion = EGL_CONTEXT_GLES_3_2;
struct SCurrentRenderData {
PHLMONITORREF pMonitor;
Mat3x3 projection;
Mat3x3 savedProjection;
Mat3x3 monitorProjection;
enum eCachedCapStatus : uint8_t {
CAP_STATUS_BLEND = 0,
CAP_STATUS_SCISSOR_TEST,
CAP_STATUS_STENCIL_TEST,
CAP_STATUS_END
SP<IFramebuffer> currentFB = nullptr; // current rendering to
SP<IFramebuffer> mainFB = nullptr; // main to render to
SP<IFramebuffer> outFB = nullptr; // out to render to (if offloaded, etc)
CRegion damage;
CRegion finalDamage; // damage used for funal off -> main
Render::SRenderModifData renderModif;
float mouseZoomFactor = 1.f;
bool mouseZoomUseMouse = true; // true by default
bool useNearestNeighbor = false;
bool blockScreenShader = false;
bool simplePass = false;
bool transformDamage = true;
bool noSimplify = false;
Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1);
Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
CBox clipBox = {}; // scaled coordinates
CRegion clipRegion;
uint32_t discardMode = DISCARD_OPAQUE;
float discardOpacity = 0.f;
PHLLSREF currentLS;
PHLWINDOWREF currentWindow;
WP<CWLSurfaceResource> surface;
};
private:
struct {
GLint x = 0;
GLint y = 0;
GLsizei width = 0;
GLsizei height = 0;
} m_lastViewport;
class CEGLSync {
public:
static UP<CEGLSync> create();
std::array<bool, CAP_STATUS_END> m_capStatus = {};
~CEGLSync();
std::vector<SDRMFormat> m_drmFormats;
bool m_hasModifiers = false;
Hyprutils::OS::CFileDescriptor& fd();
Hyprutils::OS::CFileDescriptor&& takeFd();
bool isValid();
int m_drmFD = -1;
std::string m_extensions;
private:
CEGLSync() = default;
bool m_fakeFrame = false;
bool m_applyFinalShader = false;
bool m_blend = false;
bool m_offloadedFramebuffer = false;
bool m_cmSupported = true;
Hyprutils::OS::CFileDescriptor m_fd;
EGLSyncKHR m_sync = EGL_NO_SYNC_KHR;
bool m_valid = false;
SP<CShader> m_finalScreenShader;
GLuint m_currentProgram;
friend class CHyprOpenGLImpl;
};
void initDRMFormats();
void initEGL(bool gbm);
EGLDeviceEXT eglDeviceFromDRMFD(int drmFD);
class CHyprOpenGLImpl {
public:
CHyprOpenGLImpl();
~CHyprOpenGLImpl();
// for the final shader
std::array<CTimer, POINTER_PRESSED_HISTORY_LENGTH> m_pressedHistoryTimers = {};
std::array<Vector2D, POINTER_PRESSED_HISTORY_LENGTH> m_pressedHistoryPositions = {};
GLint m_pressedHistoryKilled = 0;
GLint m_pressedHistoryTouched = 0;
struct SRectRenderData {
const CRegion* damage = nullptr;
int round = 0;
float roundingPower = 2.F;
bool blur = false;
float blurA = 1.F;
bool xray = false;
};
//
std::optional<std::vector<uint64_t>> getModsForFormat(EGLint format);
struct STextureRenderData {
bool blur = false;
float blurA = 1.F, overallA = 1.F;
bool blockBlurOptimization = false;
SP<ITexture> blurredBG;
// returns the out FB, can be either Mirror or MirrorSwap
SP<IFramebuffer> blurFramebufferWithDamage(float a, CRegion* damage, CGLFramebuffer& source);
const CRegion* damage = nullptr;
SP<CWLSurfaceResource> surface = nullptr;
float a = 1.F;
int round = 0;
float roundingPower = 2.F;
bool discardActive = false;
bool allowCustomUV = false;
bool allowDim = true;
bool noAA = false; // unused
GLenum wrapX = GL_CLAMP_TO_EDGE, wrapY = GL_CLAMP_TO_EDGE;
bool cmBackToSRGB = false;
bool finalMonitorCM = false;
SP<CMonitor> cmBackToSRGBSource;
void passCMUniforms(WP<CShader>, const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1);
void passCMUniforms(WP<CShader>, const NColorManagement::PImageDescription imageDescription);
void renderRectInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
void renderRectWithBlurInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
void renderRectWithDamageInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
WP<CShader> renderToOutputInternal();
WP<CShader> renderToFBInternal(const STextureRenderData& data, eTextureType texType, const CBox& newBox);
void renderTextureInternal(SP<ITexture>, const CBox&, const STextureRenderData& data);
void renderTextureWithBlurInternal(SP<ITexture>, const CBox&, const STextureRenderData& data);
uint32_t discardMode = DISCARD_OPAQUE;
float discardOpacity = 0.f;
friend class IHyprRenderer;
friend class CHyprGLRenderer;
friend class CTexPassElement;
friend class CPreBlurElement;
friend class CSurfacePassElement;
};
CRegion clipRegion;
PHLLSREF currentLS;
inline UP<CHyprOpenGLImpl> g_pHyprOpenGL;
Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1);
Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
};
struct SBorderRenderData {
int round = 0;
float roundingPower = 2.F;
int borderSize = 1;
float a = 1.0;
int outerRound = -1; /* use round */
};
void makeEGLCurrent();
void begin(PHLMONITOR, const CRegion& damage, SP<IFramebuffer> fb = nullptr, std::optional<CRegion> finalDamage = {});
void beginSimple(PHLMONITOR, const CRegion& damage, SP<IRenderbuffer> rb = nullptr, SP<IFramebuffer> fb = nullptr);
void end();
void renderRect(const CBox&, const CHyprColor&, SRectRenderData data);
void renderTexture(SP<ITexture>, const CBox&, STextureRenderData data);
void renderRoundedShadow(const CBox&, int round, float roundingPower, int range, const CHyprColor& color, float a = 1.0);
void renderBorder(const CBox&, const CGradientValueData&, SBorderRenderData data);
void renderBorder(const CBox&, const CGradientValueData&, const CGradientValueData&, float lerp, SBorderRenderData data);
void renderTextureMatte(SP<ITexture> tex, const CBox& pBox, SP<IFramebuffer> matte);
void renderTexturePrimitive(SP<ITexture> tex, const CBox& box);
void setViewport(GLint x, GLint y, GLsizei width, GLsizei height);
void setCapStatus(int cap, bool status);
void blend(bool enabled);
void scissor(const CBox&, bool transform = true);
void scissor(const pixman_box32*, bool transform = true);
void scissor(const int x, const int y, const int w, const int h, bool transform = true);
void destroyMonitorResources(PHLMONITORREF);
void preRender(PHLMONITOR);
void saveBufferForMirror(const CBox&);
void applyScreenShader(const std::string& path);
void renderOffToMain(IFramebuffer* off);
std::vector<SDRMFormat> getDRMFormats();
std::vector<uint64_t> getDRMFormatModifiers(DRMFormat format);
EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs);
bool initShaders(const std::string& path = "");
WP<CShader> useShader(WP<CShader> prog);
bool explicitSyncSupported();
WP<CShader> getShaderVariant(Render::ePreparedFragmentShader frag, Render::ShaderFeatureFlags features = 0);
bool m_shadersInitialized = false;
SP<SPreparedShaders> m_shaders;
Hyprutils::OS::CFileDescriptor m_gbmFD;
gbm_device* m_gbmDevice = nullptr;
EGLContext m_eglContext = nullptr;
EGLDisplay m_eglDisplay = nullptr;
EGLDeviceEXT m_eglDevice = nullptr;
std::map<PHLMONITORREF, SP<IFramebuffer>> m_monitorBGFBs;
struct {
PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES = nullptr;
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = nullptr;
PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR = nullptr;
PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = nullptr;
PFNEGLQUERYDMABUFFORMATSEXTPROC eglQueryDmaBufFormatsEXT = nullptr;
PFNEGLQUERYDMABUFMODIFIERSEXTPROC eglQueryDmaBufModifiersEXT = nullptr;
PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = nullptr;
PFNEGLDEBUGMESSAGECONTROLKHRPROC eglDebugMessageControlKHR = nullptr;
PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT = nullptr;
PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT = nullptr;
PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT = nullptr;
PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR = nullptr;
PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR = nullptr;
PFNEGLDUPNATIVEFENCEFDANDROIDPROC eglDupNativeFenceFDANDROID = nullptr;
PFNEGLWAITSYNCKHRPROC eglWaitSyncKHR = nullptr;
} m_proc;
struct {
bool EXT_read_format_bgra = false;
bool EXT_image_dma_buf_import = false;
bool EXT_image_dma_buf_import_modifiers = false;
bool KHR_context_flush_control = false;
bool KHR_display_reference = false;
bool IMG_context_priority = false;
bool EXT_create_context_robustness = false;
bool EGL_ANDROID_native_fence_sync_ext = false;
} m_exts;
enum eEGLContextVersion : uint8_t {
EGL_CONTEXT_GLES_2_0 = 0,
EGL_CONTEXT_GLES_3_0,
EGL_CONTEXT_GLES_3_2,
};
eEGLContextVersion m_eglContextVersion = EGL_CONTEXT_GLES_3_2;
enum eCachedCapStatus : uint8_t {
CAP_STATUS_BLEND = 0,
CAP_STATUS_SCISSOR_TEST,
CAP_STATUS_STENCIL_TEST,
CAP_STATUS_END
};
private:
struct {
GLint x = 0;
GLint y = 0;
GLsizei width = 0;
GLsizei height = 0;
} m_lastViewport;
std::array<bool, CAP_STATUS_END> m_capStatus = {};
std::vector<SDRMFormat> m_drmFormats;
bool m_hasModifiers = false;
int m_drmFD = -1;
std::string m_extensions;
bool m_fakeFrame = false;
bool m_applyFinalShader = false;
bool m_blend = false;
bool m_offloadedFramebuffer = false;
bool m_cmSupported = true;
SP<CShader> m_finalScreenShader;
GLuint m_currentProgram;
void initDRMFormats();
void initEGL(bool gbm);
EGLDeviceEXT eglDeviceFromDRMFD(int drmFD);
// for the final shader
std::array<CTimer, POINTER_PRESSED_HISTORY_LENGTH> m_pressedHistoryTimers = {};
std::array<Vector2D, POINTER_PRESSED_HISTORY_LENGTH> m_pressedHistoryPositions = {};
GLint m_pressedHistoryKilled = 0;
GLint m_pressedHistoryTouched = 0;
//
std::optional<std::vector<uint64_t>> getModsForFormat(EGLint format);
// returns the out FB, can be either Mirror or MirrorSwap
SP<IFramebuffer> blurFramebufferWithDamage(float a, CRegion* damage, CGLFramebuffer& source);
void passCMUniforms(WP<CShader>, const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1);
void passCMUniforms(WP<CShader>, const NColorManagement::PImageDescription imageDescription);
void renderRectInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
void renderRectWithBlurInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
void renderRectWithDamageInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
WP<CShader> renderToOutputInternal();
WP<CShader> renderToFBInternal(const STextureRenderData& data, eTextureType texType, const CBox& newBox);
void renderTextureInternal(SP<ITexture>, const CBox&, const STextureRenderData& data);
void renderTextureWithBlurInternal(SP<ITexture>, const CBox&, const STextureRenderData& data);
friend class IHyprRenderer;
friend class CHyprGLRenderer;
friend class CGLElementRenderer;
friend class CTexPassElement;
friend class CPreBlurElement;
friend class CSurfacePassElement;
};
inline UP<CHyprOpenGLImpl> g_pHyprOpenGL;
}

View file

@ -47,11 +47,11 @@
#include "../protocols/types/ContentType.hpp"
#include "../helpers/MiscFunctions.hpp"
#include "AsyncResourceGatherer.hpp"
#include "ElementRenderer.hpp"
#include "Framebuffer.hpp"
#include "OpenGL.hpp"
#include "Texture.hpp"
#include "pass/BorderPassElement.hpp"
#include "pass/PreBlurElement.hpp"
#include "./pass/PreBlurElement.hpp"
#include <hyprutils/math/Mat3x3.hpp>
#include <hyprutils/math/Region.hpp>
#include <hyprutils/math/Vector2D.hpp>
@ -65,6 +65,7 @@ using namespace Hyprutils::Utils;
using namespace Hyprutils::OS;
using enum NContentType::eContentType;
using namespace NColorManagement;
using namespace Render;
extern "C" {
#include <xf86drm.h>
@ -212,8 +213,8 @@ IHyprRenderer::~IHyprRenderer() {
wl_event_source_remove(m_cursorTicker);
}
WP<CHyprOpenGLImpl> IHyprRenderer::glBackend() {
return g_pHyprOpenGL;
WP<Render::GL::CHyprOpenGLImpl> IHyprRenderer::glBackend() {
return Render::GL::g_pHyprOpenGL;
}
bool IHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor) {
@ -502,7 +503,7 @@ void IHyprRenderer::bindOffMain() {
RASSERT(m_renderData.pMonitor->m_offMainFB->isAllocated(), "IHyprRenderer::beginRender should allocate monitor FBs")
m_renderData.pMonitor->m_offMainFB->bind();
draw(makeUnique<CClearPassElement>(CClearPassElement::SClearData{{0, 0, 0, 0}}), {});
draw(makeShared<CClearPassElement>(CClearPassElement::SClearData{{0, 0, 0, 0}}), {});
m_renderData.currentFB = m_renderData.pMonitor->m_offMainFB;
}
@ -769,347 +770,12 @@ void IHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, const T
m_renderData.currentWindow.reset();
}
void IHyprRenderer::drawRect(CRectPassElement* element, const CRegion& damage) {
auto& data = element->m_data;
if (data.box.w <= 0 || data.box.h <= 0)
return;
if (!data.clipBox.empty())
m_renderData.clipBox = data.clipBox;
data.modifiedBox = data.box;
m_renderData.renderModif.applyToBox(data.modifiedBox);
CBox transformedBox = data.box;
transformedBox.transform(Math::wlTransformToHyprutils(Math::invertTransform(m_renderData.pMonitor->m_transform)), m_renderData.pMonitor->m_transformedSize.x,
m_renderData.pMonitor->m_transformedSize.y);
data.TOPLEFT[0] = sc<float>(transformedBox.x);
data.TOPLEFT[1] = sc<float>(transformedBox.y);
data.FULLSIZE[0] = sc<float>(transformedBox.width);
data.FULLSIZE[1] = sc<float>(transformedBox.height);
data.drawRegion = data.color.a == 1.F || !data.blur ? damage : m_renderData.damage;
if (m_renderData.clipBox.width != 0 && m_renderData.clipBox.height != 0) {
CRegion damageClip{m_renderData.clipBox.x, m_renderData.clipBox.y, m_renderData.clipBox.width, m_renderData.clipBox.height};
data.drawRegion = damageClip.intersect(data.drawRegion);
}
draw(element, damage);
m_renderData.clipBox = {};
}
void IHyprRenderer::drawHints(CRendererHintsPassElement* element, const CRegion& damage) {
const auto m_data = element->m_data;
if (m_data.renderModif.has_value())
m_renderData.renderModif = *m_data.renderModif;
}
void IHyprRenderer::drawPreBlur(CPreBlurElement* element, const CRegion& damage) {
TRACY_GPU_ZONE("RenderPreBlurForCurrentMonitor");
const auto SAVEDRENDERMODIF = m_renderData.renderModif;
m_renderData.renderModif = {}; // fix shit
// make the fake dmg
CRegion fakeDamage{0, 0, m_renderData.pMonitor->m_transformedSize.x, m_renderData.pMonitor->m_transformedSize.y};
draw(element, fakeDamage);
m_renderData.pMonitor->m_blurFBDirty = false;
m_renderData.pMonitor->m_blurFBShouldRender = false;
m_renderData.renderModif = SAVEDRENDERMODIF;
}
void IHyprRenderer::drawSurface(CSurfacePassElement* element, const CRegion& damage) {
const auto m_data = element->m_data;
CScopeGuard x = {[]() {
g_pHyprRenderer->m_renderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
g_pHyprRenderer->m_renderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
}};
if (!m_data.texture)
return;
const auto& TEXTURE = m_data.texture;
// this is bad, probably has been logged elsewhere. Means the texture failed
// uploading to the GPU.
if (!TEXTURE->ok())
return;
const auto INTERACTIVERESIZEINPROGRESS = m_data.pWindow && g_layoutManager->dragController()->target() && g_layoutManager->dragController()->mode() == MBIND_RESIZE;
TRACY_GPU_ZONE("RenderSurface");
auto PSURFACE = Desktop::View::CWLSurface::fromResource(m_data.surface);
const float ALPHA = m_data.alpha * m_data.fadeAlpha * (PSURFACE ? PSURFACE->m_alphaModifier : 1.F);
const float OVERALL_ALPHA = PSURFACE ? PSURFACE->m_overallOpacity : 1.F;
const bool BLUR = m_data.blur && (!TEXTURE->m_opaque || ALPHA < 1.F || OVERALL_ALPHA < 1.F);
auto windowBox = element->getTexBox();
const auto PROJSIZEUNSCALED = windowBox.size();
windowBox.scale(m_data.pMonitor->m_scale);
windowBox.round();
if (windowBox.width <= 1 || windowBox.height <= 1) {
element->discard();
return;
}
const bool MISALIGNEDFSV1 = std::floor(m_data.pMonitor->m_scale) != m_data.pMonitor->m_scale /* Fractional */ && m_data.surface->m_current.scale == 1 /* fs protocol */ &&
windowBox.size() != m_data.surface->m_current.bufferSize /* misaligned */ && DELTALESSTHAN(windowBox.width, m_data.surface->m_current.bufferSize.x, 3) &&
DELTALESSTHAN(windowBox.height, m_data.surface->m_current.bufferSize.y, 3) /* off by one-or-two */ &&
(!m_data.pWindow || (!m_data.pWindow->m_realSize->isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */ &&
(!m_data.pLS || (!m_data.pLS->m_realSize->isBeingAnimated())); /* not LS or not animated */
calculateUVForSurface(m_data.pWindow, m_data.surface, m_data.pMonitor->m_self.lock(), m_data.mainSurface, windowBox.size(), PROJSIZEUNSCALED, MISALIGNEDFSV1);
auto cancelRender = false;
auto clipRegion = element->visibleRegion(cancelRender);
if (cancelRender)
return;
// check for fractional scale surfaces misaligning the buffer size
// in those cases it's better to just force nearest neighbor
// as long as the window is not animated. During those it'd look weird.
// UV will fixup it as well
if (MISALIGNEDFSV1)
m_renderData.useNearestNeighbor = true;
float rounding = m_data.rounding;
float roundingPower = m_data.roundingPower;
rounding -= 1; // to fix a border issue
if (m_data.dontRound) {
rounding = 0;
roundingPower = 2.0f;
}
const bool WINDOWOPAQUE = m_data.pWindow && m_data.pWindow->wlSurface()->resource() == m_data.surface ? m_data.pWindow->opaque() : false;
const bool CANDISABLEBLEND = ALPHA >= 1.f && OVERALL_ALPHA >= 1.f && rounding <= 0 && WINDOWOPAQUE;
if (CANDISABLEBLEND)
blend(false);
else
blend(true);
// FIXME: This is wrong and will bug the blur out as shit if the first surface
// is a subsurface that does NOT cover the entire frame. In such cases, we probably should fall back
// to what we do for misaligned surfaces (blur the entire thing and then render shit without blur)
if (m_data.surfaceCounter == 0 && !m_data.popup) {
if (BLUR)
draw(makeUnique<CTexPassElement>(CTexPassElement::SRenderData{
.tex = TEXTURE,
.box = windowBox,
.a = ALPHA,
.blurA = m_data.fadeAlpha,
.overallA = OVERALL_ALPHA,
.round = rounding,
.roundingPower = roundingPower,
.blur = true,
.blockBlurOptimization = m_data.blockBlurOptimization,
.allowCustomUV = true,
.surface = m_data.surface,
.discardMode = m_data.discardMode,
.discardOpacity = m_data.discardOpacity,
.clipRegion = clipRegion,
.currentLS = m_data.pLS,
}),
m_renderData.damage.copy().intersect(windowBox));
else
draw(makeUnique<CTexPassElement>(CTexPassElement::SRenderData{
.tex = TEXTURE,
.box = windowBox,
.a = ALPHA * OVERALL_ALPHA,
.round = rounding,
.roundingPower = roundingPower,
.discardActive = false,
.allowCustomUV = true,
.surface = m_data.surface,
.discardMode = m_data.discardMode,
.discardOpacity = m_data.discardOpacity,
.clipRegion = clipRegion,
.currentLS = m_data.pLS,
}),
m_renderData.damage.copy().intersect(windowBox));
} else {
if (BLUR && m_data.popup)
draw(makeUnique<CTexPassElement>(CTexPassElement::SRenderData{
.tex = TEXTURE,
.box = windowBox,
.a = ALPHA,
.blurA = m_data.fadeAlpha,
.overallA = OVERALL_ALPHA,
.round = rounding,
.roundingPower = roundingPower,
.blur = true,
.blockBlurOptimization = true,
.allowCustomUV = true,
.surface = m_data.surface,
.discardMode = m_data.discardMode,
.discardOpacity = m_data.discardOpacity,
.clipRegion = clipRegion,
.currentLS = m_data.pLS,
}),
m_renderData.damage.copy().intersect(windowBox));
else
draw(makeUnique<CTexPassElement>(CTexPassElement::SRenderData{
.tex = TEXTURE,
.box = windowBox,
.a = ALPHA * OVERALL_ALPHA,
.round = rounding,
.roundingPower = roundingPower,
.discardActive = false,
.allowCustomUV = true,
.surface = m_data.surface,
.discardMode = m_data.discardMode,
.discardOpacity = m_data.discardOpacity,
.clipRegion = clipRegion,
.currentLS = m_data.pLS,
}),
m_renderData.damage.copy().intersect(windowBox));
}
blend(true);
};
void IHyprRenderer::preDrawSurface(CSurfacePassElement* element, const CRegion& damage) {
m_renderData.clipBox = element->m_data.clipBox;
m_renderData.useNearestNeighbor = element->m_data.useNearestNeighbor;
pushMonitorTransformEnabled(element->m_data.flipEndFrame);
m_renderData.currentWindow = element->m_data.pWindow;
drawSurface(element, damage);
if (!m_bBlockSurfaceFeedback)
element->m_data.surface->presentFeedback(element->m_data.when, element->m_data.pMonitor->m_self.lock());
// add async (dmabuf) buffers to usedBuffers so we can handle release later
// sync (shm) buffers will be released in commitState, so no need to track them here
if (element->m_data.surface->m_current.buffer && !element->m_data.surface->m_current.buffer->isSynchronous())
m_usedAsyncBuffers.emplace_back(element->m_data.surface->m_current.buffer);
m_renderData.clipBox = {};
m_renderData.useNearestNeighbor = false;
popMonitorTransformEnabled();
m_renderData.currentWindow.reset();
}
void IHyprRenderer::drawTex(CTexPassElement* element, const CRegion& damage) {
if (!element->m_data.clipBox.empty())
m_renderData.clipBox = element->m_data.clipBox;
pushMonitorTransformEnabled(element->m_data.flipEndFrame);
if (element->m_data.useMirrorProjection)
setProjectionType(RPT_MIRROR);
m_renderData.surface = element->m_data.surface;
CScopeGuard x = {[useMirrorProjection = element->m_data.useMirrorProjection]() {
g_pHyprRenderer->popMonitorTransformEnabled();
if (useMirrorProjection)
g_pHyprRenderer->setProjectionType(RPT_MONITOR);
g_pHyprRenderer->m_renderData.surface.reset();
}};
if (element->m_data.blur) {
// make a damage region for this window
CRegion texDamage{m_renderData.damage};
texDamage.intersect(element->m_data.box.x, element->m_data.box.y, element->m_data.box.width, element->m_data.box.height);
// While renderTextureInternalWithDamage will clip the blur as well,
// clipping texDamage here allows blur generation to be optimized.
if (!element->m_data.clipRegion.empty())
texDamage.intersect(element->m_data.clipRegion);
if (texDamage.empty())
return;
m_renderData.renderModif.applyToRegion(texDamage);
element->m_data.damage = texDamage;
// amazing hack: the surface has an opaque region!
const auto& surface = element->m_data.surface;
const auto& box = element->m_data.box;
CRegion inverseOpaque;
if (element->m_data.a >= 1.f && surface && std::round(surface->m_current.size.x * m_renderData.pMonitor->m_scale) == box.w &&
std::round(surface->m_current.size.y * m_renderData.pMonitor->m_scale) == box.h) {
pixman_box32_t surfbox = {0, 0, surface->m_current.size.x * surface->m_current.scale, surface->m_current.size.y * surface->m_current.scale};
inverseOpaque = surface->m_current.opaque;
inverseOpaque.invert(&surfbox).intersect(0, 0, surface->m_current.size.x * surface->m_current.scale, surface->m_current.size.y * surface->m_current.scale);
if (inverseOpaque.empty()) {
element->m_data.blur = false;
draw(element, damage);
m_renderData.clipBox = {};
return;
}
} else
inverseOpaque = {0, 0, element->m_data.box.width, element->m_data.box.height};
inverseOpaque.scale(m_renderData.pMonitor->m_scale);
element->m_data.blockBlurOptimization =
element->m_data.blockBlurOptimization.value_or(false) || !shouldUseNewBlurOptimizations(element->m_data.currentLS.lock(), m_renderData.currentWindow.lock());
// vvv TODO: layered blur fbs?
if (element->m_data.blockBlurOptimization.value_or(false)) {
inverseOpaque.translate(box.pos());
m_renderData.renderModif.applyToRegion(inverseOpaque);
inverseOpaque.intersect(element->m_data.damage);
element->m_data.blurredBG = blurMainFramebuffer(element->m_data.a, &inverseOpaque);
m_renderData.currentFB->bind();
} else
element->m_data.blurredBG = m_renderData.pMonitor->m_blurFB ? m_renderData.pMonitor->m_blurFB->getTexture() : nullptr;
draw(element, damage);
} else
draw(element, damage);
m_renderData.clipBox = {};
}
void IHyprRenderer::drawTexMatte(CTextureMatteElement* element, const CRegion& damage) {
if (m_renderData.damage.empty())
return;
const auto m_data = element->m_data;
if (m_data.disableTransformAndModify) {
pushMonitorTransformEnabled(true);
m_renderData.renderModif.enabled = false;
draw(element, damage);
m_renderData.renderModif.enabled = true;
popMonitorTransformEnabled();
} else
draw(element, damage);
}
void IHyprRenderer::draw(WP<IPassElement> element, const CRegion& damage) {
ASSERT(element);
if (!element)
return;
switch (element->type()) {
case EK_BORDER: draw(dc<CBorderPassElement*>(element.get()), damage); break;
case EK_CLEAR: draw(dc<CClearPassElement*>(element.get()), damage); break;
case EK_FRAMEBUFFER: draw(dc<CFramebufferElement*>(element.get()), damage); break;
case EK_PRE_BLUR: drawPreBlur(dc<CPreBlurElement*>(element.get()), damage); break;
case EK_RECT: drawRect(dc<CRectPassElement*>(element.get()), damage); break;
case EK_HINTS: drawHints(dc<CRendererHintsPassElement*>(element.get()), damage); break;
case EK_SHADOW: draw(dc<CShadowPassElement*>(element.get()), damage); break;
case EK_SURFACE: preDrawSurface(dc<CSurfacePassElement*>(element.get()), damage); break;
case EK_TEXTURE: drawTex(dc<CTexPassElement*>(element.get()), damage); break;
case EK_TEXTURE_MATTE: drawTexMatte(dc<CTextureMatteElement*>(element.get()), damage); break;
default: Log::logger->log(Log::WARN, "Unimplimented draw for {}", element->passName());
}
elementRenderer()->drawElement(element, damage);
}
bool IHyprRenderer::preBlurQueued(PHLMONITORREF pMonitor) {
@ -1892,126 +1558,6 @@ void IHyprRenderer::renderSessionLockMissing(PHLMONITOR pMonitor) {
}
}
static std::optional<Vector2D> getSurfaceExpectedSize(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface, PHLMONITOR pMonitor, bool main) {
const auto CAN_USE_WINDOW = pWindow && main;
const auto WINDOW_SIZE_MISALIGN = CAN_USE_WINDOW && pWindow->getReportedSize() != pWindow->wlSurface()->resource()->m_current.size;
if (pSurface->m_current.viewport.hasDestination)
return (pSurface->m_current.viewport.destination * pMonitor->m_scale).round();
if (pSurface->m_current.viewport.hasSource)
return (pSurface->m_current.viewport.source.size() * pMonitor->m_scale).round();
if (WINDOW_SIZE_MISALIGN)
return (pSurface->m_current.size * pMonitor->m_scale).round();
if (CAN_USE_WINDOW)
return (pWindow->getReportedSize() * pMonitor->m_scale).round();
return std::nullopt;
}
void IHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface, PHLMONITOR pMonitor, bool main, const Vector2D& projSize,
const Vector2D& projSizeUnscaled, bool fixMisalignedFSV1) {
if (!pWindow || !pWindow->m_isX11) {
static auto PEXPANDEDGES = CConfigValue<Hyprlang::INT>("render:expand_undersized_textures");
Vector2D uvTL;
Vector2D uvBR = Vector2D(1, 1);
if (pSurface->m_current.viewport.hasSource) {
// we stretch it to dest. if no dest, to 1,1
Vector2D const& bufferSize = pSurface->m_current.bufferSize;
auto const& bufferSource = pSurface->m_current.viewport.source;
// calculate UV for the basic src_box. Assume dest == size. Scale to dest later
uvTL = Vector2D(bufferSource.x / bufferSize.x, bufferSource.y / bufferSize.y);
uvBR = Vector2D((bufferSource.x + bufferSource.width) / bufferSize.x, (bufferSource.y + bufferSource.height) / bufferSize.y);
if (uvBR.x < 0.01f || uvBR.y < 0.01f) {
uvTL = Vector2D();
uvBR = Vector2D(1, 1);
}
}
if (projSize != Vector2D{} && fixMisalignedFSV1) {
// instead of nearest_neighbor (we will repeat / skip)
// just cut off / expand surface
const Vector2D PIXELASUV = Vector2D{1, 1} / pSurface->m_current.bufferSize;
const auto& BUFFER_SIZE = pSurface->m_current.bufferSize;
// compute MISALIGN from the adjusted UV coordinates.
const Vector2D MISALIGNMENT = (uvBR - uvTL) * BUFFER_SIZE - projSize;
if (MISALIGNMENT != Vector2D{})
uvBR -= MISALIGNMENT * PIXELASUV;
} else {
// if the surface is smaller than our viewport, extend its edges.
// this will break if later on xdg geometry is hit, but we really try
// to let the apps know to NOT add CSD. Also if source is there.
// there is no way to fix this if that's the case
const auto MONITOR_WL_SCALE = std::ceil(pMonitor->m_scale);
const bool SCALE_UNAWARE = pMonitor->m_scale != 1.f && (MONITOR_WL_SCALE == pSurface->m_current.scale || !pSurface->m_current.viewport.hasDestination);
const auto EXPECTED_SIZE = getSurfaceExpectedSize(pWindow, pSurface, pMonitor, main).value_or((projSize * pMonitor->m_scale).round());
const auto RATIO = projSize / EXPECTED_SIZE;
if (!SCALE_UNAWARE || MONITOR_WL_SCALE == 1) {
if (*PEXPANDEDGES && !SCALE_UNAWARE && (RATIO.x > 1 || RATIO.y > 1)) {
const auto FIX = RATIO.clamp(Vector2D{1, 1}, Vector2D{1000000, 1000000});
uvBR = uvBR * FIX;
}
// FIXME: probably do this for in anims on all views...
const auto SHOULD_SKIP = !pWindow || pWindow->m_animatingIn;
if (!SHOULD_SKIP && (RATIO.x < 1 || RATIO.y < 1)) {
const auto FIX = RATIO.clamp(Vector2D{0.0001, 0.0001}, Vector2D{1, 1});
uvBR = uvBR * FIX;
}
}
}
m_renderData.primarySurfaceUVTopLeft = uvTL;
m_renderData.primarySurfaceUVBottomRight = uvBR;
if (m_renderData.primarySurfaceUVTopLeft == Vector2D() && m_renderData.primarySurfaceUVBottomRight == Vector2D(1, 1)) {
// No special UV mods needed
m_renderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
m_renderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
}
if (!main || !pWindow)
return;
// FIXME: this doesn't work. We always set MAXIMIZED anyways, so this doesn't need to work, but it's problematic.
// CBox geom = pWindow->m_xdgSurface->m_current.geometry;
// // Adjust UV based on the xdg_surface geometry
// if (geom.x != 0 || geom.y != 0 || geom.w != 0 || geom.h != 0) {
// const auto XPERC = geom.x / pSurface->m_current.size.x;
// const auto YPERC = geom.y / pSurface->m_current.size.y;
// const auto WPERC = (geom.x + geom.w ? geom.w : pSurface->m_current.size.x) / pSurface->m_current.size.x;
// const auto HPERC = (geom.y + geom.h ? geom.h : pSurface->m_current.size.y) / pSurface->m_current.size.y;
// const auto TOADDTL = Vector2D(XPERC * (uvBR.x - uvTL.x), YPERC * (uvBR.y - uvTL.y));
// uvBR = uvBR - Vector2D((1.0 - WPERC) * (uvBR.x - uvTL.x), (1.0 - HPERC) * (uvBR.y - uvTL.y));
// uvTL = uvTL + TOADDTL;
// }
m_renderData.primarySurfaceUVTopLeft = uvTL;
m_renderData.primarySurfaceUVBottomRight = uvBR;
if (m_renderData.primarySurfaceUVTopLeft == Vector2D() && m_renderData.primarySurfaceUVBottomRight == Vector2D(1, 1)) {
// No special UV mods needed
m_renderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
m_renderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
}
} else {
m_renderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
m_renderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
}
}
bool IHyprRenderer::beginRender(PHLMONITOR pMonitor, CRegion& damage, eRenderMode mode, SP<IHLBuffer> buffer, SP<IFramebuffer> fb, bool simple) {
m_renderPass.clear();
m_renderMode = mode;
@ -2165,11 +1711,11 @@ void IHyprRenderer::preBlurForCurrentMonitor(CRegion* fakeDamage) {
m_renderData.pMonitor->m_blurFB->alloc(m_renderData.pMonitor->m_pixelSize.x, m_renderData.pMonitor->m_pixelSize.y, m_renderData.pMonitor->m_output->state->state().drmFormat);
m_renderData.pMonitor->m_blurFB->bind();
draw(makeUnique<CClearPassElement>(CClearPassElement::SClearData{{0, 0, 0, 0}}), {});
draw(makeShared<CClearPassElement>(CClearPassElement::SClearData{{0, 0, 0, 0}}), {});
pushMonitorTransformEnabled(true);
draw(makeUnique<CTexPassElement>(CTexPassElement::SRenderData{
draw(makeShared<CTexPassElement>(CTexPassElement::SRenderData{
.tex = blurredTex,
.box = CBox{0, 0, m_renderData.pMonitor->m_transformedSize.x, m_renderData.pMonitor->m_transformedSize.y},
.damage = *fakeDamage,
@ -3351,7 +2897,7 @@ void IHyprRenderer::makeSnapshot(PHLWINDOW pWindow) {
m_bRenderingSnapshot = true;
draw(makeUnique<CClearPassElement>(CClearPassElement::SClearData{CHyprColor(0, 0, 0, 0)}), {});
draw(makeShared<CClearPassElement>(CClearPassElement::SClearData{CHyprColor(0, 0, 0, 0)}), {});
startRenderPass();
Log::logger->log(Log::DEBUG, "renderer: cleared a snapshot of {:x}", rc<uintptr_t>(pWindow.get()));
@ -3392,7 +2938,7 @@ void IHyprRenderer::makeSnapshot(PHLLS pLayer) {
m_bRenderingSnapshot = true;
draw(makeUnique<CClearPassElement>(CClearPassElement::SClearData{CHyprColor(0, 0, 0, 0)}), {});
draw(makeShared<CClearPassElement>(CClearPassElement::SClearData{CHyprColor(0, 0, 0, 0)}), {});
startRenderPass();
Log::logger->log(Log::DEBUG, "renderer: cleared a snapshot of layer {:x}", rc<uintptr_t>(pLayer.get()));
@ -3434,7 +2980,7 @@ void IHyprRenderer::makeSnapshot(WP<Desktop::View::CPopup> popup) {
m_bRenderingSnapshot = true;
draw(makeUnique<CClearPassElement>(CClearPassElement::SClearData{CHyprColor(0, 0, 0, 0)}), {});
draw(makeShared<CClearPassElement>(CClearPassElement::SClearData{CHyprColor(0, 0, 0, 0)}), {});
CSurfacePassElement::SRenderData renderdata;
renderdata.pos = popup->coordsGlobal();

View file

@ -5,6 +5,8 @@
#include <hyprutils/math/Box.hpp>
#include <list>
#include <optional>
#include "OpenGL.hpp"
#include "types.hpp"
#include "../helpers/Monitor.hpp"
#include "../desktop/view/LayerSurface.hpp"
#include "./pass/Pass.hpp"
@ -13,19 +15,12 @@
#include "../helpers/math/Math.hpp"
#include "../helpers/time/Time.hpp"
#include "../../protocols/cursor-shape-v1.hpp"
#include "../desktop/view/Popup.hpp"
#include "desktop/view/Popup.hpp"
#include "Framebuffer.hpp"
#include "Texture.hpp"
#include "pass/BorderPassElement.hpp"
#include "pass/ClearPassElement.hpp"
#include "pass/FramebufferElement.hpp"
#include "pass/PreBlurElement.hpp"
#include "pass/RectPassElement.hpp"
#include "pass/RendererHintsPassElement.hpp"
#include "pass/ShadowPassElement.hpp"
#include "pass/SurfacePassElement.hpp"
#include "pass/TexPassElement.hpp"
#include "pass/TextureMatteElement.hpp"
#include "./pass/SurfacePassElement.hpp"
#include "./pass/TexPassElement.hpp"
#include "./pass/TextureMatteElement.hpp"
struct SMonitorRule;
class CWorkspace;
@ -33,14 +28,6 @@ class CInputPopup;
class IHLBuffer;
class CEventLoopTimer;
class CRenderPass;
const std::vector<const char*> ASSET_PATHS = {
#ifdef DATAROOTDIR
DATAROOTDIR,
#endif
"/usr/share",
"/usr/local/share",
};
class CToplevelExportProtocolManager;
class CInputManager;
struct SSessionLockSurface;
@ -48,329 +35,229 @@ namespace Screenshare {
class CScreenshareFrame;
};
enum eDamageTrackingModes : int8_t {
DAMAGE_TRACKING_INVALID = -1,
DAMAGE_TRACKING_NONE = 0,
DAMAGE_TRACKING_MONITOR,
DAMAGE_TRACKING_FULL,
};
namespace Render {
class IElementRenderer;
enum eRenderPassMode : uint8_t {
RENDER_PASS_ALL = 0,
RENDER_PASS_MAIN,
RENDER_PASS_POPUP
};
class IHyprRenderer {
public:
IHyprRenderer();
virtual ~IHyprRenderer();
enum eRenderMode : uint8_t {
RENDER_MODE_NORMAL = 0,
RENDER_MODE_FULL_FAKE = 1,
RENDER_MODE_TO_BUFFER = 2,
RENDER_MODE_TO_BUFFER_READ_ONLY = 3,
};
WP<Render::GL::CHyprOpenGLImpl> glBackend();
struct SRenderWorkspaceUntilData {
PHLLS ls;
PHLWINDOW w;
};
void renderMonitor(PHLMONITOR pMonitor, bool commit = true);
void arrangeLayersForMonitor(const MONITORID&);
void damageSurface(SP<CWLSurfaceResource>, double, double, double scale = 1.0);
void damageWindow(PHLWINDOW, bool forceFull = false);
void damageBox(const CBox&, bool skipFrameSchedule = false);
void damageBox(const int& x, const int& y, const int& w, const int& h);
void damageRegion(const CRegion&);
void damageMonitor(PHLMONITOR);
void damageMirrorsWith(PHLMONITOR, const CRegion&);
bool shouldRenderWindow(PHLWINDOW, PHLMONITOR);
bool shouldRenderWindow(PHLWINDOW);
void ensureCursorRenderingMode();
bool shouldRenderCursor();
void setCursorHidden(bool hide);
enum eRenderProjectionType : uint8_t {
RPT_MONITOR,
RPT_MIRROR,
RPT_FB,
RPT_EXPORT,
};
std::tuple<float, float, float> getRenderTimes(PHLMONITOR pMonitor); // avg max min
void ensureLockTexturesRendered(bool load);
void renderLockscreen(PHLMONITOR pMonitor, const Time::steady_tp& now, const CBox& geometry);
void setCursorSurface(SP<Desktop::View::CWLSurface> surf, int hotspotX, int hotspotY, bool force = false);
void setCursorFromName(const std::string& name, bool force = false);
void onRenderbufferDestroy(IRenderbuffer* rb);
bool isNvidia();
bool isIntel();
bool isSoftware();
bool isMgpu();
void addWindowToRenderUnfocused(PHLWINDOW window);
void makeSnapshot(PHLWINDOW);
void makeSnapshot(PHLLS);
void makeSnapshot(WP<Desktop::View::CPopup>);
void renderSnapshot(PHLWINDOW);
void renderSnapshot(PHLLS);
void renderSnapshot(WP<Desktop::View::CPopup>);
bool beginFullFakeRender(PHLMONITOR pMonitor, CRegion& damage, SP<IFramebuffer> fb);
bool beginRenderToBuffer(PHLMONITOR pMonitor, CRegion& damage, SP<IHLBuffer> buffer, bool simple = false);
virtual void startRenderPass() {};
virtual void endRender(const std::function<void()>& renderingDoneCallback = {}) = 0;
struct SRenderData {
// can be private
Mat3x3 targetProjection;
NColorManagement::PImageDescription workBufferImageDescription();
bool m_bBlockSurfaceFeedback = false;
bool m_bRenderingSnapshot = false;
PHLMONITORREF m_mostHzMonitor;
bool m_directScanoutBlocked = false;
// ----------------------
void setSurfaceScanoutMode(SP<CWLSurfaceResource> surface, PHLMONITOR monitor); // nullptr monitor resets
// used by public
Vector2D fbSize = {-1, -1};
PHLMONITORREF pMonitor;
void initiateManualCrash();
const SRenderData& renderData();
eRenderProjectionType projectionType = RPT_MONITOR;
bool m_crashingInProgress = false;
float m_crashingDistort = 0.5f;
wl_event_source* m_crashingLoop = nullptr;
wl_event_source* m_cursorTicker = nullptr;
SP<IFramebuffer> currentFB = nullptr; // current rendering to
SP<IFramebuffer> mainFB = nullptr; // main to render to
SP<IFramebuffer> outFB = nullptr; // out to render to (if offloaded, etc)
std::vector<CHLBufferReference> m_usedAsyncBuffers;
CRegion damage;
CRegion finalDamage; // damage used for funal off -> main
struct {
int hotspotX = 0;
int hotspotY = 0;
wpCursorShapeDeviceV1Shape shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT;
wpCursorShapeDeviceV1Shape shapePrevious = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT;
CTimer switchedTimer;
std::optional<SP<Desktop::View::CWLSurface>> surf;
std::string name;
} m_lastCursorData;
SRenderModifData renderModif;
float mouseZoomFactor = 1.f;
bool mouseZoomUseMouse = true; // true by default
bool useNearestNeighbor = false;
bool blockScreenShader = false;
CRenderPass m_renderPass;
Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1);
Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
SP<ITexture> renderSplash(const std::function<SP<ITexture>(const int, const int, unsigned char* const)>& handleData, const int fontSize, const int maxWidth = 1024,
const int maxHeight = 1024);
// TODO remove and pass directly
CBox clipBox = {}; // scaled coordinates
PHLWINDOWREF currentWindow;
WP<CWLSurfaceResource> surface;
virtual SP<IRenderbuffer> getOrCreateRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t fmt); // TODO? move to protected and fix CPointerManager::renderHWCursorBuffer
bool commitPendingAndDoExplicitSync(PHLMONITOR pMonitor); // TODO? move to protected and fix CMonitorFrameScheduler::onPresented
SRenderData m_renderData; // TODO? move to protected and fix CRenderPass
SP<ITexture> m_screencopyDeniedTexture; // TODO? make readonly
uint m_failedAssetsNo = 0; // TODO? make readonly
bool m_reloadScreenShader = true; // at launch it can be set
CTimer m_globalTimer;
bool transformDamage = true;
bool noSimplify = false;
};
void draw(WP<IPassElement> element, const CRegion& damage);
virtual WP<IElementRenderer> elementRenderer() = 0;
virtual SP<ITexture> createStencilTexture(const int width, const int height) = 0;
virtual SP<ITexture> createTexture(bool opaque = false) = 0;
virtual SP<ITexture> createTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false, bool opaque = false) = 0;
virtual SP<ITexture> createTexture(const Aquamarine::SDMABUFAttrs&, bool opaque = false) = 0;
virtual SP<ITexture> createTexture(const int width, const int height, unsigned char* const) = 0;
virtual SP<ITexture> createTexture(cairo_surface_t* cairo) = 0;
virtual SP<ITexture> createTexture(std::span<const float> lut3D, size_t N) = 0;
virtual SP<ITexture> createTexture(const SP<Aquamarine::IBuffer> buffer, bool keepDataCopy = false);
virtual SP<ITexture> renderText(const std::string& text, CHyprColor col, int pt, bool italic = false, const std::string& fontFamily = "", int maxWidth = 0,
int weight = 400);
SP<ITexture> loadAsset(const std::string& filename);
virtual bool shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindow);
virtual bool explicitSyncSupported() = 0;
virtual std::vector<SDRMFormat> getDRMFormats() = 0;
virtual std::vector<uint64_t> getDRMFormatModifiers(DRMFormat format) = 0;
virtual SP<IFramebuffer> createFB(const std::string& name = "") = 0;
virtual void disableScissor() = 0;
virtual void blend(bool enabled) = 0;
virtual void drawShadow(const CBox& box, int round, float roundingPower, int range, CHyprColor color, float a) = 0;
virtual void setViewport(int x, int y, int width, int height) = 0;
struct STFRange {
float min = 0;
float max = 80;
};
bool preBlurQueued(PHLMONITORREF pMonitor);
void pushMonitorTransformEnabled(bool enabled);
void popMonitorTransformEnabled();
bool monitorTransformEnabled();
struct SCMSettings {
NColorManagement::eTransferFunction sourceTF = NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22;
NColorManagement::eTransferFunction targetTF = NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22;
STFRange srcTFRange;
STFRange dstTFRange;
float srcRefLuminance = 80;
float dstRefLuminance = 80;
std::array<std::array<double, 3>, 3> convertMatrix;
void setProjectionType(const Vector2D& fbSize);
void setProjectionType(eRenderProjectionType projectionType);
Mat3x3 getBoxProjection(const CBox& box, std::optional<eTransform> transform = std::nullopt);
Mat3x3 projectBoxToTarget(const CBox& box, std::optional<eTransform> transform = std::nullopt);
bool needsTonemap = false;
float maxLuminance = 80;
float dstMaxLuminance = 80;
std::array<std::array<double, 3>, 3> dstPrimaries2XYZ;
bool needsSDRmod = false;
float sdrSaturation = 1.0;
float sdrBrightnessMultiplier = 1.0;
};
SP<ITexture> blurMainFramebuffer(float a, CRegion* originalDamage);
virtual SP<ITexture> blurFramebuffer(SP<IFramebuffer> source, float a, CRegion* originalDamage) = 0;
void preBlurForCurrentMonitor(CRegion* fakeDamage);
class IHyprRenderer {
public:
IHyprRenderer();
virtual ~IHyprRenderer();
SCMSettings getCMSettings(const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
SP<CWLSurfaceResource> surface = nullptr, bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1);
virtual bool reloadShaders(const std::string& path = "") = 0;
WP<CHyprOpenGLImpl> glBackend();
bool needsACopyFB(PHLMONITOR mon);
void renderMonitor(PHLMONITOR pMonitor, bool commit = true);
void arrangeLayersForMonitor(const MONITORID&);
void damageSurface(SP<CWLSurfaceResource>, double, double, double scale = 1.0);
void damageWindow(PHLWINDOW, bool forceFull = false);
void damageBox(const CBox&, bool skipFrameSchedule = false);
void damageBox(const int& x, const int& y, const int& w, const int& h);
void damageRegion(const CRegion&);
void damageMonitor(PHLMONITOR);
void damageMirrorsWith(PHLMONITOR, const CRegion&);
bool shouldRenderWindow(PHLWINDOW, PHLMONITOR);
bool shouldRenderWindow(PHLWINDOW);
void ensureCursorRenderingMode();
bool shouldRenderCursor();
void setCursorHidden(bool hide);
void calculateUVForSurface(PHLWINDOW, SP<CWLSurfaceResource>, PHLMONITOR pMonitor, bool main = false, const Vector2D& projSize = {}, const Vector2D& projSizeUnscaled = {},
bool fixMisalignedFSV1 = false);
std::tuple<float, float, float> getRenderTimes(PHLMONITOR pMonitor); // avg max min
void ensureLockTexturesRendered(bool load);
void renderLockscreen(PHLMONITOR pMonitor, const Time::steady_tp& now, const CBox& geometry);
void setCursorSurface(SP<Desktop::View::CWLSurface> surf, int hotspotX, int hotspotY, bool force = false);
void setCursorFromName(const std::string& name, bool force = false);
void onRenderbufferDestroy(IRenderbuffer* rb);
bool isNvidia();
bool isIntel();
bool isSoftware();
bool isMgpu();
void addWindowToRenderUnfocused(PHLWINDOW window);
void makeSnapshot(PHLWINDOW);
void makeSnapshot(PHLLS);
void makeSnapshot(WP<Desktop::View::CPopup>);
void renderSnapshot(PHLWINDOW);
void renderSnapshot(PHLLS);
void renderSnapshot(WP<Desktop::View::CPopup>);
bool beginFullFakeRender(PHLMONITOR pMonitor, CRegion& damage, SP<IFramebuffer> fb);
bool beginRenderToBuffer(PHLMONITOR pMonitor, CRegion& damage, SP<IHLBuffer> buffer, bool simple = false);
virtual void startRenderPass() {};
virtual void endRender(const std::function<void()>& renderingDoneCallback = {}) = 0;
protected:
virtual void renderOffToMain(IFramebuffer* off) = 0;
virtual SP<IRenderbuffer> getOrCreateRenderbufferInternal(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) = 0;
void renderMirrored();
void setDamage(const CRegion& damage_, std::optional<CRegion> finalDamage);
// if RENDER_MODE_NORMAL, provided damage will be written to.
// otherwise, it will be the one used.
bool beginRender(PHLMONITOR pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP<IHLBuffer> buffer = {}, SP<IFramebuffer> fb = nullptr,
bool simple = false);
NColorManagement::PImageDescription workBufferImageDescription();
bool m_bBlockSurfaceFeedback = false;
bool m_bRenderingSnapshot = false;
PHLMONITORREF m_mostHzMonitor;
bool m_directScanoutBlocked = false;
virtual bool beginRenderInternal(PHLMONITOR pMonitor, CRegion& damage, bool simple = false) {
return false;
};
virtual bool beginFullFakeRenderInternal(PHLMONITOR pMonitor, CRegion& damage, SP<IFramebuffer> fb, bool simple = false) {
return false;
};
virtual void initRender() {};
virtual bool initRenderBuffer(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) {
return false;
};
void setSurfaceScanoutMode(SP<CWLSurfaceResource> surface, PHLMONITOR monitor); // nullptr monitor resets
SP<ITexture> getBackground(PHLMONITOR pMonitor);
virtual SP<ITexture> getBlurTexture(PHLMONITORREF pMonitor);
SP<ITexture> m_lockDeadTexture;
SP<ITexture> m_lockDead2Texture;
SP<ITexture> m_lockTtyTextTexture;
bool m_monitorTransformEnabled = false; // do not modify directly
std::stack<bool> m_monitorTransformStack;
void initiateManualCrash();
const SRenderData& renderData();
// old private:
void arrangeLayerArray(PHLMONITOR, const std::vector<PHLLSREF>&, bool, CBox*);
void renderWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now, const CBox& geometry);
void renderWorkspaceWindowsFullscreen(PHLMONITOR, PHLWORKSPACE, const Time::steady_tp&); // renders workspace windows (fullscreen) (tiled, floating, pinned, but no special)
void renderWorkspaceWindows(PHLMONITOR, PHLWORKSPACE, const Time::steady_tp&); // renders workspace windows (no fullscreen) (tiled, floating, pinned, but no special)
void renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now, const Vector2D& translate = {0, 0}, const float& scale = 1.f);
void renderWindow(PHLWINDOW, PHLMONITOR, const Time::steady_tp&, bool, eRenderPassMode, bool ignorePosition = false, bool standalone = false);
void renderLayer(PHLLS, PHLMONITOR, const Time::steady_tp&, bool popups = false, bool lockscreen = false);
void renderSessionLockSurface(WP<SSessionLockSurface>, PHLMONITOR, const Time::steady_tp&);
void renderDragIcon(PHLMONITOR, const Time::steady_tp&);
void renderIMEPopup(CInputPopup*, PHLMONITOR, const Time::steady_tp&);
void sendFrameEventsToWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace,
const Time::steady_tp& now); // sends frame displayed events but doesn't actually render anything
void renderSessionLockPrimer(PHLMONITOR pMonitor);
void renderSessionLockMissing(PHLMONITOR pMonitor);
void renderBackground(PHLMONITOR pMonitor);
void requestBackgroundResource();
std::string resolveAssetPath(const std::string& file);
void initMissingAssetTexture();
void initAssets();
SP<ITexture> m_missingAssetTexture;
ASP<Hyprgraphics::CImageResource> m_backgroundResource;
bool m_backgroundResourceFailed = false;
bool m_crashingInProgress = false;
float m_crashingDistort = 0.5f;
wl_event_source* m_crashingLoop = nullptr;
wl_event_source* m_cursorTicker = nullptr;
bool shouldBlur(PHLLS ls);
bool shouldBlur(PHLWINDOW w);
bool shouldBlur(WP<Desktop::View::CPopup> p);
std::vector<CHLBufferReference> m_usedAsyncBuffers;
bool m_cursorHidden = false;
bool m_cursorHiddenByCondition = false;
bool m_cursorHasSurface = false;
SP<Aquamarine::IBuffer> m_currentBuffer = nullptr;
eRenderMode m_renderMode = RENDER_MODE_NORMAL;
bool m_nvidia = false;
bool m_intel = false;
bool m_software = false;
bool m_mgpu = false;
struct {
int hotspotX = 0;
int hotspotY = 0;
wpCursorShapeDeviceV1Shape shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT;
wpCursorShapeDeviceV1Shape shapePrevious = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT;
CTimer switchedTimer;
std::optional<SP<Desktop::View::CWLSurface>> surf;
std::string name;
} m_lastCursorData;
struct {
bool hiddenOnTouch = false;
bool hiddenOnTablet = false;
bool hiddenOnTimeout = false;
bool hiddenOnKeyboard = false;
} m_cursorHiddenConditions;
CRenderPass m_renderPass;
std::vector<SP<IRenderbuffer>> m_renderbuffers;
std::vector<PHLWINDOWREF> m_renderUnfocused;
SP<CEventLoopTimer> m_renderUnfocusedTimer;
SP<ITexture> renderSplash(const std::function<SP<ITexture>(const int, const int, unsigned char* const)>& handleData, const int fontSize, const int maxWidth = 1024,
const int maxHeight = 1024);
friend class CRenderPass;
friend class Render::GL::CHyprOpenGLImpl;
friend class CToplevelExportFrame;
friend class Screenshare::CScreenshareFrame;
friend class CInputManager;
friend class CPointerManager;
friend class CMonitor;
friend class CMonitorFrameScheduler;
virtual SP<IRenderbuffer> getOrCreateRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t fmt); // TODO? move to protected and fix CPointerManager::renderHWCursorBuffer
bool commitPendingAndDoExplicitSync(PHLMONITOR pMonitor); // TODO? move to protected and fix CMonitorFrameScheduler::onPresented
SRenderData m_renderData; // TODO? move to protected and fix CRenderPass
SP<ITexture> m_screencopyDeniedTexture; // TODO? make readonly
uint m_failedAssetsNo = 0; // TODO? make readonly
bool m_reloadScreenShader = true; // at launch it can be set
CTimer m_globalTimer;
void draw(WP<IPassElement> element, const CRegion& damage);
virtual SP<ITexture> createStencilTexture(const int width, const int height) = 0;
virtual SP<ITexture> createTexture(bool opaque = false) = 0;
virtual SP<ITexture> createTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false, bool opaque = false) = 0;
virtual SP<ITexture> createTexture(const Aquamarine::SDMABUFAttrs&, bool opaque = false) = 0;
virtual SP<ITexture> createTexture(const int width, const int height, unsigned char* const) = 0;
virtual SP<ITexture> createTexture(cairo_surface_t* cairo) = 0;
virtual SP<ITexture> createTexture(std::span<const float> lut3D, size_t N) = 0;
virtual SP<ITexture> createTexture(const SP<Aquamarine::IBuffer> buffer, bool keepDataCopy = false);
virtual SP<ITexture> renderText(const std::string& text, CHyprColor col, int pt, bool italic = false, const std::string& fontFamily = "", int maxWidth = 0, int weight = 400);
SP<ITexture> loadAsset(const std::string& filename);
virtual bool shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindow);
virtual bool explicitSyncSupported() = 0;
virtual std::vector<SDRMFormat> getDRMFormats() = 0;
virtual std::vector<uint64_t> getDRMFormatModifiers(DRMFormat format) = 0;
virtual SP<IFramebuffer> createFB(const std::string& name = "") = 0;
virtual void disableScissor() = 0;
virtual void blend(bool enabled) = 0;
virtual void drawShadow(const CBox& box, int round, float roundingPower, int range, CHyprColor color, float a) = 0;
virtual void setViewport(int x, int y, int width, int height) = 0;
bool preBlurQueued(PHLMONITORREF pMonitor);
void pushMonitorTransformEnabled(bool enabled);
void popMonitorTransformEnabled();
bool monitorTransformEnabled();
void setProjectionType(const Vector2D& fbSize);
void setProjectionType(eRenderProjectionType projectionType);
Mat3x3 getBoxProjection(const CBox& box, std::optional<eTransform> transform = std::nullopt);
Mat3x3 projectBoxToTarget(const CBox& box, std::optional<eTransform> transform = std::nullopt);
SP<ITexture> blurMainFramebuffer(float a, CRegion* originalDamage);
virtual SP<ITexture> blurFramebuffer(SP<IFramebuffer> source, float a, CRegion* originalDamage) = 0;
void preBlurForCurrentMonitor(CRegion* fakeDamage);
SCMSettings getCMSettings(const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
SP<CWLSurfaceResource> surface = nullptr, bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1);
virtual bool reloadShaders(const std::string& path = "") = 0;
bool needsACopyFB(PHLMONITOR mon);
protected:
virtual void renderOffToMain(IFramebuffer* off) = 0;
virtual SP<IRenderbuffer> getOrCreateRenderbufferInternal(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) = 0;
void renderMirrored();
void setDamage(const CRegion& damage_, std::optional<CRegion> finalDamage);
// if RENDER_MODE_NORMAL, provided damage will be written to.
// otherwise, it will be the one used.
bool beginRender(PHLMONITOR pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP<IHLBuffer> buffer = {}, SP<IFramebuffer> fb = nullptr, bool simple = false);
virtual bool beginRenderInternal(PHLMONITOR pMonitor, CRegion& damage, bool simple = false) {
return false;
};
virtual bool beginFullFakeRenderInternal(PHLMONITOR pMonitor, CRegion& damage, SP<IFramebuffer> fb, bool simple = false) {
return false;
};
virtual void initRender() {};
virtual bool initRenderBuffer(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) {
return false;
private:
void bindOffMain();
void bindBackOnMain();
};
SP<ITexture> getBackground(PHLMONITOR pMonitor);
virtual void draw(CBorderPassElement* element, const CRegion& damage) = 0;
virtual void draw(CClearPassElement* element, const CRegion& damage) = 0;
virtual void draw(CFramebufferElement* element, const CRegion& damage) = 0;
virtual void draw(CPreBlurElement* element, const CRegion& damage) = 0;
virtual void draw(CRectPassElement* element, const CRegion& damage) = 0;
virtual void draw(CShadowPassElement* element, const CRegion& damage) = 0;
virtual void draw(CTexPassElement* element, const CRegion& damage) = 0;
virtual void draw(CTextureMatteElement* element, const CRegion& damage) = 0;
virtual SP<ITexture> getBlurTexture(PHLMONITORREF pMonitor);
SP<ITexture> m_lockDeadTexture;
SP<ITexture> m_lockDead2Texture;
SP<ITexture> m_lockTtyTextTexture;
bool m_monitorTransformEnabled = false; // do not modify directly
std::stack<bool> m_monitorTransformStack;
}
// old private:
void arrangeLayerArray(PHLMONITOR, const std::vector<PHLLSREF>&, bool, CBox*);
void renderWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now, const CBox& geometry);
void renderWorkspaceWindowsFullscreen(PHLMONITOR, PHLWORKSPACE, const Time::steady_tp&); // renders workspace windows (fullscreen) (tiled, floating, pinned, but no special)
void renderWorkspaceWindows(PHLMONITOR, PHLWORKSPACE, const Time::steady_tp&); // renders workspace windows (no fullscreen) (tiled, floating, pinned, but no special)
void renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now, const Vector2D& translate = {0, 0}, const float& scale = 1.f);
void renderWindow(PHLWINDOW, PHLMONITOR, const Time::steady_tp&, bool, eRenderPassMode, bool ignorePosition = false, bool standalone = false);
void renderLayer(PHLLS, PHLMONITOR, const Time::steady_tp&, bool popups = false, bool lockscreen = false);
void renderSessionLockSurface(WP<SSessionLockSurface>, PHLMONITOR, const Time::steady_tp&);
void renderDragIcon(PHLMONITOR, const Time::steady_tp&);
void renderIMEPopup(CInputPopup*, PHLMONITOR, const Time::steady_tp&);
void sendFrameEventsToWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now); // sends frame displayed events but doesn't actually render anything
void renderSessionLockPrimer(PHLMONITOR pMonitor);
void renderSessionLockMissing(PHLMONITOR pMonitor);
void renderBackground(PHLMONITOR pMonitor);
void requestBackgroundResource();
std::string resolveAssetPath(const std::string& file);
void initMissingAssetTexture();
void initAssets();
SP<ITexture> m_missingAssetTexture;
ASP<Hyprgraphics::CImageResource> m_backgroundResource;
bool m_backgroundResourceFailed = false;
bool shouldBlur(PHLLS ls);
bool shouldBlur(PHLWINDOW w);
bool shouldBlur(WP<Desktop::View::CPopup> p);
bool m_cursorHidden = false;
bool m_cursorHiddenByCondition = false;
bool m_cursorHasSurface = false;
SP<Aquamarine::IBuffer> m_currentBuffer = nullptr;
eRenderMode m_renderMode = RENDER_MODE_NORMAL;
bool m_nvidia = false;
bool m_intel = false;
bool m_software = false;
bool m_mgpu = false;
struct {
bool hiddenOnTouch = false;
bool hiddenOnTablet = false;
bool hiddenOnTimeout = false;
bool hiddenOnKeyboard = false;
} m_cursorHiddenConditions;
std::vector<SP<IRenderbuffer>> m_renderbuffers;
std::vector<PHLWINDOWREF> m_renderUnfocused;
SP<CEventLoopTimer> m_renderUnfocusedTimer;
friend class CRenderPass;
friend class CHyprOpenGLImpl;
friend class CToplevelExportFrame;
friend class Screenshare::CScreenshareFrame;
friend class CInputManager;
friend class CPointerManager;
friend class CMonitor;
friend class CMonitorFrameScheduler;
private:
void bindOffMain();
void bindBackOnMain();
void drawRect(CRectPassElement* element, const CRegion& damage);
void drawHints(CRendererHintsPassElement* element, const CRegion& damage);
void drawPreBlur(CPreBlurElement* element, const CRegion& damage);
void drawSurface(CSurfacePassElement* element, const CRegion& damage);
void preDrawSurface(CSurfacePassElement* element, const CRegion& damage);
void drawTex(CTexPassElement* element, const CRegion& damage);
void drawTexMatte(CTextureMatteElement* element, const CRegion& damage);
};
inline UP<IHyprRenderer> g_pHyprRenderer;
inline UP<Render::IHyprRenderer> g_pHyprRenderer;

View file

@ -5,6 +5,8 @@
#define EPSILON(x, y) (std::abs((x) - (y)) < 1e-5f)
using namespace Render::GL;
static bool compareFloat(auto a, auto b) {
if (a.size() != b.size())
return false;

View file

@ -14,8 +14,6 @@
using namespace Render;
using namespace Render;
CShaderLoader::CShaderLoader(const std::vector<std::string> includes, const std::array<std::string, SH_FRAG_LAST>& frags, const std::string shaderPath) : m_shaderPath(shaderPath) {
m_callbacks = glsl_include_callbacks_t{
.include_local =

View file

@ -4,6 +4,7 @@
#include "../../config/ConfigValue.hpp"
#include "../pass/ShadowPassElement.hpp"
#include "../Renderer.hpp"
#include "../pass/RectPassElement.hpp"
#include "../pass/TextureMatteElement.hpp"
CHyprDropShadowDecoration::CHyprDropShadowDecoration(PHLWINDOW pWindow) : IHyprWindowDecoration(pWindow), m_window(pWindow) {
@ -245,14 +246,14 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) {
// build the matte
// 10-bit formats have dogshit alpha channels, so we have to use the matte to its fullest.
// first, clear region of interest with black (fully transparent)
g_pHyprRenderer->draw(makeUnique<CRectPassElement>(CRectPassElement::SRectData{.box = data.fullBox, .color = CHyprColor(0, 0, 0, 1), .round = 0}), monbox);
g_pHyprRenderer->draw(makeShared<CRectPassElement>(CRectPassElement::SRectData{.box = data.fullBox, .color = CHyprColor(0, 0, 0, 1), .round = 0}), monbox);
// render white shadow with the alpha of the shadow color (otherwise we clear with alpha later and shit it to 2 bit)
drawShadowInternal(data.fullBox, data.rounding * pMonitor->m_scale, data.roundingPower, data.size * pMonitor->m_scale,
CHyprColor(1, 1, 1, PWINDOW->m_realShadowColor->value().a), a);
// render black window box ("clip")
g_pHyprRenderer->draw(makeUnique<CRectPassElement>(CRectPassElement::SRectData{
g_pHyprRenderer->draw(makeShared<CRectPassElement>(CRectPassElement::SRectData{
.box = data.windowBox,
.color = CHyprColor(0, 0, 0, 1),
.round = (data.rounding + 1 /* This fixes small pixel gaps. */) * pMonitor->m_scale,
@ -263,7 +264,7 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) {
alphaSwapFB->bind();
// alpha swap just has the shadow color. It will be the "texture" to render.
g_pHyprRenderer->draw(makeUnique<CRectPassElement>(CRectPassElement::SRectData{.box = data.fullBox, .color = PWINDOW->m_realShadowColor->value().stripA(), .round = 0}),
g_pHyprRenderer->draw(makeShared<CRectPassElement>(CRectPassElement::SRectData{.box = data.fullBox, .color = PWINDOW->m_realShadowColor->value().stripA(), .round = 0}),
monbox);
LASTFB->bind();
@ -271,7 +272,7 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) {
g_pHyprRenderer->pushMonitorTransformEnabled(true);
g_pHyprRenderer->m_renderData.renderModif.enabled = false;
g_pHyprRenderer->draw(makeUnique<CTextureMatteElement>(CTextureMatteElement::STextureMatteData{
g_pHyprRenderer->draw(makeShared<CTextureMatteElement>(CTextureMatteElement::STextureMatteData{
.box = monbox,
.tex = alphaSwapFB->getTexture(),
.fb = alphaFB,
@ -303,7 +304,7 @@ void CHyprDropShadowDecoration::drawShadowInternal(const CBox& box, int round, f
color.a *= a;
if (*PSHADOWSHARP)
g_pHyprRenderer->draw(makeUnique<CRectPassElement>(CRectPassElement::SRectData{
g_pHyprRenderer->draw(makeShared<CRectPassElement>(CRectPassElement::SRectData{
.box = box,
.color = color,
.round = round,

View file

@ -0,0 +1,131 @@
#include "GLElementRenderer.hpp"
#include "../Renderer.hpp"
#include "../decorations/CHyprDropShadowDecoration.hpp"
#include "../OpenGL.hpp"
#include <cstdint>
using namespace Render::GL;
void CGLElementRenderer::draw(WP<CBorderPassElement> element, const CRegion& damage) {
const auto m_data = element->m_data;
if (m_data.hasGrad2)
g_pHyprOpenGL->renderBorder(
m_data.box, m_data.grad1, m_data.grad2, m_data.lerp,
{.round = m_data.round, .roundingPower = m_data.roundingPower, .borderSize = m_data.borderSize, .a = m_data.a, .outerRound = m_data.outerRound});
else
g_pHyprOpenGL->renderBorder(
m_data.box, m_data.grad1,
{.round = m_data.round, .roundingPower = m_data.roundingPower, .borderSize = m_data.borderSize, .a = m_data.a, .outerRound = m_data.outerRound});
};
void CGLElementRenderer::draw(WP<CClearPassElement> element, const CRegion& damage) {
const auto& color = element->m_data.color;
RASSERT(g_pHyprRenderer->m_renderData.pMonitor, "Tried to render without begin()!");
TRACY_GPU_ZONE("RenderClear");
GLCALL(glClearColor(color.r, color.g, color.b, color.a));
if (!g_pHyprRenderer->m_renderData.damage.empty()) {
g_pHyprRenderer->m_renderData.damage.forEachRect([](const auto& RECT) {
g_pHyprOpenGL->scissor(&RECT, g_pHyprRenderer->m_renderData.transformDamage);
glClear(GL_COLOR_BUFFER_BIT);
});
}
};
void CGLElementRenderer::draw(WP<CFramebufferElement> element, const CRegion& damage) {
const auto m_data = element->m_data;
SP<IFramebuffer> fb = nullptr;
if (m_data.main) {
switch (m_data.framebufferID) {
case FB_MONITOR_RENDER_MAIN: fb = g_pHyprRenderer->m_renderData.mainFB; break;
case FB_MONITOR_RENDER_CURRENT: fb = g_pHyprRenderer->m_renderData.currentFB; break;
case FB_MONITOR_RENDER_OUT: fb = g_pHyprRenderer->m_renderData.outFB; break;
default: fb = nullptr;
}
if (!fb) {
Log::logger->log(Log::ERR, "BUG THIS: CFramebufferElement::draw: main but null");
return;
}
} else {
switch (m_data.framebufferID) {
case FB_MONITOR_RENDER_EXTRA_OFFLOAD: fb = g_pHyprRenderer->m_renderData.pMonitor->m_offloadFB; break;
case FB_MONITOR_RENDER_EXTRA_MIRROR: fb = g_pHyprRenderer->m_renderData.pMonitor->m_mirrorFB; break;
case FB_MONITOR_RENDER_EXTRA_MIRROR_SWAP: fb = g_pHyprRenderer->m_renderData.pMonitor->m_mirrorSwapFB; break;
case FB_MONITOR_RENDER_EXTRA_OFF_MAIN: fb = g_pHyprRenderer->m_renderData.pMonitor->m_offMainFB; break;
case FB_MONITOR_RENDER_EXTRA_MONITOR_MIRROR: fb = g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB; break;
case FB_MONITOR_RENDER_EXTRA_BLUR: fb = g_pHyprRenderer->m_renderData.pMonitor->m_blurFB; break;
default: fb = nullptr;
}
if (!fb) {
Log::logger->log(Log::ERR, "BUG THIS: CFramebufferElement::draw: not main but null");
return;
}
}
fb->bind();
};
void CGLElementRenderer::draw(WP<CPreBlurElement> element, const CRegion& damage) {
auto dmg = damage;
g_pHyprRenderer->preBlurForCurrentMonitor(&dmg);
};
void CGLElementRenderer::draw(WP<CRectPassElement> element, const CRegion& damage) {
const auto m_data = element->m_data;
if (m_data.color.a == 1.F || !m_data.blur)
g_pHyprOpenGL->renderRect(m_data.box, m_data.color, {.damage = &damage, .round = m_data.round, .roundingPower = m_data.roundingPower});
else
g_pHyprOpenGL->renderRect(m_data.box, m_data.color,
{.round = m_data.round, .roundingPower = m_data.roundingPower, .blur = true, .blurA = m_data.blurA, .xray = m_data.xray});
};
void CGLElementRenderer::draw(WP<CShadowPassElement> element, const CRegion& damage) {
const auto m_data = element->m_data;
m_data.deco->render(g_pHyprRenderer->m_renderData.pMonitor.lock(), m_data.a);
};
void CGLElementRenderer::draw(WP<CTexPassElement> element, const CRegion& damage) {
const auto m_data = element->m_data;
g_pHyprOpenGL->renderTexture( //
m_data.tex, m_data.box,
{
// blur settings for m_data.blur == true
.blur = m_data.blur,
.blurA = m_data.blurA,
.overallA = m_data.overallA,
.blockBlurOptimization = m_data.blockBlurOptimization.value_or(false),
.blurredBG = m_data.blurredBG,
// common settings
.damage = m_data.damage.empty() ? &damage : &m_data.damage,
.surface = m_data.surface,
.a = m_data.a,
.round = m_data.round,
.roundingPower = m_data.roundingPower,
.discardActive = m_data.discardActive,
.allowCustomUV = m_data.allowCustomUV,
.cmBackToSRGB = m_data.cmBackToSRGB,
.cmBackToSRGBSource = m_data.cmBackToSRGBSource,
.discardMode = m_data.ignoreAlpha.has_value() ? sc<uint32_t>(DISCARD_ALPHA) : m_data.discardMode,
.discardOpacity = m_data.ignoreAlpha.has_value() ? *m_data.ignoreAlpha : m_data.discardOpacity,
.clipRegion = m_data.clipRegion,
.currentLS = m_data.currentLS,
.primarySurfaceUVTopLeft = g_pHyprRenderer->m_renderData.primarySurfaceUVTopLeft,
.primarySurfaceUVBottomRight = g_pHyprRenderer->m_renderData.primarySurfaceUVBottomRight,
});
};
void CGLElementRenderer::draw(WP<CTextureMatteElement> element, const CRegion& damage) {
const auto m_data = element->m_data;
g_pHyprOpenGL->renderTextureMatte(m_data.tex, m_data.box, m_data.fb);
};

View file

@ -0,0 +1,21 @@
#pragma once
#include "../ElementRenderer.hpp"
namespace Render::GL {
class CGLElementRenderer : public Render::IElementRenderer {
public:
CGLElementRenderer() = default;
~CGLElementRenderer() = default;
private:
void draw(WP<CBorderPassElement> element, const Hyprutils::Math::CRegion& damage);
void draw(WP<CClearPassElement> element, const CRegion& damage);
void draw(WP<CFramebufferElement> element, const CRegion& damage);
void draw(WP<CPreBlurElement> element, const CRegion& damage);
void draw(WP<CRectPassElement> element, const CRegion& damage);
void draw(WP<CShadowPassElement> element, const CRegion& damage);
void draw(WP<CTexPassElement> element, const CRegion& damage);
void draw(WP<CTextureMatteElement> element, const CRegion& damage);
};
}

View file

@ -4,6 +4,8 @@
#include "macros.hpp"
#include "../Framebuffer.hpp"
using namespace Render::GL;
CGLFramebuffer::CGLFramebuffer() : IFramebuffer() {}
CGLFramebuffer::CGLFramebuffer(const std::string& name) : IFramebuffer(name) {}

View file

@ -5,26 +5,28 @@
#include "../Framebuffer.hpp"
#include <drm_fourcc.h>
class CGLFramebuffer : public IFramebuffer {
public:
CGLFramebuffer();
CGLFramebuffer(const std::string& name);
~CGLFramebuffer();
namespace Render::GL {
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 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);
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;
protected:
bool internalAlloc(int w, int h, uint32_t format = DRM_FORMAT_ARGB8888) override;
private:
GLuint m_fb = -1;
private:
GLuint m_fb = -1;
friend class CGLRenderbuffer;
};
friend class CGLRenderbuffer;
};
}

View file

@ -11,6 +11,8 @@
#include <dlfcn.h>
using namespace Render::GL;
CGLRenderbuffer::~CGLRenderbuffer() {
if (!g_pCompositor || g_pCompositor->m_isShuttingDown || !g_pHyprRenderer)
return;

View file

@ -6,15 +6,17 @@
class CMonitor;
class CGLRenderbuffer : public IRenderbuffer {
public:
CGLRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t format);
~CGLRenderbuffer();
namespace Render::GL {
class CGLRenderbuffer : public IRenderbuffer {
public:
CGLRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t format);
~CGLRenderbuffer();
void bind() override;
void unbind() override;
void bind() override;
void unbind() override;
private:
void* m_image = nullptr;
GLuint m_rbo = 0;
};
private:
void* m_image = nullptr;
GLuint m_rbo = 0;
};
}

View file

@ -5,6 +5,8 @@
#include "../Texture.hpp"
#include <cstring>
using namespace Render::GL;
CGLTexture::CGLTexture(bool opaque) {
m_opaque = opaque;
}

View file

@ -4,46 +4,49 @@
#include <aquamarine/buffer/Buffer.hpp>
#include <hyprutils/math/Misc.hpp>
class CGLTexture : public ITexture {
public:
using ITexture::ITexture;
namespace Render::GL {
CGLTexture(CGLTexture&) = delete;
CGLTexture(CGLTexture&&) = delete;
CGLTexture(const CGLTexture&&) = delete;
CGLTexture(const CGLTexture&) = delete;
class CGLTexture : public ITexture {
public:
using ITexture::ITexture;
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();
CGLTexture(CGLTexture&) = delete;
CGLTexture(CGLTexture&&) = delete;
CGLTexture(const CGLTexture&&) = delete;
CGLTexture(const CGLTexture&) = delete;
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;
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();
private:
void* m_eglImage = nullptr;
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;
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,
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;
};
GLenum m_target = GL_TEXTURE_2D;
void swizzle(const std::array<GLint, 4>& colors);
constexpr std::optional<size_t> getCacheStateIndex(GLenum pname);
std::array<std::optional<GLint>, TEXTURE_PAR_LAST> m_cachedStates;
};
}

View file

@ -10,6 +10,11 @@
#include "../../render/Renderer.hpp"
#include "../../desktop/state/FocusState.hpp"
#include "../../protocols/core/Compositor.hpp"
#include "RectPassElement.hpp"
#include "macros.hpp"
#include "render/pass/ClearPassElement.hpp"
using namespace Render;
bool CRenderPass::empty() const {
return false;
@ -216,12 +221,12 @@ void CRenderPass::renderDebugData() {
CRectPassElement::SRectData data;
data.box = box;
data.color = Colors::RED.modifyA(0.1F);
g_pHyprRenderer->draw(makeUnique<CRectPassElement>(data), rg);
g_pHyprRenderer->draw(makeShared<CRectPassElement>(data), rg);
}
CRectPassElement::SRectData data;
data.box = box;
data.color = Colors::GREEN.modifyA(0.1F);
g_pHyprRenderer->draw(makeUnique<CRectPassElement>(data), m_totalLiveBlurRegion);
g_pHyprRenderer->draw(makeShared<CRectPassElement>(data), m_totalLiveBlurRegion);
std::unordered_map<CWLSurfaceResource*, float> offsets;
@ -249,7 +254,7 @@ void CRenderPass::renderDebugData() {
CRectPassElement::SRectData data;
data.box = box;
data.color = color;
g_pHyprRenderer->draw(makeUnique<CRectPassElement>(data), FULL_REGION);
g_pHyprRenderer->draw(makeShared<CRectPassElement>(data), FULL_REGION);
if (offsets.contains(surface.get()))
box.translate(Vector2D{0.F, offsets[surface.get()]});
@ -261,12 +266,12 @@ void CRenderPass::renderDebugData() {
data.box = box;
data.color = color;
data.round = std::min(5.0, box.size().y);
g_pHyprRenderer->draw(makeUnique<CRectPassElement>(data2), FULL_REGION);
g_pHyprRenderer->draw(makeShared<CRectPassElement>(data2), FULL_REGION);
CTexPassElement::SRenderData texData;
texData.tex = texture;
texData.box = box;
g_pHyprRenderer->draw(makeUnique<CTexPassElement>(texData), {});
g_pHyprRenderer->draw(makeShared<CTexPassElement>(texData), {});
offsets[surface.get()] += texture->m_size.y;
};
@ -287,7 +292,7 @@ void CRenderPass::renderDebugData() {
CRectPassElement::SRectData data;
data.box = box;
data.color = CHyprColor{0.8F, 0.8F, 0.2F, 0.4F};
g_pHyprRenderer->draw(makeUnique<CRectPassElement>(data), region);
g_pHyprRenderer->draw(makeShared<CRectPassElement>(data), region);
}
}
}
@ -303,7 +308,7 @@ void CRenderPass::renderDebugData() {
CTexPassElement::SRenderData texData;
texData.tex = tex;
texData.box = box;
g_pHyprRenderer->draw(makeUnique<CTexPassElement>(texData), {});
g_pHyprRenderer->draw(makeShared<CTexPassElement>(texData), {});
}
std::string passStructure;
@ -323,7 +328,7 @@ void CRenderPass::renderDebugData() {
CTexPassElement::SRenderData texData;
texData.tex = tex;
texData.box = box;
g_pHyprRenderer->draw(makeUnique<CTexPassElement>(texData), {});
g_pHyprRenderer->draw(makeShared<CTexPassElement>(texData), {});
}
}

View file

@ -1,12 +1,11 @@
#pragma once
#include "PassElement.hpp"
#include <optional>
#include "../OpenGL.hpp"
#include "../types.hpp"
class CRendererHintsPassElement : public IPassElement {
public:
struct SData {
std::optional<SRenderModifData> renderModif;
std::optional<Render::SRenderModifData> renderModif;
};
CRendererHintsPassElement(const SData& data);

131
src/render/types.hpp Normal file
View file

@ -0,0 +1,131 @@
#pragma once
#include "Framebuffer.hpp"
#include "../desktop/DesktopTypes.hpp"
#include "../helpers/cm/ColorManagement.hpp"
#include "../protocols/core/Compositor.hpp"
#include <hyprgraphics/color/Color.hpp>
#include <hyprutils/math/Box.hpp>
#include <hyprutils/math/Mat3x3.hpp>
#include <hyprutils/math/Region.hpp>
#include <hyprutils/math/Vector2D.hpp>
namespace Render {
const std::vector<const char*> ASSET_PATHS = {
#ifdef DATAROOTDIR
DATAROOTDIR,
#endif
"/usr/share",
"/usr/local/share",
};
enum eDamageTrackingModes : int8_t {
DAMAGE_TRACKING_INVALID = -1,
DAMAGE_TRACKING_NONE = 0,
DAMAGE_TRACKING_MONITOR,
DAMAGE_TRACKING_FULL,
};
enum eRenderPassMode : uint8_t {
RENDER_PASS_ALL = 0,
RENDER_PASS_MAIN,
RENDER_PASS_POPUP
};
enum eRenderMode : uint8_t {
RENDER_MODE_NORMAL = 0,
RENDER_MODE_FULL_FAKE = 1,
RENDER_MODE_TO_BUFFER = 2,
RENDER_MODE_TO_BUFFER_READ_ONLY = 3,
};
struct SRenderWorkspaceUntilData {
PHLLS ls;
PHLWINDOW w;
};
enum eRenderProjectionType : uint8_t {
RPT_MONITOR,
RPT_MIRROR,
RPT_FB,
RPT_EXPORT,
};
struct SRenderModifData {
enum eRenderModifType : uint8_t {
RMOD_TYPE_SCALE, /* scale by a float */
RMOD_TYPE_SCALECENTER, /* scale by a float from the center */
RMOD_TYPE_TRANSLATE, /* translate by a Vector2D */
RMOD_TYPE_ROTATE, /* rotate by a float in rad from top left */
RMOD_TYPE_ROTATECENTER, /* rotate by a float in rad from center */
};
std::vector<std::pair<eRenderModifType, std::any>> modifs;
void applyToBox(Hyprutils::Math::CBox& box);
void applyToRegion(Hyprutils::Math::CRegion& rg);
float combinedScale();
bool enabled = true;
};
struct SRenderData {
// can be private
Hyprutils::Math::Mat3x3 targetProjection;
// ----------------------
// used by public
Hyprutils::Math::Vector2D fbSize = {-1, -1};
PHLMONITORREF pMonitor;
eRenderProjectionType projectionType = RPT_MONITOR;
SP<IFramebuffer> currentFB = nullptr; // current rendering to
SP<IFramebuffer> mainFB = nullptr; // main to render to
SP<IFramebuffer> outFB = nullptr; // out to render to (if offloaded, etc)
CRegion damage;
CRegion finalDamage; // damage used for funal off -> main
SRenderModifData renderModif;
float mouseZoomFactor = 1.f;
bool mouseZoomUseMouse = true; // true by default
bool useNearestNeighbor = false;
bool blockScreenShader = false;
Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1);
Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
// TODO remove and pass directly
CBox clipBox = {}; // scaled coordinates
PHLWINDOWREF currentWindow;
WP<CWLSurfaceResource> surface;
bool transformDamage = true;
bool noSimplify = false;
};
struct STFRange {
float min = 0;
float max = 80;
};
struct SCMSettings {
NColorManagement::eTransferFunction sourceTF = NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22;
NColorManagement::eTransferFunction targetTF = NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22;
STFRange srcTFRange;
STFRange dstTFRange;
float srcRefLuminance = 80;
float dstRefLuminance = 80;
std::array<std::array<double, 3>, 3> convertMatrix;
bool needsTonemap = false;
float maxLuminance = 80;
float dstMaxLuminance = 80;
std::array<std::array<double, 3>, 3> dstPrimaries2XYZ;
bool needsSDRmod = false;
float sdrSaturation = 1.0;
float sdrBrightnessMultiplier = 1.0;
};
}