Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  DMABufFormats.cpp   Sprache: C

 

/* 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 <xf86drm.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <gbm.h>
#include <mutex>

#include "DMABufDevice.h"
#include "DMABufFormats.h"
#include "WidgetUtilsGtk.h"
#ifdef MOZ_WAYLAND
#  include "nsWaylandDisplay.h"
#  include "mozilla/widget/mozwayland.h"
#  include "mozilla/widget/linux-dmabuf-unstable-v1-client-protocol.h"
#endif
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/gfx/Logging.h"  // for gfxCriticalNote

// drm_fourcc.h defines DRM_FORMAT_MOD_INVALID without a guard; undef the
// fallback from DMABufFormats.h first so the unified build doesn't see a
// redefinition (same pattern as DMABufSurface.cpp).
#ifdef DRM_FORMAT_MOD_INVALID
#  undef DRM_FORMAT_MOD_INVALID
#endif
#include <libdrm/drm_fourcc.h>
#include "GfxInfo.h"
#include "mozilla/Components.h"

using namespace mozilla::gfx;

#ifndef GBM_FORMAT_P010
#  define GBM_FORMAT_P010 \
    __gbm_fourcc_code('P', '0', '1', '0') /* 2x2 subsampled Cr:Cb plane */
#endif

namespace mozilla::widget {

// Table of all supported DRM formats, every format is stored as
// FOURCC format + modifier pair and
// one FOURCC format can be stored with more modifiers.
// The format table data are provided via. mapped memory
// so we don't copy it, just map fd and read.
class DMABufFormatTable final {
 public:
  bool IsSet() { return mData && mSize && mData != MAP_FAILED; }

  void Set(int32_t aFd, uint32_t aSize) {
    MOZ_DIAGNOSTIC_ASSERT(!mData && !mSize);
    mSize = aSize;
    mData = (DRMFormatTableEntry*)mmap(nullptr, aSize, PROT_READ, MAP_PRIVATE,
                                       aFd, 0);
    close(aFd);
  }

  bool GetFormat(uint16_t aIndex, uint32_t* aFormat, uint64_t* aModifier) {
    if (aIndex >= mSize / sizeof(DRMFormatTableEntry)) {
      gfxCriticalNote << "Wrong DRM DMABuf format index!";
      return false;
    }
    *aFormat = mData[aIndex].mFormat;
    *aModifier = mData[aIndex].mModifier;
    return true;
  }

  ~DMABufFormatTable() {
    if (mData && mData != MAP_FAILED) {
      munmap(mData, mSize);
    }
  }

 private:
  unsigned int mSize = 0;
  struct DRMFormatTableEntry {
    uint32_t mFormat;
    uint32_t padding; /* unused */
    uint64_t mModifier;
  }* mData = nullptr;
};

class DMABufFeedbackTranche final {
 public:
#ifdef MOZ_WAYLAND
  void SetFormats(DMABufFormatTable* aFormatTable, wl_array* aIndices) {
    // Formats are reported as array with appropriate modifiers.
    // Modifiers are sorted from the most preffered.
    // There's a sample output of weston-simple-dmabuf-feedback utility
    // which prints the format table:
    //
    // format ABGR16161616F, modifier
    // AMD_GFX10_RBPLUS,64KB_R_X,PIPE_XOR_BITS=3... format ABGR16161616F,
    // modifier AMD_GFX10,64KB_S_X,PIPE_XOR_BITS=3 format ABGR16161616F,
    // modifier AMD_GFX9,64KB_D format ABGR16161616F, modifier AMD_GFX9,64KB_S
    // format ABGR16161616F, modifier LINEAR

    RefPtr<DRMFormat> currentDrmFormat;

    // We need to use such ugly constructions because wl_array_for_each
    // is not C++ compliant
    // (https://gitlab.freedesktop.org/wayland/wayland/-/issues/34)
    uint16_t* index = (uint16_t*)aIndices->data;
    uint16_t* lastIndex =
        (uint16_t*)((const char*)aIndices->data + aIndices->size);

    for (; index < lastIndex; index++) {
      uint32_t format;
      uint64_t modifier;
      if (!aFormatTable->GetFormat(*index, &format, &modifier)) {
        return;
      }
      LOGDMABUF(("DMABufFeedbackTranche [%p] format 0x%x modifier %" PRIx64,
                 this, format, modifier));
      if (!currentDrmFormat || !currentDrmFormat->Matches(format)) {
        currentDrmFormat = new DRMFormat(format, modifier);
        mFormats.AppendElement(currentDrmFormat);
        continue;
      }
      currentDrmFormat->AddModifier(modifier);
    }
  }
#endif
  void SetScanout(bool aIsScanout) { mIsScanout = aIsScanout; }
  bool IsScanout() { return mIsScanout; }

