Backed out changeset b2f82cada9b0 (bug 1934497) Backed out changeset e6b221a0e987 (bug 1934497) Backed out changeset e535888994ed (bug 1934497) Backed out changeset 31f0a398817f (bug 1934497) Backed out changeset 6225ae4714a9 (bug 1934497) Backed out changeset 2f0971ca8b41 (bug 1934497) Backed out changeset ed34f4ff5a2b (bug 1934497) Backed out changeset 739018e9ae4a (bug 1934497) Backed out changeset 4f50bd47febd (bug 1934497) Backed out changeset bbe16df11895 (bug 1934497) Backed out changeset d6e7e274dda3 (bug 1934497) Backed out changeset a1cf316b3e7a (bug 1934497) Backed out changeset 2fbec9faf49c (bug 1934497) Backed out changeset f6ea1323c158 (bug 1934497) Backed out changeset fe1e2b1b4f8b (bug 1934497) Backed out changeset 59b2a1f052e4 (bug 1934497)
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
|