summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLee Bousfield <ljbousfield@gmail.com>2025-03-22 11:13:44 -0500
committerGitHub <noreply@github.com>2025-03-22 17:13:44 +0100
commit6384f4acf4e2988bcb35d3dfc5821f07867a34d0 (patch)
tree2da8d2275cc4acc435906c7fa84956ae2b17ade6 /src
parent4600043a498b015360a0f2b6f682ae82aff1b198 (diff)
core/compositor: Correctly track SHM buffer damage (#9678)
Diffstat (limited to 'src')
-rw-r--r--src/desktop/WLSurface.cpp2
-rw-r--r--src/events/Windows.cpp2
-rw-r--r--src/helpers/Monitor.cpp2
-rw-r--r--src/protocols/DRMSyncobj.cpp2
-rw-r--r--src/protocols/Viewporter.cpp2
-rw-r--r--src/protocols/XDGShell.cpp2
-rw-r--r--src/protocols/core/Compositor.cpp53
-rw-r--r--src/protocols/core/Compositor.hpp3
-rw-r--r--src/protocols/core/Shm.cpp11
-rw-r--r--src/protocols/core/Shm.hpp2
-rw-r--r--src/protocols/types/SurfaceState.cpp58
-rw-r--r--src/protocols/types/SurfaceState.hpp18
-rw-r--r--src/render/Texture.cpp5
-rw-r--r--src/render/Texture.hpp17
-rw-r--r--src/xwayland/XSurface.cpp6
15 files changed, 103 insertions, 82 deletions
diff --git a/src/desktop/WLSurface.cpp b/src/desktop/WLSurface.cpp
index e86ac036..11da7b68 100644
--- a/src/desktop/WLSurface.cpp
+++ b/src/desktop/WLSurface.cpp
@@ -98,7 +98,7 @@ CRegion CWLSurface::computeDamage() const {
if (!m_pResource->current.texture)
return {};
- CRegion damage = m_pResource->accumulateCurrentBufferDamage();
+ CRegion damage = m_pResource->current.accumulateBufferDamage();
damage.transform(wlTransformToHyprutils(m_pResource->current.transform), m_pResource->current.bufferSize.x, m_pResource->current.bufferSize.y);
const auto BUFSIZE = m_pResource->current.bufferSize;
diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp
index b5273187..adc0c762 100644
--- a/src/events/Windows.cpp
+++ b/src/events/Windows.cpp
@@ -880,7 +880,7 @@ void Events::listener_commitWindow(void* owner, void* data) {
// tearing: if solitary, redraw it. This still might be a single surface window
if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.texture) {
- CRegion damageBox{PWINDOW->m_pWLSurface->resource()->accumulateCurrentBufferDamage()};
+ CRegion damageBox{PWINDOW->m_pWLSurface->resource()->current.accumulateBufferDamage()};
if (!damageBox.empty()) {
if (PMONITOR->tearingState.busy) {
diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp
index fe8ab9df..75c0d8b9 100644
--- a/src/helpers/Monitor.cpp
+++ b/src/helpers/Monitor.cpp
@@ -1400,7 +1400,7 @@ bool CMonitor::attemptDirectScanout() {
clock_gettime(CLOCK_MONOTONIC, &now);
PSURFACE->presentFeedback(&now, self.lock());
- output->state->addDamage(PSURFACE->accumulateCurrentBufferDamage());
+ output->state->addDamage(PSURFACE->current.accumulateBufferDamage());
output->state->resetExplicitFences();
auto cleanup = CScopeGuard([this]() { output->state->resetExplicitFences(); });
diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp
index 943aad4d..5238d1fb 100644
--- a/src/protocols/DRMSyncobj.cpp
+++ b/src/protocols/DRMSyncobj.cpp
@@ -137,7 +137,7 @@ CDRMSyncobjSurfaceResource::~CDRMSyncobjSurfaceResource() {
}
bool CDRMSyncobjSurfaceResource::protocolError() {
- if (!surface->pending.texture) {
+ if (!surface->pending.buffer) {
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_BUFFER, "Missing buffer");
surface->pending.rejected = true;
return true;
diff --git a/src/protocols/Viewporter.cpp b/src/protocols/Viewporter.cpp
index 4964bead..d14e7ee5 100644
--- a/src/protocols/Viewporter.cpp
+++ b/src/protocols/Viewporter.cpp
@@ -52,7 +52,7 @@ CViewportResource::CViewportResource(SP<CWpViewport> resource_, SP<CWLSurfaceRes
});
listeners.surfacePrecommit = surface->events.precommit.registerListener([this](std::any d) {
- if (!surface || !surface->pending.texture)
+ if (!surface || !surface->pending.buffer)
return;
if (surface->pending.viewport.hasSource) {
diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp
index 9424a9d6..db274e3c 100644
--- a/src/protocols/XDGShell.cpp
+++ b/src/protocols/XDGShell.cpp
@@ -387,7 +387,7 @@ CXDGSurfaceResource::CXDGSurfaceResource(SP<CXdgSurface> resource_, SP<CXDGWMBas
if (toplevel)
toplevel->current = toplevel->pending;
- if UNLIKELY (initialCommit && surface->pending.texture) {
+ if UNLIKELY (initialCommit && surface->pending.buffer) {
resource->error(-1, "Buffer attached before initial commit");
return;
}
diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp
index 6b47b503..5462fbe9 100644
--- a/src/protocols/core/Compositor.cpp
+++ b/src/protocols/core/Compositor.cpp
@@ -12,6 +12,7 @@
#include "../DRMSyncobj.hpp"
#include "../../render/Renderer.hpp"
#include "config/ConfigValue.hpp"
+#include "render/Texture.hpp"
#include <cstring>
class CDefaultSurfaceRole : public ISurfaceRole {
@@ -91,10 +92,10 @@ CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : resource(reso
});
resource->setCommit([this](CWlSurface* r) {
- if (pending.texture)
+ if (pending.buffer)
pending.bufferDamage.intersect(CBox{{}, pending.bufferSize});
- if (!pending.texture)
+ if (!pending.buffer)
pending.size = {};
else if (pending.viewport.hasDestination)
pending.size = pending.viewport.destination;
@@ -399,36 +400,8 @@ CBox CWLSurfaceResource::extends() {
return full.getExtents();
}
-Vector2D CWLSurfaceResource::sourceSize() {
- if UNLIKELY (!current.texture)
- return {};
-
- if UNLIKELY (current.viewport.hasSource)
- return current.viewport.source.size();
-
- Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.bufferSize.y, current.bufferSize.x} : current.bufferSize;
- return trc / current.scale;
-}
-
-CRegion CWLSurfaceResource::accumulateCurrentBufferDamage() {
- if UNLIKELY (!current.texture)
- return {};
-
- CRegion surfaceDamage = current.damage;
- if (current.viewport.hasDestination) {
- Vector2D scale = sourceSize() / current.viewport.destination;
- surfaceDamage.scale(scale);
- }
-
- if (current.viewport.hasSource)
- surfaceDamage.translate(current.viewport.source.pos());
-
- Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.bufferSize.y, current.bufferSize.x} : current.bufferSize;
-
- return surfaceDamage.scale(current.scale).transform(wlTransformToHyprutils(invertTransform(current.transform)), trc.x, trc.y).add(current.bufferDamage);
-}
-
void CWLSurfaceResource::commitPendingState(SSurfaceState& state) {
+ auto lastTexture = current.texture;
if (state.newBuffer) {
state.newBuffer = false;
current = state;
@@ -437,20 +410,19 @@ void CWLSurfaceResource::commitPendingState(SSurfaceState& state) {
state.buffer.reset();
}
- if (current.texture)
- current.texture->m_eTransform = wlTransformToHyprutils(current.transform);
-
if (current.buffer) {
- const auto DAMAGE = accumulateCurrentBufferDamage();
- current.buffer->buffer->update(DAMAGE);
+ if (current.buffer->buffer->isSynchronous())
+ current.updateSynchronousTexture(lastTexture);
// if the surface is a cursor, update the shm buffer
// TODO: don't update the entire texture
- if (role->role() == SURFACE_ROLE_CURSOR && !DAMAGE.empty())
- updateCursorShm(DAMAGE);
+ if (role->role() == SURFACE_ROLE_CURSOR)
+ updateCursorShm(current.accumulateBufferDamage());
}
- // TODO: we should _accumulate_ and not replace above if sync
+ if (current.texture)
+ current.texture->m_eTransform = wlTransformToHyprutils(current.transform);
+
if (role->role() == SURFACE_ROLE_SUBSURFACE) {
auto subsurface = ((CSubsurfaceRole*)role.get())->subsurface.lock();
if (subsurface->sync)
@@ -478,6 +450,9 @@ void CWLSurfaceResource::commitPendingState(SSurfaceState& state) {
}
void CWLSurfaceResource::updateCursorShm(CRegion damage) {
+ if (damage.empty())
+ return;
+
auto buf = current.buffer ? current.buffer->buffer : SP<IHLBuffer>{};
if UNLIKELY (!buf)
diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp
index f958528c..5d2240a7 100644
--- a/src/protocols/core/Compositor.hpp
+++ b/src/protocols/core/Compositor.hpp
@@ -11,6 +11,7 @@
#include <vector>
#include <cstdint>
#include "../WaylandProtocol.hpp"
+#include "render/Texture.hpp"
#include "wayland.hpp"
#include "../../helpers/signal/Signal.hpp"
#include "../../helpers/math/Math.hpp"
@@ -75,7 +76,6 @@ class CWLSurfaceResource {
SP<CWlSurface> getResource();
CBox extends();
void resetRole();
- Vector2D sourceSize();
struct {
CSignal precommit; // before commit
@@ -102,7 +102,6 @@ class CWLSurfaceResource {
void breadthfirst(std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data);
SP<CWLSurfaceResource> findFirstPreorder(std::function<bool(SP<CWLSurfaceResource>)> fn);
- CRegion accumulateCurrentBufferDamage();
void presentFeedback(timespec* when, PHLMONITOR pMonitor, bool discarded = false);
void commitPendingState(SSurfaceState& state);
diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp
index 37a48fd3..420b4a3f 100644
--- a/src/protocols/core/Shm.cpp
+++ b/src/protocols/core/Shm.cpp
@@ -22,19 +22,12 @@ CWLSHMBuffer::CWLSHMBuffer(SP<CWLSHMPoolResource> pool_, uint32_t id, int32_t of
offset = offset_;
opaque = NFormatUtils::isFormatOpaque(NFormatUtils::shmToDRM(fmt_));
- texture = makeShared<CTexture>(NFormatUtils::shmToDRM(fmt), (uint8_t*)pool->data + offset, stride, size_);
-
resource = CWLBufferResource::create(makeShared<CWlBuffer>(pool_->resource->client(), 1, id));
listeners.bufferResourceDestroy = events.destroy.registerListener([this](std::any d) {
listeners.bufferResourceDestroy.reset();
PROTO::shm->destroyResource(this);
});
-
- success = texture->m_iTexID;
-
- if UNLIKELY (!success)
- Debug::log(ERR, "Failed creating a shm texture: null texture id");
}
CWLSHMBuffer::~CWLSHMBuffer() {
@@ -74,11 +67,11 @@ void CWLSHMBuffer::endDataPtr() {
}
bool CWLSHMBuffer::good() {
- return success;
+ return true;
}
void CWLSHMBuffer::update(const CRegion& damage) {
- texture->update(NFormatUtils::shmToDRM(fmt), (uint8_t*)pool->data + offset, stride, damage);
+ ;
}
CSHMPool::CSHMPool(CFileDescriptor fd_, size_t size_) : fd(std::move(fd_)), size(size_), data(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd.get(), 0)) {
diff --git a/src/protocols/core/Shm.hpp b/src/protocols/core/Shm.hpp
index fa5f29a4..61b26f12 100644
--- a/src/protocols/core/Shm.hpp
+++ b/src/protocols/core/Shm.hpp
@@ -50,8 +50,6 @@ class CWLSHMBuffer : public IHLBuffer {
SP<CSHMPool> pool;
private:
- bool success = false;
-
struct {
CHyprSignalListener bufferResourceDestroy;
} listeners;
diff --git a/src/protocols/types/SurfaceState.cpp b/src/protocols/types/SurfaceState.cpp
new file mode 100644
index 00000000..6f9636ff
--- /dev/null
+++ b/src/protocols/types/SurfaceState.cpp
@@ -0,0 +1,58 @@
+#include "SurfaceState.hpp"
+#include "helpers/Format.hpp"
+#include "protocols/types/Buffer.hpp"
+#include "render/Texture.hpp"
+
+Vector2D SSurfaceState::sourceSize() {
+ if UNLIKELY (!texture)
+ return {};
+
+ if UNLIKELY (viewport.hasSource)
+ return viewport.source.size();
+
+ Vector2D trc = transform % 2 == 1 ? Vector2D{bufferSize.y, bufferSize.x} : bufferSize;
+ return trc / scale;
+}
+
+CRegion SSurfaceState::accumulateBufferDamage() {
+ if (damage.empty())
+ return bufferDamage;
+
+ CRegion surfaceDamage = damage;
+ if (viewport.hasDestination) {
+ Vector2D scale = sourceSize() / viewport.destination;
+ surfaceDamage.scale(scale);
+ }
+
+ if (viewport.hasSource)
+ surfaceDamage.translate(viewport.source.pos());
+
+ Vector2D trc = transform % 2 == 1 ? Vector2D{bufferSize.y, bufferSize.x} : bufferSize;
+
+ bufferDamage = surfaceDamage.scale(scale).transform(wlTransformToHyprutils(invertTransform(transform)), trc.x, trc.y).add(bufferDamage);
+ damage.clear();
+ return bufferDamage;
+}
+
+void SSurfaceState::updateSynchronousTexture(SP<CTexture> lastTexture) {
+ auto [dataPtr, fmt, size] = buffer->buffer->beginDataPtr(0);
+ if (dataPtr) {
+ auto drmFmt = NFormatUtils::shmToDRM(fmt);
+ auto stride = bufferSize.y ? size / bufferSize.y : 0;
+ if (lastTexture && lastTexture->m_isSynchronous && lastTexture->m_vSize == bufferSize) {
+ texture = lastTexture;
+ texture->update(drmFmt, dataPtr, stride, accumulateBufferDamage());
+ } else
+ texture = makeShared<CTexture>(drmFmt, dataPtr, stride, bufferSize);
+ }
+ buffer->buffer->endDataPtr();
+}
+
+void SSurfaceState::reset() {
+ damage.clear();
+ bufferDamage.clear();
+ transform = WL_OUTPUT_TRANSFORM_NORMAL;
+ scale = 1;
+ offset = {};
+ size = {};
+}
diff --git a/src/protocols/types/SurfaceState.hpp b/src/protocols/types/SurfaceState.hpp
index cd9be5ca..b5093759 100644
--- a/src/protocols/types/SurfaceState.hpp
+++ b/src/protocols/types/SurfaceState.hpp
@@ -20,16 +20,12 @@ struct SSurfaceState {
Vector2D destination;
CBox source;
} viewport;
- bool rejected = false;
- bool newBuffer = false;
+ bool rejected = false;
+ bool newBuffer = false;
- //
- void reset() {
- damage.clear();
- bufferDamage.clear();
- transform = WL_OUTPUT_TRANSFORM_NORMAL;
- scale = 1;
- offset = {};
- size = {};
- }
+ Vector2D sourceSize();
+ // Translates damage into bufferDamage, clearing damage and returning the updated bufferDamage
+ CRegion accumulateBufferDamage();
+ void updateSynchronousTexture(SP<CTexture> lastTexture);
+ void reset();
};
diff --git a/src/render/Texture.cpp b/src/render/Texture.cpp
index 95efb15e..fd5b682e 100644
--- a/src/render/Texture.cpp
+++ b/src/render/Texture.cpp
@@ -64,8 +64,9 @@ void CTexture::createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t strid
const auto format = NFormatUtils::getPixelFormatFromDRM(drmFormat);
ASSERT(format);
- m_iType = format->withAlpha ? TEXTURE_RGBA : TEXTURE_RGBX;
- m_vSize = size_;
+ m_iType = format->withAlpha ? TEXTURE_RGBA : TEXTURE_RGBX;
+ m_vSize = size_;
+ m_isSynchronous = true;
allocate();
GLCALL(glBindTexture(GL_TEXTURE_2D, m_iTexID));
diff --git a/src/render/Texture.hpp b/src/render/Texture.hpp
index 60134707..039b5247 100644
--- a/src/render/Texture.hpp
+++ b/src/render/Texture.hpp
@@ -35,14 +35,15 @@ class CTexture {
void update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage);
const std::vector<uint8_t>& dataCopy();
- eTextureType m_iType = TEXTURE_RGBA;
- GLenum m_iTarget = GL_TEXTURE_2D;
- GLuint m_iTexID = 0;
- Vector2D m_vSize = {};
- void* m_pEglImage = nullptr;
- eTransform m_eTransform = HYPRUTILS_TRANSFORM_NORMAL;
- bool m_bOpaque = false;
- uint32_t m_iDrmFormat = 0; // for shm
+ eTextureType m_iType = TEXTURE_RGBA;
+ GLenum m_iTarget = GL_TEXTURE_2D;
+ GLuint m_iTexID = 0;
+ Vector2D m_vSize = {};
+ void* m_pEglImage = nullptr;
+ eTransform m_eTransform = HYPRUTILS_TRANSFORM_NORMAL;
+ bool m_bOpaque = false;
+ uint32_t m_iDrmFormat = 0; // for shm
+ bool m_isSynchronous = false;
private:
void createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size);
diff --git a/src/xwayland/XSurface.cpp b/src/xwayland/XSurface.cpp
index b297c29c..30e38ac2 100644
--- a/src/xwayland/XSurface.cpp
+++ b/src/xwayland/XSurface.cpp
@@ -62,12 +62,12 @@ void CXWaylandSurface::ensureListeners() {
});
listeners.commitSurface = surface->events.commit.registerListener([this](std::any d) {
- if (surface->pending.texture && !mapped) {
+ if (surface->current.texture && !mapped) {
map();
return;
}
- if (!surface->pending.texture && mapped) {
+ if (!surface->current.texture && mapped) {
unmap();
return;
}
@@ -131,7 +131,7 @@ void CXWaylandSurface::considerMap() {
return;
}
- if (surface->pending.texture) {
+ if (surface->current.texture) {
Debug::log(LOG, "XWayland surface: considerMap, sure, we have a buffer");
map();
return;