Skip to content

core: refactor and improve surface commit #9805

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Apr 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/helpers/Monitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1348,13 +1348,13 @@ bool CMonitor::attemptDirectScanout() {
return false;

// we can't scanout shm buffers.
const auto params = PSURFACE->current.buffer->buffer->dmabuf();
const auto params = PSURFACE->current.buffer->dmabuf();
if (!params.success || !PSURFACE->current.texture->m_pEglImage /* dmabuf */)
return false;

Debug::log(TRACE, "attemptDirectScanout: surface {:x} passed, will attempt, buffer {}", (uintptr_t)PSURFACE.get(), (uintptr_t)PSURFACE->current.buffer->buffer.get());
Debug::log(TRACE, "attemptDirectScanout: surface {:x} passed, will attempt, buffer {}", (uintptr_t)PSURFACE.get(), (uintptr_t)PSURFACE->current.buffer.buffer.get());

auto PBUFFER = PSURFACE->current.buffer->buffer;
auto PBUFFER = PSURFACE->current.buffer.buffer;

if (PBUFFER == output->state->state().buffer) {
if (scanoutNeedsCursorUpdate) {
Expand Down Expand Up @@ -1407,10 +1407,10 @@ bool CMonitor::attemptDirectScanout() {

auto explicitOptions = g_pHyprRenderer->getExplicitSyncSettings(output);

bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->current.buffer && PSURFACE->current.buffer->acquire && explicitOptions.explicitKMSEnabled;
bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->current.buffer && PSURFACE->current.acquire && explicitOptions.explicitKMSEnabled;
if (DOEXPLICIT) {
// wait for surface's explicit fence if present
inFence = PSURFACE->current.buffer->acquire->exportAsFD();
inFence = PSURFACE->current.acquire.exportAsFD();
if (inFence.isValid()) {
Debug::log(TRACE, "attemptDirectScanout: setting IN_FENCE for aq to {}", inFence.get());
output->state->setExplicitInFence(inFence.get());
Expand Down
103 changes: 23 additions & 80 deletions src/protocols/DRMSyncobj.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,100 +75,43 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(UP<CWpLinuxDrmSyncobjSurf
});

listeners.surfacePrecommit = surface->events.precommit.registerListener([this](std::any d) {
const bool PENDING_HAS_NEW_BUFFER = surface->pending.updated & SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_BUFFER;

if (!surface->pending.buffer && PENDING_HAS_NEW_BUFFER && !surface->pending.texture) {
removeAllWaiters();
surface->commitPendingState(surface->pending);
return; // null buffer attached.
if (!surface->pending.updated.buffer || !surface->pending.buffer) {
if (pendingAcquire.timeline() || pendingRelease.timeline()) {
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_BUFFER, "Missing buffer");
surface->pending.rejected = true;
}
return;
}

if (!surface->pending.buffer && !PENDING_HAS_NEW_BUFFER && surface->current.buffer) {
surface->current.bufferDamage.clear();
surface->current.damage.clear();
surface->commitPendingState(surface->current);
return; // no new buffer, but we still have current around and a commit happend, commit current again.
if (!pendingAcquire.timeline()) {
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_ACQUIRE_POINT, "Missing acquire timeline");
surface->pending.rejected = true;
return;
}

if (!surface->pending.buffer && !PENDING_HAS_NEW_BUFFER && !surface->current.buffer) {
surface->commitPendingState(surface->pending); // no pending buffer, no current buffer. probably first commit
if (!pendingRelease.timeline()) {
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_RELEASE_POINT, "Missing release timeline");
surface->pending.rejected = true;
return;
}

if (pendingAcquire.timeline()) {
surface->pending.buffer->acquire = makeUnique<CDRMSyncPointState>(std::move(pendingAcquire));
pendingAcquire = {};
if (pendingAcquire.timeline() == pendingRelease.timeline() && pendingAcquire.point() >= pendingRelease.point()) {
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_CONFLICTING_POINTS, "Acquire and release points are on the same timeline, and acquire >= release");
surface->pending.rejected = true;
return;
}

if (pendingRelease.timeline()) {
surface->pending.buffer->release = makeUnique<CDRMSyncPointState>(std::move(pendingRelease));
pendingRelease = {};
}
surface->pending.updated.acquire = true;
surface->pending.acquire = pendingAcquire;
pendingAcquire = {};

if (protocolError())
return;
surface->pending.buffer.release = pendingRelease;
pendingRelease = {};

const auto& state = pendingStates.emplace_back(makeShared<SSurfaceState>(surface->pending));
surface->pending.damage.clear();
surface->pending.bufferDamage.clear();
surface->pending.updated &= ~SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_BUFFER;
surface->pending.updated &= ~SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_DAMAGE;
surface->pending.buffer.reset();

state->buffer->buffer->syncReleaser = state->buffer->release->createSyncRelease();
state->buffer->acquire->addWaiter([this, surf = surface, wp = CWeakPointer<SSurfaceState>(*std::prev(pendingStates.end()))] {
if (!surf)
return;

surf->commitPendingState(*wp.lock());
std::erase(pendingStates, wp);
});
surface->pending.buffer->syncReleaser = surface->pending.buffer.release.createSyncRelease();
});
}

void CDRMSyncobjSurfaceResource::removeAllWaiters() {
for (auto& s : pendingStates) {
if (s && s->buffer && s->buffer->acquire)
s->buffer->acquire->timeline()->removeAllWaiters();
}

pendingStates.clear();
}

CDRMSyncobjSurfaceResource::~CDRMSyncobjSurfaceResource() {
removeAllWaiters();
}

bool CDRMSyncobjSurfaceResource::protocolError() {
if (!surface->pending.buffer) {
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_BUFFER, "Missing buffer");
surface->pending.rejected = true;
return true;
}

if (!surface->pending.buffer->acquire || !surface->pending.buffer->acquire->timeline()) {
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_ACQUIRE_POINT, "Missing acquire timeline");
surface->pending.rejected = true;
return true;
}

if (!surface->pending.buffer->release || !surface->pending.buffer->release->timeline()) {
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_RELEASE_POINT, "Missing release timeline");
surface->pending.rejected = true;
return true;
}

if (surface->pending.buffer->acquire->timeline() == surface->pending.buffer->release->timeline()) {
if (surface->pending.buffer->acquire->point() >= surface->pending.buffer->release->point()) {
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_CONFLICTING_POINTS, "Acquire and release points are on the same timeline, and acquire >= release");
surface->pending.rejected = true;
return true;
}
}

return false;
}

