mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 22:32:46 +00:00
8a0a0f7524
MOZ_RUNINIT => initialized at runtime MOZ_CONSTINIT => initialized at compile time MOZ_GLOBINIT => initialized either at runtime or compile time, depending on template parameter, macro parameter etc This annotation is only understood by our clang-tidy plugin. It has no effect on regular compilation. Differential Revision: https://phabricator.services.mozilla.com/D223341
226 lines
6.6 KiB
C++
226 lines
6.6 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "WaylandBuffer.h"
|
|
|
|
#include <sys/mman.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
|
|
#include "gfx2DGlue.h"
|
|
#include "gfxPlatform.h"
|
|
#include "mozilla/WidgetUtilsGtk.h"
|
|
#include "mozilla/gfx/Tools.h"
|
|
#include "nsGtkUtils.h"
|
|
#include "nsPrintfCString.h"
|
|
#include "prenv.h" // For PR_GetEnv
|
|
|
|
#ifdef MOZ_LOGGING
|
|
# include "mozilla/Logging.h"
|
|
# include "mozilla/ScopeExit.h"
|
|
# include "Units.h"
|
|
extern mozilla::LazyLogModule gWidgetWaylandLog;
|
|
# define LOGWAYLAND(...) \
|
|
MOZ_LOG(gWidgetWaylandLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
|
|
#else
|
|
# define LOGWAYLAND(...)
|
|
#endif /* MOZ_LOGGING */
|
|
|
|
using namespace mozilla::gl;
|
|
|
|
namespace mozilla::widget {
|
|
|
|
#define BUFFER_BPP 4
|
|
gfx::SurfaceFormat WaylandBuffer::mFormat = gfx::SurfaceFormat::B8G8R8A8;
|
|
|
|
#ifdef MOZ_LOGGING
|
|
MOZ_RUNINIT int WaylandBufferSHM::mDumpSerial =
|
|
PR_GetEnv("MOZ_WAYLAND_DUMP_WL_BUFFERS") ? 1 : 0;
|
|
MOZ_RUNINIT char* WaylandBufferSHM::mDumpDir =
|
|
PR_GetEnv("MOZ_WAYLAND_DUMP_DIR");
|
|
#endif
|
|
|
|
/* static */
|
|
RefPtr<WaylandShmPool> WaylandShmPool::Create(nsWaylandDisplay* aWaylandDisplay,
|
|
int aSize) {
|
|
if (!aWaylandDisplay->GetShm()) {
|
|
NS_WARNING("WaylandShmPool: Missing Wayland shm interface!");
|
|
return nullptr;
|
|
}
|
|
|
|
RefPtr<WaylandShmPool> shmPool = new WaylandShmPool();
|
|
|
|
shmPool->mShm = MakeRefPtr<ipc::SharedMemory>();
|
|
if (!shmPool->mShm->Create(aSize)) {
|
|
NS_WARNING("WaylandShmPool: Unable to allocate shared memory!");
|
|
return nullptr;
|
|
}
|
|
|
|
shmPool->mSize = aSize;
|
|
shmPool->mShmPool = wl_shm_create_pool(
|
|
aWaylandDisplay->GetShm(), shmPool->mShm->CloneHandle().get(), aSize);
|
|
if (!shmPool->mShmPool) {
|
|
NS_WARNING("WaylandShmPool: Unable to allocate shared memory pool!");
|
|
return nullptr;
|
|
}
|
|
|
|
return shmPool;
|
|
}
|
|
|
|
void* WaylandShmPool::GetImageData() {
|
|
if (mImageData) {
|
|
return mImageData;
|
|
}
|
|
if (!mShm->Map(mSize)) {
|
|
NS_WARNING("WaylandShmPool: Failed to map Shm!");
|
|
return nullptr;
|
|
}
|
|
mImageData = mShm->Memory();
|
|
return mImageData;
|
|
}
|
|
|
|
WaylandShmPool::~WaylandShmPool() {
|
|
MozClearPointer(mShmPool, wl_shm_pool_destroy);
|
|
}
|
|
|
|
static const struct wl_buffer_listener sBufferListenerWaylandBuffer = {
|
|
WaylandBuffer::BufferReleaseCallbackHandler};
|
|
|
|
WaylandBuffer::WaylandBuffer(const LayoutDeviceIntSize& aSize) : mSize(aSize) {}
|
|
|
|
void WaylandBuffer::AttachAndCommit(wl_surface* aSurface) {
|
|
LOGWAYLAND(
|
|
"WaylandBuffer::AttachAndCommit [%p] wl_surface %p ID %d wl_buffer "
|
|
"%p ID %d\n",
|
|
(void*)this, (void*)aSurface,
|
|
aSurface ? wl_proxy_get_id((struct wl_proxy*)aSurface) : -1,
|
|
(void*)GetWlBuffer(),
|
|
GetWlBuffer() ? wl_proxy_get_id((struct wl_proxy*)GetWlBuffer()) : -1);
|
|
|
|
wl_buffer* buffer = GetWlBuffer();
|
|
if (buffer) {
|
|
mAttached = true;
|
|
wl_surface_attach(aSurface, buffer, 0, 0);
|
|
wl_surface_commit(aSurface);
|
|
}
|
|
}
|
|
|
|
void WaylandBuffer::BufferReleaseCallbackHandler(wl_buffer* aBuffer) {
|
|
mAttached = false;
|
|
|
|
if (mBufferReleaseFunc) {
|
|
mBufferReleaseFunc(mBufferReleaseData, aBuffer);
|
|
}
|
|
}
|
|
|
|
void WaylandBuffer::BufferReleaseCallbackHandler(void* aData,
|
|
wl_buffer* aBuffer) {
|
|
auto* buffer = reinterpret_cast<WaylandBuffer*>(aData);
|
|
buffer->BufferReleaseCallbackHandler(aBuffer);
|
|
}
|
|
|
|
/* static */
|
|
RefPtr<WaylandBufferSHM> WaylandBufferSHM::Create(
|
|
const LayoutDeviceIntSize& aSize) {
|
|
RefPtr<WaylandBufferSHM> buffer = new WaylandBufferSHM(aSize);
|
|
nsWaylandDisplay* waylandDisplay = WaylandDisplayGet();
|
|
|
|
int size = aSize.width * aSize.height * BUFFER_BPP;
|
|
buffer->mShmPool = WaylandShmPool::Create(waylandDisplay, size);
|
|
if (!buffer->mShmPool) {
|
|
return nullptr;
|
|
}
|
|
|
|
buffer->mWLBuffer = wl_shm_pool_create_buffer(
|
|
buffer->mShmPool->GetShmPool(), 0, aSize.width, aSize.height,
|
|
aSize.width * BUFFER_BPP, WL_SHM_FORMAT_ARGB8888);
|
|
if (!buffer->mWLBuffer) {
|
|
return nullptr;
|
|
}
|
|
|
|
wl_buffer_add_listener(buffer->GetWlBuffer(), &sBufferListenerWaylandBuffer,
|
|
buffer.get());
|
|
|
|
LOGWAYLAND("WaylandBufferSHM Created [%p] WaylandDisplay [%p]\n",
|
|
buffer.get(), waylandDisplay);
|
|
|
|
return buffer;
|
|
}
|
|
|
|
WaylandBufferSHM::WaylandBufferSHM(const LayoutDeviceIntSize& aSize)
|
|
: WaylandBuffer(aSize) {}
|
|
|
|
WaylandBufferSHM::~WaylandBufferSHM() {
|
|
MozClearPointer(mWLBuffer, wl_buffer_destroy);
|
|
}
|
|
|
|
already_AddRefed<gfx::DrawTarget> WaylandBufferSHM::Lock() {
|
|
return gfxPlatform::CreateDrawTargetForData(
|
|
static_cast<unsigned char*>(mShmPool->GetImageData()),
|
|
mSize.ToUnknownSize(), BUFFER_BPP * mSize.width, GetSurfaceFormat());
|
|
}
|
|
|
|
void WaylandBufferSHM::Clear() {
|
|
memset(mShmPool->GetImageData(), 0, mSize.height * mSize.width * BUFFER_BPP);
|
|
}
|
|
|
|
#ifdef MOZ_LOGGING
|
|
void WaylandBufferSHM::DumpToFile(const char* aHint) {
|
|
if (!mDumpSerial) {
|
|
return;
|
|
}
|
|
|
|
cairo_surface_t* surface = nullptr;
|
|
auto unmap = MakeScopeExit([&] {
|
|
if (surface) {
|
|
cairo_surface_destroy(surface);
|
|
}
|
|
});
|
|
surface = cairo_image_surface_create_for_data(
|
|
(unsigned char*)mShmPool->GetImageData(), CAIRO_FORMAT_ARGB32,
|
|
mSize.width, mSize.height, BUFFER_BPP * mSize.width);
|
|
if (cairo_surface_status(surface) == CAIRO_STATUS_SUCCESS) {
|
|
nsCString filename;
|
|
if (mDumpDir) {
|
|
filename.Append(mDumpDir);
|
|
filename.Append('/');
|
|
}
|
|
filename.Append(
|
|
nsPrintfCString("firefox-wl-buffer-%.5d-%s.png", mDumpSerial++, aHint));
|
|
cairo_surface_write_to_png(surface, filename.get());
|
|
LOGWAYLAND("Dumped wl_buffer to %s\n", filename.get());
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* static */
|
|
RefPtr<WaylandBufferDMABUF> WaylandBufferDMABUF::Create(
|
|
const LayoutDeviceIntSize& aSize, GLContext* aGL) {
|
|
RefPtr<WaylandBufferDMABUF> buffer = new WaylandBufferDMABUF(aSize);
|
|
|
|
const auto flags =
|
|
static_cast<DMABufSurfaceFlags>(DMABUF_TEXTURE | DMABUF_ALPHA);
|
|
buffer->mDMABufSurface =
|
|
DMABufSurfaceRGBA::CreateDMABufSurface(aSize.width, aSize.height, flags);
|
|
if (!buffer->mDMABufSurface || !buffer->mDMABufSurface->CreateTexture(aGL)) {
|
|
return nullptr;
|
|
}
|
|
|
|
if (!buffer->mDMABufSurface->CreateWlBuffer()) {
|
|
return nullptr;
|
|
}
|
|
|
|
wl_buffer_add_listener(buffer->GetWlBuffer(), &sBufferListenerWaylandBuffer,
|
|
buffer.get());
|
|
|
|
return buffer;
|
|
}
|
|
|
|
WaylandBufferDMABUF::WaylandBufferDMABUF(const LayoutDeviceIntSize& aSize)
|
|
: WaylandBuffer(aSize) {}
|
|
|
|
} // namespace mozilla::widget
|