Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/widget/gtk/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 12 kB image not shown  

Quelle  WaylandBuffer.cpp   Sprache: 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 "WaylandSurface.h"
#include "WaylandSurfaceLock.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

#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);
}

WaylandBuffer::WaylandBuffer(const LayoutDeviceIntSize& aSize) : mSize(aSize) {}

wl_buffer* WaylandBuffer::BorrowBuffer(RefPtr<WaylandSurface> aWaylandSurface) {
  MOZ_RELEASE_ASSERT(!mSurface, "We're already attached!");

  if (CreateWlBuffer()) {
    mSurface = std::move(aWaylandSurface);
  }

  LOGWAYLAND(
      "WaylandBuffer::BorrowBuffer() [%p] WaylandSurface [%p] wl_buffer [%p]",
      (void*)this, mSurface ? mSurface->GetLoggingWidget() : nullptr,
      mWLBuffer);

  MOZ_DIAGNOSTIC_ASSERT(!IsWaitingToBufferDelete(), "We're already deleted!");
  return mWLBuffer;
}

void WaylandBuffer::DeleteWlBuffer() {
  if (!mWLBuffer) {
    return;
  }
  LOGWAYLAND("WaylandBuffer::DeleteWlBuffer() [%p] wl_buffer [%p]\n",
             (void*)this, mWLBuffer);
  MozClearPointer(mWLBuffer, wl_buffer_destroy);
}

static void BufferDeleteSyncFinished(void* aData, struct wl_callback* callback,
                                     uint32_t time) {
  LOGWAYLAND("BufferDeleteSyncFinished() [%p]", aData);
  RefPtr buffer = already_AddRefed(static_cast<WaylandBuffer*>(aData));
  // wl_buffer should be already deleted on our side.
  buffer->BufferDetachedCallbackHandler(nullptr, /* aWlBufferDeleted */ true);
}

static const struct wl_callback_listener sBufferDeleteSyncListener = {
    .done = BufferDeleteSyncFinished,
};

void WaylandBuffer::ReturnBuffer(RefPtr<WaylandSurface> aWaylandSurface) {
  LOGWAYLAND("WaylandBuffer::ReturnBuffer() [%p] WaylandSurface [%p]",
             (void*)this, mSurface.get());

  MutexAutoLock lock(mBufferReleaseMutex);
  MOZ_RELEASE_ASSERT(aWaylandSurface == mSurface || !mSurface);

  if (mBufferDeleteSyncCallback) {
    MOZ_DIAGNOSTIC_ASSERT(!HasWlBuffer());
    return;
  }

  DeleteWlBuffer();

  // We're already detached from WaylandSurface
  if (!mSurface) {
    return;
  }

  // There are various Wayland queues processed for every thread.
  // It's possible that wl_buffer release event is pending in any
  // queue while we already asked for wl_buffer delete.
  // We need to finish wl_buffer removal when all events from this
  // point are processed so we use sync callback.
  //
  // When wl_display_sync comes back to us (from main thread)
  // we know all events are processed and there isn't any
  // wl_buffer operation pending so we can safely release WaylandSurface
  // and WaylandBuffer objects.
  mBufferDeleteSyncCallback = wl_display_sync(WaylandDisplayGetWLDisplay());
  // Addref this to keep it live until sync,
  // we're unref it at sBufferDeleteSyncListener
  AddRef();
  wl_callback_add_listener(mBufferDeleteSyncCallback,
                           &sBufferDeleteSyncListener, this);
}

