зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1460499 - Use DirectComposition for hardware decoded video on Windows r=nical
Use ID3D11VideoProcessor for video frame rendering. WebRenderError::VIDEO_OVERLAY does not cause disabling WebRender. It just change gfxVars::UseWebRenderDCompVideoOverlayWin() to false. Differential Revision: https://phabricator.services.mozilla.com/D88763
This commit is contained in:
Родитель
d79aa27e63
Коммит
54ede5160d
|
@ -42,6 +42,7 @@ class gfxVarReceiver;
|
|||
_(UseWebRenderANGLE, bool, false) \
|
||||
_(UseWebRenderFlipSequentialWin, bool, false) \
|
||||
_(UseWebRenderDCompWin, bool, false) \
|
||||
_(UseWebRenderDCompVideoOverlayWin, bool, false) \
|
||||
_(UseWebRenderTripleBufferingWin, bool, false) \
|
||||
_(UseWebRenderCompositor, bool, false) \
|
||||
_(UseWebRenderProgramBinaryDisk, bool, false) \
|
||||
|
|
|
@ -475,6 +475,7 @@ void GPUProcessManager::DisableWebRender(wr::WebRenderError aError,
|
|||
MOZ_ASSERT_UNREACHABLE("Invalid value");
|
||||
}
|
||||
gfx::gfxVars::SetUseWebRender(false);
|
||||
gfx::gfxVars::SetUseWebRenderDCompVideoOverlayWin(false);
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
// If aError is not wr::WebRenderError::INITIALIZE, nsWindow does not
|
||||
|
@ -493,6 +494,14 @@ void GPUProcessManager::DisableWebRender(wr::WebRenderError aError,
|
|||
}
|
||||
|
||||
void GPUProcessManager::NotifyWebRenderError(wr::WebRenderError aError) {
|
||||
if (aError == wr::WebRenderError::VIDEO_OVERLAY) {
|
||||
#ifdef XP_WIN
|
||||
gfxVars::SetUseWebRenderDCompVideoOverlayWin(false);
|
||||
#else
|
||||
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
DisableWebRender(aError, nsCString());
|
||||
}
|
||||
|
||||
|
|
|
@ -981,8 +981,8 @@ bool DXGITextureHostD3D11::AcquireTextureSource(
|
|||
|
||||
void DXGITextureHostD3D11::CreateRenderTexture(
|
||||
const wr::ExternalImageId& aExternalImageId) {
|
||||
RefPtr<wr::RenderTextureHost> texture =
|
||||
new wr::RenderDXGITextureHostOGL(mHandle, mFormat, mSize);
|
||||
RefPtr<wr::RenderTextureHost> texture = new wr::RenderDXGITextureHostOGL(
|
||||
mHandle, mFormat, mYUVColorSpace, mColorRange, mSize);
|
||||
|
||||
wr::RenderThread::Get()->RegisterExternalImage(wr::AsUint64(aExternalImageId),
|
||||
texture.forget());
|
||||
|
@ -1097,12 +1097,19 @@ void DXGITextureHostD3D11::PushDisplayItems(
|
|||
case gfx::SurfaceFormat::P016:
|
||||
case gfx::SurfaceFormat::NV12: {
|
||||
MOZ_ASSERT(aImageKeys.length() == 2);
|
||||
bool supportsExternalCompositing = false;
|
||||
// XXX Add P010 and P016 support.
|
||||
if (GetFormat() == gfx::SurfaceFormat::NV12 &&
|
||||
gfx::gfxVars::UseWebRenderDCompVideoOverlayWin()) {
|
||||
supportsExternalCompositing = true;
|
||||
}
|
||||
aBuilder.PushNV12Image(
|
||||
aBounds, aClip, true, aImageKeys[0], aImageKeys[1],
|
||||
GetFormat() == gfx::SurfaceFormat::NV12 ? wr::ColorDepth::Color8
|
||||
: wr::ColorDepth::Color16,
|
||||
wr::ToWrYuvColorSpace(mYUVColorSpace),
|
||||
wr::ToWrColorRange(mColorRange), aFilter, aPreferCompositorSurface);
|
||||
wr::ToWrColorRange(mColorRange), aFilter, aPreferCompositorSurface,
|
||||
supportsExternalCompositing);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
|
|
@ -51,6 +51,10 @@ decltype(D3D11CreateDevice)* sD3D11CreateDeviceFn = nullptr;
|
|||
// It should only be used within CreateDirectCompositionDevice.
|
||||
decltype(DCompositionCreateDevice2)* sDcompCreateDevice2Fn = nullptr;
|
||||
|
||||
// It should only be used within CreateDCompSurfaceHandle
|
||||
decltype(DCompositionCreateSurfaceHandle)* sDcompCreateSurfaceHandleFn =
|
||||
nullptr;
|
||||
|
||||
// We don't have access to the DirectDrawCreateEx type in gfxWindowsPlatform.h,
|
||||
// since it doesn't include ddraw.h, so we use a static here. It should only
|
||||
// be used within InitializeDirectDrawConfig.
|
||||
|
@ -125,6 +129,14 @@ bool DeviceManagerDx::LoadDcomp() {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Load optional API for external compositing
|
||||
sDcompCreateSurfaceHandleFn =
|
||||
(decltype(DCompositionCreateSurfaceHandle)*)::GetProcAddress(
|
||||
module, "DCompositionCreateSurfaceHandle");
|
||||
if (!sDcompCreateDevice2Fn) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mDcompModule.steal(module);
|
||||
return true;
|
||||
}
|
||||
|
@ -413,6 +425,22 @@ void DeviceManagerDx::CreateDirectCompositionDevice() {
|
|||
mDirectCompositionDevice = compositionDevice;
|
||||
}
|
||||
|
||||
/* static */
|
||||
HANDLE DeviceManagerDx::CreateDCompSurfaceHandle() {
|
||||
if (!sDcompCreateSurfaceHandleFn) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
HANDLE handle = 0;
|
||||
HRESULT hr = sDcompCreateSurfaceHandleFn(COMPOSITIONOBJECT_ALL_ACCESS,
|
||||
nullptr, &handle);
|
||||
if (FAILED(hr)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void DeviceManagerDx::ImportDeviceInfo(const D3D11DeviceStatus& aDeviceStatus) {
|
||||
MOZ_ASSERT(!ProcessOwnsCompositor());
|
||||
|
||||
|
|
|
@ -99,6 +99,8 @@ class DeviceManagerDx final {
|
|||
void CreateDirectCompositionDevice();
|
||||
bool CreateCanvasDevice();
|
||||
|
||||
static HANDLE CreateDCompSurfaceHandle();
|
||||
|
||||
void GetCompositorDevices(
|
||||
RefPtr<ID3D11Device>* aOutDevice,
|
||||
RefPtr<layers::DeviceAttachmentsD3D11>* aOutAttachments);
|
||||
|
|
|
@ -2767,6 +2767,13 @@ void gfxPlatform::InitWebRenderConfig() {
|
|||
if (gfxConfig::IsEnabled(Feature::WEBRENDER_DCOMP_PRESENT)) {
|
||||
gfxVars::SetUseWebRenderDCompWin(true);
|
||||
}
|
||||
if (Preferences::GetBool("gfx.webrender.dcomp-video-overlay-win", false)) {
|
||||
if (IsWin10AnniversaryUpdateOrLater() &&
|
||||
gfxConfig::IsEnabled(Feature::WEBRENDER_COMPOSITOR)) {
|
||||
MOZ_ASSERT(gfxConfig::IsEnabled(Feature::WEBRENDER_DCOMP_PRESENT));
|
||||
gfxVars::SetUseWebRenderDCompVideoOverlayWin(true);
|
||||
}
|
||||
}
|
||||
if (Preferences::GetBool("gfx.webrender.flip-sequential", false)) {
|
||||
// XXX relax win version to windows 8.
|
||||
if (IsWin10OrLater() && UseWebRender() && gfxVars::UseWebRenderANGLE()) {
|
||||
|
|
|
@ -9,7 +9,10 @@
|
|||
#include "GLContext.h"
|
||||
#include "GLContextEGL.h"
|
||||
#include "mozilla/gfx/DeviceManagerDx.h"
|
||||
#include "mozilla/gfx/gfxVars.h"
|
||||
#include "mozilla/StaticPrefs_gfx.h"
|
||||
#include "mozilla/webrender/RenderD3D11TextureHostOGL.h"
|
||||
#include "mozilla/webrender/RenderTextureHost.h"
|
||||
#include "mozilla/webrender/RenderThread.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
|
@ -19,6 +22,7 @@
|
|||
#define NTDDI_VERSION NTDDI_WINBLUE
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <d3d11_1.h>
|
||||
#include <dcomp.h>
|
||||
#include <dxgi1_2.h>
|
||||
|
||||
|
@ -28,7 +32,9 @@ namespace wr {
|
|||
/* static */
|
||||
UniquePtr<DCLayerTree> DCLayerTree::Create(gl::GLContext* aGL,
|
||||
EGLConfig aEGLConfig,
|
||||
ID3D11Device* aDevice, HWND aHwnd) {
|
||||
ID3D11Device* aDevice,
|
||||
ID3D11DeviceContext* aCtx,
|
||||
HWND aHwnd) {
|
||||
RefPtr<IDCompositionDevice2> dCompDevice =
|
||||
gfx::DeviceManagerDx::Get()->GetDirectCompositionDevice();
|
||||
if (!dCompDevice) {
|
||||
|
@ -36,7 +42,7 @@ UniquePtr<DCLayerTree> DCLayerTree::Create(gl::GLContext* aGL,
|
|||
}
|
||||
|
||||
auto layerTree =
|
||||
MakeUnique<DCLayerTree>(aGL, aEGLConfig, aDevice, dCompDevice);
|
||||
MakeUnique<DCLayerTree>(aGL, aEGLConfig, aDevice, aCtx, dCompDevice);
|
||||
if (!layerTree->Initialize(aHwnd)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -45,12 +51,14 @@ UniquePtr<DCLayerTree> DCLayerTree::Create(gl::GLContext* aGL,
|
|||
}
|
||||
|
||||
DCLayerTree::DCLayerTree(gl::GLContext* aGL, EGLConfig aEGLConfig,
|
||||
ID3D11Device* aDevice,
|
||||
ID3D11Device* aDevice, ID3D11DeviceContext* aCtx,
|
||||
IDCompositionDevice2* aCompositionDevice)
|
||||
: mGL(aGL),
|
||||
mEGLConfig(aEGLConfig),
|
||||
mDevice(aDevice),
|
||||
mCtx(aCtx),
|
||||
mCompositionDevice(aCompositionDevice),
|
||||
mVideoOverlaySupported(false),
|
||||
mDebugCounter(false),
|
||||
mDebugVisualRedrawRegions(false),
|
||||
mEGLImage(EGL_NO_IMAGE),
|
||||
|
@ -103,6 +111,12 @@ bool DCLayerTree::Initialize(HWND aHwnd) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (gfx::gfxVars::UseWebRenderDCompVideoOverlayWin()) {
|
||||
if (!InitializeVideoOverlaySupport()) {
|
||||
RenderThread::Get()->HandleWebRenderError(WebRenderError::VIDEO_OVERLAY);
|
||||
}
|
||||
}
|
||||
|
||||
mCompositionTarget->SetRoot(mRootVisual);
|
||||
// Set interporation mode to nearest, to ensure 1:1 sampling.
|
||||
// By default, a visual inherits the interpolation mode of the parent visual.
|
||||
|
@ -113,6 +127,32 @@ bool DCLayerTree::Initialize(HWND aHwnd) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool DCLayerTree::InitializeVideoOverlaySupport() {
|
||||
HRESULT hr;
|
||||
|
||||
hr = mDevice->QueryInterface(
|
||||
(ID3D11VideoDevice**)getter_AddRefs(mVideoDevice));
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalNote << "Failed to get D3D11VideoDevice: " << gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
hr =
|
||||
mCtx->QueryInterface((ID3D11VideoContext**)getter_AddRefs(mVideoContext));
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalNote << "Failed to get D3D11VideoContext: " << gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
// XXX When video is rendered to DXGI_FORMAT_B8G8R8A8_UNORM SwapChain with
|
||||
// VideoProcessor, it seems that we do not need to check
|
||||
// IDXGIOutput3::CheckOverlaySupport().
|
||||
// If we want to yuv at DecodeSwapChain, its support seems necessary.
|
||||
|
||||
mVideoOverlaySupported = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
DCSurface* DCLayerTree::GetSurface(wr::NativeSurfaceId aId) const {
|
||||
auto surface_it = mDCSurfaces.find(aId);
|
||||
MOZ_RELEASE_ASSERT(surface_it != mDCSurfaces.end());
|
||||
|
@ -316,6 +356,21 @@ void DCLayerTree::CreateSurface(wr::NativeSurfaceId aId,
|
|||
mDCSurfaces[aId] = std::move(surface);
|
||||
}
|
||||
|
||||
void DCLayerTree::CreateExternalSurface(wr::NativeSurfaceId aId,
|
||||
bool aIsOpaque) {
|
||||
auto it = mDCSurfaces.find(aId);
|
||||
MOZ_RELEASE_ASSERT(it == mDCSurfaces.end());
|
||||
|
||||
auto surface = MakeUnique<DCSurfaceVideo>(aIsOpaque, this);
|
||||
if (!surface->Initialize()) {
|
||||
gfxCriticalNote << "Failed to initialize DCSurfaceVideo: "
|
||||
<< wr::AsUint64(aId);
|
||||
return;
|
||||
}
|
||||
|
||||
mDCSurfaces[aId] = std::move(surface);
|
||||
}
|
||||
|
||||
void DCLayerTree::DestroySurface(NativeSurfaceId aId) {
|
||||
auto surface_it = mDCSurfaces.find(aId);
|
||||
MOZ_RELEASE_ASSERT(surface_it != mDCSurfaces.end());
|
||||
|
@ -335,6 +390,16 @@ void DCLayerTree::DestroyTile(wr::NativeSurfaceId aId, int aX, int aY) {
|
|||
surface->DestroyTile(aX, aY);
|
||||
}
|
||||
|
||||
void DCLayerTree::AttachExternalImage(wr::NativeSurfaceId aId,
|
||||
wr::ExternalImageId aExternalImage) {
|
||||
auto surface_it = mDCSurfaces.find(aId);
|
||||
MOZ_RELEASE_ASSERT(surface_it != mDCSurfaces.end());
|
||||
auto* surfaceVideo = surface_it->second->AsDCSurfaceVideo();
|
||||
MOZ_RELEASE_ASSERT(surfaceVideo);
|
||||
|
||||
surfaceVideo->AttachExternalImage(aExternalImage);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline D2D1_RECT_F D2DRect(const T& aRect) {
|
||||
return D2D1::RectF(aRect.X(), aRect.Y(), aRect.XMost(), aRect.YMost());
|
||||
|
@ -438,6 +503,58 @@ GLuint DCLayerTree::GetOrCreateFbo(int aWidth, int aHeight) {
|
|||
return fboId;
|
||||
}
|
||||
|
||||
bool DCLayerTree::EnsureVideoProcessor(const gfx::IntSize& aVideoSize) {
|
||||
HRESULT hr;
|
||||
|
||||
if (!mVideoDevice || !mVideoContext) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mVideoProcessor && aVideoSize == mVideoSize) {
|
||||
return true;
|
||||
}
|
||||
|
||||
mVideoProcessor = nullptr;
|
||||
mVideoProcessorEnumerator = nullptr;
|
||||
|
||||
D3D11_VIDEO_PROCESSOR_CONTENT_DESC desc = {};
|
||||
desc.InputFrameFormat = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE;
|
||||
desc.InputFrameRate.Numerator = 60;
|
||||
desc.InputFrameRate.Denominator = 1;
|
||||
desc.InputWidth = aVideoSize.width;
|
||||
desc.InputHeight = aVideoSize.height;
|
||||
desc.OutputFrameRate.Numerator = 60;
|
||||
desc.OutputFrameRate.Denominator = 1;
|
||||
desc.OutputWidth = aVideoSize.width;
|
||||
desc.OutputHeight = aVideoSize.height;
|
||||
desc.Usage = D3D11_VIDEO_USAGE_PLAYBACK_NORMAL;
|
||||
|
||||
hr = mVideoDevice->CreateVideoProcessorEnumerator(
|
||||
&desc, getter_AddRefs(mVideoProcessorEnumerator));
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalNote << "Failed to create VideoProcessorEnumerator: "
|
||||
<< gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = mVideoDevice->CreateVideoProcessor(mVideoProcessorEnumerator, 0,
|
||||
getter_AddRefs(mVideoProcessor));
|
||||
if (FAILED(hr)) {
|
||||
mVideoProcessor = nullptr;
|
||||
mVideoProcessorEnumerator = nullptr;
|
||||
gfxCriticalNote << "Failed to create VideoProcessor: " << gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reduce power cosumption
|
||||
// By default, the driver might perform certain processing tasks automatically
|
||||
mVideoContext->VideoProcessorSetStreamAutoProcessingMode(mVideoProcessor, 0,
|
||||
FALSE);
|
||||
|
||||
mVideoSize = aVideoSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
DCSurface::DCSurface(wr::DeviceIntSize aTileSize,
|
||||
wr::DeviceIntPoint aVirtualOffset, bool aIsOpaque,
|
||||
DCLayerTree* aDCLayerTree)
|
||||
|
@ -529,6 +646,271 @@ DCTile* DCSurface::GetTile(int aX, int aY) const {
|
|||
return tile_it->second.get();
|
||||
}
|
||||
|
||||
DCSurfaceVideo::DCSurfaceVideo(bool aIsOpaque, DCLayerTree* aDCLayerTree)
|
||||
: DCSurface(wr::DeviceIntSize{}, wr::DeviceIntPoint{}, aIsOpaque,
|
||||
aDCLayerTree) {}
|
||||
|
||||
void DCSurfaceVideo::AttachExternalImage(wr::ExternalImageId aExternalImage) {
|
||||
RenderTextureHost* texture =
|
||||
RenderThread::Get()->GetRenderTexture(aExternalImage);
|
||||
MOZ_RELEASE_ASSERT(texture);
|
||||
|
||||
// XXX if software decoded video frame format is nv12, it could be used as
|
||||
// video overlay.
|
||||
if (!texture || !texture->AsRenderDXGITextureHostOGL() ||
|
||||
texture->AsRenderDXGITextureHostOGL()->GetFormat() !=
|
||||
gfx::SurfaceFormat::NV12) {
|
||||
gfxCriticalNote << "Unsupported RenderTexture for overlay: "
|
||||
<< gfx::hexa(texture);
|
||||
return;
|
||||
}
|
||||
|
||||
gfx::IntSize size = texture->AsRenderDXGITextureHostOGL()->GetSize(0);
|
||||
if (!mVideoSwapChain || mSwapChainSize != size) {
|
||||
ReleaseDecodeSwapChainResources();
|
||||
CreateVideoSwapChain(texture);
|
||||
}
|
||||
|
||||
if (!mVideoSwapChain) {
|
||||
gfxCriticalNote << "Failed to create VideoSwapChain";
|
||||
RenderThread::Get()->NotifyWebRenderError(
|
||||
wr::WebRenderError::VIDEO_OVERLAY);
|
||||
return;
|
||||
}
|
||||
|
||||
mVisual->SetContent(mVideoSwapChain);
|
||||
|
||||
if (!CallVideoProcessorBlt(texture)) {
|
||||
RenderThread::Get()->NotifyWebRenderError(
|
||||
wr::WebRenderError::VIDEO_OVERLAY);
|
||||
return;
|
||||
}
|
||||
|
||||
mVideoSwapChain->Present(0, 0);
|
||||
}
|
||||
|
||||
bool DCSurfaceVideo::CreateVideoSwapChain(RenderTextureHost* aTexture) {
|
||||
const auto device = mDCLayerTree->GetDevice();
|
||||
|
||||
RefPtr<IDXGIDevice> dxgiDevice;
|
||||
device->QueryInterface((IDXGIDevice**)getter_AddRefs(dxgiDevice));
|
||||
|
||||
RefPtr<IDXGIFactoryMedia> dxgiFactoryMedia;
|
||||
{
|
||||
RefPtr<IDXGIAdapter> adapter;
|
||||
dxgiDevice->GetAdapter(getter_AddRefs(adapter));
|
||||
adapter->GetParent(
|
||||
IID_PPV_ARGS((IDXGIFactoryMedia**)getter_AddRefs(dxgiFactoryMedia)));
|
||||
}
|
||||
|
||||
mSwapChainSurfaceHandle = gfx::DeviceManagerDx::CreateDCompSurfaceHandle();
|
||||
if (!mSwapChainSurfaceHandle) {
|
||||
gfxCriticalNote << "Failed to create DCompSurfaceHandle";
|
||||
return false;
|
||||
}
|
||||
|
||||
gfx::IntSize size = aTexture->AsRenderDXGITextureHostOGL()->GetSize(0);
|
||||
DXGI_ALPHA_MODE alpha_mode =
|
||||
mIsOpaque ? DXGI_ALPHA_MODE_IGNORE : DXGI_ALPHA_MODE_PREMULTIPLIED;
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC1 desc = {};
|
||||
desc.Width = size.width;
|
||||
desc.Height = size.height;
|
||||
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
desc.Stereo = FALSE;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.BufferCount = 2;
|
||||
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
desc.Scaling = DXGI_SCALING_STRETCH;
|
||||
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
|
||||
desc.Flags = 0;
|
||||
desc.AlphaMode = alpha_mode;
|
||||
|
||||
HRESULT hr;
|
||||
hr = dxgiFactoryMedia->CreateSwapChainForCompositionSurfaceHandle(
|
||||
device, mSwapChainSurfaceHandle, &desc, nullptr,
|
||||
getter_AddRefs(mVideoSwapChain));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalNote << "Failed to create video SwapChain: " << gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
mSwapChainSize = size;
|
||||
return true;
|
||||
}
|
||||
|
||||
static Maybe<DXGI_COLOR_SPACE_TYPE> GetSourceDXGIColorSpace(
|
||||
const gfx::YUVColorSpace aYUVColorSpace,
|
||||
const gfx::ColorRange aColorRange) {
|
||||
if (aYUVColorSpace == gfx::YUVColorSpace::BT601) {
|
||||
if (aColorRange == gfx::ColorRange::FULL) {
|
||||
return Some(DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P601);
|
||||
} else {
|
||||
return Some(DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601);
|
||||
}
|
||||
} else if (aYUVColorSpace == gfx::YUVColorSpace::BT709) {
|
||||
if (aColorRange == gfx::ColorRange::FULL) {
|
||||
return Some(DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P709);
|
||||
} else {
|
||||
return Some(DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709);
|
||||
}
|
||||
} else if (aYUVColorSpace == gfx::YUVColorSpace::BT2020) {
|
||||
if (aColorRange == gfx::ColorRange::FULL) {
|
||||
// XXX Add SMPTEST2084 handling. HDR content is not handled yet by
|
||||
// video overlay.
|
||||
return Some(DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020);
|
||||
} else {
|
||||
return Some(DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P2020);
|
||||
}
|
||||
}
|
||||
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
bool DCSurfaceVideo::CallVideoProcessorBlt(RenderTextureHost* aTexture) {
|
||||
HRESULT hr;
|
||||
const auto videoDevice = mDCLayerTree->GetVideoDevice();
|
||||
const auto videoContext = mDCLayerTree->GetVideoContext();
|
||||
const auto texture = aTexture->AsRenderDXGITextureHostOGL();
|
||||
|
||||
Maybe<DXGI_COLOR_SPACE_TYPE> sourceColorSpace = GetSourceDXGIColorSpace(
|
||||
texture->GetYUVColorSpace(), texture->GetColorRange());
|
||||
if (sourceColorSpace.isNothing()) {
|
||||
gfxCriticalNote << "Unsupported color space";
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<ID3D11Texture2D> texture2D = texture->GetD3D11Texture2D();
|
||||
if (!texture2D) {
|
||||
gfxCriticalNote << "Failed to get D3D11Texture2D";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mVideoSwapChain) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mDCLayerTree->EnsureVideoProcessor(mSwapChainSize)) {
|
||||
gfxCriticalNote << "EnsureVideoProcessor Failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<IDXGISwapChain3> swapChain3;
|
||||
mVideoSwapChain->QueryInterface(
|
||||
(IDXGISwapChain3**)getter_AddRefs(swapChain3));
|
||||
if (!swapChain3) {
|
||||
gfxCriticalNote << "Failed to get IDXGISwapChain3";
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<ID3D11VideoContext1> videoContext1;
|
||||
videoContext->QueryInterface(
|
||||
(ID3D11VideoContext1**)getter_AddRefs(videoContext1));
|
||||
if (!videoContext1) {
|
||||
gfxCriticalNote << "Failed to get ID3D11VideoContext1";
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto videoProcessor = mDCLayerTree->GetVideoProcessor();
|
||||
const auto videoProcessorEnumerator =
|
||||
mDCLayerTree->GetVideoProcessorEnumerator();
|
||||
|
||||
DXGI_COLOR_SPACE_TYPE inputColorSpace = sourceColorSpace.ref();
|
||||
videoContext1->VideoProcessorSetStreamColorSpace1(videoProcessor, 0,
|
||||
inputColorSpace);
|
||||
// XXX when content is hdr or yuv swapchain, it need to use other color space.
|
||||
DXGI_COLOR_SPACE_TYPE outputColorSpace =
|
||||
DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
|
||||
hr = swapChain3->SetColorSpace1(outputColorSpace);
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalNote << "SetColorSpace1 failed: " << gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
videoContext1->VideoProcessorSetOutputColorSpace1(videoProcessor,
|
||||
outputColorSpace);
|
||||
|
||||
D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC inputDesc = {};
|
||||
inputDesc.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D;
|
||||
inputDesc.Texture2D.ArraySlice = 0;
|
||||
|
||||
RefPtr<ID3D11VideoProcessorInputView> inputView;
|
||||
hr = videoDevice->CreateVideoProcessorInputView(
|
||||
texture2D, videoProcessorEnumerator, &inputDesc,
|
||||
getter_AddRefs(inputView));
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalNote << "ID3D11VideoProcessorInputView creation failed: "
|
||||
<< gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
D3D11_VIDEO_PROCESSOR_STREAM stream = {};
|
||||
stream.Enable = true;
|
||||
stream.OutputIndex = 0;
|
||||
stream.InputFrameOrField = 0;
|
||||
stream.PastFrames = 0;
|
||||
stream.FutureFrames = 0;
|
||||
stream.pInputSurface = inputView.get();
|
||||
|
||||
RECT destRect;
|
||||
destRect.left = 0;
|
||||
destRect.top = 0;
|
||||
destRect.right = mSwapChainSize.width;
|
||||
destRect.bottom = mSwapChainSize.height;
|
||||
|
||||
videoContext->VideoProcessorSetOutputTargetRect(videoProcessor, TRUE,
|
||||
&destRect);
|
||||
videoContext->VideoProcessorSetStreamDestRect(videoProcessor, 0, TRUE,
|
||||
&destRect);
|
||||
RECT sourceRect;
|
||||
sourceRect.left = 0;
|
||||
sourceRect.top = 0;
|
||||
sourceRect.right = mSwapChainSize.width;
|
||||
sourceRect.bottom = mSwapChainSize.height;
|
||||
videoContext->VideoProcessorSetStreamSourceRect(videoProcessor, 0, TRUE,
|
||||
&sourceRect);
|
||||
|
||||
if (!mOutputView) {
|
||||
RefPtr<ID3D11Texture2D> backBuf;
|
||||
mVideoSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D),
|
||||
(void**)getter_AddRefs(backBuf));
|
||||
|
||||
D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC outputDesc = {};
|
||||
outputDesc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D;
|
||||
outputDesc.Texture2D.MipSlice = 0;
|
||||
|
||||
hr = videoDevice->CreateVideoProcessorOutputView(
|
||||
backBuf, videoProcessorEnumerator, &outputDesc,
|
||||
getter_AddRefs(mOutputView));
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalNote << "ID3D11VideoProcessorOutputView creation failed: "
|
||||
<< gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
hr = videoContext->VideoProcessorBlt(videoProcessor, mOutputView, 0, 1,
|
||||
&stream);
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalNote << "VideoProcessorBlt failed: " << gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DCSurfaceVideo::ReleaseDecodeSwapChainResources() {
|
||||
mOutputView = nullptr;
|
||||
mVideoSwapChain = nullptr;
|
||||
mDecodeSwapChain = nullptr;
|
||||
mDecodeResource = nullptr;
|
||||
if (mSwapChainSurfaceHandle) {
|
||||
::CloseHandle(mSwapChainSurfaceHandle);
|
||||
mSwapChainSurfaceHandle = 0;
|
||||
}
|
||||
mSwapChainSize = gfx::IntSize();
|
||||
}
|
||||
|
||||
DCTile::DCTile(DCLayerTree* aDCLayerTree) : mDCLayerTree(aDCLayerTree) {}
|
||||
|
||||
DCTile::~DCTile() {}
|
||||
|
|
|
@ -18,10 +18,17 @@
|
|||
|
||||
struct ID3D11Device;
|
||||
struct ID3D11DeviceContext;
|
||||
struct ID3D11VideoDevice;
|
||||
struct ID3D11VideoContext;
|
||||
struct ID3D11VideoProcessor;
|
||||
struct ID3D11VideoProcessorEnumerator;
|
||||
struct ID3D11VideoProcessorOutputView;
|
||||
struct IDCompositionDevice2;
|
||||
struct IDCompositionSurface;
|
||||
struct IDCompositionTarget;
|
||||
struct IDCompositionVisual2;
|
||||
struct IDXGIDecodeSwapChain;
|
||||
struct IDXGIResource;
|
||||
struct IDXGISwapChain1;
|
||||
struct IDCompositionVirtualSurface;
|
||||
|
||||
|
@ -39,6 +46,8 @@ namespace wr {
|
|||
|
||||
class DCTile;
|
||||
class DCSurface;
|
||||
class DCSurfaceVideo;
|
||||
class RenderTextureHost;
|
||||
|
||||
/**
|
||||
* DCLayerTree manages direct composition layers.
|
||||
|
@ -47,9 +56,10 @@ class DCSurface;
|
|||
class DCLayerTree {
|
||||
public:
|
||||
static UniquePtr<DCLayerTree> Create(gl::GLContext* aGL, EGLConfig aEGLConfig,
|
||||
ID3D11Device* aDevice, HWND aHwnd);
|
||||
ID3D11Device* aDevice,
|
||||
ID3D11DeviceContext* aCtx, HWND aHwnd);
|
||||
explicit DCLayerTree(gl::GLContext* aGL, EGLConfig aEGLConfig,
|
||||
ID3D11Device* aDevice,
|
||||
ID3D11Device* aDevice, ID3D11DeviceContext* aCtx,
|
||||
IDCompositionDevice2* aCompositionDevice);
|
||||
~DCLayerTree();
|
||||
|
||||
|
@ -67,9 +77,12 @@ class DCLayerTree {
|
|||
void Unbind();
|
||||
void CreateSurface(wr::NativeSurfaceId aId, wr::DeviceIntPoint aVirtualOffset,
|
||||
wr::DeviceIntSize aTileSize, bool aIsOpaque);
|
||||
void CreateExternalSurface(wr::NativeSurfaceId aId, bool aIsOpaque);
|
||||
void DestroySurface(NativeSurfaceId aId);
|
||||
void CreateTile(wr::NativeSurfaceId aId, int32_t aX, int32_t aY);
|
||||
void DestroyTile(wr::NativeSurfaceId aId, int32_t aX, int32_t aY);
|
||||
void AttachExternalImage(wr::NativeSurfaceId aId,
|
||||
wr::ExternalImageId aExternalImage);
|
||||
void AddSurface(wr::NativeSurfaceId aId,
|
||||
const wr::CompositorSurfaceTransform& aTransform,
|
||||
wr::DeviceIntRect aClipRect,
|
||||
|
@ -81,6 +94,14 @@ class DCLayerTree {
|
|||
IDCompositionDevice2* GetCompositionDevice() const {
|
||||
return mCompositionDevice;
|
||||
}
|
||||
ID3D11VideoDevice* GetVideoDevice() const { return mVideoDevice; }
|
||||
ID3D11VideoContext* GetVideoContext() const { return mVideoContext; }
|
||||
ID3D11VideoProcessor* GetVideoProcessor() const { return mVideoProcessor; }
|
||||
ID3D11VideoProcessorEnumerator* GetVideoProcessorEnumerator() const {
|
||||
return mVideoProcessorEnumerator;
|
||||
}
|
||||
bool EnsureVideoProcessor(const gfx::IntSize& aVideoSize);
|
||||
|
||||
DCSurface* GetSurface(wr::NativeSurfaceId aId) const;
|
||||
|
||||
// Get or create an FBO with depth buffer suitable for specified dimensions
|
||||
|
@ -88,6 +109,7 @@ class DCLayerTree {
|
|||
|
||||
protected:
|
||||
bool Initialize(HWND aHwnd);
|
||||
bool InitializeVideoOverlaySupport();
|
||||
bool MaybeUpdateDebugCounter();
|
||||
bool MaybeUpdateDebugVisualRedrawRegions();
|
||||
void DestroyEGLSurface();
|
||||
|
@ -101,12 +123,21 @@ class DCLayerTree {
|
|||
EGLConfig mEGLConfig;
|
||||
|
||||
RefPtr<ID3D11Device> mDevice;
|
||||
RefPtr<ID3D11DeviceContext> mCtx;
|
||||
|
||||
RefPtr<IDCompositionDevice2> mCompositionDevice;
|
||||
RefPtr<IDCompositionTarget> mCompositionTarget;
|
||||
RefPtr<IDCompositionVisual2> mRootVisual;
|
||||
RefPtr<IDCompositionVisual2> mDefaultSwapChainVisual;
|
||||
|
||||
RefPtr<ID3D11VideoDevice> mVideoDevice;
|
||||
RefPtr<ID3D11VideoContext> mVideoContext;
|
||||
RefPtr<ID3D11VideoProcessor> mVideoProcessor;
|
||||
RefPtr<ID3D11VideoProcessorEnumerator> mVideoProcessorEnumerator;
|
||||
gfx::IntSize mVideoSize;
|
||||
|
||||
bool mVideoOverlaySupported;
|
||||
|
||||
bool mDebugCounter;
|
||||
bool mDebugVisualRedrawRegions;
|
||||
|
||||
|
@ -165,7 +196,7 @@ class DCSurface {
|
|||
explicit DCSurface(wr::DeviceIntSize aTileSize,
|
||||
wr::DeviceIntPoint aVirtualOffset, bool aIsOpaque,
|
||||
DCLayerTree* aDCLayerTree);
|
||||
~DCSurface();
|
||||
virtual ~DCSurface();
|
||||
|
||||
bool Initialize();
|
||||
void CreateTile(int32_t aX, int32_t aY);
|
||||
|
@ -191,6 +222,8 @@ class DCSurface {
|
|||
void UpdateAllocatedRect();
|
||||
void DirtyAllocatedRect();
|
||||
|
||||
virtual DCSurfaceVideo* AsDCSurfaceVideo() { return nullptr; }
|
||||
|
||||
protected:
|
||||
DCLayerTree* mDCLayerTree;
|
||||
|
||||
|
@ -214,6 +247,27 @@ class DCSurface {
|
|||
RefPtr<IDCompositionVirtualSurface> mVirtualSurface;
|
||||
};
|
||||
|
||||
class DCSurfaceVideo : public DCSurface {
|
||||
public:
|
||||
DCSurfaceVideo(bool aIsOpaque, DCLayerTree* aDCLayerTree);
|
||||
|
||||
void AttachExternalImage(wr::ExternalImageId aExternalImage);
|
||||
|
||||
DCSurfaceVideo* AsDCSurfaceVideo() override { return this; }
|
||||
|
||||
protected:
|
||||
bool CreateVideoSwapChain(RenderTextureHost* aTexture);
|
||||
bool CallVideoProcessorBlt(RenderTextureHost* aTexture);
|
||||
void ReleaseDecodeSwapChainResources();
|
||||
|
||||
RefPtr<ID3D11VideoProcessorOutputView> mOutputView;
|
||||
RefPtr<IDXGIResource> mDecodeResource;
|
||||
RefPtr<IDXGISwapChain1> mVideoSwapChain;
|
||||
RefPtr<IDXGIDecodeSwapChain> mDecodeSwapChain;
|
||||
HANDLE mSwapChainSurfaceHandle;
|
||||
gfx::IntSize mSwapChainSize;
|
||||
};
|
||||
|
||||
class DCTile {
|
||||
public:
|
||||
explicit DCTile(DCLayerTree* aDCLayerTree);
|
||||
|
|
|
@ -167,7 +167,7 @@ bool RenderCompositorANGLE::Initialize() {
|
|||
HWND compositorHwnd = GetCompositorHwnd();
|
||||
if (compositorHwnd) {
|
||||
mDCLayerTree =
|
||||
DCLayerTree::Create(gl, mEGLConfig, mDevice, compositorHwnd);
|
||||
DCLayerTree::Create(gl, mEGLConfig, mDevice, mCtx, compositorHwnd);
|
||||
if (!mDCLayerTree) {
|
||||
gfxCriticalNote << "Failed to create DCLayerTree";
|
||||
return false;
|
||||
|
@ -851,6 +851,11 @@ void RenderCompositorANGLE::CreateSurface(wr::NativeSurfaceId aId,
|
|||
mDCLayerTree->CreateSurface(aId, aVirtualOffset, aTileSize, aIsOpaque);
|
||||
}
|
||||
|
||||
void RenderCompositorANGLE::CreateExternalSurface(wr::NativeSurfaceId aId,
|
||||
bool aIsOpaque) {
|
||||
mDCLayerTree->CreateExternalSurface(aId, aIsOpaque);
|
||||
}
|
||||
|
||||
void RenderCompositorANGLE::DestroySurface(NativeSurfaceId aId) {
|
||||
mDCLayerTree->DestroySurface(aId);
|
||||
}
|
||||
|
@ -865,6 +870,11 @@ void RenderCompositorANGLE::DestroyTile(wr::NativeSurfaceId aId, int aX,
|
|||
mDCLayerTree->DestroyTile(aId, aX, aY);
|
||||
}
|
||||
|
||||
void RenderCompositorANGLE::AttachExternalImage(
|
||||
wr::NativeSurfaceId aId, wr::ExternalImageId aExternalImage) {
|
||||
mDCLayerTree->AttachExternalImage(aId, aExternalImage);
|
||||
}
|
||||
|
||||
void RenderCompositorANGLE::AddSurface(
|
||||
wr::NativeSurfaceId aId, const wr::CompositorSurfaceTransform& aTransform,
|
||||
wr::DeviceIntRect aClipRect, wr::ImageRendering aImageRendering) {
|
||||
|
|
|
@ -78,9 +78,12 @@ class RenderCompositorANGLE : public RenderCompositor {
|
|||
void Unbind() override;
|
||||
void CreateSurface(wr::NativeSurfaceId aId, wr::DeviceIntPoint aVirtualOffset,
|
||||
wr::DeviceIntSize aTileSize, bool aIsOpaque) override;
|
||||
void CreateExternalSurface(wr::NativeSurfaceId aId, bool aIsOpaque) override;
|
||||
void DestroySurface(NativeSurfaceId aId) override;
|
||||
void CreateTile(wr::NativeSurfaceId aId, int32_t aX, int32_t aY) override;
|
||||
void DestroyTile(wr::NativeSurfaceId aId, int32_t aX, int32_t aY) override;
|
||||
void AttachExternalImage(wr::NativeSurfaceId aId,
|
||||
wr::ExternalImageId aExternalImage) override;
|
||||
void AddSurface(wr::NativeSurfaceId aId,
|
||||
const wr::CompositorSurfaceTransform& aTransform,
|
||||
wr::DeviceIntRect aClipRect,
|
||||
|
|
|
@ -17,14 +17,17 @@
|
|||
namespace mozilla {
|
||||
namespace wr {
|
||||
|
||||
RenderDXGITextureHostOGL::RenderDXGITextureHostOGL(WindowsHandle aHandle,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize)
|
||||
RenderDXGITextureHostOGL::RenderDXGITextureHostOGL(
|
||||
WindowsHandle aHandle, gfx::SurfaceFormat aFormat,
|
||||
gfx::YUVColorSpace aYUVColorSpace, gfx::ColorRange aColorRange,
|
||||
gfx::IntSize aSize)
|
||||
: mHandle(aHandle),
|
||||
mSurface(0),
|
||||
mStream(0),
|
||||
mTextureHandle{0},
|
||||
mFormat(aFormat),
|
||||
mYUVColorSpace(aYUVColorSpace),
|
||||
mColorRange(aColorRange),
|
||||
mSize(aSize),
|
||||
mLocked(false) {
|
||||
MOZ_COUNT_CTOR_INHERITED(RenderDXGITextureHostOGL, RenderTextureHostOGL);
|
||||
|
|
|
@ -21,6 +21,8 @@ class RenderDXGITextureHostOGL final : public RenderTextureHostOGL {
|
|||
public:
|
||||
explicit RenderDXGITextureHostOGL(WindowsHandle aHandle,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
gfx::YUVColorSpace aYUVColorSpace,
|
||||
gfx::ColorRange aColorRange,
|
||||
gfx::IntSize aSize);
|
||||
|
||||
wr::WrExternalImage Lock(uint8_t aChannelIndex, gl::GLContext* aGL,
|
||||
|
@ -37,6 +39,12 @@ class RenderDXGITextureHostOGL final : public RenderTextureHostOGL {
|
|||
return this;
|
||||
}
|
||||
|
||||
gfx::SurfaceFormat GetFormat() const { return mFormat; }
|
||||
|
||||
gfx::YUVColorSpace GetYUVColorSpace() const { return mYUVColorSpace; }
|
||||
|
||||
gfx::ColorRange GetColorRange() const { return mColorRange; }
|
||||
|
||||
ID3D11Texture2D* GetD3D11Texture2D();
|
||||
|
||||
private:
|
||||
|
@ -60,8 +68,10 @@ class RenderDXGITextureHostOGL final : public RenderTextureHostOGL {
|
|||
// handles for Y and CbCr data.
|
||||
GLuint mTextureHandle[2];
|
||||
|
||||
gfx::SurfaceFormat mFormat;
|
||||
gfx::IntSize mSize;
|
||||
const gfx::SurfaceFormat mFormat;
|
||||
const gfx::YUVColorSpace mYUVColorSpace;
|
||||
const gfx::ColorRange mColorRange;
|
||||
const gfx::IntSize mSize;
|
||||
|
||||
bool mLocked;
|
||||
};
|
||||
|
|
|
@ -64,5 +64,14 @@ RenderTextureHostWrapper::AsRenderMacIOSurfaceTextureHostOGL() {
|
|||
return mTextureHost->AsRenderMacIOSurfaceTextureHostOGL();
|
||||
}
|
||||
|
||||
RenderDXGITextureHostOGL*
|
||||
RenderTextureHostWrapper::AsRenderDXGITextureHostOGL() {
|
||||
EnsureTextureHost();
|
||||
if (!mTextureHost) {
|
||||
return nullptr;
|
||||
}
|
||||
return mTextureHost->AsRenderDXGITextureHostOGL();
|
||||
}
|
||||
|
||||
} // namespace wr
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -36,6 +36,8 @@ class RenderTextureHostWrapper final : public RenderTextureHost {
|
|||
RenderMacIOSurfaceTextureHostOGL* AsRenderMacIOSurfaceTextureHostOGL()
|
||||
override;
|
||||
|
||||
virtual RenderDXGITextureHostOGL* AsRenderDXGITextureHostOGL() override;
|
||||
|
||||
private:
|
||||
~RenderTextureHostWrapper() override;
|
||||
|
||||
|
|
|
@ -835,13 +835,20 @@ static void DoNotifyWebRenderError(WebRenderError aError) {
|
|||
layers::CompositorManagerParent::NotifyWebRenderError(aError);
|
||||
}
|
||||
|
||||
void RenderThread::NotifyWebRenderError(WebRenderError aError) {
|
||||
MOZ_ASSERT(IsInRenderThread());
|
||||
|
||||
layers::CompositorThread()->Dispatch(NewRunnableFunction(
|
||||
"DoNotifyWebRenderErrorRunnable", &DoNotifyWebRenderError, aError));
|
||||
}
|
||||
|
||||
void RenderThread::HandleWebRenderError(WebRenderError aError) {
|
||||
if (mHandlingWebRenderError) {
|
||||
return;
|
||||
}
|
||||
|
||||
layers::CompositorThread()->Dispatch(NewRunnableFunction(
|
||||
"DoNotifyWebRenderErrorRunnable", &DoNotifyWebRenderError, aError));
|
||||
NotifyWebRenderError(aError);
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mRenderTextureMapLock);
|
||||
mRenderTexturesDeferred.clear();
|
||||
|
|
|
@ -264,6 +264,9 @@ class RenderThread final {
|
|||
/// Can be called from any thread.
|
||||
void SimulateDeviceReset();
|
||||
|
||||
/// Can only be called from the render thread.
|
||||
void NotifyWebRenderError(WebRenderError aError);
|
||||
|
||||
/// Can only be called from the render thread.
|
||||
void HandleWebRenderError(WebRenderError aError);
|
||||
/// Can only be called from the render thread.
|
||||
|
|
|
@ -767,6 +767,7 @@ enum class WebRenderError : int8_t {
|
|||
MAKE_CURRENT,
|
||||
RENDER,
|
||||
NEW_SURFACE,
|
||||
VIDEO_OVERLAY,
|
||||
|
||||
Sentinel /* this must be last for serialization purposes. */
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче