Bug 1961723 [Linux] Add WaylandBufferDMABUFHolder class to cache wl_buffer and allow WaylandBufferDMABUF to set wl_buffer from external source r=emilio

If DMABufSurface are recycled we don't want to create/delete wl_buffer for recycled frames as it eats GPU/power resources.
Instead store wl_buffers for DMABuf surfaces and re-use them if possible.
The behaviour is inspired by MPV which does the same.

Differential Revision: https://phabricator.services.mozilla.com/D248224
This commit is contained in:
stransky
2025-05-13 08:26:16 +00:00
committed by stransky@redhat.com
parent d22a34224c
commit b21bb9b241
2 changed files with 81 additions and 3 deletions

View File

@@ -123,9 +123,15 @@ void WaylandBuffer::DeleteWlBuffer() {
if (!mWLBuffer) {
return;
}
LOGWAYLAND("WaylandBuffer::DeleteWlBuffer() [%p] wl_buffer [%p]\n",
(void*)this, mWLBuffer);
MozClearPointer(mWLBuffer, wl_buffer_destroy);
LOGWAYLAND("WaylandBuffer::DeleteWlBuffer() [%p] wl_buffer [%p] managed %d",
(void*)this, mWLBuffer, mManagingWLBuffer);
if (mManagingWLBuffer) {
MozClearPointer(mWLBuffer, wl_buffer_destroy);
} else {
// Remove reference to this WaylandBuffer
wl_proxy_set_user_data((wl_proxy*)mWLBuffer, nullptr);
mWLBuffer = nullptr;
}
}
void WaylandBuffer::ReturnBufferDetached(WaylandSurfaceLock& aSurfaceLock) {
@@ -137,6 +143,28 @@ void WaylandBuffer::ReturnBufferDetached(WaylandSurfaceLock& aSurfaceLock) {
mAttachedToSurface = nullptr;
}
wl_buffer* WaylandBuffer::CreateAndTakeWLBuffer() {
LOGWAYLAND("WaylandBuffer::CreateAndTakeWLBuffer() [%p]", (void*)this);
MOZ_DIAGNOSTIC_ASSERT(!mAttachedToSurface);
if (!CreateWlBuffer()) {
return nullptr;
}
mManagingWLBuffer = false;
return mWLBuffer;
}
void WaylandBuffer::SetExternalWLBuffer(wl_buffer* aWLBuffer) {
LOGWAYLAND("WaylandBuffer::SetExternalWLBuffer() [%p] wl_buffer %p",
(void*)this, aWLBuffer);
MOZ_DIAGNOSTIC_ASSERT(!mAttachedToSurface);
MOZ_DIAGNOSTIC_ASSERT(!mWLBuffer);
mManagingWLBuffer = false;
mWLBuffer = aWLBuffer;
mWLBufferID = reinterpret_cast<uintptr_t>(mWLBuffer);
}
struct SurfaceAndBuffer {
SurfaceAndBuffer(WaylandSurface* aSurface, WaylandBuffer* aBuffer)
: mSurface(aSurface), mBuffer(aBuffer) {};
@@ -378,4 +406,27 @@ void WaylandBufferDMABUF::DumpToFile(const char* aHint) {
}
#endif
WaylandBufferDMABUFHolder::WaylandBufferDMABUFHolder(DMABufSurface* aSurface,
wl_buffer* aWLBuffer)
: mWLBuffer(aWLBuffer) {
mUID = aSurface->GetUID();
mPID = aSurface->GetPID();
LOGWAYLAND(
"WaylandBufferDMABUFHolder::WaylandBufferDMABUFHolder wl_buffer [%p] UID "
"%d PID %d",
mWLBuffer, mUID, mPID);
}
WaylandBufferDMABUFHolder::~WaylandBufferDMABUFHolder() {
LOGWAYLAND(
"WaylandBufferDMABUFHolder::~WaylandBufferDMABUFHolder wl_buffer [%p] "
"UID %d PID %d",
mWLBuffer, mUID, mPID);
MozClearPointer(mWLBuffer, wl_buffer_destroy);
}
bool WaylandBufferDMABUFHolder::Matches(DMABufSurface* aSurface) const {
return mUID == aSurface->GetUID() && mPID == aSurface->GetPID();
}
} // namespace mozilla::widget

View File

@@ -85,6 +85,13 @@ class WaylandBuffer {
virtual void DumpToFile(const char* aHint) = 0;
#endif
// Create and move away wl_buffer and mark is as not managed.
// From this point wl_buffer is not owned by WaylandBuffer.
wl_buffer* CreateAndTakeWLBuffer();
// Set wl_buffer from external source (WaylandBufferDMABUFHolder).
void SetExternalWLBuffer(wl_buffer* aWLBuffer);
protected:
explicit WaylandBuffer(const LayoutDeviceIntSize& aSize);
virtual ~WaylandBuffer() = default;
@@ -105,6 +112,11 @@ class WaylandBuffer {
wl_buffer* mWLBuffer = nullptr;
uintptr_t mWLBufferID = 0;
// Owns and manages WL buffer. If set to false, wl_buffer is managed by
// someone else (for instance WaylandBufferDMABUFHolder)
// and WaylandBuffer can't destroy it.
bool mManagingWLBuffer = true;
// Wayland buffer is tied to WaylandSurface.
// We keep reference to WaylandSurface until WaylandSurface returns the
// buffer.
@@ -192,6 +204,21 @@ class WaylandBufferDMABUF final : public WaylandBuffer {
RefPtr<DMABufSurface> mDMABufSurface;
};
class WaylandBufferDMABUFHolder final {
public:
bool Matches(DMABufSurface* aSurface) const;
wl_buffer* GetWLBuffer() { return mWLBuffer; }
WaylandBufferDMABUFHolder(DMABufSurface* aSurface, wl_buffer* aWLBuffer);
~WaylandBufferDMABUFHolder();
private:
wl_buffer* mWLBuffer = nullptr;
uint32_t mUID = 0;
uint32_t mPID = 0;
};
} // namespace mozilla::widget
#endif // _MOZILLA_WIDGET_GTK_WAYLAND_BUFFER_H