void WaylandBuffer::BufferDetachedCallbackHandler(wl_buffer* aBuffer,
                                                  bool aWlBufferDeleted) {
  LOGWAYLAND(
      "WaylandBuffer::BufferDetachedCallbackHandler() [%p] WaylandSurface [%p] "
      "aBuffer [%p] aWlBufferDeleted %d GetWlBuffer() [%p]",
      (void*)this, mSurface ? mSurface->GetLoggingWidget() : nullptr, aBuffer,
      aWlBufferDeleted, GetWlBuffer());

  // BufferDetachedCallbackHandler() should be caled by Wayland compostor
  // on main thread only.
  AssertIsOnMainThread();

  // aWlBufferDeleted means wl_buffer should be nullptr
  MOZ_DIAGNOSTIC_ASSERT(!aBuffer == aWlBufferDeleted);

  RefPtr<WaylandSurface> surface;

  // Don't take mBufferReleaseMutex and mSurface locks together,
  // may lead to deadlock.
  {
    MutexAutoLock lock(mBufferReleaseMutex);

    // We should release correct buffer.
    // If GetWlBuffer() is nullptr (deleted) we should have valid delete
    // callback.
    MOZ_DIAGNOSTIC_ASSERT(aBuffer == GetWlBuffer() ||
                          (!GetWlBuffer() && mBufferDeleteSyncCallback));

    if (aWlBufferDeleted) {
      MOZ_DIAGNOSTIC_ASSERT(mBufferDeleteSyncCallback);
      mBufferDeleteSyncCallback = nullptr;
    }

    // We might be unreffed by previous BufferDetachedCallbackHandler() callback
    // as it's called for both wl_buffer delete and wl_buffer detach events.
    if (!mSurface) {
      return;
    }

    // Clear surface reference so WaylandBuffer is marked as not attached now.
    surface = std::move(mSurface);
  }

  // Notify WaylandSurface we're detached by Wayland compositor
  // so it can clear reference to us.
  WaylandSurfaceLock surfaceLock(surface);
  surface->DetachedByWaylandCompositorLocked(surfaceLock, this);
}

static void BufferDetachedCallbackHandler(void* aData, wl_buffer* aBuffer) {
  LOGWAYLAND("BufferDetachedCallbackHandler() [%p] received wl_buffer [%p]",
             aData, aBuffer);
  RefPtr<WaylandBuffer> buffer = static_cast<WaylandBuffer*>(aData);
  buffer->BufferDetachedCallbackHandler(aBuffer, /* aWlBufferDeleted */ false);
}

static const struct wl_buffer_listener sBufferDetachListener = {
    BufferDetachedCallbackHandler};

/* static */
RefPtr<WaylandBufferSHM> WaylandBufferSHM::Create(
    const LayoutDeviceIntSize& aSize) {
  RefPtr<WaylandBufferSHM> buffer = new WaylandBufferSHM(aSize);
  nsWaylandDisplay* waylandDisplay = WaylandDisplayGet();

  LOGWAYLAND("WaylandBufferSHM::Create() [%p] [%d x %d]", (void*)buffer,
             aSize.width, aSize.height);

  int size = aSize.width * aSize.height * BUFFER_BPP;
  buffer->mShmPool = WaylandShmPool::Create(waylandDisplay, size);
  if (!buffer->mShmPool) {
    LOGWAYLAND(" failed to create shmPool");
    return nullptr;
  }

  LOGWAYLAND(" created [%p] WaylandDisplay [%p]\n", buffer.get(),
             waylandDisplay);

  return buffer;
}

bool WaylandBufferSHM::CreateWlBuffer() {
  if (mWLBuffer) {
    return true;
  }
  LOGWAYLAND("WaylandBufferSHM::CreateWlBuffer() [%p]", (void*)this);

  mWLBuffer = wl_shm_pool_create_buffer(mShmPool->GetShmPool(), 0, mSize.width,
                                        mSize.height, mSize.width * BUFFER_BPP,
                                        WL_SHM_FORMAT_ARGB8888);
  if (!mWLBuffer) {
    LOGWAYLAND(" failed to create wl_buffer");
    return false;
  }

  if (wl_buffer_add_listener(mWLBuffer, &sBufferDetachListener, this) < 0) {
    LOGWAYLAND(" failed to attach listener");
    return false;
  }

  return true;
}

WaylandBufferSHM::WaylandBufferSHM(const LayoutDeviceIntSize& aSize)
    : WaylandBuffer(aSize) {
  LOGWAYLAND("WaylandBufferSHM::WaylandBufferSHM() [%p]\n", (void*)this);
}

WaylandBufferSHM::~WaylandBufferSHM() {
  LOGWAYLAND("WaylandBufferSHM::~WaylandBufferSHM() [%p]\n", (void*)this);
  MOZ_DIAGNOSTIC_ASSERT(!IsWaitingToBufferDelete());
  MOZ_DIAGNOSTIC_ASSERT(!IsAttached());
  if (!IsAttached()) {
    DeleteWlBuffer();
  }
  MOZ_DIAGNOSTIC_ASSERT(!HasWlBuffer());
}

