mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Bug 1722447 - Add YUV SwapChain support to hardware decoded video r=gfx-reviewers,nical
Implementation is borrowed from chromium's SwapChainPresenter. Differential Revision: https://phabricator.services.mozilla.com/D136460
This commit is contained in:
parent
943733bcc3
commit
f9873bede0
@ -15,6 +15,7 @@
|
||||
#include "mozilla/webrender/RenderD3D11TextureHost.h"
|
||||
#include "mozilla/webrender/RenderTextureHost.h"
|
||||
#include "mozilla/webrender/RenderThread.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "WinUtils.h"
|
||||
@ -35,6 +36,8 @@ namespace wr {
|
||||
extern LazyLogModule gRenderThreadLog;
|
||||
#define LOG(...) MOZ_LOG(gRenderThreadLog, LogLevel::Debug, (__VA_ARGS__))
|
||||
|
||||
UniquePtr<GpuOverlayInfo> DCLayerTree::sGpuOverlayInfo;
|
||||
|
||||
/* static */
|
||||
UniquePtr<DCLayerTree> DCLayerTree::Create(gl::GLContext* aGL,
|
||||
EGLConfig aEGLConfig,
|
||||
@ -57,6 +60,8 @@ UniquePtr<DCLayerTree> DCLayerTree::Create(gl::GLContext* aGL,
|
||||
return layerTree;
|
||||
}
|
||||
|
||||
void DCLayerTree::Shutdown() { DCLayerTree::sGpuOverlayInfo = nullptr; }
|
||||
|
||||
DCLayerTree::DCLayerTree(gl::GLContext* aGL, EGLConfig aEGLConfig,
|
||||
ID3D11Device* aDevice, ID3D11DeviceContext* aCtx,
|
||||
IDCompositionDevice2* aCompositionDevice)
|
||||
@ -65,7 +70,6 @@ DCLayerTree::DCLayerTree(gl::GLContext* aGL, EGLConfig aEGLConfig,
|
||||
mDevice(aDevice),
|
||||
mCtx(aCtx),
|
||||
mCompositionDevice(aCompositionDevice),
|
||||
mVideoOverlaySupported(false),
|
||||
mDebugCounter(false),
|
||||
mDebugVisualRedrawRegions(false),
|
||||
mEGLImage(EGL_NO_IMAGE),
|
||||
@ -132,6 +136,10 @@ bool DCLayerTree::Initialize(HWND aHwnd, nsACString& aError) {
|
||||
RenderThread::Get()->HandleWebRenderError(WebRenderError::VIDEO_OVERLAY);
|
||||
}
|
||||
}
|
||||
if (!sGpuOverlayInfo) {
|
||||
// Set default if sGpuOverlayInfo was not set.
|
||||
sGpuOverlayInfo = MakeUnique<GpuOverlayInfo>();
|
||||
}
|
||||
|
||||
mCompositionTarget->SetRoot(mRootVisual);
|
||||
// Set interporation mode to nearest, to ensure 1:1 sampling.
|
||||
@ -143,7 +151,37 @@ bool DCLayerTree::Initialize(HWND aHwnd, nsACString& aError) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FlagsSupportsOverlays(UINT flags) {
|
||||
return (flags & (DXGI_OVERLAY_SUPPORT_FLAG_DIRECT |
|
||||
DXGI_OVERLAY_SUPPORT_FLAG_SCALING));
|
||||
}
|
||||
|
||||
// A warpper of IDXGIOutput4::CheckOverlayColorSpaceSupport()
|
||||
bool CheckOverlayColorSpaceSupport(DXGI_FORMAT aDxgiFormat,
|
||||
DXGI_COLOR_SPACE_TYPE aDxgiColorSpace,
|
||||
RefPtr<IDXGIOutput> aOutput,
|
||||
RefPtr<ID3D11Device> aD3d11Device) {
|
||||
UINT colorSpaceSupportFlags = 0;
|
||||
RefPtr<IDXGIOutput4> output4;
|
||||
|
||||
if (FAILED(aOutput->QueryInterface(__uuidof(IDXGIOutput4),
|
||||
getter_AddRefs(output4)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FAILED(output4->CheckOverlayColorSpaceSupport(
|
||||
aDxgiFormat, aDxgiColorSpace, aD3d11Device,
|
||||
&colorSpaceSupportFlags))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (colorSpaceSupportFlags &
|
||||
DXGI_OVERLAY_COLOR_SPACE_SUPPORT_FLAG_PRESENT);
|
||||
}
|
||||
|
||||
bool DCLayerTree::InitializeVideoOverlaySupport() {
|
||||
MOZ_ASSERT(IsWin10AnniversaryUpdateOrLater());
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
hr = mDevice->QueryInterface(
|
||||
@ -160,12 +198,76 @@ bool DCLayerTree::InitializeVideoOverlaySupport() {
|
||||
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.
|
||||
if (sGpuOverlayInfo) {
|
||||
return true;
|
||||
}
|
||||
|
||||
mVideoOverlaySupported = true;
|
||||
UniquePtr<GpuOverlayInfo> info = MakeUnique<GpuOverlayInfo>();
|
||||
|
||||
RefPtr<IDXGIDevice> dxgiDevice;
|
||||
RefPtr<IDXGIAdapter> adapter;
|
||||
mDevice->QueryInterface((IDXGIDevice**)getter_AddRefs(dxgiDevice));
|
||||
dxgiDevice->GetAdapter(getter_AddRefs(adapter));
|
||||
|
||||
unsigned int i = 0;
|
||||
while (true) {
|
||||
RefPtr<IDXGIOutput> output;
|
||||
if (FAILED(adapter->EnumOutputs(i++, getter_AddRefs(output)))) {
|
||||
break;
|
||||
}
|
||||
RefPtr<IDXGIOutput3> output3;
|
||||
if (FAILED(output->QueryInterface(__uuidof(IDXGIOutput3),
|
||||
getter_AddRefs(output3)))) {
|
||||
break;
|
||||
}
|
||||
|
||||
output3->CheckOverlaySupport(DXGI_FORMAT_NV12, mDevice,
|
||||
&info->mNv12OverlaySupportFlags);
|
||||
output3->CheckOverlaySupport(DXGI_FORMAT_YUY2, mDevice,
|
||||
&info->mYuy2OverlaySupportFlags);
|
||||
output3->CheckOverlaySupport(DXGI_FORMAT_R10G10B10A2_UNORM, mDevice,
|
||||
&info->mRgb10a2OverlaySupportFlags);
|
||||
|
||||
if (FlagsSupportsOverlays(info->mNv12OverlaySupportFlags)) {
|
||||
// NV12 format is preferred if it's supported.
|
||||
info->mOverlayFormatUsed = DXGI_FORMAT_NV12;
|
||||
info->mSupportsHardwareOverlays = true;
|
||||
}
|
||||
|
||||
if (!info->mSupportsHardwareOverlays &&
|
||||
FlagsSupportsOverlays(info->mYuy2OverlaySupportFlags)) {
|
||||
// If NV12 isn't supported, fallback to YUY2 if it's supported.
|
||||
info->mOverlayFormatUsed = DXGI_FORMAT_YUY2;
|
||||
info->mSupportsHardwareOverlays = true;
|
||||
}
|
||||
|
||||
// RGB10A2 overlay is used for displaying HDR content. In Intel's
|
||||
// platform, RGB10A2 overlay is enabled only when
|
||||
// DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 is supported.
|
||||
if (FlagsSupportsOverlays(info->mRgb10a2OverlaySupportFlags)) {
|
||||
if (!CheckOverlayColorSpaceSupport(
|
||||
DXGI_FORMAT_R10G10B10A2_UNORM,
|
||||
DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020, output, mDevice))
|
||||
info->mRgb10a2OverlaySupportFlags = 0;
|
||||
}
|
||||
|
||||
// Early out after the first output that reports overlay support. All
|
||||
// outputs are expected to report the same overlay support according to
|
||||
// Microsoft's WDDM documentation:
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/display/multiplane-overlay-hardware-requirements
|
||||
if (info->mSupportsHardwareOverlays) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!StaticPrefs::gfx_webrender_dcomp_video_yuv_overlay_win_AtStartup()) {
|
||||
info->mOverlayFormatUsed = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
info->mSupportsHardwareOverlays = false;
|
||||
}
|
||||
|
||||
info->mSupportsOverlays = info->mSupportsHardwareOverlays;
|
||||
|
||||
sGpuOverlayInfo = std::move(info);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -579,6 +681,14 @@ bool DCLayerTree::EnsureVideoProcessor(const gfx::IntSize& aVideoSize) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DCLayerTree::SupportsHardwareOverlays() {
|
||||
return sGpuOverlayInfo->mSupportsHardwareOverlays;
|
||||
}
|
||||
|
||||
DXGI_FORMAT DCLayerTree::GetOverlayFormatForSDR() {
|
||||
return sGpuOverlayInfo->mOverlayFormatUsed;
|
||||
}
|
||||
|
||||
DCSurface::DCSurface(wr::DeviceIntSize aTileSize,
|
||||
wr::DeviceIntPoint aVirtualOffset, bool aIsOpaque,
|
||||
DCLayerTree* aDCLayerTree)
|
||||
@ -718,6 +828,21 @@ void DCSurfaceVideo::AttachExternalImage(wr::ExternalImageId aExternalImage) {
|
||||
mPrevTexture = texture;
|
||||
}
|
||||
|
||||
bool IsYUVSwapChainFormat(DXGI_FORMAT aFormat) {
|
||||
if (aFormat == DXGI_FORMAT_NV12 || aFormat == DXGI_FORMAT_YUY2) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
DXGI_FORMAT DCSurfaceVideo::GetSwapChainFormat() {
|
||||
if (mFailedToCreateYuvSwapChain ||
|
||||
!mDCLayerTree->SupportsHardwareOverlays()) {
|
||||
return DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
}
|
||||
return mDCLayerTree->GetOverlayFormatForSDR();
|
||||
}
|
||||
|
||||
bool DCSurfaceVideo::CreateVideoSwapChain(RenderTextureHost* aTexture) {
|
||||
const auto device = mDCLayerTree->GetDevice();
|
||||
|
||||
@ -739,21 +864,23 @@ bool DCSurfaceVideo::CreateVideoSwapChain(RenderTextureHost* aTexture) {
|
||||
}
|
||||
|
||||
gfx::IntSize size = aTexture->AsRenderDXGITextureHost()->GetSize(0);
|
||||
DXGI_ALPHA_MODE alpha_mode =
|
||||
mIsOpaque ? DXGI_ALPHA_MODE_IGNORE : DXGI_ALPHA_MODE_PREMULTIPLIED;
|
||||
auto swapChainFormat = GetSwapChainFormat();
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC1 desc = {};
|
||||
desc.Width = size.width;
|
||||
desc.Height = size.height;
|
||||
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
desc.Format = swapChainFormat;
|
||||
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;
|
||||
desc.Flags = DXGI_SWAP_CHAIN_FLAG_FULLSCREEN_VIDEO;
|
||||
if (IsYUVSwapChainFormat(swapChainFormat)) {
|
||||
desc.Flags |= DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO;
|
||||
}
|
||||
desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
|
||||
|
||||
HRESULT hr;
|
||||
hr = dxgiFactoryMedia->CreateSwapChainForCompositionSurfaceHandle(
|
||||
@ -761,11 +888,13 @@ bool DCSurfaceVideo::CreateVideoSwapChain(RenderTextureHost* aTexture) {
|
||||
getter_AddRefs(mVideoSwapChain));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
mFailedToCreateYuvSwapChain = true;
|
||||
gfxCriticalNote << "Failed to create video SwapChain: " << gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
mSwapChainSize = size;
|
||||
mSwapChainFormat = swapChainFormat;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -855,9 +984,11 @@ bool DCSurfaceVideo::CallVideoProcessorBlt(RenderTextureHost* aTexture) {
|
||||
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;
|
||||
IsYUVSwapChainFormat(mSwapChainFormat)
|
||||
? inputColorSpace
|
||||
: DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
|
||||
hr = swapChain3->SetColorSpace1(outputColorSpace);
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalNote << "SetColorSpace1 failed: " << gfx::hexa(hr);
|
||||
|
@ -7,6 +7,7 @@
|
||||
#ifndef MOZILLA_GFX_DCLAYER_TREE_H
|
||||
#define MOZILLA_GFX_DCLAYER_TREE_H
|
||||
|
||||
#include <dxgiformat.h>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <windows.h>
|
||||
@ -51,6 +52,16 @@ class DCSurface;
|
||||
class DCSurfaceVideo;
|
||||
class RenderTextureHost;
|
||||
|
||||
struct GpuOverlayInfo {
|
||||
bool mSupportsOverlays = false;
|
||||
bool mSupportsHardwareOverlays = false;
|
||||
DXGI_FORMAT mOverlayFormatUsed = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
DXGI_FORMAT mOverlayFormatUsedHdr = DXGI_FORMAT_R10G10B10A2_UNORM;
|
||||
UINT mNv12OverlaySupportFlags = 0;
|
||||
UINT mYuy2OverlaySupportFlags = 0;
|
||||
UINT mRgb10a2OverlaySupportFlags = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* DCLayerTree manages direct composition layers.
|
||||
* It does not manage gecko's layers::Layer.
|
||||
@ -61,6 +72,9 @@ class DCLayerTree {
|
||||
ID3D11Device* aDevice,
|
||||
ID3D11DeviceContext* aCtx, HWND aHwnd,
|
||||
nsACString& aError);
|
||||
|
||||
static void Shutdown();
|
||||
|
||||
explicit DCLayerTree(gl::GLContext* aGL, EGLConfig aEGLConfig,
|
||||
ID3D11Device* aDevice, ID3D11DeviceContext* aCtx,
|
||||
IDCompositionDevice2* aCompositionDevice);
|
||||
@ -110,6 +124,9 @@ class DCLayerTree {
|
||||
// Get or create an FBO with depth buffer suitable for specified dimensions
|
||||
GLuint GetOrCreateFbo(int aWidth, int aHeight);
|
||||
|
||||
bool SupportsHardwareOverlays();
|
||||
DXGI_FORMAT GetOverlayFormatForSDR();
|
||||
|
||||
protected:
|
||||
bool Initialize(HWND aHwnd, nsACString& aError);
|
||||
bool InitializeVideoOverlaySupport();
|
||||
@ -139,8 +156,6 @@ class DCLayerTree {
|
||||
RefPtr<ID3D11VideoProcessorEnumerator> mVideoProcessorEnumerator;
|
||||
gfx::IntSize mVideoSize;
|
||||
|
||||
bool mVideoOverlaySupported;
|
||||
|
||||
bool mDebugCounter;
|
||||
bool mDebugVisualRedrawRegions;
|
||||
|
||||
@ -185,6 +200,8 @@ class DCLayerTree {
|
||||
int mCurrentFrame = 0;
|
||||
|
||||
bool mPendingCommit;
|
||||
|
||||
static UniquePtr<GpuOverlayInfo> sGpuOverlayInfo;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -259,6 +276,7 @@ class DCSurfaceVideo : public DCSurface {
|
||||
DCSurfaceVideo* AsDCSurfaceVideo() override { return this; }
|
||||
|
||||
protected:
|
||||
DXGI_FORMAT GetSwapChainFormat();
|
||||
bool CreateVideoSwapChain(RenderTextureHost* aTexture);
|
||||
bool CallVideoProcessorBlt(RenderTextureHost* aTexture);
|
||||
void ReleaseDecodeSwapChainResources();
|
||||
@ -269,6 +287,8 @@ class DCSurfaceVideo : public DCSurface {
|
||||
RefPtr<IDXGIDecodeSwapChain> mDecodeSwapChain;
|
||||
HANDLE mSwapChainSurfaceHandle;
|
||||
gfx::IntSize mSwapChainSize;
|
||||
DXGI_FORMAT mSwapChainFormat = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
bool mFailedToCreateYuvSwapChain = false;
|
||||
RefPtr<RenderTextureHost> mPrevTexture;
|
||||
};
|
||||
|
||||
|
@ -35,6 +35,7 @@
|
||||
# include "GLLibraryEGL.h"
|
||||
# include "mozilla/widget/WinCompositorWindowThread.h"
|
||||
# include "mozilla/gfx/DeviceManagerDx.h"
|
||||
# include "mozilla/webrender/DCLayerTree.h"
|
||||
//# include "nsWindowsHelpers.h"
|
||||
//# include <d3d11.h>
|
||||
#endif
|
||||
@ -173,6 +174,10 @@ void RenderThread::ShutDownTask(layers::SynchronousTask* aTask) {
|
||||
// remaining textures from the texture map.
|
||||
layers::SharedSurfacesParent::ShutdownRenderThread();
|
||||
|
||||
#ifdef XP_WIN
|
||||
DCLayerTree::Shutdown();
|
||||
#endif
|
||||
|
||||
ClearAllBlobImageResources();
|
||||
ClearSingletonGL();
|
||||
ClearSharedSurfacePool();
|
||||
|
@ -5728,6 +5728,11 @@
|
||||
type: bool
|
||||
value: false
|
||||
mirror: once
|
||||
# Whether to use a yuv video overlay layers with DirectComposition
|
||||
- name: gfx.webrender.dcomp-video-yuv-overlay-win
|
||||
type: bool
|
||||
value: false
|
||||
mirror: once
|
||||
#endif
|
||||
|
||||
# Whether or not fallback to Software WebRender requires the GPU process.
|
||||
|
Loading…
Reference in New Issue
Block a user