Bug 1422966 - implemented WindowBackBuffer to encapsulate wl_buffer, r?jhorak
wl_buffer is a main Wayland object with graphics data. wl_buffer basically represent one complete window screen.
When double buffering is involved every window (GdkWindow in our case) utilises two wl_buffers which are cycled.
One is filed with data by application and one is rendered by compositor.
WindowBackBuffer class manages one wl_buffer. It owns wl_buffer object, owns WaylandShmPool (which provides shared memory)
and ties them together.
MozReview-Commit-ID: v8Hlezo7oD
--- a/widget/gtk/WindowSurfaceWayland.cpp
+++ b/widget/gtk/WindowSurfaceWayland.cpp
@@ -129,16 +129,18 @@ We allocate shared memory (shm) by mmap(
between us and wayland compositor. We draw our graphics data to the shm and
handle to wayland compositor by WindowBackBuffer/WindowSurfaceWayland
(wl_buffer/wl_surface).
*/
namespace mozilla {
namespace widget {
+#define BUFFER_BPP 4
+
// TODO: How many rendering threads do we actualy handle?
static nsCOMArray<nsWaylandDisplay> gWaylandDisplays;
static StaticMutex gWaylandDisplaysMutex;
// Each thread which is using wayland connection (wl_display) has to operate
// its own wl_event_queue. Main Firefox thread wl_event_queue is handled
// by Gtk main loop, other threads/wl_event_queue has to be handled by us.
//
@@ -412,17 +414,129 @@ WaylandShmPool::Resize(int aSize)
PROT_READ | PROT_WRITE, MAP_SHARED, mShmPoolFd, 0);
if (mImageData == MAP_FAILED)
return false;
mAllocatedSize = aSize;
return true;
}
+void
+WaylandShmPool::SetImageDataFromPool(class WaylandShmPool* aSourcePool,
+ int aImageDataSize)
+{
+ MOZ_ASSERT(mAllocatedSize <= aImageDataSize, "WaylandShmPool overflows!");
+ memcpy(mImageData, aSourcePool->GetImageData(), aImageDataSize);
+}
+
WaylandShmPool::~WaylandShmPool()
{
munmap(mImageData, mAllocatedSize);
wl_shm_pool_destroy(mShmPool);
close(mShmPoolFd);
}
+static void
+buffer_release(void *data, wl_buffer *buffer)
+{
+ auto surface = reinterpret_cast<WindowBackBuffer*>(data);
+ surface->Detach();
+}
+
+static const struct wl_buffer_listener buffer_listener = {
+ buffer_release
+};
+
+void WindowBackBuffer::Create(int aWidth, int aHeight)
+{
+ MOZ_ASSERT(!IsAttached(), "We can't resize attached buffers.");
+
+ int newBufferSize = aWidth*aHeight*BUFFER_BPP;
+ mShmPool.Resize(newBufferSize);
+
+ mWaylandBuffer = wl_shm_pool_create_buffer(mShmPool.GetShmPool(), 0,
+ aWidth, aHeight, aWidth*BUFFER_BPP,
+ WL_SHM_FORMAT_ARGB8888);
+ wl_proxy_set_queue((struct wl_proxy *)mWaylandBuffer,
+ mWaylandDisplay->GetEventQueue());
+ wl_buffer_add_listener(mWaylandBuffer, &buffer_listener, this);
+
+ mWidth = aWidth;
+ mHeight = aHeight;
+}
+
+void WindowBackBuffer::Release()
+{
+ wl_buffer_destroy(mWaylandBuffer);
+ mWidth = mHeight = 0;
+}
+
+WindowBackBuffer::WindowBackBuffer(nsWaylandDisplay* aWaylandDisplay,
+ int aWidth, int aHeight)
+ : mShmPool(aWaylandDisplay, aWidth*aHeight*BUFFER_BPP)
+ ,mWaylandBuffer(nullptr)
+ ,mWidth(aWidth)
+ ,mHeight(aHeight)
+ ,mAttached(false)
+ ,mWaylandDisplay(aWaylandDisplay)
+{
+ Create(aWidth, aHeight);
+}
+
+WindowBackBuffer::~WindowBackBuffer()
+{
+ Release();
+}
+
+bool
+WindowBackBuffer::Resize(int aWidth, int aHeight)
+{
+ if (aWidth == mWidth && aHeight == mHeight)
+ return true;
+
+ Release();
+ Create(aWidth, aHeight);
+
+ return (mWaylandBuffer != nullptr);
+}
+
+void
+WindowBackBuffer::Attach(wl_surface* aSurface)
+{
+ wl_surface_attach(aSurface, mWaylandBuffer, 0, 0);
+ wl_surface_commit(aSurface);
+ wl_display_flush(mWaylandDisplay->GetDisplay());
+ mAttached = true;
+}
+
+void
+WindowBackBuffer::Detach()
+{
+ mAttached = false;
+}
+
+bool
+WindowBackBuffer::SetImageDataFromBackBuffer(
+ class WindowBackBuffer* aSourceBuffer)
+{
+ if (!MatchSize(aSourceBuffer)) {
+ Resize(aSourceBuffer->mWidth, aSourceBuffer->mHeight);
+ }
+
+ mShmPool.SetImageDataFromPool(aSourceBuffer->mShmPool,
+ aSourceBuffer->mWidth * aSourceBuffer->mHeight * BUFFER_BPP);
+ return true;
+}
+
+already_AddRefed<gfx::DrawTarget>
+WindowBackBuffer::Lock(const LayoutDeviceIntRegion& aRegion)
+{
+ gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect();
+ gfx::IntSize lockSize(bounds.XMost(), bounds.YMost());
+
+ return gfxPlatform::CreateDrawTargetForData(static_cast<unsigned char*>(mShmPool.GetImageData()),
+ lockSize,
+ BUFFER_BPP * mWidth,
+ mWaylandDisplay->GetSurfaceFormat());
+}
+
} // namespace widget
} // namespace mozilla
--- a/widget/gtk/WindowSurfaceWayland.h
+++ b/widget/gtk/WindowSurfaceWayland.h
@@ -43,22 +43,63 @@ private:
class WaylandShmPool {
public:
WaylandShmPool(nsWaylandDisplay* aDisplay, int aSize);
~WaylandShmPool();
bool Resize(int aSize);
wl_shm_pool* GetShmPool() { return mShmPool; };
void* GetImageData() { return mImageData; };
+ void SetImageDataFromPool(class WaylandShmPool* aSourcePool);
private:
int CreateTemporaryFile(int aSize);
wl_shm_pool* mShmPool;
int mShmPoolFd;
int mAllocatedSize;
void* mImageData;
};
+// Holds actual graphics data for wl_surface
+class WindowBackBuffer {
+public:
+ WindowBackBuffer(nsWaylandDisplay* aDisplay, int aWidth, int aHeight);
+ ~WindowBackBuffer();
+
+ already_AddRefed<gfx::DrawTarget> Lock(const LayoutDeviceIntRegion& aRegion);
+
+ void Attach(wl_surface* aSurface);
+ void Detach();
+ bool IsAttached() { return mAttached; }
+
+ bool Resize(int aWidth, int aHeight);
+ bool SetImageDataFromBackBuffer(class WindowBackBuffer* aSourceBuffer);
+
+ bool MatchSize(int aWidth, int aHeight)
+ {
+ return aWidth == mWidth && aHeight == mHeight;
+ }
+ bool MatchSize(class WindowBackBuffer *aBuffer)
+ {
+ return aBuffer->mWidth == mWidth && aBuffer->mHeight == mHeight;
+ }
+
+private:
+ void Create(int aWidth, int aHeight);
+ void Release();
+
+ // WaylandShmPool provides actual shared memory we draw into
+ WaylandShmPool mShmPool;
+
+ // wl_buffer is a wayland object that encapsulates the shared memory
+ // and passes it to wayland compositor by wl_surface object.
+ wl_buffer* mWaylandBuffer;
+ int mWidth;
+ int mHeight;
+ bool mAttached;
+ nsWaylandDisplay* mWaylandDisplay;
+};
+
} // namespace widget
} // namespace mozilla
#endif // _MOZILLA_WIDGET_GTK_WINDOW_SURFACE_WAYLAND_H