  void AddFormat(uint32_t aFormat, uint64_t aModifier) {
    DRMFormat* format = GetFormat(aFormat);
    if (format) {
      format->AddModifier(aModifier);
      return;
    }
    mFormats.AppendElement(new DRMFormat(aFormat, aModifier));
  }

  DRMFormat* GetFormat(uint32_t aFormat) {
    for (const auto& format : mFormats) {
      if (format->Matches(aFormat)) {
        return format.get();
      }
    }
    return nullptr;
  }

 private:
  bool mIsScanout = false;
  nsTArray<RefPtr<DRMFormat>> mFormats;
};

class DMABufFeedback final {
 public:
  DMABufFormatTable* FormatTable() { return &mFormatTable; }
  DMABufFeedbackTranche* PendingTranche() {
    if (!mPendingTranche) {
      mPendingTranche = MakeUnique<DMABufFeedbackTranche>();
    }
    return mPendingTranche.get();
  }
  void PendingTrancheDone() {
    // It's possible that Wayland compositor doesn't send us any format,
    // so !mPendingTranche
    if (mPendingTranche) {
      mTranches.AppendElement(std::move(mPendingTranche));
    }
  }
  DRMFormat* GetFormat(uint32_t aFormat, bool aRequestScanoutFormat) {
    for (const auto& tranche : mTranches) {
      if (aRequestScanoutFormat && !tranche->IsScanout()) {
        continue;
      }
      if (DRMFormat* format = tranche->GetFormat(aFormat)) {
        return format;
      }
    }
    return nullptr;
  }

