tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

RenderD3D11TextureHost.cpp (25528B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "RenderD3D11TextureHost.h"
      8 
      9 #include <dcomp.h>
     10 
     11 #include "GLContextEGL.h"
     12 #include "GLLibraryEGL.h"
     13 #include "RenderThread.h"
     14 #include "RenderCompositor.h"
     15 #include "RenderCompositorD3D11SWGL.h"
     16 #include "ScopedGLHelpers.h"
     17 #include "mozilla/gfx/CanvasManagerParent.h"
     18 #include "mozilla/gfx/DeviceManagerDx.h"
     19 #include "mozilla/gfx/gfxVars.h"
     20 #include "mozilla/gfx/Logging.h"
     21 #include "mozilla/layers/FenceD3D11.h"
     22 #include "mozilla/layers/GpuProcessD3D11TextureMap.h"
     23 #include "mozilla/layers/CompositeProcessD3D11FencesHolderMap.h"
     24 #include "mozilla/layers/TextureD3D11.h"
     25 
     26 namespace mozilla {
     27 namespace wr {
     28 
     29 RenderDXGITextureHost::RenderDXGITextureHost(
     30    const RefPtr<gfx::FileHandleWrapper> aHandle,
     31    const Maybe<layers::GpuProcessTextureId>& aGpuProcessTextureId,
     32    const uint32_t aArrayIndex, const gfx::SurfaceFormat aFormat,
     33    const gfx::ColorSpace2 aColorSpace, const gfx::ColorRange aColorRange,
     34    const gfx::IntSize aSize, bool aHasKeyedMutex,
     35    const Maybe<layers::CompositeProcessFencesHolderId>& aFencesHolderId)
     36    : mHandle(aHandle),
     37      mGpuProcessTextureId(aGpuProcessTextureId),
     38      mArrayIndex(aArrayIndex),
     39      mSurface(0),
     40      mStream(0),
     41      mTextureHandle{0},
     42      mFormat(aFormat),
     43      mColorSpace(aColorSpace),
     44      mColorRange(aColorRange),
     45      mSize(aSize),
     46      mHasKeyedMutex(aHasKeyedMutex),
     47      mFencesHolderId(aFencesHolderId),
     48      mLocked(false) {
     49  MOZ_COUNT_CTOR_INHERITED(RenderDXGITextureHost, RenderTextureHost);
     50  MOZ_ASSERT((mFormat != gfx::SurfaceFormat::NV12 &&
     51              mFormat != gfx::SurfaceFormat::P010 &&
     52              mFormat != gfx::SurfaceFormat::P016) ||
     53             (mSize.width % 2 == 0 && mSize.height % 2 == 0));
     54  MOZ_ASSERT(!(!aHandle && aGpuProcessTextureId.isNothing()));
     55 }
     56 
     57 RenderDXGITextureHost::~RenderDXGITextureHost() {
     58  MOZ_COUNT_DTOR_INHERITED(RenderDXGITextureHost, RenderTextureHost);
     59  DeleteTextureHandle();
     60 }
     61 
     62 /* static */
     63 bool RenderDXGITextureHost::UseDCompositionTextureOverlay(
     64    gfx::SurfaceFormat aFormat) {
     65  if (!gfx::gfxVars::UseWebRenderDCompositionTextureOverlayWin()) {
     66    return false;
     67  }
     68 
     69  if (!gfx::DeviceManagerDx::Get()->CanUseDCompositionTexture()) {
     70    return false;
     71  }
     72 
     73  if (aFormat != gfx::SurfaceFormat::B8G8R8A8 &&
     74      aFormat != gfx::SurfaceFormat::B8G8R8X8) {
     75    return false;
     76  }
     77 
     78  return true;
     79 }
     80 
     81 IDCompositionTexture* RenderDXGITextureHost::GetDCompositionTexture() {
     82  if (mDCompositionTexture) {
     83    return mDCompositionTexture;
     84  }
     85 
     86  if (!UseDCompositionTextureOverlay(mFormat)) {
     87    return nullptr;
     88  }
     89 
     90  if (mFencesHolderId.isNothing()) {
     91    MOZ_ASSERT_UNREACHABLE("Unexpected to be called!");
     92    return nullptr;
     93  }
     94 
     95  HRESULT hr;
     96  RefPtr<IDCompositionDevice2> dcomp =
     97      gfx::DeviceManagerDx::Get()->GetDirectCompositionDevice();
     98  if (!dcomp) {
     99    MOZ_ASSERT_UNREACHABLE("Unexpected to be called!");
    100    gfxCriticalNoteOnce << "Failed to get DirectCompositionDevice";
    101    return nullptr;
    102  }
    103 
    104  RefPtr<IDCompositionDevice4> dcomp4;
    105  hr = dcomp->QueryInterface((IDCompositionDevice4**)getter_AddRefs(dcomp4));
    106  if (FAILED(hr)) {
    107    MOZ_ASSERT_UNREACHABLE("Unexpected to be called!");
    108    gfxCriticalNoteOnce << "Failed to get DCompositionDevice4";
    109    return nullptr;
    110  }
    111 
    112  RefPtr<ID3D11Texture2D> texture2D = GetD3D11Texture2DWithGL();
    113  if (!texture2D) {
    114    gfxCriticalNoteOnce << "Failed to get D3D11Texture";
    115    return nullptr;
    116  }
    117 
    118  RefPtr<IDCompositionTexture> dcompTexture;
    119  hr =
    120      dcomp4->CreateCompositionTexture(texture2D, getter_AddRefs(dcompTexture));
    121  if (FAILED(hr)) {
    122    gfxCriticalNoteOnce << "CreateCompositionTexture failed:  "
    123                        << gfx::hexa(hr);
    124    return nullptr;
    125  }
    126 
    127  mDCompositionTexture = dcompTexture;
    128 
    129  return mDCompositionTexture;
    130 }
    131 
    132 ID3D11Texture2D* RenderDXGITextureHost::GetD3D11Texture2DWithGL() {
    133  if (mTexture) {
    134    return mTexture;
    135  }
    136 
    137  if (!mGL) {
    138    // SingletonGL is always used on Windows with ANGLE.
    139    mGL = RenderThread::Get()->SingletonGL();
    140  }
    141 
    142  if (!EnsureD3D11Texture2DWithGL()) {
    143    return nullptr;
    144  }
    145 
    146  return mTexture;
    147 }
    148 
    149 size_t RenderDXGITextureHost::GetPlaneCount() const {
    150  switch (mFormat) {
    151    case gfx::SurfaceFormat::NV12:
    152    case gfx::SurfaceFormat::P010:
    153    case gfx::SurfaceFormat::P016: {
    154      return 2;
    155    }
    156    case gfx::SurfaceFormat::B8G8R8A8:
    157    case gfx::SurfaceFormat::B8G8R8X8:
    158    case gfx::SurfaceFormat::R8G8B8A8:
    159    case gfx::SurfaceFormat::R8G8B8X8:
    160    case gfx::SurfaceFormat::A8R8G8B8:
    161    case gfx::SurfaceFormat::X8R8G8B8:
    162    case gfx::SurfaceFormat::R8G8B8:
    163    case gfx::SurfaceFormat::B8G8R8:
    164    case gfx::SurfaceFormat::R5G6B5_UINT16:
    165    case gfx::SurfaceFormat::R10G10B10A2_UINT32:
    166    case gfx::SurfaceFormat::R10G10B10X2_UINT32:
    167    case gfx::SurfaceFormat::R16G16B16A16F:
    168    case gfx::SurfaceFormat::A8:
    169    case gfx::SurfaceFormat::A16:
    170    case gfx::SurfaceFormat::R8G8:
    171    case gfx::SurfaceFormat::R16G16:
    172    case gfx::SurfaceFormat::YUV420:
    173    case gfx::SurfaceFormat::YUV420P10:
    174    case gfx::SurfaceFormat::YUV422P10:
    175    case gfx::SurfaceFormat::NV16:
    176    case gfx::SurfaceFormat::YUY2:
    177    case gfx::SurfaceFormat::HSV:
    178    case gfx::SurfaceFormat::Lab:
    179    case gfx::SurfaceFormat::Depth:
    180    case gfx::SurfaceFormat::UNKNOWN:
    181      return 1;
    182  }
    183  MOZ_ASSERT_UNREACHABLE("unhandled enum value for gfx::SurfaceFormat");
    184  return 1;
    185 }
    186 
    187 template <typename T>
    188 static bool MapTexture(T* aHost, RenderCompositor* aCompositor,
    189                       RefPtr<ID3D11Texture2D>& aTexture,
    190                       RefPtr<ID3D11DeviceContext>& aDeviceContext,
    191                       RefPtr<ID3D11Texture2D>& aCpuTexture,
    192                       D3D11_MAPPED_SUBRESOURCE& aMappedSubresource) {
    193  if (!aCompositor) {
    194    return false;
    195  }
    196 
    197  RenderCompositorD3D11SWGL* compositor =
    198      aCompositor->AsRenderCompositorD3D11SWGL();
    199  if (!compositor) {
    200    return false;
    201  }
    202 
    203  if (!aHost->EnsureD3D11Texture2D(compositor->GetDevice())) {
    204    return false;
    205  }
    206 
    207  if (!aHost->LockInternal()) {
    208    return false;
    209  }
    210 
    211  D3D11_TEXTURE2D_DESC textureDesc = {0};
    212  aTexture->GetDesc(&textureDesc);
    213 
    214  compositor->GetDevice()->GetImmediateContext(getter_AddRefs(aDeviceContext));
    215 
    216  textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
    217  textureDesc.Usage = D3D11_USAGE_STAGING;
    218  textureDesc.BindFlags = 0;
    219  textureDesc.MiscFlags = 0;
    220  textureDesc.MipLevels = 1;
    221  HRESULT hr = compositor->GetDevice()->CreateTexture2D(
    222      &textureDesc, nullptr, getter_AddRefs(aCpuTexture));
    223  if (FAILED(hr)) {
    224    return false;
    225  }
    226 
    227  aDeviceContext->CopyResource(aCpuTexture, aTexture);
    228  aHost->Unlock();
    229 
    230  hr = aDeviceContext->Map(aCpuTexture, 0, D3D11_MAP_READ, 0,
    231                           &aMappedSubresource);
    232  return SUCCEEDED(hr);
    233 }
    234 
    235 bool RenderDXGITextureHost::MapPlane(RenderCompositor* aCompositor,
    236                                     uint8_t aChannelIndex,
    237                                     PlaneInfo& aPlaneInfo) {
    238  // TODO: We currently readback from the GPU texture into a new
    239  // staging texture every time this is mapped. We might be better
    240  // off retaining the mapped memory to trade performance for memory
    241  // usage.
    242  if (!mCpuTexture && !MapTexture(this, aCompositor, mTexture, mDeviceContext,
    243                                  mCpuTexture, mMappedSubresource)) {
    244    return false;
    245  }
    246 
    247  aPlaneInfo.mSize = GetSize(aChannelIndex);
    248  aPlaneInfo.mStride = mMappedSubresource.RowPitch;
    249  aPlaneInfo.mData = mMappedSubresource.pData;
    250 
    251  // If this is the second plane, then offset the data pointer by the
    252  // size of the first plane.
    253  if (aChannelIndex == 1) {
    254    aPlaneInfo.mData =
    255        (uint8_t*)aPlaneInfo.mData + aPlaneInfo.mStride * GetSize(0).height;
    256  }
    257  return true;
    258 }
    259 
    260 void RenderDXGITextureHost::UnmapPlanes() {
    261  mMappedSubresource.pData = nullptr;
    262  if (mCpuTexture) {
    263    mDeviceContext->Unmap(mCpuTexture, 0);
    264    mCpuTexture = nullptr;
    265  }
    266  mDeviceContext = nullptr;
    267 }
    268 
    269 bool RenderDXGITextureHost::EnsureD3D11Texture2DWithGL() {
    270  if (mTexture) {
    271    return true;
    272  }
    273 
    274  const auto& gle = gl::GLContextEGL::Cast(mGL);
    275  const auto& egl = gle->mEgl;
    276 
    277  // Fetch the D3D11 device.
    278  EGLDeviceEXT eglDevice = nullptr;
    279  egl->fQueryDisplayAttribEXT(LOCAL_EGL_DEVICE_EXT, (EGLAttrib*)&eglDevice);
    280  MOZ_ASSERT(eglDevice);
    281  ID3D11Device* device = nullptr;
    282  egl->mLib->fQueryDeviceAttribEXT(eglDevice, LOCAL_EGL_D3D11_DEVICE_ANGLE,
    283                                   (EGLAttrib*)&device);
    284  // There's a chance this might fail if we end up on d3d9 angle for some
    285  // reason.
    286  if (!device) {
    287    gfxCriticalNote << "RenderDXGITextureHost device is not available";
    288    return false;
    289  }
    290 
    291  return EnsureD3D11Texture2D(device);
    292 }
    293 
    294 bool RenderDXGITextureHost::EnsureD3D11Texture2D(ID3D11Device* aDevice) {
    295  if (mTexture) {
    296    RefPtr<ID3D11Device> device;
    297    mTexture->GetDevice(getter_AddRefs(device));
    298    if (aDevice != device) {
    299      gfxCriticalNote << "RenderDXGITextureHost uses obsoleted device";
    300      return false;
    301    }
    302    return true;
    303  }
    304 
    305  if (mGpuProcessTextureId.isSome()) {
    306    auto* textureMap = layers::GpuProcessD3D11TextureMap::Get();
    307    if (textureMap) {
    308      RefPtr<ID3D11Texture2D> texture;
    309      textureMap->WaitTextureReady(mGpuProcessTextureId.ref());
    310      mTexture = textureMap->GetTexture(mGpuProcessTextureId.ref());
    311      if (mTexture) {
    312        return true;
    313      } else {
    314        gfxCriticalNote << "GpuProcessTextureId is not valid";
    315      }
    316    }
    317    return false;
    318  }
    319 
    320  RefPtr<ID3D11Device1> device1;
    321  aDevice->QueryInterface((ID3D11Device1**)getter_AddRefs(device1));
    322  if (!device1) {
    323    gfxCriticalNoteOnce << "Failed to get ID3D11Device1";
    324    return 0;
    325  }
    326 
    327  // Get the D3D11 texture from shared handle.
    328  HRESULT hr = device1->OpenSharedResource1(
    329      (HANDLE)mHandle->GetHandle(), __uuidof(ID3D11Texture2D),
    330      (void**)(ID3D11Texture2D**)getter_AddRefs(mTexture));
    331  if (FAILED(hr)) {
    332    MOZ_ASSERT(false,
    333               "RenderDXGITextureHost::EnsureLockable(): Failed to open shared "
    334               "texture");
    335    gfxCriticalNote
    336        << "RenderDXGITextureHost Failed to open shared texture, hr="
    337        << gfx::hexa(hr);
    338    return false;
    339  }
    340  MOZ_ASSERT(mTexture.get());
    341  mTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mKeyedMutex));
    342 
    343  MOZ_ASSERT(mHasKeyedMutex == !!mKeyedMutex);
    344  if (mHasKeyedMutex != !!mKeyedMutex) {
    345    gfxCriticalNoteOnce << "KeyedMutex mismatch";
    346  }
    347  return true;
    348 }
    349 
    350 bool RenderDXGITextureHost::EnsureLockable() {
    351  if (mTextureHandle[0]) {
    352    return true;
    353  }
    354 
    355  const auto& gle = gl::GLContextEGL::Cast(mGL);
    356  const auto& egl = gle->mEgl;
    357 
    358  // We use EGLStream to get the converted gl handle from d3d texture. The
    359  // NV_stream_consumer_gltexture_yuv and ANGLE_stream_producer_d3d_texture
    360  // could support nv12 and rgb d3d texture format.
    361  if (!egl->IsExtensionSupported(
    362          gl::EGLExtension::NV_stream_consumer_gltexture_yuv) ||
    363      !egl->IsExtensionSupported(
    364          gl::EGLExtension::ANGLE_stream_producer_d3d_texture)) {
    365    gfxCriticalNote << "RenderDXGITextureHost egl extensions are not suppored";
    366    return false;
    367  }
    368 
    369  // Get the D3D11 texture from shared handle.
    370  if (!EnsureD3D11Texture2DWithGL()) {
    371    return false;
    372  }
    373 
    374  // Create the EGLStream.
    375  mStream = egl->fCreateStreamKHR(nullptr);
    376  MOZ_ASSERT(mStream);
    377 
    378  bool ok = true;
    379  if (mFormat != gfx::SurfaceFormat::NV12 &&
    380      mFormat != gfx::SurfaceFormat::P010 &&
    381      mFormat != gfx::SurfaceFormat::P016) {
    382    // The non-nv12 format.
    383 
    384    mGL->fGenTextures(1, mTextureHandle);
    385    ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE0,
    386                                 LOCAL_GL_TEXTURE_EXTERNAL_OES,
    387                                 mTextureHandle[0]);
    388    ok &=
    389        bool(egl->fStreamConsumerGLTextureExternalAttribsNV(mStream, nullptr));
    390    ok &= bool(egl->fCreateStreamProducerD3DTextureANGLE(mStream, nullptr));
    391  } else {
    392    // The nv12/p016 format.
    393 
    394    // Setup the NV12 stream consumer/producer.
    395    EGLAttrib consumerAttributes[] = {
    396        LOCAL_EGL_COLOR_BUFFER_TYPE,
    397        LOCAL_EGL_YUV_BUFFER_EXT,
    398        LOCAL_EGL_YUV_NUMBER_OF_PLANES_EXT,
    399        2,
    400        LOCAL_EGL_YUV_PLANE0_TEXTURE_UNIT_NV,
    401        0,
    402        LOCAL_EGL_YUV_PLANE1_TEXTURE_UNIT_NV,
    403        1,
    404        LOCAL_EGL_NONE,
    405    };
    406    mGL->fGenTextures(2, mTextureHandle);
    407    ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE0,
    408                                 LOCAL_GL_TEXTURE_EXTERNAL_OES,
    409                                 mTextureHandle[0]);
    410    ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE1,
    411                                 LOCAL_GL_TEXTURE_EXTERNAL_OES,
    412                                 mTextureHandle[1]);
    413    ok &= bool(egl->fStreamConsumerGLTextureExternalAttribsNV(
    414        mStream, consumerAttributes));
    415    ok &= bool(egl->fCreateStreamProducerD3DTextureANGLE(mStream, nullptr));
    416  }
    417 
    418  const EGLAttrib frameAttributes[] = {
    419      LOCAL_EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE,
    420      static_cast<EGLAttrib>(mArrayIndex),
    421      LOCAL_EGL_NONE,
    422  };
    423 
    424  // Insert the d3d texture.
    425  ok &= bool(egl->fStreamPostD3DTextureANGLE(mStream, (void*)mTexture.get(),
    426                                             frameAttributes));
    427 
    428  if (!ok) {
    429    gfxCriticalNote << "RenderDXGITextureHost init stream failed";
    430    DeleteTextureHandle();
    431    return false;
    432  }
    433 
    434  // Now, we could get the gl handle from the stream.
    435  MOZ_ALWAYS_TRUE(egl->fStreamConsumerAcquireKHR(mStream));
    436 
    437  return true;
    438 }
    439 
    440 wr::WrExternalImage RenderDXGITextureHost::Lock(uint8_t aChannelIndex,
    441                                                gl::GLContext* aGL) {
    442  if (mGL.get() != aGL) {
    443    // Release the texture handle in the previous gl context.
    444    DeleteTextureHandle();
    445    mGL = aGL;
    446  }
    447 
    448  if (!mGL) {
    449    // XXX Software WebRender is not handled yet.
    450    // Software WebRender does not provide GLContext
    451    gfxCriticalNoteOnce
    452        << "Software WebRender is not suppored by RenderDXGITextureHost.";
    453    return InvalidToWrExternalImage();
    454  }
    455 
    456  if (!EnsureLockable()) {
    457    return InvalidToWrExternalImage();
    458  }
    459 
    460  if (!LockInternal()) {
    461    return InvalidToWrExternalImage();
    462  }
    463 
    464  const gfx::IntSize size = GetSize(aChannelIndex);
    465  return NativeTextureToWrExternalImage(GetGLHandle(aChannelIndex), 0.0, 0.0,
    466                                        static_cast<float>(size.width),
    467                                        static_cast<float>(size.height));
    468 }
    469 
    470 bool RenderDXGITextureHost::LockInternal() {
    471  MOZ_ASSERT(mTexture);
    472 
    473  if (!mLocked) {
    474    if (mFencesHolderId.isSome()) {
    475      auto* fencesHolderMap =
    476          layers::CompositeProcessD3D11FencesHolderMap::Get();
    477      if (!fencesHolderMap) {
    478        MOZ_ASSERT_UNREACHABLE("unexpected to be called");
    479        return false;
    480      }
    481      RefPtr<ID3D11Device> device;
    482      mTexture->GetDevice(getter_AddRefs(device));
    483 
    484      if (!fencesHolderMap->WaitWriteFence(mFencesHolderId.ref(), device)) {
    485        return false;
    486      }
    487    }
    488    if (mKeyedMutex) {
    489      HRESULT hr = mKeyedMutex->AcquireSync(0, 10000);
    490      if (hr != S_OK) {
    491        gfxCriticalError() << "RenderDXGITextureHost AcquireSync timeout, hr="
    492                           << gfx::hexa(hr);
    493        return false;
    494      }
    495    }
    496    mLocked = true;
    497  }
    498  return true;
    499 }
    500 
    501 void RenderDXGITextureHost::Unlock() {
    502  if (mLocked) {
    503    if (mKeyedMutex) {
    504      mKeyedMutex->ReleaseSync(0);
    505    }
    506    mLocked = false;
    507  }
    508 }
    509 
    510 void RenderDXGITextureHost::ClearCachedResources() {
    511  DeleteTextureHandle();
    512  mGL = nullptr;
    513 }
    514 
    515 void RenderDXGITextureHost::DeleteTextureHandle() {
    516  if (mTextureHandle[0] == 0) {
    517    return;
    518  }
    519 
    520  MOZ_ASSERT(mGL.get());
    521  if (!mGL) {
    522    return;
    523  }
    524 
    525  if (mGL->MakeCurrent()) {
    526    mGL->fDeleteTextures(2, mTextureHandle);
    527 
    528    const auto& gle = gl::GLContextEGL::Cast(mGL);
    529    const auto& egl = gle->mEgl;
    530    if (mSurface) {
    531      egl->fDestroySurface(mSurface);
    532    }
    533    if (mStream) {
    534      egl->fDestroyStreamKHR(mStream);
    535    }
    536  }
    537 
    538  for (int i = 0; i < 2; ++i) {
    539    mTextureHandle[i] = 0;
    540  }
    541 
    542  mTexture = nullptr;
    543  mKeyedMutex = nullptr;
    544  mSurface = 0;
    545  mStream = 0;
    546 }
    547 
    548 GLuint RenderDXGITextureHost::GetGLHandle(uint8_t aChannelIndex) const {
    549  MOZ_ASSERT(((mFormat == gfx::SurfaceFormat::NV12 ||
    550               mFormat == gfx::SurfaceFormat::P010 ||
    551               mFormat == gfx::SurfaceFormat::P016) &&
    552              aChannelIndex < 2) ||
    553             aChannelIndex < 1);
    554  return mTextureHandle[aChannelIndex];
    555 }
    556 
    557 gfx::IntSize RenderDXGITextureHost::GetSize(uint8_t aChannelIndex) const {
    558  MOZ_ASSERT(((mFormat == gfx::SurfaceFormat::NV12 ||
    559               mFormat == gfx::SurfaceFormat::P010 ||
    560               mFormat == gfx::SurfaceFormat::P016) &&
    561              aChannelIndex < 2) ||
    562             aChannelIndex < 1);
    563 
    564  if (aChannelIndex == 0) {
    565    return mSize;
    566  } else {
    567    // The CbCr channel size is a half of Y channel size in NV12 format.
    568    return mSize / 2;
    569  }
    570 }
    571 
    572 bool RenderDXGITextureHost::SyncObjectNeeded() {
    573  return mGpuProcessTextureId.isNothing() && !mHasKeyedMutex &&
    574         mFencesHolderId.isNothing();
    575 }
    576 
    577 RenderDXGIYCbCrTextureHost::RenderDXGIYCbCrTextureHost(
    578    const RefPtr<gfx::FileHandleWrapper> (&aHandles)[3],
    579    const gfx::YUVColorSpace aYUVColorSpace, const gfx::ColorDepth aColorDepth,
    580    const gfx::ColorRange aColorRange, const gfx::IntSize aSizeY,
    581    const gfx::IntSize aSizeCbCr,
    582    const layers::CompositeProcessFencesHolderId aFencesHolderId)
    583    : mHandles{aHandles[0], aHandles[1], aHandles[2]},
    584      mSurfaces{0},
    585      mStreams{0},
    586      mTextureHandles{0},
    587      mYUVColorSpace(aYUVColorSpace),
    588      mColorDepth(aColorDepth),
    589      mColorRange(aColorRange),
    590      mSizeY(aSizeY),
    591      mSizeCbCr(aSizeCbCr),
    592      mFencesHolderId(aFencesHolderId) {
    593  MOZ_COUNT_CTOR_INHERITED(RenderDXGIYCbCrTextureHost, RenderTextureHost);
    594  // Assume the chroma planes are rounded up if the luma plane is odd sized.
    595  MOZ_ASSERT((mSizeCbCr.width == mSizeY.width ||
    596              mSizeCbCr.width == (mSizeY.width + 1) >> 1) &&
    597             (mSizeCbCr.height == mSizeY.height ||
    598              mSizeCbCr.height == (mSizeY.height + 1) >> 1));
    599  MOZ_ASSERT(aHandles[0] && aHandles[1] && aHandles[2]);
    600 }
    601 
    602 bool RenderDXGIYCbCrTextureHost::MapPlane(RenderCompositor* aCompositor,
    603                                          uint8_t aChannelIndex,
    604                                          PlaneInfo& aPlaneInfo) {
    605  D3D11_MAPPED_SUBRESOURCE mappedSubresource;
    606  if (!MapTexture(this, aCompositor, mTextures[aChannelIndex], mDeviceContext,
    607                  mCpuTexture[aChannelIndex], mappedSubresource)) {
    608    return false;
    609  }
    610 
    611  aPlaneInfo.mSize = GetSize(aChannelIndex);
    612  aPlaneInfo.mStride = mappedSubresource.RowPitch;
    613  aPlaneInfo.mData = mappedSubresource.pData;
    614  return true;
    615 }
    616 
    617 void RenderDXGIYCbCrTextureHost::UnmapPlanes() {
    618  for (uint32_t i = 0; i < 3; i++) {
    619    if (mCpuTexture[i]) {
    620      mDeviceContext->Unmap(mCpuTexture[i], 0);
    621      mCpuTexture[i] = nullptr;
    622    }
    623  }
    624  mDeviceContext = nullptr;
    625 }
    626 
    627 RenderDXGIYCbCrTextureHost::~RenderDXGIYCbCrTextureHost() {
    628  MOZ_COUNT_DTOR_INHERITED(RenderDXGIYCbCrTextureHost, RenderTextureHost);
    629  DeleteTextureHandle();
    630 }
    631 
    632 bool RenderDXGIYCbCrTextureHost::EnsureLockable() {
    633  if (mTextureHandles[0]) {
    634    return true;
    635  }
    636 
    637  const auto& gle = gl::GLContextEGL::Cast(mGL);
    638  const auto& egl = gle->mEgl;
    639 
    640  // The eglCreatePbufferFromClientBuffer doesn't support R8 format, so we
    641  // use EGLStream to get the converted gl handle from d3d R8 texture.
    642 
    643  if (!egl->IsExtensionSupported(
    644          gl::EGLExtension::NV_stream_consumer_gltexture_yuv) ||
    645      !egl->IsExtensionSupported(
    646          gl::EGLExtension::ANGLE_stream_producer_d3d_texture)) {
    647    gfxCriticalNote
    648        << "RenderDXGIYCbCrTextureHost egl extensions are not suppored";
    649    return false;
    650  }
    651 
    652  // Fetch the D3D11 device.
    653  EGLDeviceEXT eglDevice = nullptr;
    654  egl->fQueryDisplayAttribEXT(LOCAL_EGL_DEVICE_EXT, (EGLAttrib*)&eglDevice);
    655  MOZ_ASSERT(eglDevice);
    656  ID3D11Device* device = nullptr;
    657  egl->mLib->fQueryDeviceAttribEXT(eglDevice, LOCAL_EGL_D3D11_DEVICE_ANGLE,
    658                                   (EGLAttrib*)&device);
    659  // There's a chance this might fail if we end up on d3d9 angle for some
    660  // reason.
    661  if (!device) {
    662    gfxCriticalNote << "RenderDXGIYCbCrTextureHost device is not available";
    663    return false;
    664  }
    665 
    666  if (!EnsureD3D11Texture2D(device)) {
    667    return false;
    668  }
    669 
    670  mGL->fGenTextures(3, mTextureHandles);
    671  bool ok = true;
    672  for (int i = 0; i < 3; ++i) {
    673    ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE0 + i,
    674                                 LOCAL_GL_TEXTURE_EXTERNAL_OES,
    675                                 mTextureHandles[i]);
    676 
    677    // Create the EGLStream.
    678    mStreams[i] = egl->fCreateStreamKHR(nullptr);
    679    MOZ_ASSERT(mStreams[i]);
    680 
    681    ok &= bool(
    682        egl->fStreamConsumerGLTextureExternalAttribsNV(mStreams[i], nullptr));
    683    ok &= bool(egl->fCreateStreamProducerD3DTextureANGLE(mStreams[i], nullptr));
    684 
    685    // Insert the R8 texture.
    686    ok &= bool(egl->fStreamPostD3DTextureANGLE(
    687        mStreams[i], (void*)mTextures[i].get(), nullptr));
    688 
    689    // Now, we could get the R8 gl handle from the stream.
    690    MOZ_ALWAYS_TRUE(egl->fStreamConsumerAcquireKHR(mStreams[i]));
    691  }
    692 
    693  if (!ok) {
    694    gfxCriticalNote << "RenderDXGIYCbCrTextureHost init stream failed";
    695    DeleteTextureHandle();
    696    return false;
    697  }
    698 
    699  return true;
    700 }
    701 
    702 bool RenderDXGIYCbCrTextureHost::EnsureD3D11Texture2D(ID3D11Device* aDevice) {
    703  RefPtr<ID3D11Device1> device1;
    704  aDevice->QueryInterface((ID3D11Device1**)getter_AddRefs(device1));
    705  if (!device1) {
    706    gfxCriticalNoteOnce << "Failed to get ID3D11Device1";
    707    return false;
    708  }
    709 
    710  if (mTextures[0]) {
    711    RefPtr<ID3D11Device> device;
    712    mTextures[0]->GetDevice(getter_AddRefs(device));
    713    if (aDevice != device) {
    714      gfxCriticalNote << "RenderDXGIYCbCrTextureHost uses obsoleted device";
    715      return false;
    716    }
    717  }
    718 
    719  if (mTextureHandles[0]) {
    720    return true;
    721  }
    722 
    723  for (int i = 0; i < 3; ++i) {
    724    // Get the R8 D3D11 texture from shared handle.
    725    HRESULT hr = device1->OpenSharedResource1(
    726        (HANDLE)mHandles[i]->GetHandle(), __uuidof(ID3D11Texture2D),
    727        (void**)(ID3D11Texture2D**)getter_AddRefs(mTextures[i]));
    728    if (FAILED(hr)) {
    729      NS_WARNING(
    730          "RenderDXGIYCbCrTextureHost::EnsureLockable(): Failed to open "
    731          "shared "
    732          "texture");
    733      gfxCriticalNote
    734          << "RenderDXGIYCbCrTextureHost Failed to open shared texture, hr="
    735          << gfx::hexa(hr);
    736      return false;
    737    }
    738  }
    739 
    740  mDevice = aDevice;
    741 
    742  return true;
    743 }
    744 
    745 bool RenderDXGIYCbCrTextureHost::LockInternal() {
    746  if (!mLocked) {
    747    auto* fencesHolderMap = layers::CompositeProcessD3D11FencesHolderMap::Get();
    748    if (!fencesHolderMap) {
    749      MOZ_ASSERT_UNREACHABLE("unexpected to be called");
    750      return false;
    751    }
    752    if (!fencesHolderMap->WaitWriteFence(mFencesHolderId, mDevice)) {
    753      return false;
    754    }
    755    mLocked = true;
    756  }
    757  return true;
    758 }
    759 
    760 wr::WrExternalImage RenderDXGIYCbCrTextureHost::Lock(uint8_t aChannelIndex,
    761                                                     gl::GLContext* aGL) {
    762  if (mGL.get() != aGL) {
    763    // Release the texture handle in the previous gl context.
    764    DeleteTextureHandle();
    765    mGL = aGL;
    766  }
    767 
    768  if (!mGL) {
    769    // XXX Software WebRender is not handled yet.
    770    // Software WebRender does not provide GLContext
    771    gfxCriticalNoteOnce << "Software WebRender is not suppored by "
    772                           "RenderDXGIYCbCrTextureHost.";
    773    return InvalidToWrExternalImage();
    774  }
    775 
    776  if (!EnsureLockable()) {
    777    return InvalidToWrExternalImage();
    778  }
    779 
    780  if (!LockInternal()) {
    781    return InvalidToWrExternalImage();
    782  }
    783 
    784  const gfx::IntSize size = GetSize(aChannelIndex);
    785  return NativeTextureToWrExternalImage(GetGLHandle(aChannelIndex), 0.0, 0.0,
    786                                        static_cast<float>(size.width),
    787                                        static_cast<float>(size.height));
    788 }
    789 
    790 void RenderDXGIYCbCrTextureHost::Unlock() {
    791  if (mLocked) {
    792    mLocked = false;
    793  }
    794 }
    795 
    796 void RenderDXGIYCbCrTextureHost::ClearCachedResources() {
    797  DeleteTextureHandle();
    798  mGL = nullptr;
    799 }
    800 
    801 GLuint RenderDXGIYCbCrTextureHost::GetGLHandle(uint8_t aChannelIndex) const {
    802  MOZ_ASSERT(aChannelIndex < 3);
    803 
    804  return mTextureHandles[aChannelIndex];
    805 }
    806 
    807 gfx::IntSize RenderDXGIYCbCrTextureHost::GetSize(uint8_t aChannelIndex) const {
    808  MOZ_ASSERT(aChannelIndex < 3);
    809 
    810  if (aChannelIndex == 0) {
    811    return mSizeY;
    812  } else {
    813    return mSizeCbCr;
    814  }
    815 }
    816 
    817 void RenderDXGIYCbCrTextureHost::DeleteTextureHandle() {
    818  if (mTextureHandles[0] == 0) {
    819    return;
    820  }
    821 
    822  MOZ_ASSERT(mGL.get());
    823  if (!mGL) {
    824    return;
    825  }
    826 
    827  if (mGL->MakeCurrent()) {
    828    mGL->fDeleteTextures(3, mTextureHandles);
    829 
    830    const auto& gle = gl::GLContextEGL::Cast(mGL);
    831    const auto& egl = gle->mEgl;
    832    for (int i = 0; i < 3; ++i) {
    833      mTextureHandles[i] = 0;
    834      mTextures[i] = nullptr;
    835 
    836      if (mSurfaces[i]) {
    837        egl->fDestroySurface(mSurfaces[i]);
    838        mSurfaces[i] = 0;
    839      }
    840      if (mStreams[i]) {
    841        egl->fDestroyStreamKHR(mStreams[i]);
    842        mStreams[i] = 0;
    843      }
    844    }
    845  }
    846  mDevice = nullptr;
    847 }
    848 
    849 }  // namespace wr
    850 }  // namespace mozilla