mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-05-19 08:30:22 -07:00
protocols: add hyprland_surface_v1.set_visible_region implementation (#9120)
This commit is contained in:
parent
1a0a22ad03
commit
465cf66df1
@ -87,7 +87,8 @@ class CWLSurface {
|
|||||||
float m_fAlphaModifier = 1.F;
|
float m_fAlphaModifier = 1.F;
|
||||||
|
|
||||||
// used by the hyprland-surface protocol
|
// used by the hyprland-surface protocol
|
||||||
float m_fOverallOpacity = 1.F;
|
float m_fOverallOpacity = 1.F;
|
||||||
|
CRegion m_visibleRegion;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
CSignal destroy;
|
CSignal destroy;
|
||||||
|
@ -168,7 +168,7 @@ CProtocolManager::CProtocolManager() {
|
|||||||
PROTO::singlePixel = makeUnique<CSinglePixelProtocol>(&wp_single_pixel_buffer_manager_v1_interface, 1, "SinglePixel");
|
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::securityContext = makeUnique<CSecurityContextProtocol>(&wp_security_context_manager_v1_interface, 1, "SecurityContext");
|
||||||
PROTO::ctm = makeUnique<CHyprlandCTMControlProtocol>(&hyprland_ctm_control_manager_v1_interface, 1, "CTMControl");
|
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) {
|
if (*PENABLEXXCM) {
|
||||||
PROTO::colorManagement = makeUnique<CColorManagementProtocol>(&xx_color_manager_v4_interface, 1, "ColorManagement");
|
PROTO::colorManagement = makeUnique<CColorManagementProtocol>(&xx_color_manager_v4_interface, 1, "ColorManagement");
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
#include "../render/Renderer.hpp"
|
#include "../render/Renderer.hpp"
|
||||||
#include "core/Compositor.hpp"
|
#include "core/Compositor.hpp"
|
||||||
#include "hyprland-surface-v1.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) {
|
CHyprlandSurface::CHyprlandSurface(SP<CHyprlandSurfaceV1> resource, SP<CWLSurfaceResource> surface) : m_pSurface(surface) {
|
||||||
setResource(std::move(resource));
|
setResource(std::move(resource));
|
||||||
@ -36,11 +38,25 @@ void CHyprlandSurface::setResource(SP<CHyprlandSurfaceV1> resource) {
|
|||||||
m_fOpacity = fOpacity;
|
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) {
|
listeners.surfaceCommitted = m_pSurface->events.commit.registerListener([this](std::any data) {
|
||||||
auto surface = CWLSurface::fromResource(m_pSurface.lock());
|
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_fOverallOpacity = m_fOpacity;
|
||||||
|
surface->m_visibleRegion = m_visibleRegion;
|
||||||
auto box = surface->getSurfaceBoxGlobal();
|
auto box = surface->getSurfaceBoxGlobal();
|
||||||
|
|
||||||
if (box.has_value())
|
if (box.has_value())
|
||||||
@ -61,6 +77,11 @@ void CHyprlandSurface::destroy() {
|
|||||||
m_pResource.reset();
|
m_pResource.reset();
|
||||||
m_fOpacity = 1.F;
|
m_fOpacity = 1.F;
|
||||||
|
|
||||||
|
if (!m_visibleRegion.empty())
|
||||||
|
m_bVisibleRegionChanged = true;
|
||||||
|
|
||||||
|
m_visibleRegion.clear();
|
||||||
|
|
||||||
if (!m_pSurface)
|
if (!m_pSurface)
|
||||||
PROTO::hyprlandSurface->destroySurface(this);
|
PROTO::hyprlandSurface->destroySurface(this);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <hyprutils/math/Region.hpp>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include "WaylandProtocol.hpp"
|
#include "WaylandProtocol.hpp"
|
||||||
@ -19,7 +20,9 @@ class CHyprlandSurface {
|
|||||||
private:
|
private:
|
||||||
SP<CHyprlandSurfaceV1> m_pResource;
|
SP<CHyprlandSurfaceV1> m_pResource;
|
||||||
WP<CWLSurfaceResource> m_pSurface;
|
WP<CWLSurfaceResource> m_pSurface;
|
||||||
float m_fOpacity = 1.0;
|
float m_fOpacity = 1.0;
|
||||||
|
bool m_bVisibleRegionChanged = false;
|
||||||
|
CRegion m_visibleRegion;
|
||||||
|
|
||||||
void destroy();
|
void destroy();
|
||||||
|
|
||||||
|
@ -1556,9 +1556,15 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, CBox* pB
|
|||||||
glEnableVertexAttribArray(shader->posAttrib);
|
glEnableVertexAttribArray(shader->posAttrib);
|
||||||
glEnableVertexAttribArray(shader->texAttrib);
|
glEnableVertexAttribArray(shader->texAttrib);
|
||||||
|
|
||||||
if (m_RenderData.clipBox.width != 0 && m_RenderData.clipBox.height != 0) {
|
if (!m_RenderData.clipBox.empty() || !m_RenderData.clipRegion.empty()) {
|
||||||
CRegion damageClip{m_RenderData.clipBox.x, m_RenderData.clipBox.y, m_RenderData.clipBox.width, m_RenderData.clipBox.height};
|
CRegion damageClip = m_RenderData.clipBox;
|
||||||
damageClip.intersect(damage);
|
|
||||||
|
if (!m_RenderData.clipRegion.empty()) {
|
||||||
|
if (m_RenderData.clipBox.empty())
|
||||||
|
damageClip = m_RenderData.clipRegion;
|
||||||
|
else
|
||||||
|
damageClip.intersect(m_RenderData.clipRegion);
|
||||||
|
}
|
||||||
|
|
||||||
if (!damageClip.empty()) {
|
if (!damageClip.empty()) {
|
||||||
for (auto const& RECT : damageClip.getRects()) {
|
for (auto const& RECT : damageClip.getRects()) {
|
||||||
@ -2079,6 +2085,11 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP<CTexture> tex, CBox* pBox, float
|
|||||||
CRegion texDamage{m_RenderData.damage};
|
CRegion texDamage{m_RenderData.damage};
|
||||||
texDamage.intersect(pBox->x, pBox->y, pBox->width, pBox->height);
|
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())
|
if (texDamage.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -133,6 +133,7 @@ struct SCurrentRenderData {
|
|||||||
Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
|
Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
|
||||||
|
|
||||||
CBox clipBox = {}; // scaled coordinates
|
CBox clipBox = {}; // scaled coordinates
|
||||||
|
CRegion clipRegion;
|
||||||
|
|
||||||
uint32_t discardMode = DISCARD_OPAQUE;
|
uint32_t discardMode = DISCARD_OPAQUE;
|
||||||
float discardOpacity = 0.f;
|
float discardOpacity = 0.f;
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
#include "../../managers/input/InputManager.hpp"
|
#include "../../managers/input/InputManager.hpp"
|
||||||
#include "../Renderer.hpp"
|
#include "../Renderer.hpp"
|
||||||
|
|
||||||
|
#include <hyprutils/math/Box.hpp>
|
||||||
|
#include <hyprutils/math/Vector2D.hpp>
|
||||||
#include <hyprutils/utils/ScopeGuard.hpp>
|
#include <hyprutils/utils/ScopeGuard.hpp>
|
||||||
using namespace Hyprutils::Utils;
|
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.primarySurfaceUVBottomRight = Vector2D(-1, -1);
|
||||||
g_pHyprOpenGL->m_RenderData.useNearestNeighbor = false;
|
g_pHyprOpenGL->m_RenderData.useNearestNeighbor = false;
|
||||||
g_pHyprOpenGL->m_RenderData.clipBox = {};
|
g_pHyprOpenGL->m_RenderData.clipBox = {};
|
||||||
|
g_pHyprOpenGL->m_RenderData.clipRegion = {};
|
||||||
g_pHyprOpenGL->m_RenderData.discardMode = 0;
|
g_pHyprOpenGL->m_RenderData.discardMode = 0;
|
||||||
g_pHyprOpenGL->m_RenderData.discardOpacity = 0;
|
g_pHyprOpenGL->m_RenderData.discardOpacity = 0;
|
||||||
g_pHyprOpenGL->m_RenderData.useNearestNeighbor = false;
|
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");
|
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);
|
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
|
// check for fractional scale surfaces misaligning the buffer size
|
||||||
// in those cases it's better to just force nearest neighbor
|
// 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.
|
// 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{};
|
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() {
|
void CSurfacePassElement::discard() {
|
||||||
if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) {
|
if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) {
|
||||||
Debug::log(TRACE, "discard for invisible surface");
|
Debug::log(TRACE, "discard for invisible surface");
|
||||||
|
@ -57,6 +57,7 @@ class CSurfacePassElement : public IPassElement {
|
|||||||
virtual std::optional<CBox> boundingBox();
|
virtual std::optional<CBox> boundingBox();
|
||||||
virtual CRegion opaqueRegion();
|
virtual CRegion opaqueRegion();
|
||||||
virtual void discard();
|
virtual void discard();
|
||||||
|
CRegion visibleRegion(bool& cancel);
|
||||||
|
|
||||||
virtual const char* passName() {
|
virtual const char* passName() {
|
||||||
return "CSurfacePassElement";
|
return "CSurfacePassElement";
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 455c055883d9639d4fcbfcedb4c6d12ce313791e
|
Subproject commit 4c75dd5c015c8a0e5a34c6d02a018a650f57feb5
|
Loading…
x
Reference in New Issue
Block a user