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:
sotaro 2020-09-09 01:04:53 +00:00
Родитель d79aa27e63
Коммит 54ede5160d
17 изменённых файлов: 555 добавлений и 17 удалений

Просмотреть файл

@ -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. */
};