mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-09-22 19:28:29 +00:00
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:
@@ -1348,13 +1348,13 @@ bool CMonitor::attemptDirectScanout() {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// we can't scanout shm buffers.
|
// 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 */)
|
if (!params.success || !PSURFACE->current.texture->m_pEglImage /* dmabuf */)
|
||||||
return false;
|
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 (PBUFFER == output->state->state().buffer) {
|
||||||
if (scanoutNeedsCursorUpdate) {
|
if (scanoutNeedsCursorUpdate) {
|
||||||
@@ -1407,10 +1407,10 @@ bool CMonitor::attemptDirectScanout() {
|
|||||||
|
|
||||||
auto explicitOptions = g_pHyprRenderer->getExplicitSyncSettings(output);
|
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) {
|
if (DOEXPLICIT) {
|
||||||
// wait for surface's explicit fence if present
|
// wait for surface's explicit fence if present
|
||||||
inFence = PSURFACE->current.buffer->acquire->exportAsFD();
|
inFence = PSURFACE->current.acquire.exportAsFD();
|
||||||
if (inFence.isValid()) {
|
if (inFence.isValid()) {
|
||||||
Debug::log(TRACE, "attemptDirectScanout: setting IN_FENCE for aq to {}", inFence.get());
|
Debug::log(TRACE, "attemptDirectScanout: setting IN_FENCE for aq to {}", inFence.get());
|
||||||
output->state->setExplicitInFence(inFence.get());
|
output->state->setExplicitInFence(inFence.get());
|
||||||
|
@@ -75,98 +75,41 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(UP<CWpLinuxDrmSyncobjSurf
|
|||||||
});
|
});
|
||||||
|
|
||||||
listeners.surfacePrecommit = surface->events.precommit.registerListener([this](std::any d) {
|
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.updated.buffer || !surface->pending.buffer) {
|
||||||
|
if (pendingAcquire.timeline() || pendingRelease.timeline()) {
|
||||||
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
|
|
||||||
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())
|
|
||||||
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();
|
|
||||||
|
|
||||||
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");
|
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_BUFFER, "Missing buffer");
|
||||||
surface->pending.rejected = true;
|
surface->pending.rejected = true;
|
||||||
return true;
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!surface->pending.buffer->acquire || !surface->pending.buffer->acquire->timeline()) {
|
if (!pendingAcquire.timeline()) {
|
||||||
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_ACQUIRE_POINT, "Missing acquire timeline");
|
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_ACQUIRE_POINT, "Missing acquire timeline");
|
||||||
surface->pending.rejected = true;
|
surface->pending.rejected = true;
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!surface->pending.buffer->release || !surface->pending.buffer->release->timeline()) {
|
if (!pendingRelease.timeline()) {
|
||||||
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_RELEASE_POINT, "Missing release timeline");
|
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_RELEASE_POINT, "Missing release timeline");
|
||||||
surface->pending.rejected = true;
|
surface->pending.rejected = true;
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (surface->pending.buffer->acquire->timeline() == surface->pending.buffer->release->timeline()) {
|
if (pendingAcquire.timeline() == pendingRelease.timeline() && pendingAcquire.point() >= pendingRelease.point()) {
|
||||||
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");
|
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;
|
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() {
|
bool CDRMSyncobjSurfaceResource::good() {
|
||||||
|
@@ -5,14 +5,11 @@
|
|||||||
#include "../helpers/sync/SyncReleaser.hpp"
|
#include "../helpers/sync/SyncReleaser.hpp"
|
||||||
#include "linux-drm-syncobj-v1.hpp"
|
#include "linux-drm-syncobj-v1.hpp"
|
||||||
#include "../helpers/signal/Signal.hpp"
|
#include "../helpers/signal/Signal.hpp"
|
||||||
#include "types/SurfaceState.hpp"
|
|
||||||
#include <hyprutils/os/FileDescriptor.hpp>
|
#include <hyprutils/os/FileDescriptor.hpp>
|
||||||
#include <list>
|
|
||||||
|
|
||||||
class CWLSurfaceResource;
|
class CWLSurfaceResource;
|
||||||
class CDRMSyncobjTimelineResource;
|
class CDRMSyncobjTimelineResource;
|
||||||
class CSyncTimeline;
|
class CSyncTimeline;
|
||||||
struct SSurfaceState;
|
|
||||||
|
|
||||||
class CDRMSyncPointState {
|
class CDRMSyncPointState {
|
||||||
public:
|
public:
|
||||||
@@ -28,6 +25,10 @@ class CDRMSyncPointState {
|
|||||||
Hyprutils::OS::CFileDescriptor exportAsFD();
|
Hyprutils::OS::CFileDescriptor exportAsFD();
|
||||||
void signal();
|
void signal();
|
||||||
|
|
||||||
|
operator bool() const {
|
||||||
|
return m_timeline;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SP<CSyncTimeline> m_timeline = {};
|
SP<CSyncTimeline> m_timeline = {};
|
||||||
uint64_t m_point = 0;
|
uint64_t m_point = 0;
|
||||||
@@ -38,19 +39,15 @@ class CDRMSyncPointState {
|
|||||||
class CDRMSyncobjSurfaceResource {
|
class CDRMSyncobjSurfaceResource {
|
||||||
public:
|
public:
|
||||||
CDRMSyncobjSurfaceResource(UP<CWpLinuxDrmSyncobjSurfaceV1>&& resource_, SP<CWLSurfaceResource> surface_);
|
CDRMSyncobjSurfaceResource(UP<CWpLinuxDrmSyncobjSurfaceV1>&& resource_, SP<CWLSurfaceResource> surface_);
|
||||||
~CDRMSyncobjSurfaceResource();
|
|
||||||
|
|
||||||
bool protocolError();
|
|
||||||
bool good();
|
bool good();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void removeAllWaiters();
|
|
||||||
WP<CWLSurfaceResource> surface;
|
WP<CWLSurfaceResource> surface;
|
||||||
UP<CWpLinuxDrmSyncobjSurfaceV1> resource;
|
UP<CWpLinuxDrmSyncobjSurfaceV1> resource;
|
||||||
|
|
||||||
CDRMSyncPointState pendingAcquire;
|
CDRMSyncPointState pendingAcquire;
|
||||||
CDRMSyncPointState pendingRelease;
|
CDRMSyncPointState pendingRelease;
|
||||||
std::vector<SP<SSurfaceState>> pendingStates;
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
CHyprSignalListener surfacePrecommit;
|
CHyprSignalListener surfacePrecommit;
|
||||||
|
@@ -14,11 +14,6 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <functional>
|
#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_) {
|
CScreencopyFrame::CScreencopyFrame(SP<CZwlrScreencopyFrameV1> resource_, int32_t overlay_cursor, wl_resource* output, CBox box_) : resource(resource_) {
|
||||||
if UNLIKELY (!good())
|
if UNLIKELY (!good())
|
||||||
return;
|
return;
|
||||||
@@ -102,8 +97,6 @@ void CScreencopyFrame::copy(CZwlrScreencopyFrameV1* pFrame, wl_resource* buffer_
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PBUFFER->buffer->lock();
|
|
||||||
|
|
||||||
if UNLIKELY (PBUFFER->buffer->size != box.size()) {
|
if UNLIKELY (PBUFFER->buffer->size != box.size()) {
|
||||||
LOGM(ERR, "Invalid dimensions in {:x}", (uintptr_t)this);
|
LOGM(ERR, "Invalid dimensions in {:x}", (uintptr_t)this);
|
||||||
resource->error(ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions");
|
resource->error(ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions");
|
||||||
@@ -146,7 +139,7 @@ void CScreencopyFrame::copy(CZwlrScreencopyFrameV1* pFrame, wl_resource* buffer_
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer = PBUFFER->buffer;
|
buffer = CHLBufferReference(PBUFFER->buffer.lock());
|
||||||
|
|
||||||
PROTO::screencopy->m_vFramesAwaitingWrite.emplace_back(self);
|
PROTO::screencopy->m_vFramesAwaitingWrite.emplace_back(self);
|
||||||
|
|
||||||
@@ -207,7 +200,7 @@ void CScreencopyFrame::copyDmabuf(std::function<void(bool)> callback) {
|
|||||||
|
|
||||||
CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX};
|
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");
|
LOGM(ERR, "Can't copy: failed to begin rendering to dma frame");
|
||||||
callback(false);
|
callback(false);
|
||||||
return;
|
return;
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../defines.hpp"
|
#include "../defines.hpp"
|
||||||
|
#include "./types/Buffer.hpp"
|
||||||
#include "wlr-screencopy-unstable-v1.hpp"
|
#include "wlr-screencopy-unstable-v1.hpp"
|
||||||
#include "WaylandProtocol.hpp"
|
#include "WaylandProtocol.hpp"
|
||||||
|
|
||||||
@@ -50,7 +51,6 @@ class CScreencopyClient {
|
|||||||
class CScreencopyFrame {
|
class CScreencopyFrame {
|
||||||
public:
|
public:
|
||||||
CScreencopyFrame(SP<CZwlrScreencopyFrameV1> resource, int32_t overlay_cursor, wl_resource* output, CBox box);
|
CScreencopyFrame(SP<CZwlrScreencopyFrameV1> resource, int32_t overlay_cursor, wl_resource* output, CBox box);
|
||||||
~CScreencopyFrame();
|
|
||||||
|
|
||||||
bool good();
|
bool good();
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ class CScreencopyFrame {
|
|||||||
bool withDamage = false;
|
bool withDamage = false;
|
||||||
bool lockedSWCursors = false;
|
bool lockedSWCursors = false;
|
||||||
|
|
||||||
WP<IHLBuffer> buffer;
|
CHLBufferReference buffer;
|
||||||
bool bufferDMA = false;
|
bool bufferDMA = false;
|
||||||
uint32_t shmFormat = 0;
|
uint32_t shmFormat = 0;
|
||||||
uint32_t dmabufFormat = 0;
|
uint32_t dmabufFormat = 0;
|
||||||
|
@@ -73,11 +73,6 @@ bool CToplevelExportClient::good() {
|
|||||||
return resource->resource();
|
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_) {
|
CToplevelExportFrame::CToplevelExportFrame(SP<CHyprlandToplevelExportFrameV1> resource_, int32_t overlayCursor_, PHLWINDOW pWindow_) : resource(resource_), pWindow(pWindow_) {
|
||||||
if UNLIKELY (!good())
|
if UNLIKELY (!good())
|
||||||
return;
|
return;
|
||||||
@@ -159,8 +154,6 @@ void CToplevelExportFrame::copy(CHyprlandToplevelExportFrameV1* pFrame, wl_resou
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PBUFFER->buffer->lock();
|
|
||||||
|
|
||||||
if UNLIKELY (PBUFFER->buffer->size != box.size()) {
|
if UNLIKELY (PBUFFER->buffer->size != box.size()) {
|
||||||
resource->error(HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions");
|
resource->error(HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions");
|
||||||
PROTO::toplevelExport->destroyResource(this);
|
PROTO::toplevelExport->destroyResource(this);
|
||||||
@@ -197,7 +190,7 @@ void CToplevelExportFrame::copy(CHyprlandToplevelExportFrameV1* pFrame, wl_resou
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer = PBUFFER->buffer;
|
buffer = CHLBufferReference(PBUFFER->buffer.lock());
|
||||||
|
|
||||||
m_ignoreDamage = ignoreDamage;
|
m_ignoreDamage = ignoreDamage;
|
||||||
|
|
||||||
@@ -340,7 +333,7 @@ bool CToplevelExportFrame::copyDmabuf(timespec* now) {
|
|||||||
g_pPointerManager->damageCursor(PMONITOR->self.lock());
|
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;
|
return false;
|
||||||
|
|
||||||
g_pHyprOpenGL->clear(CHyprColor(0, 0, 0, 1.0));
|
g_pHyprOpenGL->clear(CHyprColor(0, 0, 0, 1.0));
|
||||||
|
@@ -40,7 +40,6 @@ class CToplevelExportClient {
|
|||||||
class CToplevelExportFrame {
|
class CToplevelExportFrame {
|
||||||
public:
|
public:
|
||||||
CToplevelExportFrame(SP<CHyprlandToplevelExportFrameV1> resource_, int32_t overlayCursor, PHLWINDOW pWindow);
|
CToplevelExportFrame(SP<CHyprlandToplevelExportFrameV1> resource_, int32_t overlayCursor, PHLWINDOW pWindow);
|
||||||
~CToplevelExportFrame();
|
|
||||||
|
|
||||||
bool good();
|
bool good();
|
||||||
|
|
||||||
@@ -55,7 +54,7 @@ class CToplevelExportFrame {
|
|||||||
bool m_ignoreDamage = false;
|
bool m_ignoreDamage = false;
|
||||||
bool lockedSWCursors = false;
|
bool lockedSWCursors = false;
|
||||||
|
|
||||||
WP<IHLBuffer> buffer;
|
CHLBufferReference buffer;
|
||||||
bool bufferDMA = false;
|
bool bufferDMA = false;
|
||||||
uint32_t shmFormat = 0;
|
uint32_t shmFormat = 0;
|
||||||
uint32_t dmabufFormat = 0;
|
uint32_t dmabufFormat = 0;
|
||||||
|
@@ -15,6 +15,8 @@ CViewportResource::CViewportResource(SP<CWpViewport> resource_, SP<CWLSurfaceRes
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
surface->pending.updated.viewport = true;
|
||||||
|
|
||||||
if (x == -1 && y == -1) {
|
if (x == -1 && y == -1) {
|
||||||
surface->pending.viewport.hasDestination = false;
|
surface->pending.viewport.hasDestination = false;
|
||||||
return;
|
return;
|
||||||
@@ -35,6 +37,8 @@ CViewportResource::CViewportResource(SP<CWpViewport> resource_, SP<CWLSurfaceRes
|
|||||||
return;
|
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);
|
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) {
|
if (x == -1 && y == -1 && w == -1 && h == -1) {
|
||||||
|
@@ -71,23 +71,32 @@ CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : resource(reso
|
|||||||
resource->setOnDestroy([this](CWlSurface* r) { destroy(); });
|
resource->setOnDestroy([this](CWlSurface* r) { destroy(); });
|
||||||
|
|
||||||
resource->setAttach([this](CWlSurface* r, wl_resource* buffer, int32_t x, int32_t y) {
|
resource->setAttach([this](CWlSurface* r, wl_resource* buffer, int32_t x, int32_t y) {
|
||||||
pending.offset = {x, y};
|
pending.updated.buffer = true;
|
||||||
pending.updated |= SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_BUFFER | SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_OFFSET;
|
pending.updated.offset = true;
|
||||||
|
|
||||||
if (!buffer) {
|
pending.offset = {x, y};
|
||||||
pending.buffer.reset();
|
|
||||||
pending.texture.reset();
|
if (pending.buffer)
|
||||||
pending.bufferSize = Vector2D{};
|
pending.buffer.drop();
|
||||||
|
|
||||||
|
auto buf = buffer ? CWLBufferResource::fromResource(buffer) : nullptr;
|
||||||
|
|
||||||
|
if (buf && buf->buffer) {
|
||||||
|
pending.buffer = CHLBufferReference(buf->buffer.lock());
|
||||||
|
pending.texture = buf->buffer->texture;
|
||||||
|
pending.size = buf->buffer->size;
|
||||||
|
pending.bufferSize = buf->buffer->size;
|
||||||
} else {
|
} else {
|
||||||
auto res = CWLBufferResource::fromResource(buffer);
|
pending.buffer = {};
|
||||||
pending.buffer = res && res->buffer ? makeShared<CHLBufferReference>(res->buffer.lock(), self.lock()) : nullptr;
|
pending.texture.reset();
|
||||||
pending.size = res && res->buffer ? res->buffer->size : Vector2D{};
|
pending.size = Vector2D{};
|
||||||
pending.texture = res && res->buffer ? res->buffer->texture : nullptr;
|
pending.bufferSize = Vector2D{};
|
||||||
pending.bufferSize = res && res->buffer ? res->buffer->size : Vector2D{};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pending.bufferSize != current.bufferSize)
|
if (pending.bufferSize != current.bufferSize) {
|
||||||
|
pending.updated.damage = true;
|
||||||
pending.bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}};
|
pending.bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}};
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
resource->setCommit([this](CWlSurface* r) {
|
resource->setCommit([this](CWlSurface* r) {
|
||||||
@@ -109,34 +118,78 @@ CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : resource(reso
|
|||||||
|
|
||||||
events.precommit.emit();
|
events.precommit.emit();
|
||||||
if (pending.rejected) {
|
if (pending.rejected) {
|
||||||
|
pending.rejected = false;
|
||||||
dropPendingBuffer();
|
dropPendingBuffer();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!syncobj)
|
if ((!pending.updated.buffer) || // no new buffer attached
|
||||||
commitPendingState(pending);
|
(!pending.buffer && !pending.texture) || // null buffer attached
|
||||||
|
(!pending.updated.acquire && pending.buffer->isSynchronous()) // synchronous buffers (ex. shm) can be read immediately
|
||||||
|
) {
|
||||||
|
commitState(pending);
|
||||||
|
pending.reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// save state while we wait for buffer to become ready
|
||||||
|
const auto& state = pendingStates.emplace(makeUnique<SSurfaceState>(pending));
|
||||||
|
pending.reset();
|
||||||
|
|
||||||
|
auto whenReadable = [this, surf = self, state = WP<SSurfaceState>(pendingStates.back())] {
|
||||||
|
if (!surf || state.expired())
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (!pendingStates.empty() && pendingStates.front() != state) {
|
||||||
|
commitState(*pendingStates.front());
|
||||||
|
pendingStates.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
commitState(*pendingStates.front());
|
||||||
|
pendingStates.pop();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (state->updated.acquire) {
|
||||||
|
// wait on acquire point for this surface, from explicit sync protocol
|
||||||
|
state->acquire.addWaiter(whenReadable);
|
||||||
|
} else if (state->buffer->dmabuf().success) {
|
||||||
|
// https://www.kernel.org/doc/html/latest/driver-api/dma-buf.html#implicit-fence-poll-support
|
||||||
|
// TODO: wait for the dma-buf fd's to become readable
|
||||||
|
whenReadable();
|
||||||
|
} else {
|
||||||
|
// huh??? only buffers with acquire or dmabuf should get through here...
|
||||||
|
Debug::log(ERR, "BUG THIS: wl_surface.commit: non-acquire non-dmabuf buffers needs wait...");
|
||||||
|
whenReadable();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
resource->setDamage([this](CWlSurface* r, int32_t x, int32_t y, int32_t w, int32_t h) {
|
resource->setDamage([this](CWlSurface* r, int32_t x, int32_t y, int32_t w, int32_t h) {
|
||||||
pending.updated |= SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_DAMAGE;
|
pending.updated.damage = true;
|
||||||
pending.damage.add(CBox{x, y, w, h});
|
pending.damage.add(CBox{x, y, w, h});
|
||||||
});
|
});
|
||||||
resource->setDamageBuffer([this](CWlSurface* r, int32_t x, int32_t y, int32_t w, int32_t h) {
|
resource->setDamageBuffer([this](CWlSurface* r, int32_t x, int32_t y, int32_t w, int32_t h) {
|
||||||
pending.updated |= SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_DAMAGE;
|
pending.updated.damage = true;
|
||||||
pending.bufferDamage.add(CBox{x, y, w, h});
|
pending.bufferDamage.add(CBox{x, y, w, h});
|
||||||
});
|
});
|
||||||
|
|
||||||
resource->setSetBufferScale([this](CWlSurface* r, int32_t scale) {
|
resource->setSetBufferScale([this](CWlSurface* r, int32_t scale) {
|
||||||
if (scale == pending.scale)
|
if (scale == pending.scale)
|
||||||
return;
|
return;
|
||||||
pending.updated |= SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_SCALE | SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_DAMAGE;
|
|
||||||
|
pending.updated.scale = true;
|
||||||
|
pending.updated.damage = true;
|
||||||
|
|
||||||
pending.scale = scale;
|
pending.scale = scale;
|
||||||
pending.bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}};
|
pending.bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}};
|
||||||
});
|
});
|
||||||
|
|
||||||
resource->setSetBufferTransform([this](CWlSurface* r, uint32_t tr) {
|
resource->setSetBufferTransform([this](CWlSurface* r, uint32_t tr) {
|
||||||
if (tr == pending.transform)
|
if (tr == pending.transform)
|
||||||
return;
|
return;
|
||||||
pending.updated |= SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_TRANSFORM | SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_DAMAGE;
|
|
||||||
|
pending.updated.transform = true;
|
||||||
|
pending.updated.damage = true;
|
||||||
|
|
||||||
pending.transform = (wl_output_transform)tr;
|
pending.transform = (wl_output_transform)tr;
|
||||||
pending.bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}};
|
pending.bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}};
|
||||||
});
|
});
|
||||||
@@ -147,7 +200,7 @@ CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : resource(reso
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pending.updated |= SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_INPUT;
|
pending.updated.input = true;
|
||||||
|
|
||||||
auto RG = CWLRegionResource::fromResource(region);
|
auto RG = CWLRegionResource::fromResource(region);
|
||||||
pending.input = RG->region;
|
pending.input = RG->region;
|
||||||
@@ -159,7 +212,7 @@ CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : resource(reso
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pending.updated |= SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_OPAQUE;
|
pending.updated.opaque = true;
|
||||||
|
|
||||||
auto RG = CWLRegionResource::fromResource(region);
|
auto RG = CWLRegionResource::fromResource(region);
|
||||||
pending.opaque = RG->region;
|
pending.opaque = RG->region;
|
||||||
@@ -168,7 +221,7 @@ CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : resource(reso
|
|||||||
resource->setFrame([this](CWlSurface* r, uint32_t id) { callbacks.emplace_back(makeShared<CWLCallbackResource>(makeShared<CWlCallback>(pClient, 1, id))); });
|
resource->setFrame([this](CWlSurface* r, uint32_t id) { callbacks.emplace_back(makeShared<CWLCallbackResource>(makeShared<CWlCallback>(pClient, 1, id))); });
|
||||||
|
|
||||||
resource->setOffset([this](CWlSurface* r, int32_t x, int32_t y) {
|
resource->setOffset([this](CWlSurface* r, int32_t x, int32_t y) {
|
||||||
pending.updated |= SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_OFFSET;
|
pending.updated.offset = true;
|
||||||
pending.offset = {x, y};
|
pending.offset = {x, y};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -188,11 +241,11 @@ void CWLSurfaceResource::destroy() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CWLSurfaceResource::dropPendingBuffer() {
|
void CWLSurfaceResource::dropPendingBuffer() {
|
||||||
pending.buffer.reset();
|
pending.buffer = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWLSurfaceResource::dropCurrentBuffer() {
|
void CWLSurfaceResource::dropCurrentBuffer() {
|
||||||
current.buffer.reset();
|
current.buffer = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
SP<CWLSurfaceResource> CWLSurfaceResource::fromResource(wl_resource* res) {
|
SP<CWLSurfaceResource> CWLSurfaceResource::fromResource(wl_resource* res) {
|
||||||
@@ -279,7 +332,6 @@ void CWLSurfaceResource::resetRole() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CWLSurfaceResource::bfHelper(std::vector<SP<CWLSurfaceResource>> const& nodes, std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data) {
|
void CWLSurfaceResource::bfHelper(std::vector<SP<CWLSurfaceResource>> const& nodes, std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data) {
|
||||||
|
|
||||||
std::vector<SP<CWLSurfaceResource>> nodes2;
|
std::vector<SP<CWLSurfaceResource>> nodes2;
|
||||||
nodes2.reserve(nodes.size() * 2);
|
nodes2.reserve(nodes.size() * 2);
|
||||||
|
|
||||||
@@ -424,13 +476,12 @@ CBox CWLSurfaceResource::extends() {
|
|||||||
return full.getExtents();
|
return full.getExtents();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWLSurfaceResource::commitPendingState(SSurfaceState& state) {
|
void CWLSurfaceResource::commitState(SSurfaceState& state) {
|
||||||
auto lastTexture = current.texture;
|
auto lastTexture = current.texture;
|
||||||
current.updateFrom(state);
|
current.updateFrom(state);
|
||||||
state.updated = 0;
|
|
||||||
|
|
||||||
if (current.buffer) {
|
if (current.buffer) {
|
||||||
if (current.buffer->buffer->isSynchronous())
|
if (current.buffer->isSynchronous())
|
||||||
current.updateSynchronousTexture(lastTexture);
|
current.updateSynchronousTexture(lastTexture);
|
||||||
|
|
||||||
// if the surface is a cursor, update the shm buffer
|
// if the surface is a cursor, update the shm buffer
|
||||||
@@ -465,7 +516,7 @@ void CWLSurfaceResource::commitPendingState(SSurfaceState& state) {
|
|||||||
// release the buffer if it's synchronous (SHM) as update() has done everything thats needed
|
// release the buffer if it's synchronous (SHM) as update() has done everything thats needed
|
||||||
// so we can let the app know we're done.
|
// so we can let the app know we're done.
|
||||||
// if it doesn't have a role, we can't release it yet, in case it gets turned into a cursor.
|
// if it doesn't have a role, we can't release it yet, in case it gets turned into a cursor.
|
||||||
if (current.buffer && current.buffer->buffer && current.buffer->buffer->isSynchronous() && role->role() != SURFACE_ROLE_UNASSIGNED)
|
if (current.buffer && current.buffer->isSynchronous() && role->role() != SURFACE_ROLE_UNASSIGNED)
|
||||||
dropCurrentBuffer();
|
dropCurrentBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -473,7 +524,7 @@ void CWLSurfaceResource::updateCursorShm(CRegion damage) {
|
|||||||
if (damage.empty())
|
if (damage.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto buf = current.buffer ? current.buffer->buffer : SP<IHLBuffer>{};
|
auto buf = current.buffer ? current.buffer : SP<IHLBuffer>{};
|
||||||
|
|
||||||
if UNLIKELY (!buf)
|
if UNLIKELY (!buf)
|
||||||
return;
|
return;
|
||||||
|
@@ -9,6 +9,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <queue>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include "../WaylandProtocol.hpp"
|
#include "../WaylandProtocol.hpp"
|
||||||
#include "../../render/Texture.hpp"
|
#include "../../render/Texture.hpp"
|
||||||
@@ -87,6 +88,7 @@ class CWLSurfaceResource {
|
|||||||
} events;
|
} events;
|
||||||
|
|
||||||
SSurfaceState current, pending;
|
SSurfaceState current, pending;
|
||||||
|
std::queue<UP<SSurfaceState>> pendingStates;
|
||||||
|
|
||||||
std::vector<SP<CWLCallbackResource>> callbacks;
|
std::vector<SP<CWLCallbackResource>> callbacks;
|
||||||
WP<CWLSurfaceResource> self;
|
WP<CWLSurfaceResource> self;
|
||||||
@@ -103,7 +105,7 @@ class CWLSurfaceResource {
|
|||||||
void breadthfirst(std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data);
|
void breadthfirst(std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data);
|
||||||
SP<CWLSurfaceResource> findFirstPreorder(std::function<bool(SP<CWLSurfaceResource>)> fn);
|
SP<CWLSurfaceResource> findFirstPreorder(std::function<bool(SP<CWLSurfaceResource>)> fn);
|
||||||
void presentFeedback(timespec* when, PHLMONITOR pMonitor, bool discarded = false);
|
void presentFeedback(timespec* when, PHLMONITOR pMonitor, bool discarded = false);
|
||||||
void commitPendingState(SSurfaceState& state);
|
void commitState(SSurfaceState& state);
|
||||||
|
|
||||||
// returns a pair: found surface (null if not found) and surface local coords.
|
// returns a pair: found surface (null if not found) and surface local coords.
|
||||||
// localCoords param is relative to 0,0 of this surface
|
// localCoords param is relative to 0,0 of this surface
|
||||||
|
@@ -40,13 +40,61 @@ void IHLBuffer::onBackendRelease(const std::function<void()>& fn) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
CHLBufferReference::CHLBufferReference(SP<IHLBuffer> buffer_, SP<CWLSurfaceResource> surface_) : buffer(buffer_), surface(surface_) {
|
CHLBufferReference::CHLBufferReference() : buffer(nullptr) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHLBufferReference::CHLBufferReference(const CHLBufferReference& other) : release(other.release), buffer(other.buffer) {
|
||||||
|
if (buffer)
|
||||||
|
buffer->lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
CHLBufferReference::CHLBufferReference(SP<IHLBuffer> buffer_) : buffer(buffer_) {
|
||||||
|
if (buffer)
|
||||||
buffer->lock();
|
buffer->lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
CHLBufferReference::~CHLBufferReference() {
|
CHLBufferReference::~CHLBufferReference() {
|
||||||
|
if (buffer)
|
||||||
|
buffer->unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
CHLBufferReference& CHLBufferReference::operator=(const CHLBufferReference& other) {
|
||||||
|
if (other.buffer)
|
||||||
|
other.buffer->lock();
|
||||||
|
if (buffer)
|
||||||
|
buffer->unlock();
|
||||||
|
buffer = other.buffer;
|
||||||
|
release = other.release;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CHLBufferReference::operator==(const CHLBufferReference& other) const {
|
||||||
|
return buffer == other.buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CHLBufferReference::operator==(const SP<IHLBuffer>& other) const {
|
||||||
|
return buffer == other;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CHLBufferReference::operator==(const SP<Aquamarine::IBuffer>& other) const {
|
||||||
|
return buffer == other;
|
||||||
|
}
|
||||||
|
|
||||||
|
SP<IHLBuffer> CHLBufferReference::operator->() const {
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHLBufferReference::operator bool() const {
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHLBufferReference::drop() {
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
buffer->unlock();
|
buffer->nLocks--;
|
||||||
|
ASSERT(buffer->nLocks >= 0);
|
||||||
|
|
||||||
|
buffer = nullptr;
|
||||||
}
|
}
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
#include <aquamarine/buffer/Buffer.hpp>
|
#include <aquamarine/buffer/Buffer.hpp>
|
||||||
|
|
||||||
class CSyncReleaser;
|
class CSyncReleaser;
|
||||||
|
class CHLBufferReference;
|
||||||
|
|
||||||
class IHLBuffer : public Aquamarine::IBuffer {
|
class IHLBuffer : public Aquamarine::IBuffer {
|
||||||
public:
|
public:
|
||||||
@@ -36,19 +37,28 @@ class IHLBuffer : public Aquamarine::IBuffer {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
int nLocks = 0;
|
int nLocks = 0;
|
||||||
|
|
||||||
|
friend class CHLBufferReference;
|
||||||
};
|
};
|
||||||
|
|
||||||
// for ref-counting. Releases in ~dtor
|
// for ref-counting. Releases in ~dtor
|
||||||
// surface optional
|
|
||||||
class CHLBufferReference {
|
class CHLBufferReference {
|
||||||
public:
|
public:
|
||||||
CHLBufferReference(SP<IHLBuffer> buffer, SP<CWLSurfaceResource> surface);
|
CHLBufferReference();
|
||||||
|
CHLBufferReference(const CHLBufferReference& other);
|
||||||
|
CHLBufferReference(SP<IHLBuffer> buffer);
|
||||||
~CHLBufferReference();
|
~CHLBufferReference();
|
||||||
|
|
||||||
SP<IHLBuffer> buffer;
|
CHLBufferReference& operator=(const CHLBufferReference& other);
|
||||||
UP<CDRMSyncPointState> acquire;
|
bool operator==(const CHLBufferReference& other) const;
|
||||||
UP<CDRMSyncPointState> release;
|
bool operator==(const SP<IHLBuffer>& other) const;
|
||||||
|
bool operator==(const SP<Aquamarine::IBuffer>& other) const;
|
||||||
|
SP<IHLBuffer> operator->() const;
|
||||||
|
operator bool() const;
|
||||||
|
|
||||||
private:
|
// unlock and drop the buffer without sending release
|
||||||
WP<CWLSurfaceResource> surface;
|
void drop();
|
||||||
|
|
||||||
|
CDRMSyncPointState release;
|
||||||
|
SP<IHLBuffer> buffer;
|
||||||
};
|
};
|
||||||
|
@@ -35,7 +35,7 @@ CRegion SSurfaceState::accumulateBufferDamage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SSurfaceState::updateSynchronousTexture(SP<CTexture> lastTexture) {
|
void SSurfaceState::updateSynchronousTexture(SP<CTexture> lastTexture) {
|
||||||
auto [dataPtr, fmt, size] = buffer->buffer->beginDataPtr(0);
|
auto [dataPtr, fmt, size] = buffer->beginDataPtr(0);
|
||||||
if (dataPtr) {
|
if (dataPtr) {
|
||||||
auto drmFmt = NFormatUtils::shmToDRM(fmt);
|
auto drmFmt = NFormatUtils::shmToDRM(fmt);
|
||||||
auto stride = bufferSize.y ? size / bufferSize.y : 0;
|
auto stride = bufferSize.y ? size / bufferSize.y : 0;
|
||||||
@@ -45,49 +45,56 @@ void SSurfaceState::updateSynchronousTexture(SP<CTexture> lastTexture) {
|
|||||||
} else
|
} else
|
||||||
texture = makeShared<CTexture>(drmFmt, dataPtr, stride, bufferSize);
|
texture = makeShared<CTexture>(drmFmt, dataPtr, stride, bufferSize);
|
||||||
}
|
}
|
||||||
buffer->buffer->endDataPtr();
|
buffer->endDataPtr();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSurfaceState::reset() {
|
void SSurfaceState::reset() {
|
||||||
|
updated.all = false;
|
||||||
|
|
||||||
|
// After commit, there is no pending buffer until the next attach.
|
||||||
|
buffer = {};
|
||||||
|
|
||||||
|
// applies only to the buffer that is attached to the surface
|
||||||
|
acquire = {};
|
||||||
|
|
||||||
|
// wl_surface.commit assings pending ... and clears pending damage.
|
||||||
damage.clear();
|
damage.clear();
|
||||||
bufferDamage.clear();
|
bufferDamage.clear();
|
||||||
transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
|
||||||
scale = 1;
|
|
||||||
offset = {};
|
|
||||||
size = {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSurfaceState::updateFrom(SSurfaceState& ref) {
|
void SSurfaceState::updateFrom(SSurfaceState& ref) {
|
||||||
updated = ref.updated;
|
updated = ref.updated;
|
||||||
|
|
||||||
if (ref.updated & SURFACE_UPDATED_BUFFER) {
|
if (ref.updated.buffer) {
|
||||||
ref.updated &= ~SURFACE_UPDATED_BUFFER;
|
buffer = ref.buffer;
|
||||||
*this = ref;
|
texture = ref.texture;
|
||||||
ref.damage.clear();
|
size = ref.size;
|
||||||
ref.bufferDamage.clear();
|
bufferSize = ref.bufferSize;
|
||||||
ref.buffer.reset();
|
}
|
||||||
} else {
|
|
||||||
if (ref.updated & SURFACE_UPDATED_DAMAGE) {
|
if (ref.updated.damage) {
|
||||||
damage = ref.damage;
|
damage = ref.damage;
|
||||||
bufferDamage = ref.bufferDamage;
|
bufferDamage = ref.bufferDamage;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ref.updated & SURFACE_UPDATED_INPUT)
|
if (ref.updated.input)
|
||||||
input = ref.input;
|
input = ref.input;
|
||||||
|
|
||||||
if (ref.updated & SURFACE_UPDATED_OPAQUE)
|
if (ref.updated.opaque)
|
||||||
opaque = ref.opaque;
|
opaque = ref.opaque;
|
||||||
|
|
||||||
if (ref.updated & SURFACE_UPDATED_OFFSET)
|
if (ref.updated.offset)
|
||||||
offset = ref.offset;
|
offset = ref.offset;
|
||||||
|
|
||||||
if (ref.updated & SURFACE_UPDATED_SCALE)
|
if (ref.updated.scale)
|
||||||
scale = ref.scale;
|
scale = ref.scale;
|
||||||
|
|
||||||
if (ref.updated & SURFACE_UPDATED_VIEWPORT)
|
if (ref.updated.transform)
|
||||||
|
transform = ref.transform;
|
||||||
|
|
||||||
|
if (ref.updated.viewport)
|
||||||
viewport = ref.viewport;
|
viewport = ref.viewport;
|
||||||
|
|
||||||
if (ref.updated & SURFACE_UPDATED_TRANSFORM)
|
if (ref.updated.acquire)
|
||||||
transform = ref.transform;
|
acquire = ref.acquire;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -2,44 +2,59 @@
|
|||||||
|
|
||||||
#include "../../helpers/math/Math.hpp"
|
#include "../../helpers/math/Math.hpp"
|
||||||
#include "../WaylandProtocol.hpp"
|
#include "../WaylandProtocol.hpp"
|
||||||
|
#include "./Buffer.hpp"
|
||||||
|
|
||||||
class CHLBufferReference;
|
|
||||||
class CTexture;
|
class CTexture;
|
||||||
|
class CDRMSyncPointState;
|
||||||
|
|
||||||
struct SSurfaceState {
|
struct SSurfaceState {
|
||||||
enum eUpdatedProperties : uint8_t {
|
union {
|
||||||
SURFACE_UPDATED_OPAQUE = 1 << 0,
|
uint16_t all = 0;
|
||||||
SURFACE_UPDATED_INPUT = 1 << 1,
|
struct {
|
||||||
SURFACE_UPDATED_DAMAGE = 1 << 2,
|
bool buffer : 1;
|
||||||
SURFACE_UPDATED_SCALE = 1 << 3,
|
bool damage : 1;
|
||||||
SURFACE_UPDATED_BUFFER = 1 << 4,
|
bool opaque : 1;
|
||||||
SURFACE_UPDATED_OFFSET = 1 << 5,
|
bool input : 1;
|
||||||
SURFACE_UPDATED_VIEWPORT = 1 << 6,
|
bool transform : 1;
|
||||||
SURFACE_UPDATED_TRANSFORM = 1 << 7,
|
bool scale : 1;
|
||||||
|
bool offset : 1;
|
||||||
|
bool viewport : 1;
|
||||||
|
bool acquire : 1;
|
||||||
};
|
};
|
||||||
|
} updated;
|
||||||
|
|
||||||
CRegion opaque, input = CBox{{}, {INT32_MAX, INT32_MAX}}, damage, bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}} /* initial damage */;
|
bool rejected = false;
|
||||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
|
||||||
int scale = 1;
|
// initial values, copied from protocol text
|
||||||
SP<CHLBufferReference> buffer; // buffer ref will be released once the buffer is no longer locked. For checking if a buffer is attached to this state, check texture.
|
CHLBufferReference buffer = {}; // The initial surface contents are void
|
||||||
SP<CTexture> texture;
|
CRegion damage, bufferDamage; // The initial value for pending damage is empty
|
||||||
Vector2D offset;
|
CRegion opaque; // The initial value for an opaque region is empty
|
||||||
|
CRegion input = CBox{{}, {INT32_MAX, INT32_MAX}}; // The initial value for an input region is infinite
|
||||||
|
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; // A newly created surface has its buffer transformation set to normal
|
||||||
|
int scale = 1; // A newly created surface has its buffer scale set to 1
|
||||||
|
|
||||||
|
// these don't have well defined initial values in the protocol, but these work
|
||||||
Vector2D size, bufferSize;
|
Vector2D size, bufferSize;
|
||||||
|
Vector2D offset;
|
||||||
|
|
||||||
|
// viewporter protocol surface state
|
||||||
struct {
|
struct {
|
||||||
bool hasDestination = false;
|
bool hasDestination = false;
|
||||||
bool hasSource = false;
|
bool hasSource = false;
|
||||||
Vector2D destination;
|
Vector2D destination;
|
||||||
CBox source;
|
CBox source;
|
||||||
} viewport;
|
} viewport;
|
||||||
bool rejected = false;
|
|
||||||
uint8_t updated = 0; // eUpdatedProperties. Stores what the last update changed
|
|
||||||
|
|
||||||
Vector2D sourceSize();
|
Vector2D sourceSize();
|
||||||
// Translates damage into bufferDamage, clearing damage and returning the updated bufferDamage
|
|
||||||
CRegion accumulateBufferDamage();
|
// drm syncobj protocol surface state
|
||||||
|
CDRMSyncPointState acquire;
|
||||||
|
|
||||||
|
// texture of surface content, used for rendering
|
||||||
|
SP<CTexture> texture;
|
||||||
void updateSynchronousTexture(SP<CTexture> lastTexture);
|
void updateSynchronousTexture(SP<CTexture> lastTexture);
|
||||||
void reset();
|
|
||||||
// updates this state from a reference state. Mutates the reference state. If a new buffer is committed,
|
// helpers
|
||||||
// reference state gets its damage and buffer cleared.
|
CRegion accumulateBufferDamage(); // transforms state.damage and merges it into state.bufferDamage
|
||||||
void updateFrom(SSurfaceState& ref);
|
void updateFrom(SSurfaceState& ref); // updates this state based on a reference state.
|
||||||
|
void reset(); // resets pending state after commit
|
||||||
};
|
};
|
||||||
|
@@ -1565,10 +1565,10 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
|
|||||||
Debug::log(TRACE, "Explicit: can't add sync, monitor has no EGLSync");
|
Debug::log(TRACE, "Explicit: can't add sync, monitor has no EGLSync");
|
||||||
else {
|
else {
|
||||||
for (auto const& e : explicitPresented) {
|
for (auto const& e : explicitPresented) {
|
||||||
if (!e->current.buffer || !e->current.buffer->buffer->syncReleaser)
|
if (!e->current.buffer || !e->current.buffer->syncReleaser)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
e->current.buffer->buffer->syncReleaser->addReleaseSync(pMonitor->eglSync);
|
e->current.buffer->syncReleaser->addReleaseSync(pMonitor->eglSync);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user