 private:
  DMABufFormatTable mFormatTable;
  UniquePtr<DMABufFeedbackTranche> mPendingTranche;
  nsTArray<UniquePtr<DMABufFeedbackTranche>> mTranches;
};

DMABufFeedback* DMABufFormats::GetPendingDMABufFeedback() {
  if (!mPendingDMABufFeedback) {
    mPendingDMABufFeedback = MakeUnique<DMABufFeedback>();
  }
  return mPendingDMABufFeedback.get();
}

void DMABufFormats::PendingDMABufFeedbackDone() {
  mDMABufFeedback = std::move(mPendingDMABufFeedback);
  if (mFormatRefreshCallback) {
    mFormatRefreshCallback(this);
  }
}

#ifdef MOZ_WAYLAND
static void dmabuf_feedback_format_table(
    void* data,
    struct zwp_linux_dmabuf_feedback_v1* zwp_linux_dmabuf_feedback_v1,
    int32_t fd, uint32_t size) {
  auto* dmabuf = static_cast<DMABufFormats*>(data);
  if (!dmabuf) {
    return;
  }
  DMABufFormatTable* formats =
      dmabuf->GetPendingDMABufFeedback()->FormatTable();
  formats->Set(fd, size);
}

static void dmabuf_feedback_tranche_target_device(
    void* data, struct zwp_linux_dmabuf_feedback_v1* dmabuf_feedback,
    struct wl_array* dev) {
  // We're getting device from GL
}

static void dmabuf_feedback_tranche_formats(
    void* data, struct zwp_linux_dmabuf_feedback_v1* dmabuf_feedback,
    struct wl_array* indices) {
  auto* dmabuf = static_cast<DMABufFormats*>(data);
  if (!dmabuf) {
    return;
  }
  DMABufFeedback* feedback = dmabuf->GetPendingDMABufFeedback();
  DMABufFormatTable* formatTable = feedback->FormatTable();
  if (!formatTable->IsSet()) {
    formatTable = dmabuf->GetDMABufFeedback()
                      ? dmabuf->GetDMABufFeedback()->FormatTable()
                      : nullptr;
    if (!formatTable || !formatTable->IsSet()) {
      gfxCriticalNote << "Missing DMABuf format table!";
      return;
    }
  }
  feedback->PendingTranche()->SetFormats(formatTable, indices);
}

static void dmabuf_feedback_tranche_flags(
    void* data, struct zwp_linux_dmabuf_feedback_v1* dmabuf_feedback,
    uint32_t flags) {
  if (flags & ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT) {
    auto* dmabuf = static_cast<DMABufFormats*>(data);
    if (!dmabuf) {
      return;
    }
    LOGDMABUF(("DMABufFeedbackTranche [%p] is scanout tranche",
               dmabuf->GetPendingDMABufFeedback()->PendingTranche()));
    dmabuf->GetPendingDMABufFeedback()->PendingTranche()->SetScanout(true);
  }
}

static void dmabuf_feedback_tranche_done(
    void* data, struct zwp_linux_dmabuf_feedback_v1* dmabuf_feedback) {
  auto* dmabuf = static_cast<DMABufFormats*>(data);
  if (!dmabuf) {
    return;
  }
  LOGDMABUF(("DMABufFeedbackTranche [%p] is done",
             dmabuf->GetPendingDMABufFeedback()));
  dmabuf->GetPendingDMABufFeedback()->PendingTrancheDone();
}

static void dmabuf_feedback_done(
    void* data, struct zwp_linux_dmabuf_feedback_v1* dmabuf_feedback) {
  auto* dmabuf = static_cast<DMABufFormats*>(data);
  if (!dmabuf) {
    return;
  }
  dmabuf->PendingDMABufFeedbackDone();
}

static void dmabuf_feedback_main_device(
    void* data, struct zwp_linux_dmabuf_feedback_v1* dmabuf_feedback,
    struct wl_array* dev) {
  // We're getting DRM device from GL.
}

static const struct zwp_linux_dmabuf_feedback_v1_listener
    dmabuf_feedback_listener = {
        .done = dmabuf_feedback_done,
        .format_table = dmabuf_feedback_format_table,
        .main_device = dmabuf_feedback_main_device,
        .tranche_done = dmabuf_feedback_tranche_done,
        .tranche_target_device = dmabuf_feedback_tranche_target_device,
        .tranche_formats = dmabuf_feedback_tranche_formats,
        .tranche_flags = dmabuf_feedback_tranche_flags,
};

static void dmabuf_v3_modifiers(void* data,
                                struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf,
                                uint32_t format, uint32_t modifier_hi,
                                uint32_t modifier_lo) {
  // skip modifiers marked as invalid
  if (modifier_hi == (DRM_FORMAT_MOD_INVALID >> 32) &&
      modifier_lo == (DRM_FORMAT_MOD_INVALID & 0xffffffff)) {
    return;
  }
  auto* dmabuf = static_cast<DMABufFormats*>(data);
  if (!dmabuf) {
    return;
  }

  uint64_t modifier = ((uint64_t)modifier_hi << 32) | modifier_lo;
  LOGDMABUF(("DMABuf format 0x%x modifier %" PRIx64, format, modifier));

  dmabuf->GetPendingDMABufFeedback()->PendingTranche()->AddFormat(format,
                                                                  modifier);
}

static void dmabuf_v3_format(void* data,
                             struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf,
                             uint32_t format) {
  // XXX: deprecated
}

static const struct zwp_linux_dmabuf_v1_listener dmabuf_v3_listener = {
    dmabuf_v3_format, dmabuf_v3_modifiers};

void DMABufFormats::InitFeedback(zwp_linux_dmabuf_v1* aDMABuf,
                                 const DMABufFormatsCallback& aFormatRefreshCB,
                                 wl_surface* aSurface) {
  LOGDMABUF(("DMABufFormats::Init() feedback wl_surface %p", aSurface));
  if (aSurface) {
    mWaylandFeedback =
        zwp_linux_dmabuf_v1_get_surface_feedback(aDMABuf, aSurface);
  } else {
    mWaylandFeedback = zwp_linux_dmabuf_v1_get_default_feedback(aDMABuf);
  }
  zwp_linux_dmabuf_feedback_v1_add_listener(mWaylandFeedback,
                                            &dmabuf_feedback_listener, this);
  mFormatRefreshCallback = aFormatRefreshCB;
}

void DMABufFormats::InitV3(zwp_linux_dmabuf_v1* aDMABuf) {
  LOGDMABUF(("DMABufFormats::Init() v.3"));
  zwp_linux_dmabuf_v1_add_listener(aDMABuf, &dmabuf_v3_listener, this);
}

void DMABufFormats::InitV3Done() {
  LOGDMABUF(("DMABufFormats::Init() v.3 Done"));
  GetPendingDMABufFeedback()->PendingTrancheDone();
  PendingDMABufFeedbackDone();
}
#endif

DRMFormat* DMABufFormats::GetFormat(uint32_t aFormat,
                                    bool aRequestScanoutFormat) {
  MOZ_DIAGNOSTIC_ASSERT(mDMABufFeedback);
  return mDMABufFeedback->GetFormat(aFormat, aRequestScanoutFormat);
}

void DMABufFormats::EnsureBasicFormat(uint32_t aDrmFourcc) {
  MOZ_DIAGNOSTIC_ASSERT(mDMABufFeedback);
  if (!GetFormat(aDrmFourcc)) {
    LOGDMABUF(("DMABufFormats::EnsureBasicFormat(): %x is missing, adding.",
               aDrmFourcc));
    mDMABufFeedback->PendingTranche()->AddFormat(aDrmFourcc,
                                                 DRM_FORMAT_MOD_INVALID);
  }
}

void DMABufFormats::EnsureBasicFormats() {
  MOZ_DIAGNOSTIC_ASSERT(!mPendingDMABufFeedback,
                        "Can't add extra formats during init!");
  if (!mDMABufFeedback) {
    mDMABufFeedback = MakeUnique<DMABufFeedback>();
  }

  EnsureBasicFormat(GBM_FORMAT_XRGB8888);
  EnsureBasicFormat(GBM_FORMAT_ARGB8888);
  EnsureBasicFormat(GBM_FORMAT_P010);
  EnsureBasicFormat(GBM_FORMAT_NV12);
  EnsureBasicFormat(GBM_FORMAT_YUV420);

  mDMABufFeedback->PendingTrancheDone();
}

DMABufFormats::DMABufFormats() = default;

DMABufFormats::~DMABufFormats() {
#ifdef MOZ_WAYLAND
  if (mWaylandFeedback) {
    zwp_linux_dmabuf_feedback_v1_destroy(mWaylandFeedback);
  }
#endif
}

#ifdef MOZ_WAYLAND
RefPtr<DMABufFormats> CreateDMABufFeedbackFormats(
    wl_surface* aSurface, const DMABufFormatsCallback& aFormatRefreshCB) {
  if (!WaylandDisplayGet()->HasDMABufFeedback()) {
    return nullptr;
  }
  auto formats = MakeRefPtr<DMABufFormats>();
  formats->InitFeedback(WaylandDisplayGet()->GetDmabuf(), aFormatRefreshCB,
                        aSurface);
  return formats.forget();
}
#endif

bool GlobalDMABufFormats::ConfigureFormat(RefPtr<DMABufFormats> aFormats,
                                          RefPtr<DRMFormat>& aTargetFormat,
                                          uint32_t aDrmFourcc) {
  DRMFormat* format = aFormats->GetFormat(aDrmFourcc);
  if (!format) {
    LOGDMABUF(
        ("GlobalDMABufFormats::ConfigureFormat(): missing %x fourcc format.",
         aDrmFourcc));
    return false;
  }
  nsTArray<uint64_t> mods;
  if (!format->UseModifiers()) {
    const nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
    if (gfxInfo) {
      auto* gfx = static_cast<GfxInfo*>(gfxInfo.get());
      mods.AppendElements(gfx->GetDMABufEGLModifiers(aDrmFourcc));
    }
    LOGDMABUF(
        ("GlobalDMABufFormats::ConfigureFormat(): Adding %x fourcc format EGL "
         "modifiers num [%d].",
         aDrmFourcc, (int)mods.Length()));
  }
  if (mods.IsEmpty()) {
    mods.Assign(*format->GetModifiers());
    LOGDMABUF(
        ("GlobalDMABufFormats::ConfigureFormat(): Adding %x fourcc format "
         "dmabuf "
         "modifiers num [%d].",
         aDrmFourcc, (int)mods.Length()));
  }
  aTargetFormat = new DRMFormat(aDrmFourcc, mods);
  return true;
}

void GlobalDMABufFormats::SetModifiersToGfxVars() {
  RefPtr<DMABufFormats> formats;
#ifdef MOZ_WAYLAND
  if (GdkIsWaylandDisplay()) {
    formats = WaylandDisplayGet()->GetDMABufFormats();
  }
#endif
  if (!formats) {
    formats = new DMABufFormats();
  }
  formats->EnsureBasicFormats();

  if (!ConfigureFormat(formats, mFormatRGBX, GBM_FORMAT_XRGB8888)) {
    MOZ_DIAGNOSTIC_CRASH("Missing GBM_FORMAT_XRGB8888 dmabuf format!");
  }
  gfxVars::SetDMABufModifiersXRGB(*mFormatRGBX->GetModifiers());

  if (!ConfigureFormat(formats, mFormatRGBA, GBM_FORMAT_ARGB8888)) {
    MOZ_DIAGNOSTIC_CRASH("Missing GBM_FORMAT_ARGB8888 dmabuf format!");
  }
  gfxVars::SetDMABufModifiersARGB(*mFormatRGBA->GetModifiers());

  if (ConfigureFormat(formats, mFormatP010, GBM_FORMAT_P010)) {
    gfxVars::SetDMABufModifiersP010(*mFormatP010->GetModifiers());
  }

  if (ConfigureFormat(formats, mFormatNV12, GBM_FORMAT_NV12)) {
    gfxVars::SetDMABufModifiersNV12(*mFormatNV12->GetModifiers());
  }

  ConfigureFormat(formats, mFormatYUV420, GBM_FORMAT_YUV420);
}

void GlobalDMABufFormats::GetModifiersFromGfxVars() {
  mFormatRGBX =
      new DRMFormat(GBM_FORMAT_XRGB8888, gfxVars::DMABufModifiersXRGB());
  mFormatRGBA =
      new DRMFormat(GBM_FORMAT_ARGB8888, gfxVars::DMABufModifiersARGB());
  if (!gfxVars::DMABufModifiersP010().IsEmpty()) {
    mFormatP010 =
        new DRMFormat(GBM_FORMAT_P010, gfxVars::DMABufModifiersP010());
  }
  if (!gfxVars::DMABufModifiersNV12().IsEmpty()) {
    mFormatNV12 =
        new DRMFormat(GBM_FORMAT_NV12, gfxVars::DMABufModifiersNV12());
  }
}

DRMFormat* GlobalDMABufFormats::GetDRMFormat(int32_t aFOURCCFormat) {
  switch (aFOURCCFormat) {
    case GBM_FORMAT_XRGB8888:
      MOZ_DIAGNOSTIC_ASSERT(mFormatRGBX, "Missing RGBX dmabuf format!");
      return mFormatRGBX;
    case GBM_FORMAT_ARGB8888:
      MOZ_DIAGNOSTIC_ASSERT(mFormatRGBA, "Missing RGBA dmabuf format!");
      return mFormatRGBA;
    case GBM_FORMAT_P010:
      return mFormatP010;
    case GBM_FORMAT_NV12:
      return mFormatNV12;
    case GBM_FORMAT_YUV420:
      return mFormatYUV420;
    default:
      gfxCriticalNoteOnce << "DMABufDevice::GetDRMFormat() unknow format: "
                          << aFOURCCFormat;
      return nullptr;
  }
}

bool GlobalDMABufFormats::SupportsDirectComposition(
    mozilla::gfx::SurfaceFormat aFormat) const {
  switch (aFormat) {
    case gfx::SurfaceFormat::R8G8B8X8:
    case gfx::SurfaceFormat::R8G8B8A8:
    case gfx::SurfaceFormat::B8G8R8A8:
    case gfx::SurfaceFormat::B8G8R8X8:
      return true;
    case gfx::SurfaceFormat::NV12:
      return !!mFormatNV12;
    case gfx::SurfaceFormat::YUV420:
      return !!mFormatYUV420;
    case gfx::SurfaceFormat::P010:
      return !!mFormatP010;
    default:
      MOZ_ASSERT_UNREACHABLE("unexpected to be called");
      return false;
  }
}

void GlobalDMABufFormats::LoadFormatModifiers() {
  if (XRE_IsParentProcess()) {
    MOZ_ASSERT(NS_IsMainThread());
    SetModifiersToGfxVars();
  } else {
    GetModifiersFromGfxVars();
  }
}

GlobalDMABufFormats::GlobalDMABufFormats() { LoadFormatModifiers(); }

GlobalDMABufFormats* GetGlobalDMABufFormats() {
  static StaticAutoPtr<GlobalDMABufFormats> sGlobalDMABufFormats;
  static std::once_flag onceFlag;
  std::call_once(onceFlag, [] {
    sGlobalDMABufFormats = new GlobalDMABufFormats();
    if (NS_IsMainThread()) {
      ClearOnShutdown(&sGlobalDMABufFormats);
    } else {
      NS_DispatchToMainThread(NS_NewRunnableFunction(
          "ClearGlobalDMABufFormats",
          [] { ClearOnShutdown(&sGlobalDMABufFormats); }));
    }
  });
  return sGlobalDMABufFormats.get();
}

}  // namespace mozilla::widget

Messung V0.5 in Prozent
C=95 H=98 G=96

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet am  2026-09-28) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

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 und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1126438
#Domains=1867298