already_AddRefed<gfx::DrawTarget> WaylandBufferSHM::Lock() {
  LOGWAYLAND("WaylandBufferSHM::lock() [%p]\n", (void*)this);
  return gfxPlatform::CreateDrawTargetForData(
      static_cast<unsigned char*>(mShmPool->GetImageData()),
      mSize.ToUnknownSize(), BUFFER_BPP * mSize.width, GetSurfaceFormat());
}

void WaylandBufferSHM::Clear() {
  LOGWAYLAND("WaylandBufferSHM::Clear() [%p]\n", (void*)this);
  memset(mShmPool->GetImageData(), 0xff,
         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 */
already_AddRefed<WaylandBufferDMABUF> WaylandBufferDMABUF::CreateRGBA(
    const LayoutDeviceIntSize& aSize, GLContext* aGL,
    RefPtr<DRMFormat> aFormat) {
  RefPtr<WaylandBufferDMABUF> buffer = new WaylandBufferDMABUF(aSize);

  buffer->mDMABufSurface = DMABufSurfaceRGBA::CreateDMABufSurface(
      aSize.width, aSize.height, aFormat,
      DMABUF_SCANOUT | DMABUF_USE_MODIFIERS);
  if (!buffer->mDMABufSurface || !buffer->mDMABufSurface->CreateTexture(aGL)) {
    LOGWAYLAND(" failed to create texture");
    return nullptr;
  }

  LOGWAYLAND("WaylandBufferDMABUF::CreateRGBA() [%p] UID %d [%d x %d]",
             (void*)buffer, buffer->mDMABufSurface->GetUID(), aSize.width,
             aSize.height);
  return buffer.forget();
}

/* static */
already_AddRefed<WaylandBufferDMABUF> WaylandBufferDMABUF::CreateExternal(
    RefPtr<DMABufSurface> aSurface) {
  const auto size =
      LayoutDeviceIntSize(aSurface->GetWidth(), aSurface->GetWidth());
  RefPtr<WaylandBufferDMABUF> buffer = new WaylandBufferDMABUF(size);

  LOGWAYLAND("WaylandBufferDMABUF::CreateExternal() [%p] UID %d [%d x %d]",
             (void*)buffer, aSurface->GetUID(), size.width, size.height);

  buffer->mDMABufSurface = aSurface;
  return buffer.forget();
}

bool WaylandBufferDMABUF::CreateWlBuffer() {
  MOZ_DIAGNOSTIC_ASSERT(mDMABufSurface);

  if (mWLBuffer) {
    return true;
  }

  LOGWAYLAND("WaylandBufferDMABUF::CreateWlBuffer() [%p] UID %d", (void*)this,
             mDMABufSurface->GetUID());

  mWLBuffer = mDMABufSurface->CreateWlBuffer();
  if (!mWLBuffer) {
    LOGWAYLAND(" failed to create wl_buffer");
    return false;
  }

  if (wl_buffer_add_listener(mWLBuffer, &sBufferDetachListener, this) < 0) {
    LOGWAYLAND(" failed to attach listener!");
    return false;
  }

  return true;
}

WaylandBufferDMABUF::WaylandBufferDMABUF(const LayoutDeviceIntSize& aSize)
    : WaylandBuffer(aSize) {
  LOGWAYLAND("WaylandBufferDMABUF::WaylandBufferDMABUF [%p]\n", (void*)this);
}

WaylandBufferDMABUF::~WaylandBufferDMABUF() {
  LOGWAYLAND("WaylandBufferDMABUF::~WaylandBufferDMABUF [%p] UID %d\n",
             (void*)this, mDMABufSurface ? mDMABufSurface->GetUID() : -1);
  MOZ_DIAGNOSTIC_ASSERT(!IsWaitingToBufferDelete());
  MOZ_DIAGNOSTIC_ASSERT(!IsAttached());
  if (!IsAttached()) {
    DeleteWlBuffer();
  }
  MOZ_DIAGNOSTIC_ASSERT(!HasWlBuffer());
}

}  // namespace mozilla::widget

100%


¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.