diff options
| author | Ikalco <73481042+ikalco@users.noreply.github.com> | 2025-04-07 14:03:27 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-04-07 21:03:27 +0200 |
| commit | da86db43d47141b9d7332d3cb756ff7c05dbb39a (patch) | |
| tree | 7b187bc96aedceda108b51eff034ba75e33fb510 /src/protocols/DRMSyncobj.cpp | |
| parent | 70ae99f52162a0ed2723d45c63adfb2e61f4e2f5 (diff) | |
core: refactor and improve surface commit (#9805)
* make CHLBufferReference not a SP anymore
* copy over release and acquire points in CHLBufferReference
* use CHLBufferReference in screencopy and toplevel export
TODO: use CHLBufferReference in direct scanout properly
the only problem is the scanout buffer release timing,
specifically the onBackendRelease mechanism
* cleanup SSurfaceState and surface pending commit tracking
* move surface code from DRMSyncobj, and move acquire to SSurfaceState
* use queue for comitted pending surface states like proto says
"The content update is placed in a queue until it becomes active." - wl_surface::commit
* drop, not release, prev buffer if 2nd buffer wl_surface.attach is sent
"A wl_buffer that has been attached and then replaced by another attach instead of committed will not receive a release event, and is not used by the compositor." - wl_surface::attach
Diffstat (limited to 'src/protocols/DRMSyncobj.cpp')
| -rw-r--r-- | src/protocols/DRMSyncobj.cpp | 103 |
1 files changed, 23 insertions, 80 deletions
diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index 0a4ca439..c2960746 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -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(); } |
