Bug 1880387 - Add support of NVIDIA RTX Video TrueHDR for video playback r=gfx-reviewers,jrmuizel

Differential Revision: https://phabricator.services.mozilla.com/D201909
This commit is contained in:
sotaro 2024-02-28 11:20:33 +00:00
parent ec606a05bb
commit 26f74e078a
3 changed files with 151 additions and 32 deletions

View file

@ -1178,6 +1178,87 @@ void DCSurfaceVideo::AttachExternalImage(wr::ExternalImageId aExternalImage) {
mRenderTextureHost = texture;
}
static UINT GetVendorId(ID3D11VideoDevice* const aVideoDevice) {
RefPtr<IDXGIDevice> dxgiDevice;
RefPtr<IDXGIAdapter> adapter;
aVideoDevice->QueryInterface((IDXGIDevice**)getter_AddRefs(dxgiDevice));
dxgiDevice->GetAdapter(getter_AddRefs(adapter));
DXGI_ADAPTER_DESC adapterDesc;
adapter->GetDesc(&adapterDesc);
return adapterDesc.VendorId;
}
static bool GetNvidiaRTXVideoTrueHDRSupported(
ID3D11VideoContext* aVideoContext, ID3D11VideoProcessor* aVideoProcessor) {
const GUID kNvidiaTrueHDRInterfaceGUID = {
0xfdd62bb4,
0x620b,
0x4fd7,
{0x9a, 0xb3, 0x1e, 0x59, 0xd0, 0xd5, 0x44, 0xb3}};
UINT available = 0;
HRESULT hr = aVideoContext->VideoProcessorGetStreamExtension(
aVideoProcessor, 0, &kNvidiaTrueHDRInterfaceGUID, sizeof(available),
&available);
if (FAILED(hr)) {
return false;
}
bool driverSupportsTrueHdr = (available == 1);
return driverSupportsTrueHdr;
}
static HRESULT SetNvidiaRTXVideoTrueHDR(ID3D11VideoContext* aVideoContext,
ID3D11VideoProcessor* aVideoProcessor,
bool aEnable) {
constexpr GUID kNvidiaTrueHDRInterfaceGUID = {
0xfdd62bb4,
0x620b,
0x4fd7,
{0x9a, 0xb3, 0x1e, 0x59, 0xd0, 0xd5, 0x44, 0xb3}};
constexpr UINT kStreamExtensionMethodTrueHDR = 0x3;
const UINT TrueHDRVersion4 = 4;
struct {
UINT version;
UINT method;
UINT enable : 1;
UINT reserved : 31;
} streamExtensionInfo = {TrueHDRVersion4, kStreamExtensionMethodTrueHDR,
aEnable ? 1u : 0u, 0u};
HRESULT hr = aVideoContext->VideoProcessorSetStreamExtension(
aVideoProcessor, 0, &kNvidiaTrueHDRInterfaceGUID,
sizeof(streamExtensionInfo), &streamExtensionInfo);
return hr;
}
static bool GetVpAutoHDRSupported(UINT aGpuVendorId,
ID3D11VideoContext* aVideoContext,
ID3D11VideoProcessor* aVideoProcessor) {
MOZ_ASSERT(aVideoContext);
MOZ_ASSERT(aVideoProcessor);
if (aGpuVendorId == 0x10DE) {
return GetNvidiaRTXVideoTrueHDRSupported(aVideoContext, aVideoProcessor);
}
MOZ_ASSERT_UNREACHABLE("Unexpected to be called");
return false;
}
static HRESULT SetVpAutoHDR(UINT aGpuVendorId,
ID3D11VideoContext* aVideoContext,
ID3D11VideoProcessor* aVideoProcessor,
bool aEnable) {
MOZ_ASSERT(aVideoContext);
MOZ_ASSERT(aVideoProcessor);
if (aGpuVendorId == 0x10DE) {
return SetNvidiaRTXVideoTrueHDR(aVideoContext, aVideoProcessor, aEnable);
}
MOZ_ASSERT_UNREACHABLE("Unexpected to be called");
return E_NOTIMPL;
}
bool DCSurfaceVideo::CalculateSwapChainSize(gfx::Matrix& aTransform) {
if (!mRenderTextureHost) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
@ -1225,18 +1306,39 @@ bool DCSurfaceVideo::CalculateSwapChainSize(gfx::Matrix& aTransform) {
transform = gfx::Matrix::Translation(aTransform.GetTranslation());
}
if (!mVideoSwapChain || mSwapChainSize != swapChainSize || mIsDRM != isDRM) {
if (!mDCLayerTree->EnsureVideoProcessor(mVideoSize, swapChainSize)) {
gfxCriticalNote << "EnsureVideoProcessor Failed";
return false;
}
MOZ_ASSERT(mDCLayerTree->GetVideoContext());
MOZ_ASSERT(mDCLayerTree->GetVideoProcessor());
const UINT vendorId = GetVendorId(mDCLayerTree->GetVideoDevice());
const bool driverSupportsTrueHDR =
GetVpAutoHDRSupported(vendorId, mDCLayerTree->GetVideoContext(),
mDCLayerTree->GetVideoProcessor());
const bool contentIsHDR = false; // XXX for now, only non-HDR is supported.
const bool monitorIsHDR = gfx::DeviceManagerDx::Get()->SystemHDREnabled();
bool useVpAutoHDR =
StaticPrefs::gfx_webrender_video_true_hdr_nvidia_AtStartup() &&
!contentIsHDR && monitorIsHDR && driverSupportsTrueHDR &&
!mVpAutoHDRFailed;
if (!mVideoSwapChain || mSwapChainSize != swapChainSize || mIsDRM != isDRM ||
mUseVpAutoHDR != useVpAutoHDR) {
needsToPresent = true;
ReleaseDecodeSwapChainResources();
// Update mSwapChainSize before creating SwapChain
mSwapChainSize = swapChainSize;
mIsDRM = isDRM;
auto swapChainFormat = GetSwapChainFormat();
auto swapChainFormat = GetSwapChainFormat(useVpAutoHDR);
bool useYUVSwapChain = IsYUVSwapChainFormat(swapChainFormat);
if (useYUVSwapChain) {
// Tries to create YUV SwapChain
CreateVideoSwapChain();
CreateVideoSwapChain(swapChainFormat);
if (!mVideoSwapChain) {
mFailedYuvSwapChain = true;
ReleaseDecodeSwapChainResources();
@ -1246,11 +1348,21 @@ bool DCSurfaceVideo::CalculateSwapChainSize(gfx::Matrix& aTransform) {
}
// Tries to create RGB SwapChain
if (!mVideoSwapChain) {
CreateVideoSwapChain();
CreateVideoSwapChain(swapChainFormat);
}
if (!mVideoSwapChain && useVpAutoHDR) {
mVpAutoHDRFailed = true;
gfxCriticalNoteOnce << "Failed to create video SwapChain for VpAutoHDR";
// Disable VpAutoHDR
useVpAutoHDR = false;
swapChainFormat = GetSwapChainFormat(useVpAutoHDR);
CreateVideoSwapChain(swapChainFormat);
}
}
aTransform = transform;
mUseVpAutoHDR = useVpAutoHDR;
return needsToPresent;
}
@ -1270,8 +1382,7 @@ void DCSurfaceVideo::PresentVideo() {
mVisual->SetContent(mVideoSwapChain);
if (!CallVideoProcessorBlt()) {
auto swapChainFormat = GetSwapChainFormat();
bool useYUVSwapChain = IsYUVSwapChainFormat(swapChainFormat);
bool useYUVSwapChain = IsYUVSwapChainFormat(mSwapChainFormat);
if (useYUVSwapChain) {
mFailedYuvSwapChain = true;
ReleaseDecodeSwapChainResources();
@ -1392,14 +1503,17 @@ void DCSurfaceVideo::PresentVideo() {
}
}
DXGI_FORMAT DCSurfaceVideo::GetSwapChainFormat() {
DXGI_FORMAT DCSurfaceVideo::GetSwapChainFormat(bool aUseVpAutoHDR) {
if (aUseVpAutoHDR) {
return DXGI_FORMAT_R16G16B16A16_FLOAT;
}
if (mFailedYuvSwapChain || !mDCLayerTree->SupportsHardwareOverlays()) {
return DXGI_FORMAT_B8G8R8A8_UNORM;
}
return mDCLayerTree->GetOverlayFormatForSDR();
}
bool DCSurfaceVideo::CreateVideoSwapChain() {
bool DCSurfaceVideo::CreateVideoSwapChain(DXGI_FORMAT aSwapChainFormat) {
MOZ_ASSERT(mRenderTextureHost);
mFirstPresent = true;
@ -1423,12 +1537,10 @@ bool DCSurfaceVideo::CreateVideoSwapChain() {
return false;
}
auto swapChainFormat = GetSwapChainFormat();
DXGI_SWAP_CHAIN_DESC1 desc = {};
desc.Width = mSwapChainSize.width;
desc.Height = mSwapChainSize.height;
desc.Format = swapChainFormat;
desc.Format = aSwapChainFormat;
desc.Stereo = FALSE;
desc.SampleDesc.Count = 1;
desc.BufferCount = mSwapChainBufferCount;
@ -1436,7 +1548,7 @@ bool DCSurfaceVideo::CreateVideoSwapChain() {
desc.Scaling = DXGI_SCALING_STRETCH;
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
desc.Flags = DXGI_SWAP_CHAIN_FLAG_FULLSCREEN_VIDEO;
if (IsYUVSwapChainFormat(swapChainFormat)) {
if (IsYUVSwapChainFormat(aSwapChainFormat)) {
desc.Flags |= DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO;
}
if (mIsDRM) {
@ -1455,7 +1567,7 @@ bool DCSurfaceVideo::CreateVideoSwapChain() {
return false;
}
mSwapChainFormat = swapChainFormat;
mSwapChainFormat = aSwapChainFormat;
return true;
}
@ -1526,18 +1638,6 @@ static void SetNvidiaVideoSuperRes(ID3D11VideoContext* videoContext,
}
}
static UINT GetVendorId(ID3D11VideoDevice* const videoDevice) {
RefPtr<IDXGIDevice> dxgiDevice;
RefPtr<IDXGIAdapter> adapter;
videoDevice->QueryInterface((IDXGIDevice**)getter_AddRefs(dxgiDevice));
dxgiDevice->GetAdapter(getter_AddRefs(adapter));
DXGI_ADAPTER_DESC adapterDesc;
adapter->GetDesc(&adapterDesc);
return adapterDesc.VendorId;
}
bool DCSurfaceVideo::CallVideoProcessorBlt() {
MOZ_ASSERT(mRenderTextureHost);
@ -1576,11 +1676,6 @@ bool DCSurfaceVideo::CallVideoProcessorBlt() {
}
}
if (!mDCLayerTree->EnsureVideoProcessor(mVideoSize, mSwapChainSize)) {
gfxCriticalNote << "EnsureVideoProcessor Failed";
return false;
}
RefPtr<IDXGISwapChain3> swapChain3;
mVideoSwapChain->QueryInterface(
(IDXGISwapChain3**)getter_AddRefs(swapChain3));
@ -1609,6 +1704,13 @@ bool DCSurfaceVideo::CallVideoProcessorBlt() {
IsYUVSwapChainFormat(mSwapChainFormat)
? inputColorSpace
: DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
if (mUseVpAutoHDR) {
outputColorSpace = mSwapChainFormat == DXGI_FORMAT_R16G16B16A16_FLOAT
? DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709
: DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
}
hr = swapChain3->SetColorSpace1(outputColorSpace);
if (FAILED(hr)) {
gfxCriticalNoteOnce << "SetColorSpace1 failed: " << gfx::hexa(hr);
@ -1684,6 +1786,14 @@ bool DCSurfaceVideo::CallVideoProcessorBlt() {
SetNvidiaVideoSuperRes(videoContext, videoProcessor, true);
}
if (mUseVpAutoHDR) {
hr = SetVpAutoHDR(vendorId, videoContext, videoProcessor, true);
if (FAILED(hr)) {
gfxCriticalNoteOnce << "SetVpAutoHDR failed: " << gfx::hexa(hr);
mVpAutoHDRFailed = true;
}
}
hr = videoContext->VideoProcessorBlt(videoProcessor, mOutputView, 0, 1,
&stream);
if (FAILED(hr)) {
@ -1703,6 +1813,7 @@ void DCSurfaceVideo::ReleaseDecodeSwapChainResources() {
::CloseHandle(mSwapChainSurfaceHandle);
mSwapChainSurfaceHandle = 0;
}
mUseVpAutoHDR = false;
}
DCSurfaceHandle::DCSurfaceHandle(bool aIsOpaque, DCLayerTree* aDCLayerTree)

View file

@ -389,8 +389,8 @@ class DCSurfaceVideo : public DCSurface {
protected:
virtual ~DCSurfaceVideo();
DXGI_FORMAT GetSwapChainFormat();
bool CreateVideoSwapChain();
DXGI_FORMAT GetSwapChainFormat(bool aUseVpAutoHDR);
bool CreateVideoSwapChain(DXGI_FORMAT aFormat);
bool CallVideoProcessorBlt();
void ReleaseDecodeSwapChainResources();
@ -409,6 +409,8 @@ class DCSurfaceVideo : public DCSurface {
int mSlowPresentCount = 0;
bool mFirstPresent = true;
const UINT mSwapChainBufferCount;
bool mUseVpAutoHDR = false;
bool mVpAutoHDRFailed = false;
};
/**

View file

@ -6794,6 +6794,12 @@
value: false
mirror: once
# Enable NVIDIA RTX Video TrueHDR for video playback on Windows
- name: gfx.webrender.video-true-hdr.nvidia
type: bool
value: false
mirror: once
# Use vsync events generated by hardware
- name: gfx.work-around-driver-bugs
type: bool