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
This commit is contained in:
parent
70ae99f521
commit
da86db43d4
15 changed files with 285 additions and 223 deletions
|
|
@ -75,98 +75,41 @@ 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.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 (!surface->pending.buffer && !PENDING_HAS_NEW_BUFFER && !surface->current.buffer) {
|
||||
surface->commitPendingState(surface->pending); // no pending buffer, no current buffer. probably first commit
|
||||
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 (pendingAcquire.timeline()) {
|
||||
surface->pending.buffer->acquire = makeUnique<CDRMSyncPointState>(std::move(pendingAcquire));
|
||||
pendingAcquire = {};
|
||||
}
|
||||
|
||||
if (pendingRelease.timeline()) {
|
||||
surface->pending.buffer->release = makeUnique<CDRMSyncPointState>(std::move(pendingRelease));
|
||||
pendingRelease = {};
|
||||
}
|
||||
|
||||
if (protocolError())
|
||||
if (!pendingAcquire.timeline()) {
|
||||
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_ACQUIRE_POINT, "Missing acquire timeline");
|
||||
surface->pending.rejected = true;
|
||||
return;
|
||||
}
|
||||
|
||||
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();
|
||||
if (!pendingRelease.timeline()) {
|
||||
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_RELEASE_POINT, "Missing release timeline");
|
||||
surface->pending.rejected = true;
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
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()) {
|
||||
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 true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
surface->pending.updated.acquire = true;
|
||||
surface->pending.acquire = pendingAcquire;
|
||||
pendingAcquire = {};
|
||||
|
||||
surface->pending.buffer.release = pendingRelease;
|
||||
pendingRelease = {};
|
||||
|
||||
surface->pending.buffer->syncReleaser = surface->pending.buffer.release.createSyncRelease();
|
||||
});
|
||||
}
|
||||
|
||||
bool CDRMSyncobjSurfaceResource::good() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue