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

Quelle  GLBlitHelperD3D.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "GLBlitHelper.h"

#include <d3d11.h>
#include <d3d11_1.h>

#include "GLContextEGL.h"
#include "GLLibraryEGL.h"
#include "GPUVideoImage.h"
#include "ScopedGLHelpers.h"

#include "mozilla/layers/D3D11ShareHandleImage.h"
#include "mozilla/layers/D3D11ZeroCopyTextureImage.h"
#include "mozilla/layers/D3D11YCbCrImage.h"
#include "mozilla/layers/GpuProcessD3D11TextureMap.h"
#include "mozilla/layers/TextureD3D11.h"
#include "mozilla/StaticPrefs_gl.h"

namespace mozilla {
namespace gl {

#define NOTE_IF_FALSE(expr)                          \
  do {                                               \
    if (!(expr)) {                                   \
      gfxCriticalNote << "NOTE_IF_FALSE: " << #expr; \
    }                                                \
  } while (false)

static EGLStreamKHR StreamFromD3DTexture(EglDisplay* const egl,
                                         ID3D11Texture2D* const texD3D,
                                         const EGLAttrib* const postAttribs) {
  if (!egl->IsExtensionSupported(
          EGLExtension::NV_stream_consumer_gltexture_yuv) ||
      !egl->IsExtensionSupported(
          EGLExtension::ANGLE_stream_producer_d3d_texture)) {
    return 0;
  }

  const auto stream = egl->fCreateStreamKHR(nullptr);
  MOZ_ASSERT(stream);
  if (!stream) return 0;
  bool ok = true;
  NOTE_IF_FALSE(ok &= bool(egl->fStreamConsumerGLTextureExternalAttribsNV(
                    stream, nullptr)));
  NOTE_IF_FALSE(
      ok &= bool(egl->fCreateStreamProducerD3DTextureANGLE(stream, nullptr)));
  NOTE_IF_FALSE(
      ok &= bool(egl->fStreamPostD3DTextureANGLE(stream, texD3D, postAttribs)));
  if (ok) return stream;

  (void)egl->fDestroyStreamKHR(stream);
  return 0;
}

static RefPtr<ID3D11Texture2D> OpenSharedTexture(ID3D11Device* const d3d,
                                                 const WindowsHandle handle) {
  RefPtr<ID3D11Device1> device1;
  d3d->QueryInterface((ID3D11Device1**)getter_AddRefs(device1));
  if (!device1) {
    gfxCriticalNoteOnce << "Failed to get ID3D11Device1";
    return nullptr;
  }

  RefPtr<ID3D11Texture2D> tex;
  auto hr = device1->OpenSharedResource1(
      (HANDLE)handle, __uuidof(ID3D11Texture2D),
      (void**)(ID3D11Texture2D**)getter_AddRefs(tex));
  if (FAILED(hr)) {
    gfxCriticalError() << "Error code from OpenSharedResource1: "
                       << gfx::hexa(hr);
    return nullptr;
  }
  return tex;
}

// -------------------------------------

class BindAnglePlanes final {
  const GLBlitHelper& mParent;
  const uint8_t mNumPlanes;
  const ScopedSaveMultiTex mMultiTex;
  GLuint mTempTexs[3];
  EGLStreamKHR mStreams[3];
  RefPtr<IDXGIKeyedMutex> mMutexList[3];
  bool mSuccess;

 public:
  BindAnglePlanes(const GLBlitHelper* const parent, const uint8_t numPlanes,
                  const RefPtr<ID3D11Texture2D>* const texD3DList,
                  const EGLAttrib* const* postAttribsList = nullptr)
      : mParent(*parent),
        mNumPlanes(numPlanes),
        mMultiTex(mParent.mGL, mNumPlanes, LOCAL_GL_TEXTURE_EXTERNAL),
        mTempTexs{0},
        mStreams{0},
        mSuccess(true) {
    MOZ_RELEASE_ASSERT(numPlanes >= 1 && numPlanes <= 3);

    const auto& gl = mParent.mGL;
    const auto& gle = GLContextEGL::Cast(gl);
    const auto& egl = gle->mEgl;

    gl->fGenTextures(numPlanes, mTempTexs);

    for (uint8_t i = 0; i < mNumPlanes; i++) {
      gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
      gl->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL, mTempTexs[i]);
      const EGLAttrib* postAttribs = nullptr;
      if (postAttribsList) {
        postAttribs = postAttribsList[i];
      }
      mStreams[i] = StreamFromD3DTexture(egl.get(), texD3DList[i], postAttribs);
      mSuccess &= bool(mStreams[i]);
    }

    if (mSuccess) {
      for (uint8_t i = 0; i < mNumPlanes; i++) {
        NOTE_IF_FALSE(egl->fStreamConsumerAcquireKHR(mStreams[i]));

        auto& mutex = mMutexList[i];
        texD3DList[i]->QueryInterface(IID_IDXGIKeyedMutex,
                                      (void**)getter_AddRefs(mutex));
        if (mutex) {
          const auto hr = mutex->AcquireSync(0, 100);
          if (FAILED(hr)) {
            NS_WARNING("BindAnglePlanes failed to acquire KeyedMutex.");
            mSuccess = false;
          }
        }
      }
    }
  }

  ~BindAnglePlanes() {
    const auto& gl = mParent.mGL;
    const auto& gle = GLContextEGL::Cast(gl);
    const auto& egl = gle->mEgl;

    if (mSuccess) {
      for (uint8_t i = 0; i < mNumPlanes; i++) {
        NOTE_IF_FALSE(egl->fStreamConsumerReleaseKHR(mStreams[i]));
        if (mMutexList[i]) {
          mMutexList[i]->ReleaseSync(0);
        }
      }
    }

    for (uint8_t i = 0; i < mNumPlanes; i++) {
      (void)egl->fDestroyStreamKHR(mStreams[i]);
    }

    gl->fDeleteTextures(mNumPlanes, mTempTexs);
  }

  const bool& Success() const { return mSuccess; }
};

// -------------------------------------

ID3D11Device* GLBlitHelper::GetD3D11() const {
  if (mD3D11) return mD3D11;

  if (!mGL->IsANGLE()) return nullptr;

  const auto& gle = GLContextEGL::Cast(mGL);
  const auto& egl = gle->mEgl;
  EGLDeviceEXT deviceEGL = 0;
  NOTE_IF_FALSE(egl->fQueryDisplayAttribEXT(LOCAL_EGL_DEVICE_EXT,
                                            (EGLAttrib*)&deviceEGL));
  ID3D11Device* device = nullptr;
  // ANGLE does not `AddRef` its returned pointer for `QueryDeviceAttrib`, so no
  // `getter_AddRefs`.
  if (!egl->mLib->fQueryDeviceAttribEXT(deviceEGL, LOCAL_EGL_D3D11_DEVICE_ANGLE,
                                        (EGLAttrib*)&device)) {
    MOZ_ASSERT(false"d3d9?");
    return nullptr;
  }
  mD3D11 = device;
  return mD3D11;
}

// -------------------------------------

bool GLBlitHelper::BlitImage(layers::D3D11ShareHandleImage* const srcImage,
                             const gfx::IntSize& destSize,
                             const OriginPos destOrigin) const {
  const auto& data = srcImage->GetData();
  if (!data) return false;

  layers::SurfaceDescriptorD3D10 desc;
  if (!data->SerializeSpecific(&desc)) return false;

  return BlitDescriptor(desc, destSize, destOrigin);
}

// -------------------------------------

bool GLBlitHelper::BlitImage(layers::D3D11ZeroCopyTextureImage* const srcImage,
                             const gfx::IntSize& destSize,
                             const OriginPos destOrigin) const {
  const auto& data = srcImage->GetData();
  if (!data) return false;

  layers::SurfaceDescriptorD3D10 desc;
  if (!data->SerializeSpecific(&desc)) return false;

  return BlitDescriptor(desc, destSize, destOrigin);
}

// -------------------------------------

bool GLBlitHelper::BlitDescriptor(const layers::SurfaceDescriptorD3D10& desc,
                                  const gfx::IntSize& destSize,
                                  const OriginPos destOrigin) const {
  const auto& d3d = GetD3D11();
  if (!d3d) return false;

  const auto& gpuProcessTextureId = desc.gpuProcessTextureId();
  const auto& arrayIndex = desc.arrayIndex();
  const auto& format = desc.format();
  const auto& clipSize = desc.size();

  const auto srcOrigin = OriginPos::BottomLeft;
  const gfx::IntRect clipRect(0, 0, clipSize.width, clipSize.height);
  const auto colorSpace = desc.colorSpace();

  if (format != gfx::SurfaceFormat::NV12 &&
      format != gfx::SurfaceFormat::P010 &&
      format != gfx::SurfaceFormat::P016) {
    gfxCriticalError() << "Non-NV12 format for SurfaceDescriptorD3D10: "
                       << uint32_t(format);
    return false;
  }

  RefPtr<ID3D11Texture2D> tex;
  if (gpuProcessTextureId.isSome()) {
    auto* textureMap = layers::GpuProcessD3D11TextureMap::Get();
    if (textureMap) {
      Maybe<HANDLE> handle =
          textureMap->GetSharedHandle(gpuProcessTextureId.ref());
      if (handle.isSome()) {
        tex = OpenSharedTexture(d3d, (WindowsHandle)handle.ref());
      }
    }
  } else if (desc.handle()) {
    tex = OpenSharedTexture(d3d, (WindowsHandle)desc.handle()->GetHandle());
  }
  if (!tex) {
    MOZ_GL_ASSERT(mGL, false);  // Get a nullptr from OpenSharedResource1.
    return false;
  }
  const RefPtr<ID3D11Texture2D> texList[2] = {tex, tex};
  const EGLAttrib postAttribs0[] = {LOCAL_EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 0,
                                    LOCAL_EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE,
                                    static_cast<EGLAttrib>(arrayIndex),
                                    LOCAL_EGL_NONE};
  const EGLAttrib postAttribs1[] = {LOCAL_EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 1,
                                    LOCAL_EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE,
                                    static_cast<EGLAttrib>(arrayIndex),
                                    LOCAL_EGL_NONE};
  const EGLAttrib* const postAttribsList[2] = {postAttribs0, postAttribs1};
  // /layers/d3d11/CompositorD3D11.cpp uses bt601 for EffectTypes::NV12.
  // return BlitAngleNv12(tex, YUVColorSpace::BT601, destSize, destOrigin);

  const BindAnglePlanes bindPlanes(this, 2, texList, postAttribsList);
  if (!bindPlanes.Success()) {
    MOZ_GL_ASSERT(mGL, false);  // BindAnglePlanes failed.
    return false;
  }

  D3D11_TEXTURE2D_DESC texDesc = {0};
  tex->GetDesc(&texDesc);

  const gfx::IntSize ySize(texDesc.Width, texDesc.Height);
  const gfx::IntSize divisors(2, 2);
  MOZ_ASSERT(ySize.width % divisors.width == 0);
  MOZ_ASSERT(ySize.height % divisors.height == 0);
  const gfx::IntSize uvSize(ySize.width / divisors.width,
                            ySize.height / divisors.height);

  const auto yuvColorSpace = [&]() {
    switch (colorSpace) {
      case gfx::ColorSpace2::UNKNOWN:
      case gfx::ColorSpace2::SRGB:
      case gfx::ColorSpace2::DISPLAY_P3:
        MOZ_CRASH("Expected BT* colorspace");
      case gfx::ColorSpace2::BT601_525:
        return gfx::YUVColorSpace::BT601;
      case gfx::ColorSpace2::BT709:
        return gfx::YUVColorSpace::BT709;
      case gfx::ColorSpace2::BT2020:
        return gfx::YUVColorSpace::BT2020;
    }
    MOZ_ASSERT_UNREACHABLE();
  }();

  const bool yFlip = destOrigin != srcOrigin;
  const DrawBlitProg::BaseArgs baseArgs = {SubRectMat3(clipRect, ySize), yFlip,
                                           destSize, Nothing()};
  const DrawBlitProg::YUVArgs yuvArgs = {
      SubRectMat3(clipRect, uvSize, divisors), Some(yuvColorSpace)};

  const auto& prog = GetDrawBlitProg(
      {kFragHeader_TexExt, {kFragSample_TwoPlane, kFragConvert_ColorMatrix}});
  prog.Draw(baseArgs, &yuvArgs);
  return true;
}

bool GLBlitHelper::BlitDescriptor(
    const layers::SurfaceDescriptorDXGIYCbCr& desc,
    const gfx::IntSize& destSize, const OriginPos destOrigin) const {
  const auto& clipSize = desc.size();
  const auto& ySize = desc.sizeY();
  const auto& uvSize = desc.sizeCbCr();
  const auto& colorSpace = desc.yUVColorSpace();

  const gfx::IntRect clipRect(0, 0, clipSize.width, clipSize.height);

  auto handleY = desc.handleY() ? desc.handleY()->GetHandle() : nullptr;
  auto handleCb = desc.handleCb() ? desc.handleCb()->GetHandle() : nullptr;
  auto handleCr = desc.handleCr() ? desc.handleCr()->GetHandle() : nullptr;

  const WindowsHandle handles[3] = {
      (WindowsHandle)handleY, (WindowsHandle)handleCb, (WindowsHandle)handleCr};
  return BlitAngleYCbCr(handles, clipRect, ySize, uvSize, colorSpace, destSize,
                        destOrigin);
}

// --

bool GLBlitHelper::BlitAngleYCbCr(const WindowsHandle (&handleList)[3],
                                  const gfx::IntRect& clipRect,
                                  const gfx::IntSize& ySize,
                                  const gfx::IntSize& uvSize,
                                  const gfx::YUVColorSpace colorSpace,
                                  const gfx::IntSize& destSize,
                                  const OriginPos destOrigin) const {
  const auto& d3d = GetD3D11();
  if (!d3d) return false;

  const auto srcOrigin = OriginPos::BottomLeft;

  gfx::IntSize divisors;
  if (!GuessDivisors(ySize, uvSize, &divisors)) return false;

  const RefPtr<ID3D11Texture2D> texList[3] = {
      OpenSharedTexture(d3d, handleList[0]),
      OpenSharedTexture(d3d, handleList[1]),
      OpenSharedTexture(d3d, handleList[2])};
  const BindAnglePlanes bindPlanes(this, 3, texList);

  const bool yFlip = destOrigin != srcOrigin;
  const DrawBlitProg::BaseArgs baseArgs = {SubRectMat3(clipRect, ySize), yFlip,
                                           destSize, Nothing()};
  const DrawBlitProg::YUVArgs yuvArgs = {
      SubRectMat3(clipRect, uvSize, divisors), Some(colorSpace)};

  const auto& prog = GetDrawBlitProg(
      {kFragHeader_TexExt, {kFragSample_ThreePlane, kFragConvert_ColorMatrix}});
  prog.Draw(baseArgs, &yuvArgs);
  return true;
}

}  // namespace gl
}  // namespace mozilla

Messung V0.5
C=90 H=97 G=93

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