summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoroutfoxxed <outfoxxed@outfoxxed.me>2025-01-23 13:57:33 -0800
committerGitHub <noreply@github.com>2025-01-23 22:57:33 +0100
commit465cf66df14c28427ba30580253be6e3908bd28c (patch)
tree93bc76546ffa329972863fd2716e8856debaeef8 /src
parent1a0a22ad038bbd51c4e1514868d6dcd505af0242 (diff)
protocols: add hyprland_surface_v1.set_visible_region implementation (#9120)
Diffstat (limited to 'src')
-rw-r--r--src/desktop/WLSurface.hpp3
-rw-r--r--src/managers/ProtocolManager.cpp2
-rw-r--r--src/protocols/HyprlandSurface.cpp23
-rw-r--r--src/protocols/HyprlandSurface.hpp5
-rw-r--r--src/render/OpenGL.cpp17
-rw-r--r--src/render/OpenGL.hpp1
-rw-r--r--src/render/pass/SurfacePassElement.cpp50
-rw-r--r--src/render/pass/SurfacePassElement.hpp1
8 files changed, 95 insertions, 7 deletions
diff --git a/src/desktop/WLSurface.hpp b/src/desktop/WLSurface.hpp
index 057a6f90..5f8da715 100644
--- a/src/desktop/WLSurface.hpp
+++ b/src/desktop/WLSurface.hpp
@@ -87,7 +87,8 @@ class CWLSurface {
float m_fAlphaModifier = 1.F;
// used by the hyprland-surface protocol
- float m_fOverallOpacity = 1.F;
+ float m_fOverallOpacity = 1.F;
+ CRegion m_visibleRegion;
struct {
CSignal destroy;
diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp
index f73a6d3c..d3270fe2 100644
--- a/src/managers/ProtocolManager.cpp
+++ b/src/managers/ProtocolManager.cpp
@@ -168,7 +168,7 @@ CProtocolManager::CProtocolManager() {
PROTO::singlePixel = makeUnique<CSinglePixelProtocol>(&wp_single_pixel_buffer_manager_v1_interface, 1, "SinglePixel");
PROTO::securityContext = makeUnique<CSecurityContextProtocol>(&wp_security_context_manager_v1_interface, 1, "SecurityContext");
PROTO::ctm = makeUnique<CHyprlandCTMControlProtocol>(&hyprland_ctm_control_manager_v1_interface, 1, "CTMControl");
- PROTO::hyprlandSurface = makeUnique<CHyprlandSurfaceProtocol>(&hyprland_surface_manager_v1_interface, 1, "HyprlandSurface");
+ PROTO::hyprlandSurface = makeUnique<CHyprlandSurfaceProtocol>(&hyprland_surface_manager_v1_interface, 2, "HyprlandSurface");
if (*PENABLEXXCM) {
PROTO::colorManagement = makeUnique<CColorManagementProtocol>(&xx_color_manager_v4_interface, 1, "ColorManagement");
diff --git a/src/protocols/HyprlandSurface.cpp b/src/protocols/HyprlandSurface.cpp
index ca133b78..e3716f10 100644
--- a/src/protocols/HyprlandSurface.cpp
+++ b/src/protocols/HyprlandSurface.cpp
@@ -3,6 +3,8 @@
#include "../render/Renderer.hpp"
#include "core/Compositor.hpp"
#include "hyprland-surface-v1.hpp"
+#include <hyprutils/math/Region.hpp>
+#include <wayland-server.h>
CHyprlandSurface::CHyprlandSurface(SP<CHyprlandSurfaceV1> resource, SP<CWLSurfaceResource> surface) : m_pSurface(surface) {
setResource(std::move(resource));
@@ -36,11 +38,25 @@ void CHyprlandSurface::setResource(SP<CHyprlandSurfaceV1> resource) {
m_fOpacity = fOpacity;
});
+ m_pResource->setSetVisibleRegion([this](CHyprlandSurfaceV1* resource, wl_resource* region) {
+ if (!region) {
+ if (!m_visibleRegion.empty())
+ m_bVisibleRegionChanged = true;
+
+ m_visibleRegion.clear();
+ return;
+ }
+
+ m_bVisibleRegionChanged = true;
+ m_visibleRegion = CWLRegionResource::fromResource(region)->region;
+ });
+
listeners.surfaceCommitted = m_pSurface->events.commit.registerListener([this](std::any data) {
auto surface = CWLSurface::fromResource(m_pSurface.lock());
- if (surface && surface->m_fOverallOpacity != m_fOpacity) {
+ if (surface && (surface->m_fOverallOpacity != m_fOpacity || m_bVisibleRegionChanged)) {
surface->m_fOverallOpacity = m_fOpacity;
+ surface->m_visibleRegion = m_visibleRegion;
auto box = surface->getSurfaceBoxGlobal();
if (box.has_value())
@@ -61,6 +77,11 @@ void CHyprlandSurface::destroy() {
m_pResource.reset();
m_fOpacity = 1.F;
+ if (!m_visibleRegion.empty())
+ m_bVisibleRegionChanged = true;
+
+ m_visibleRegion.clear();
+
if (!m_pSurface)
PROTO::hyprlandSurface->destroySurface(this);
}
diff --git a/src/protocols/HyprlandSurface.hpp b/src/protocols/HyprlandSurface.hpp
index a5812b89..5c1181c4 100644
--- a/src/protocols/HyprlandSurface.hpp
+++ b/src/protocols/HyprlandSurface.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include <hyprutils/math/Region.hpp>
#include <vector>
#include <unordered_map>
#include "WaylandProtocol.hpp"
@@ -19,7 +20,9 @@ class CHyprlandSurface {
private:
SP<CHyprlandSurfaceV1> m_pResource;
WP<CWLSurfaceResource> m_pSurface;
- float m_fOpacity = 1.0;
+ float m_fOpacity = 1.0;
+ bool m_bVisibleRegionChanged = false;
+ CRegion m_visibleRegion;
void destroy();
diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp
index ceb94c81..8ae667d2 100644
--- a/src/render/OpenGL.cpp
+++ b/src/render/OpenGL.cpp
@@ -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;
diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp
index 3dc3b43a..fd84d478 100644
--- a/src/render/OpenGL.hpp
+++ b/src/render/OpenGL.hpp
@@ -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;
diff --git a/src/render/pass/SurfacePassElement.cpp b/src/render/pass/SurfacePassElement.cpp
index d720081f..b79407c8 100644
--- a/src/render/pass/SurfacePassElement.cpp
+++ b/src/render/pass/SurfacePassElement.cpp
@@ -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");
diff --git a/src/render/pass/SurfacePassElement.hpp b/src/render/pass/SurfacePassElement.hpp
index 12387367..1b6ddb0b 100644
--- a/src/render/pass/SurfacePassElement.hpp
+++ b/src/render/pass/SurfacePassElement.hpp
@@ -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";