diff options
Diffstat (limited to 'gfx/webrender_bindings/RenderD3D11TextureHost.cpp')
-rw-r--r-- | gfx/webrender_bindings/RenderD3D11TextureHost.cpp | 705 |
1 files changed, 705 insertions, 0 deletions
diff --git a/gfx/webrender_bindings/RenderD3D11TextureHost.cpp b/gfx/webrender_bindings/RenderD3D11TextureHost.cpp new file mode 100644 index 0000000000..232f8572cb --- /dev/null +++ b/gfx/webrender_bindings/RenderD3D11TextureHost.cpp @@ -0,0 +1,705 @@ +/* -*- 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 "RenderD3D11TextureHost.h" + +#include "GLContextEGL.h" +#include "GLLibraryEGL.h" +#include "RenderThread.h" +#include "RenderCompositor.h" +#include "RenderCompositorD3D11SWGL.h" +#include "ScopedGLHelpers.h" +#include "mozilla/DebugOnly.h" +#include "mozilla/gfx/Logging.h" +#include "mozilla/layers/TextureD3D11.h" + +namespace mozilla { +namespace wr { + +RenderDXGITextureHost::RenderDXGITextureHost( + WindowsHandle aHandle, + Maybe<layers::GpuProcessTextureId>& aGpuProcessTextureId, + uint32_t aArrayIndex, gfx::SurfaceFormat aFormat, + gfx::ColorSpace2 aColorSpace, gfx::ColorRange aColorRange, + gfx::IntSize aSize) + : mHandle(aHandle), + mGpuProcessTextureId(aGpuProcessTextureId), + mArrayIndex(aArrayIndex), + mSurface(0), + mStream(0), + mTextureHandle{0}, + mFormat(aFormat), + mColorSpace(aColorSpace), + mColorRange(aColorRange), + mSize(aSize), + mLocked(false) { + MOZ_COUNT_CTOR_INHERITED(RenderDXGITextureHost, RenderTextureHost); + MOZ_ASSERT((mFormat != gfx::SurfaceFormat::NV12 && + mFormat != gfx::SurfaceFormat::P010 && + mFormat != gfx::SurfaceFormat::P016) || + (mSize.width % 2 == 0 && mSize.height % 2 == 0)); + MOZ_ASSERT((aHandle && aGpuProcessTextureId.isNothing()) || + (!aHandle && aGpuProcessTextureId.isSome())); +} + +RenderDXGITextureHost::~RenderDXGITextureHost() { + MOZ_COUNT_DTOR_INHERITED(RenderDXGITextureHost, RenderTextureHost); + DeleteTextureHandle(); +} + +ID3D11Texture2D* RenderDXGITextureHost::GetD3D11Texture2DWithGL() { + if (mTexture) { + return mTexture; + } + + if (!mGL) { + // SingletonGL is always used on Windows with ANGLE. + mGL = RenderThread::Get()->SingletonGL(); + } + + if (!EnsureD3D11Texture2DWithGL()) { + return nullptr; + } + + return mTexture; +} + +size_t RenderDXGITextureHost::GetPlaneCount() const { + if (mFormat == gfx::SurfaceFormat::NV12 || + mFormat == gfx::SurfaceFormat::P010 || + mFormat == gfx::SurfaceFormat::P016) { + return 2; + } + return 1; +} + +template <typename T> +static bool MapTexture(T* aHost, RenderCompositor* aCompositor, + RefPtr<ID3D11Texture2D>& aTexture, + RefPtr<ID3D11DeviceContext>& aDeviceContext, + RefPtr<ID3D11Texture2D>& aCpuTexture, + D3D11_MAPPED_SUBRESOURCE& aMappedSubresource) { + if (!aCompositor) { + return false; + } + + RenderCompositorD3D11SWGL* compositor = + aCompositor->AsRenderCompositorD3D11SWGL(); + if (!compositor) { + return false; + } + + if (!aHost->EnsureD3D11Texture2D(compositor->GetDevice())) { + return false; + } + + if (!aHost->LockInternal()) { + return false; + } + + D3D11_TEXTURE2D_DESC textureDesc = {0}; + aTexture->GetDesc(&textureDesc); + + compositor->GetDevice()->GetImmediateContext(getter_AddRefs(aDeviceContext)); + + textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + textureDesc.Usage = D3D11_USAGE_STAGING; + textureDesc.BindFlags = 0; + textureDesc.MiscFlags = 0; + textureDesc.MipLevels = 1; + HRESULT hr = compositor->GetDevice()->CreateTexture2D( + &textureDesc, nullptr, getter_AddRefs(aCpuTexture)); + if (FAILED(hr)) { + return false; + } + + aDeviceContext->CopyResource(aCpuTexture, aTexture); + aHost->Unlock(); + + hr = aDeviceContext->Map(aCpuTexture, 0, D3D11_MAP_READ, 0, + &aMappedSubresource); + return SUCCEEDED(hr); +} + +bool RenderDXGITextureHost::MapPlane(RenderCompositor* aCompositor, + uint8_t aChannelIndex, + PlaneInfo& aPlaneInfo) { + // TODO: We currently readback from the GPU texture into a new + // staging texture every time this is mapped. We might be better + // off retaining the mapped memory to trade performance for memory + // usage. + if (!mCpuTexture && !MapTexture(this, aCompositor, mTexture, mDeviceContext, + mCpuTexture, mMappedSubresource)) { + return false; + } + + aPlaneInfo.mSize = GetSize(aChannelIndex); + aPlaneInfo.mStride = mMappedSubresource.RowPitch; + aPlaneInfo.mData = mMappedSubresource.pData; + + // If this is the second plane, then offset the data pointer by the + // size of the first plane. + if (aChannelIndex == 1) { + aPlaneInfo.mData = + (uint8_t*)aPlaneInfo.mData + aPlaneInfo.mStride * GetSize(0).height; + } + return true; +} + +void RenderDXGITextureHost::UnmapPlanes() { + mMappedSubresource.pData = nullptr; + if (mCpuTexture) { + mDeviceContext->Unmap(mCpuTexture, 0); + mCpuTexture = nullptr; + } + mDeviceContext = nullptr; +} + +bool RenderDXGITextureHost::EnsureD3D11Texture2DWithGL() { + if (mTexture) { + return true; + } + + if (mGpuProcessTextureId.isSome()) { + auto* textureMap = layers::GpuProcessD3D11TextureMap::Get(); + if (textureMap) { + RefPtr<ID3D11Texture2D> texture; + mTexture = textureMap->GetTexture(mGpuProcessTextureId.ref()); + if (mTexture) { + return true; + } + } + return false; + } + + const auto& gle = gl::GLContextEGL::Cast(mGL); + const auto& egl = gle->mEgl; + + // Fetch the D3D11 device. + EGLDeviceEXT eglDevice = nullptr; + egl->fQueryDisplayAttribEXT(LOCAL_EGL_DEVICE_EXT, (EGLAttrib*)&eglDevice); + MOZ_ASSERT(eglDevice); + ID3D11Device* device = nullptr; + egl->mLib->fQueryDeviceAttribEXT(eglDevice, LOCAL_EGL_D3D11_DEVICE_ANGLE, + (EGLAttrib*)&device); + // There's a chance this might fail if we end up on d3d9 angle for some + // reason. + if (!device) { + gfxCriticalNote << "RenderDXGITextureHost device is not available"; + return false; + } + + return EnsureD3D11Texture2D(device); +} + +bool RenderDXGITextureHost::EnsureD3D11Texture2D(ID3D11Device* aDevice) { + if (mTexture) { + RefPtr<ID3D11Device> device; + mTexture->GetDevice(getter_AddRefs(device)); + if (aDevice != device) { + gfxCriticalNote << "RenderDXGITextureHost uses obsoleted device"; + return false; + } + return true; + } + + // Get the D3D11 texture from shared handle. + HRESULT hr = aDevice->OpenSharedResource( + (HANDLE)mHandle, __uuidof(ID3D11Texture2D), + (void**)(ID3D11Texture2D**)getter_AddRefs(mTexture)); + if (FAILED(hr)) { + MOZ_ASSERT(false, + "RenderDXGITextureHost::EnsureLockable(): Failed to open shared " + "texture"); + gfxCriticalNote + << "RenderDXGITextureHost Failed to open shared texture, hr=" + << gfx::hexa(hr); + return false; + } + MOZ_ASSERT(mTexture.get()); + mTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mKeyedMutex)); + return true; +} + +bool RenderDXGITextureHost::EnsureLockable() { + if (mTextureHandle[0]) { + return true; + } + + const auto& gle = gl::GLContextEGL::Cast(mGL); + const auto& egl = gle->mEgl; + + // We use EGLStream to get the converted gl handle from d3d texture. The + // NV_stream_consumer_gltexture_yuv and ANGLE_stream_producer_d3d_texture + // could support nv12 and rgb d3d texture format. + if (!egl->IsExtensionSupported( + gl::EGLExtension::NV_stream_consumer_gltexture_yuv) || + !egl->IsExtensionSupported( + gl::EGLExtension::ANGLE_stream_producer_d3d_texture)) { + gfxCriticalNote << "RenderDXGITextureHost egl extensions are not suppored"; + return false; + } + + // Get the D3D11 texture from shared handle. + if (!EnsureD3D11Texture2DWithGL()) { + return false; + } + + // Create the EGLStream. + mStream = egl->fCreateStreamKHR(nullptr); + MOZ_ASSERT(mStream); + + bool ok = true; + if (mFormat != gfx::SurfaceFormat::NV12 && + mFormat != gfx::SurfaceFormat::P010 && + mFormat != gfx::SurfaceFormat::P016) { + // The non-nv12 format. + + mGL->fGenTextures(1, mTextureHandle); + ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE0, + LOCAL_GL_TEXTURE_EXTERNAL_OES, + mTextureHandle[0]); + ok &= + bool(egl->fStreamConsumerGLTextureExternalAttribsNV(mStream, nullptr)); + ok &= bool(egl->fCreateStreamProducerD3DTextureANGLE(mStream, nullptr)); + } else { + // The nv12/p016 format. + + // Setup the NV12 stream consumer/producer. + EGLAttrib consumerAttributes[] = { + LOCAL_EGL_COLOR_BUFFER_TYPE, + LOCAL_EGL_YUV_BUFFER_EXT, + LOCAL_EGL_YUV_NUMBER_OF_PLANES_EXT, + 2, + LOCAL_EGL_YUV_PLANE0_TEXTURE_UNIT_NV, + 0, + LOCAL_EGL_YUV_PLANE1_TEXTURE_UNIT_NV, + 1, + LOCAL_EGL_NONE, + }; + mGL->fGenTextures(2, mTextureHandle); + ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE0, + LOCAL_GL_TEXTURE_EXTERNAL_OES, + mTextureHandle[0]); + ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE1, + LOCAL_GL_TEXTURE_EXTERNAL_OES, + mTextureHandle[1]); + ok &= bool(egl->fStreamConsumerGLTextureExternalAttribsNV( + mStream, consumerAttributes)); + ok &= bool(egl->fCreateStreamProducerD3DTextureANGLE(mStream, nullptr)); + } + + const EGLAttrib frameAttributes[] = { + LOCAL_EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE, + static_cast<EGLAttrib>(mArrayIndex), + LOCAL_EGL_NONE, + }; + + // Insert the d3d texture. + ok &= bool(egl->fStreamPostD3DTextureANGLE(mStream, (void*)mTexture.get(), + frameAttributes)); + + if (!ok) { + gfxCriticalNote << "RenderDXGITextureHost init stream failed"; + DeleteTextureHandle(); + return false; + } + + // Now, we could get the gl handle from the stream. + MOZ_ALWAYS_TRUE(egl->fStreamConsumerAcquireKHR(mStream)); + + return true; +} + +wr::WrExternalImage RenderDXGITextureHost::Lock(uint8_t aChannelIndex, + gl::GLContext* aGL) { + if (mGL.get() != aGL) { + // Release the texture handle in the previous gl context. + DeleteTextureHandle(); + mGL = aGL; + } + + if (!mGL) { + // XXX Software WebRender is not handled yet. + // Software WebRender does not provide GLContext + gfxCriticalNoteOnce + << "Software WebRender is not suppored by RenderDXGITextureHost."; + return InvalidToWrExternalImage(); + } + + if (!EnsureLockable()) { + return InvalidToWrExternalImage(); + } + + if (!LockInternal()) { + return InvalidToWrExternalImage(); + } + + const auto uvs = GetUvCoords(GetSize(aChannelIndex)); + return NativeTextureToWrExternalImage(GetGLHandle(aChannelIndex), uvs.first.x, + uvs.first.y, uvs.second.x, + uvs.second.y); +} + +bool RenderDXGITextureHost::LockInternal() { + if (!mLocked) { + if (mKeyedMutex) { + HRESULT hr = mKeyedMutex->AcquireSync(0, 10000); + if (hr != S_OK) { + gfxCriticalError() << "RenderDXGITextureHost AcquireSync timeout, hr=" + << gfx::hexa(hr); + return false; + } + } + mLocked = true; + } + return true; +} + +void RenderDXGITextureHost::Unlock() { + if (mLocked) { + if (mKeyedMutex) { + mKeyedMutex->ReleaseSync(0); + } + mLocked = false; + } +} + +void RenderDXGITextureHost::ClearCachedResources() { + DeleteTextureHandle(); + mGL = nullptr; +} + +void RenderDXGITextureHost::DeleteTextureHandle() { + if (mTextureHandle[0] == 0) { + return; + } + + MOZ_ASSERT(mGL.get()); + if (!mGL) { + return; + } + + if (mGL->MakeCurrent()) { + mGL->fDeleteTextures(2, mTextureHandle); + + const auto& gle = gl::GLContextEGL::Cast(mGL); + const auto& egl = gle->mEgl; + if (mSurface) { + egl->fDestroySurface(mSurface); + } + if (mStream) { + egl->fDestroyStreamKHR(mStream); + } + } + + for (int i = 0; i < 2; ++i) { + mTextureHandle[i] = 0; + } + + mTexture = nullptr; + mKeyedMutex = nullptr; + mSurface = 0; + mStream = 0; +} + +GLuint RenderDXGITextureHost::GetGLHandle(uint8_t aChannelIndex) const { + MOZ_ASSERT(((mFormat == gfx::SurfaceFormat::NV12 || + mFormat == gfx::SurfaceFormat::P010 || + mFormat == gfx::SurfaceFormat::P016) && + aChannelIndex < 2) || + aChannelIndex < 1); + return mTextureHandle[aChannelIndex]; +} + +gfx::IntSize RenderDXGITextureHost::GetSize(uint8_t aChannelIndex) const { + MOZ_ASSERT(((mFormat == gfx::SurfaceFormat::NV12 || + mFormat == gfx::SurfaceFormat::P010 || + mFormat == gfx::SurfaceFormat::P016) && + aChannelIndex < 2) || + aChannelIndex < 1); + + if (aChannelIndex == 0) { + return mSize; + } else { + // The CbCr channel size is a half of Y channel size in NV12 format. + return mSize / 2; + } +} + +RenderDXGIYCbCrTextureHost::RenderDXGIYCbCrTextureHost( + WindowsHandle (&aHandles)[3], gfx::YUVColorSpace aYUVColorSpace, + gfx::ColorDepth aColorDepth, gfx::ColorRange aColorRange, + gfx::IntSize aSizeY, gfx::IntSize aSizeCbCr) + : mHandles{aHandles[0], aHandles[1], aHandles[2]}, + mSurfaces{0}, + mStreams{0}, + mTextureHandles{0}, + mYUVColorSpace(aYUVColorSpace), + mColorDepth(aColorDepth), + mColorRange(aColorRange), + mSizeY(aSizeY), + mSizeCbCr(aSizeCbCr), + mLocked(false) { + MOZ_COUNT_CTOR_INHERITED(RenderDXGIYCbCrTextureHost, RenderTextureHost); + // Assume the chroma planes are rounded up if the luma plane is odd sized. + MOZ_ASSERT((mSizeCbCr.width == mSizeY.width || + mSizeCbCr.width == (mSizeY.width + 1) >> 1) && + (mSizeCbCr.height == mSizeY.height || + mSizeCbCr.height == (mSizeY.height + 1) >> 1)); + MOZ_ASSERT(aHandles[0] && aHandles[1] && aHandles[2]); +} + +bool RenderDXGIYCbCrTextureHost::MapPlane(RenderCompositor* aCompositor, + uint8_t aChannelIndex, + PlaneInfo& aPlaneInfo) { + D3D11_MAPPED_SUBRESOURCE mappedSubresource; + if (!MapTexture(this, aCompositor, mTextures[aChannelIndex], mDeviceContext, + mCpuTexture[aChannelIndex], mappedSubresource)) { + return false; + } + + aPlaneInfo.mSize = GetSize(aChannelIndex); + aPlaneInfo.mStride = mappedSubresource.RowPitch; + aPlaneInfo.mData = mappedSubresource.pData; + return true; +} + +void RenderDXGIYCbCrTextureHost::UnmapPlanes() { + for (uint32_t i = 0; i < 3; i++) { + if (mCpuTexture[i]) { + mDeviceContext->Unmap(mCpuTexture[i], 0); + mCpuTexture[i] = nullptr; + } + } + mDeviceContext = nullptr; +} + +RenderDXGIYCbCrTextureHost::~RenderDXGIYCbCrTextureHost() { + MOZ_COUNT_DTOR_INHERITED(RenderDXGIYCbCrTextureHost, RenderTextureHost); + DeleteTextureHandle(); +} + +bool RenderDXGIYCbCrTextureHost::EnsureLockable() { + if (mTextureHandles[0]) { + return true; + } + + const auto& gle = gl::GLContextEGL::Cast(mGL); + const auto& egl = gle->mEgl; + + // The eglCreatePbufferFromClientBuffer doesn't support R8 format, so we + // use EGLStream to get the converted gl handle from d3d R8 texture. + + if (!egl->IsExtensionSupported( + gl::EGLExtension::NV_stream_consumer_gltexture_yuv) || + !egl->IsExtensionSupported( + gl::EGLExtension::ANGLE_stream_producer_d3d_texture)) { + gfxCriticalNote + << "RenderDXGIYCbCrTextureHost egl extensions are not suppored"; + return false; + } + + // Fetch the D3D11 device. + EGLDeviceEXT eglDevice = nullptr; + egl->fQueryDisplayAttribEXT(LOCAL_EGL_DEVICE_EXT, (EGLAttrib*)&eglDevice); + MOZ_ASSERT(eglDevice); + ID3D11Device* device = nullptr; + egl->mLib->fQueryDeviceAttribEXT(eglDevice, LOCAL_EGL_D3D11_DEVICE_ANGLE, + (EGLAttrib*)&device); + // There's a chance this might fail if we end up on d3d9 angle for some + // reason. + if (!device) { + gfxCriticalNote << "RenderDXGIYCbCrTextureHost device is not available"; + return false; + } + + EnsureD3D11Texture2D(device); + + mGL->fGenTextures(3, mTextureHandles); + bool ok = true; + for (int i = 0; i < 3; ++i) { + ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE0 + i, + LOCAL_GL_TEXTURE_EXTERNAL_OES, + mTextureHandles[i]); + + // Create the EGLStream. + mStreams[i] = egl->fCreateStreamKHR(nullptr); + MOZ_ASSERT(mStreams[i]); + + ok &= bool( + egl->fStreamConsumerGLTextureExternalAttribsNV(mStreams[i], nullptr)); + ok &= bool(egl->fCreateStreamProducerD3DTextureANGLE(mStreams[i], nullptr)); + + // Insert the R8 texture. + ok &= bool(egl->fStreamPostD3DTextureANGLE( + mStreams[i], (void*)mTextures[i].get(), nullptr)); + + // Now, we could get the R8 gl handle from the stream. + MOZ_ALWAYS_TRUE(egl->fStreamConsumerAcquireKHR(mStreams[i])); + } + + if (!ok) { + gfxCriticalNote << "RenderDXGIYCbCrTextureHost init stream failed"; + DeleteTextureHandle(); + return false; + } + + return true; +} + +bool RenderDXGIYCbCrTextureHost::EnsureD3D11Texture2D(ID3D11Device* aDevice) { + if (mTextures[0]) { + RefPtr<ID3D11Device> device; + mTextures[0]->GetDevice(getter_AddRefs(device)); + if (aDevice != device) { + gfxCriticalNote << "RenderDXGIYCbCrTextureHost uses obsoleted device"; + return false; + } + } + + if (mTextureHandles[0]) { + return true; + } + + for (int i = 0; i < 3; ++i) { + // Get the R8 D3D11 texture from shared handle. + HRESULT hr = aDevice->OpenSharedResource( + (HANDLE)mHandles[i], __uuidof(ID3D11Texture2D), + (void**)(ID3D11Texture2D**)getter_AddRefs(mTextures[i])); + if (FAILED(hr)) { + NS_WARNING( + "RenderDXGIYCbCrTextureHost::EnsureLockable(): Failed to open " + "shared " + "texture"); + gfxCriticalNote + << "RenderDXGIYCbCrTextureHost Failed to open shared texture, hr=" + << gfx::hexa(hr); + return false; + } + } + + for (int i = 0; i < 3; ++i) { + mTextures[i]->QueryInterface( + (IDXGIKeyedMutex**)getter_AddRefs(mKeyedMutexs[i])); + } + return true; +} + +bool RenderDXGIYCbCrTextureHost::LockInternal() { + if (!mLocked) { + if (mKeyedMutexs[0]) { + for (const auto& mutex : mKeyedMutexs) { + HRESULT hr = mutex->AcquireSync(0, 10000); + if (hr != S_OK) { + gfxCriticalError() + << "RenderDXGIYCbCrTextureHost AcquireSync timeout, hr=" + << gfx::hexa(hr); + return false; + } + } + } + mLocked = true; + } + return true; +} + +wr::WrExternalImage RenderDXGIYCbCrTextureHost::Lock(uint8_t aChannelIndex, + gl::GLContext* aGL) { + if (mGL.get() != aGL) { + // Release the texture handle in the previous gl context. + DeleteTextureHandle(); + mGL = aGL; + } + + if (!mGL) { + // XXX Software WebRender is not handled yet. + // Software WebRender does not provide GLContext + gfxCriticalNoteOnce << "Software WebRender is not suppored by " + "RenderDXGIYCbCrTextureHost."; + return InvalidToWrExternalImage(); + } + + if (!EnsureLockable()) { + return InvalidToWrExternalImage(); + } + + if (!LockInternal()) { + return InvalidToWrExternalImage(); + } + + const auto uvs = GetUvCoords(GetSize(aChannelIndex)); + return NativeTextureToWrExternalImage(GetGLHandle(aChannelIndex), uvs.first.x, + uvs.first.y, uvs.second.x, + uvs.second.y); +} + +void RenderDXGIYCbCrTextureHost::Unlock() { + if (mLocked) { + if (mKeyedMutexs[0]) { + for (const auto& mutex : mKeyedMutexs) { + mutex->ReleaseSync(0); + } + } + mLocked = false; + } +} + +void RenderDXGIYCbCrTextureHost::ClearCachedResources() { + DeleteTextureHandle(); + mGL = nullptr; +} + +GLuint RenderDXGIYCbCrTextureHost::GetGLHandle(uint8_t aChannelIndex) const { + MOZ_ASSERT(aChannelIndex < 3); + + return mTextureHandles[aChannelIndex]; +} + +gfx::IntSize RenderDXGIYCbCrTextureHost::GetSize(uint8_t aChannelIndex) const { + MOZ_ASSERT(aChannelIndex < 3); + + if (aChannelIndex == 0) { + return mSizeY; + } else { + return mSizeCbCr; + } +} + +void RenderDXGIYCbCrTextureHost::DeleteTextureHandle() { + if (mTextureHandles[0] == 0) { + return; + } + + MOZ_ASSERT(mGL.get()); + if (!mGL) { + return; + } + + if (mGL->MakeCurrent()) { + mGL->fDeleteTextures(3, mTextureHandles); + + const auto& gle = gl::GLContextEGL::Cast(mGL); + const auto& egl = gle->mEgl; + for (int i = 0; i < 3; ++i) { + mTextureHandles[i] = 0; + mTextures[i] = nullptr; + mKeyedMutexs[i] = nullptr; + + if (mSurfaces[i]) { + egl->fDestroySurface(mSurfaces[i]); + mSurfaces[i] = 0; + } + if (mStreams[i]) { + egl->fDestroyStreamKHR(mStreams[i]); + mStreams[i] = 0; + } + } + } +} + +} // namespace wr +} // namespace mozilla |