1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "WaylandBuffer.h"
13 #include "gfx2DGlue.h"
14 #include "gfxPlatform.h"
15 #include "mozilla/WidgetUtilsGtk.h"
16 #include "mozilla/gfx/Tools.h"
17 #include "nsGtkUtils.h"
18 #include "nsPrintfCString.h"
19 #include "prenv.h" // For PR_GetEnv
22 # include "mozilla/Logging.h"
23 # include "mozilla/ScopeExit.h"
25 extern mozilla::LazyLogModule gWidgetWaylandLog
;
26 # define LOGWAYLAND(...) \
27 MOZ_LOG(gWidgetWaylandLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
29 # define LOGWAYLAND(...)
30 #endif /* MOZ_LOGGING */
32 using namespace mozilla::gl
;
34 namespace mozilla::widget
{
37 gfx::SurfaceFormat
WaylandBuffer::mFormat
= gfx::SurfaceFormat::B8G8R8A8
;
40 int WaylandBufferSHM::mDumpSerial
=
41 PR_GetEnv("MOZ_WAYLAND_DUMP_WL_BUFFERS") ? 1 : 0;
42 char* WaylandBufferSHM::mDumpDir
= PR_GetEnv("MOZ_WAYLAND_DUMP_DIR");
46 RefPtr
<WaylandShmPool
> WaylandShmPool::Create(nsWaylandDisplay
* aWaylandDisplay
,
48 if (!aWaylandDisplay
->GetShm()) {
49 NS_WARNING("WaylandShmPool: Missing Wayland shm interface!");
53 RefPtr
<WaylandShmPool
> shmPool
= new WaylandShmPool();
55 shmPool
->mShm
= MakeUnique
<base::SharedMemory
>();
56 if (!shmPool
->mShm
->Create(aSize
)) {
57 NS_WARNING("WaylandShmPool: Unable to allocate shared memory!");
61 shmPool
->mSize
= aSize
;
62 shmPool
->mShmPool
= wl_shm_create_pool(
63 aWaylandDisplay
->GetShm(), shmPool
->mShm
->CloneHandle().get(), aSize
);
64 if (!shmPool
->mShmPool
) {
65 NS_WARNING("WaylandShmPool: Unable to allocate shared memory pool!");
72 void* WaylandShmPool::GetImageData() {
76 if (!mShm
->Map(mSize
)) {
77 NS_WARNING("WaylandShmPool: Failed to map Shm!");
80 mImageData
= mShm
->memory();
84 WaylandShmPool::~WaylandShmPool() {
85 MozClearPointer(mShmPool
, wl_shm_pool_destroy
);
88 static const struct wl_buffer_listener sBufferListenerWaylandBuffer
= {
89 WaylandBuffer::BufferReleaseCallbackHandler
};
91 WaylandBuffer::WaylandBuffer(const LayoutDeviceIntSize
& aSize
) : mSize(aSize
) {}
93 void WaylandBuffer::AttachAndCommit(wl_surface
* aSurface
) {
95 "WaylandBuffer::AttachAndCommit [%p] wl_surface %p ID %d wl_buffer "
97 (void*)this, (void*)aSurface
,
98 aSurface
? wl_proxy_get_id((struct wl_proxy
*)aSurface
) : -1,
100 GetWlBuffer() ? wl_proxy_get_id((struct wl_proxy
*)GetWlBuffer()) : -1);
102 wl_buffer
* buffer
= GetWlBuffer();
105 wl_surface_attach(aSurface
, buffer
, 0, 0);
106 wl_surface_commit(aSurface
);
110 void WaylandBuffer::BufferReleaseCallbackHandler(wl_buffer
* aBuffer
) {
113 if (mBufferReleaseFunc
) {
114 mBufferReleaseFunc(mBufferReleaseData
, aBuffer
);
118 void WaylandBuffer::BufferReleaseCallbackHandler(void* aData
,
119 wl_buffer
* aBuffer
) {
120 auto* buffer
= reinterpret_cast<WaylandBuffer
*>(aData
);
121 buffer
->BufferReleaseCallbackHandler(aBuffer
);
125 RefPtr
<WaylandBufferSHM
> WaylandBufferSHM::Create(
126 const LayoutDeviceIntSize
& aSize
) {
127 RefPtr
<WaylandBufferSHM
> buffer
= new WaylandBufferSHM(aSize
);
128 nsWaylandDisplay
* waylandDisplay
= WaylandDisplayGet();
130 int size
= aSize
.width
* aSize
.height
* BUFFER_BPP
;
131 buffer
->mShmPool
= WaylandShmPool::Create(waylandDisplay
, size
);
132 if (!buffer
->mShmPool
) {
136 buffer
->mWLBuffer
= wl_shm_pool_create_buffer(
137 buffer
->mShmPool
->GetShmPool(), 0, aSize
.width
, aSize
.height
,
138 aSize
.width
* BUFFER_BPP
, WL_SHM_FORMAT_ARGB8888
);
139 if (!buffer
->mWLBuffer
) {
143 wl_buffer_add_listener(buffer
->GetWlBuffer(), &sBufferListenerWaylandBuffer
,
146 LOGWAYLAND("WaylandBufferSHM Created [%p] WaylandDisplay [%p]\n",
147 buffer
.get(), waylandDisplay
);
152 WaylandBufferSHM::WaylandBufferSHM(const LayoutDeviceIntSize
& aSize
)
153 : WaylandBuffer(aSize
) {}
155 WaylandBufferSHM::~WaylandBufferSHM() {
156 MozClearPointer(mWLBuffer
, wl_buffer_destroy
);
159 already_AddRefed
<gfx::DrawTarget
> WaylandBufferSHM::Lock() {
160 return gfxPlatform::CreateDrawTargetForData(
161 static_cast<unsigned char*>(mShmPool
->GetImageData()),
162 mSize
.ToUnknownSize(), BUFFER_BPP
* mSize
.width
, GetSurfaceFormat());
165 void WaylandBufferSHM::Clear() {
166 memset(mShmPool
->GetImageData(), 0, mSize
.height
* mSize
.width
* BUFFER_BPP
);
170 void WaylandBufferSHM::DumpToFile(const char* aHint
) {
175 cairo_surface_t
* surface
= nullptr;
176 auto unmap
= MakeScopeExit([&] {
178 cairo_surface_destroy(surface
);
181 surface
= cairo_image_surface_create_for_data(
182 (unsigned char*)mShmPool
->GetImageData(), CAIRO_FORMAT_ARGB32
,
183 mSize
.width
, mSize
.height
, BUFFER_BPP
* mSize
.width
);
184 if (cairo_surface_status(surface
) == CAIRO_STATUS_SUCCESS
) {
187 filename
.Append(mDumpDir
);
188 filename
.Append('/');
191 nsPrintfCString("firefox-wl-buffer-%.5d-%s.png", mDumpSerial
++, aHint
));
192 cairo_surface_write_to_png(surface
, filename
.get());
193 LOGWAYLAND("Dumped wl_buffer to %s\n", filename
.get());
199 RefPtr
<WaylandBufferDMABUF
> WaylandBufferDMABUF::Create(
200 const LayoutDeviceIntSize
& aSize
, GLContext
* aGL
) {
201 RefPtr
<WaylandBufferDMABUF
> buffer
= new WaylandBufferDMABUF(aSize
);
204 static_cast<DMABufSurfaceFlags
>(DMABUF_TEXTURE
| DMABUF_ALPHA
);
205 buffer
->mDMABufSurface
=
206 DMABufSurfaceRGBA::CreateDMABufSurface(aSize
.width
, aSize
.height
, flags
);
207 if (!buffer
->mDMABufSurface
|| !buffer
->mDMABufSurface
->CreateTexture(aGL
)) {
211 if (!buffer
->mDMABufSurface
->CreateWlBuffer()) {
215 wl_buffer_add_listener(buffer
->GetWlBuffer(), &sBufferListenerWaylandBuffer
,
221 WaylandBufferDMABUF::WaylandBufferDMABUF(const LayoutDeviceIntSize
& aSize
)
222 : WaylandBuffer(aSize
) {}
224 } // namespace mozilla::widget