bool CDRMSyncobjSurfaceResource::good() {
return resource->resource();
}
Expand Down
11 changes: 4 additions & 7 deletions src/protocols/DRMSyncobj.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,11 @@
#include "../helpers/sync/SyncReleaser.hpp"
#include "linux-drm-syncobj-v1.hpp"
#include "../helpers/signal/Signal.hpp"
#include "types/SurfaceState.hpp"
#include <hyprutils/os/FileDescriptor.hpp>
#include <list>

class CWLSurfaceResource;
class CDRMSyncobjTimelineResource;
class CSyncTimeline;
struct SSurfaceState;

class CDRMSyncPointState {
public:
Expand All @@ -28,6 +25,10 @@ class CDRMSyncPointState {
Hyprutils::OS::CFileDescriptor exportAsFD();
void signal();

operator bool() const {
return m_timeline;
}

private:
SP<CSyncTimeline> m_timeline = {};
uint64_t m_point = 0;
Expand All @@ -38,19 +39,15 @@ class CDRMSyncPointState {
class CDRMSyncobjSurfaceResource {
public:
CDRMSyncobjSurfaceResource(UP<CWpLinuxDrmSyncobjSurfaceV1>&& resource_, SP<CWLSurfaceResource> surface_);
~CDRMSyncobjSurfaceResource();

bool protocolError();
bool good();

private:
void removeAllWaiters();
WP<CWLSurfaceResource> surface;
UP<CWpLinuxDrmSyncobjSurfaceV1> resource;

CDRMSyncPointState pendingAcquire;
CDRMSyncPointState pendingRelease;
std::vector<SP<SSurfaceState>> pendingStates;

struct {
CHyprSignalListener surfacePrecommit;
Expand Down
11 changes: 2 additions & 9 deletions src/protocols/Screencopy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,6 @@
#include <algorithm>
#include <functional>

CScreencopyFrame::~CScreencopyFrame() {
if (buffer && buffer->locked())
buffer->unlock();
}

CScreencopyFrame::CScreencopyFrame(SP<CZwlrScreencopyFrameV1> resource_, int32_t overlay_cursor, wl_resource* output, CBox box_) : resource(resource_) {
if UNLIKELY (!good())
return;
Expand Down Expand Up @@ -102,8 +97,6 @@ void CScreencopyFrame::copy(CZwlrScreencopyFrameV1* pFrame, wl_resource* buffer_
return;
}

PBUFFER->buffer->lock();

if UNLIKELY (PBUFFER->buffer->size != box.size()) {
LOGM(ERR, "Invalid dimensions in {:x}", (uintptr_t)this);
resource->error(ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions");
Expand Down Expand Up @@ -146,7 +139,7 @@ void CScreencopyFrame::copy(CZwlrScreencopyFrameV1* pFrame, wl_resource* buffer_
return;
}

buffer = PBUFFER->buffer;
buffer = CHLBufferReference(PBUFFER->buffer.lock());

PROTO::screencopy->m_vFramesAwaitingWrite.emplace_back(self);

Expand Down Expand Up @@ -207,7 +200,7 @@ void CScreencopyFrame::copyDmabuf(std::function<void(bool)> callback) {

CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX};

if (!g_pHyprRenderer->beginRender(pMonitor.lock(), fakeDamage, RENDER_MODE_TO_BUFFER, buffer.lock(), nullptr, true)) {
if (!g_pHyprRenderer->beginRender(pMonitor.lock(), fakeDamage, RENDER_MODE_TO_BUFFER, buffer.buffer, nullptr, true)) {
LOGM(ERR, "Can't copy: failed to begin rendering to dma frame");
callback(false);
return;
Expand Down
4 changes: 2 additions & 2 deletions src/protocols/Screencopy.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "../defines.hpp"
#include "./types/Buffer.hpp"
#include "wlr-screencopy-unstable-v1.hpp"
#include "WaylandProtocol.hpp"

Expand Down Expand Up @@ -50,7 +51,6 @@ class CScreencopyClient {
class CScreencopyFrame {
public:
CScreencopyFrame(SP<CZwlrScreencopyFrameV1> resource, int32_t overlay_cursor, wl_resource* output, CBox box);
~CScreencopyFrame();

bool good();

Expand All @@ -65,7 +65,7 @@ class CScreencopyFrame {
bool withDamage = false;
bool lockedSWCursors = false;

WP<IHLBuffer> buffer;
CHLBufferReference buffer;
bool bufferDMA = false;
uint32_t shmFormat = 0;
uint32_t dmabufFormat = 0;
Expand Down
11 changes: 2 additions & 9 deletions src/protocols/ToplevelExport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,6 @@ bool CToplevelExportClient::good() {
return resource->resource();
}

CToplevelExportFrame::~CToplevelExportFrame() {
if (buffer && buffer->locked())
buffer->unlock();
}

CToplevelExportFrame::CToplevelExportFrame(SP<CHyprlandToplevelExportFrameV1> resource_, int32_t overlayCursor_, PHLWINDOW pWindow_) : resource(resource_), pWindow(pWindow_) {
if UNLIKELY (!good())
return;
Expand Down Expand Up @@ -159,8 +154,6 @@ void CToplevelExportFrame::copy(CHyprlandToplevelExportFrameV1* pFrame, wl_resou
return;
}

PBUFFER->buffer->lock();

if UNLIKELY (PBUFFER->buffer->size != box.size()) {
resource->error(HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions");
PROTO::toplevelExport->destroyResource(this);
Expand Down Expand Up @@ -197,7 +190,7 @@ void CToplevelExportFrame::copy(CHyprlandToplevelExportFrameV1* pFrame, wl_resou
return;
}

buffer = PBUFFER->buffer;
buffer = CHLBufferReference(PBUFFER->buffer.lock());

m_ignoreDamage = ignoreDamage;

Expand Down Expand Up @@ -340,7 +333,7 @@ bool CToplevelExportFrame::copyDmabuf(timespec* now) {
g_pPointerManager->damageCursor(PMONITOR->self.lock());
}

if (!g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_TO_BUFFER, buffer.lock()))
if (!g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_TO_BUFFER, buffer.buffer))
return false;

g_pHyprOpenGL->clear(CHyprColor(0, 0, 0, 1.0));
Expand Down
3 changes: 1 addition & 2 deletions src/protocols/ToplevelExport.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ class CToplevelExportClient {
class CToplevelExportFrame {
public:
CToplevelExportFrame(SP<CHyprlandToplevelExportFrameV1> resource_, int32_t overlayCursor, PHLWINDOW pWindow);
~CToplevelExportFrame();

bool good();

Expand All @@ -55,7 +54,7 @@ class CToplevelExportFrame {
bool m_ignoreDamage = false;
bool lockedSWCursors = false;

WP<IHLBuffer> buffer;
CHLBufferReference buffer;
bool bufferDMA = false;
uint32_t shmFormat = 0;
uint32_t dmabufFormat = 0;
Expand Down
4 changes: 4 additions & 0 deletions src/protocols/Viewporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ CViewportResource::CViewportResource(SP<CWpViewport> resource_, SP<CWLSurfaceRes
return;
}

surface->pending.updated.viewport = true;

if (x == -1 && y == -1) {
surface->pending.viewport.hasDestination = false;
return;
Expand All @@ -35,6 +37,8 @@ CViewportResource::CViewportResource(SP<CWpViewport> resource_, SP<CWLSurfaceRes
return;
}

surface->pending.updated.viewport = true;

double x = wl_fixed_to_double(fx), y = wl_fixed_to_double(fy), w = wl_fixed_to_double(fw), h = wl_fixed_to_double(fh);

if (x == -1 && y == -1 && w == -1 && h == -1) {
Expand Down
Loading
Loading