protocols: add hyprland_surface_v1.set_visible_region implementation (#9120)

This commit is contained in:
outfoxxed 2025-01-23 13:57:33 -08:00 committed by GitHub
parent 1a0a22ad03
commit 465cf66df1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 96 additions and 8 deletions

View file

@ -1556,9 +1556,15 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, CBox* pB
glEnableVertexAttribArray(shader->posAttrib);
glEnableVertexAttribArray(shader->texAttrib);
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};
damageClip.intersect(damage);
if (!m_RenderData.clipBox.empty() || !m_RenderData.clipRegion.empty()) {
CRegion damageClip = m_RenderData.clipBox;
if (!m_RenderData.clipRegion.empty()) {
if (m_RenderData.clipBox.empty())
damageClip = m_RenderData.clipRegion;
else
damageClip.intersect(m_RenderData.clipRegion);
}
if (!damageClip.empty()) {
for (auto const& RECT : damageClip.getRects()) {
@ -2079,6 +2085,11 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP<CTexture> tex, CBox* pBox, float
CRegion texDamage{m_RenderData.damage};
texDamage.intersect(pBox->x, pBox->y, pBox->width, pBox->height);
// While renderTextureInternalWithDamage will clip the blur as well,
// clipping texDamage here allows blur generation to be optimized.
if (!m_RenderData.clipRegion.empty())
texDamage.intersect(m_RenderData.clipRegion);
if (texDamage.empty())
return;

View file

@ -133,6 +133,7 @@ struct SCurrentRenderData {
Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
CBox clipBox = {}; // scaled coordinates
CRegion clipRegion;
uint32_t discardMode = DISCARD_OPAQUE;
float discardOpacity = 0.f;

View file

@ -7,6 +7,8 @@
#include "../../managers/input/InputManager.hpp"
#include "../Renderer.hpp"
#include <hyprutils/math/Box.hpp>
#include <hyprutils/math/Vector2D.hpp>
#include <hyprutils/utils/ScopeGuard.hpp>
using namespace Hyprutils::Utils;
@ -28,6 +30,7 @@ void CSurfacePassElement::draw(const CRegion& damage) {
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
g_pHyprOpenGL->m_RenderData.useNearestNeighbor = false;
g_pHyprOpenGL->m_RenderData.clipBox = {};
g_pHyprOpenGL->m_RenderData.clipRegion = {};
g_pHyprOpenGL->m_RenderData.discardMode = 0;
g_pHyprOpenGL->m_RenderData.discardOpacity = 0;
g_pHyprOpenGL->m_RenderData.useNearestNeighbor = false;
@ -84,6 +87,11 @@ void CSurfacePassElement::draw(const CRegion& damage) {
Debug::log(TRACE, "FIXME: rendering surface with color management enabled, should apply necessary transformations");
g_pHyprRenderer->calculateUVForSurface(data.pWindow, data.surface, data.pMonitor->self.lock(), data.mainSurface, windowBox.size(), PROJSIZEUNSCALED, MISALIGNEDFSV1);
auto cancelRender = false;
g_pHyprOpenGL->m_RenderData.clipRegion = 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.
@ -229,6 +237,48 @@ CRegion CSurfacePassElement::opaqueRegion() {
return data.texture && data.texture->m_bOpaque ? boundingBox()->expand(-data.rounding) : CRegion{};
}
CRegion CSurfacePassElement::visibleRegion(bool& cancel) {
auto PSURFACE = CWLSurface::fromResource(data.surface);
if (!PSURFACE)
return {};
const auto& bufferSize = data.surface->current.bufferSize;
auto visibleRegion = PSURFACE->m_visibleRegion.copy();
if (visibleRegion.empty())
return {};
visibleRegion.intersect(CBox(Vector2D(), bufferSize));
if (visibleRegion.empty()) {
cancel = true;
return visibleRegion;
}
// deal with any rounding errors that might come from scaling
visibleRegion.expand(1);
auto uvTL = g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft;
auto uvBR = g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight;
if (uvTL == Vector2D(-1, -1))
uvTL = Vector2D(0, 0);
if (uvBR == Vector2D(-1, -1))
uvBR = Vector2D(1, 1);
visibleRegion.translate(-uvTL * bufferSize);
auto texBox = getTexBox();
texBox.scale(data.pMonitor->scale);
texBox.round();
visibleRegion.scale((Vector2D(1, 1) / (uvBR - uvTL)) * (texBox.size() / bufferSize));
visibleRegion.translate((data.pos + data.localPos) * data.pMonitor->scale - data.pMonitor->vecPosition);
return visibleRegion;
}
void CSurfacePassElement::discard() {
if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) {
Debug::log(TRACE, "discard for invisible surface");

View file

@ -57,6 +57,7 @@ class CSurfacePassElement : public IPassElement {
virtual std::optional<CBox> boundingBox();
virtual CRegion opaqueRegion();
virtual void discard();
CRegion visibleRegion(bool& cancel);
virtual const char* passName() {
return "CSurfacePassElement";