Add video processor based Auto HDR support on Windows
(This CL is copied from https://crrev.com/c/4535570. Author: Romain Pokrzywka.) This adds vp-based SDR-to-HDR conversion on Windows for supported NVIDIA GPUs via the ID3D11VideoProcessor interface. The feature is gated by a new disable_vp_auto_hdr flag to limit it to supported vendor/gpu/driver combinations. Currently only enabled for NVIDIA GPUs with a 545+ driver, using the vendor-specific extension. Similar to RTX Super Resolution, the feature will be off by default, requiring manual opt-in by users via a toggle in the nvidia control panel application. Bug: 1445741 Change-Id: Ib0068306168588bcb61b8196c509497083005588 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4652913 Reviewed-by: Jonathan Ross <jonross@chromium.org> Auto-Submit: Maggie Chen <magchen@chromium.org> Commit-Queue: Maggie Chen <magchen@chromium.org> Reviewed-by: Dale Curtis <dalecurtis@chromium.org> Reviewed-by: Vasiliy Telezhnikov <vasilyt@chromium.org> Cr-Commit-Position: refs/heads/main@{#1164814}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
29eaa29e6b
commit
b2fae4c984
gpu
tools/metrics/histograms/metadata/gpu
ui/gl
@ -4178,6 +4178,32 @@
|
||||
"features": [
|
||||
"force_dcomp_triple_buffer_video_swap_chain"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 414,
|
||||
"cr_bugs": [
|
||||
1318380
|
||||
],
|
||||
"description": "Only enable video processor auto HDR on NVIDIA GPUs with 545+ driver",
|
||||
"os": {
|
||||
"type": "win"
|
||||
},
|
||||
"exceptions": [
|
||||
{
|
||||
"vendor_id": "0x10de",
|
||||
"os": {
|
||||
"type": "win"
|
||||
},
|
||||
"driver_version": {
|
||||
"schema": "nvidia_driver",
|
||||
"op": ">",
|
||||
"value": "545.00"
|
||||
}
|
||||
}
|
||||
],
|
||||
"features": [
|
||||
"disable_vp_auto_hdr"
|
||||
]
|
||||
}
|
||||
|
||||
]
|
||||
|
@ -63,6 +63,7 @@ disable_skia_reduce_ops_task_splitting
|
||||
disable_software_to_accelerated_canvas_upgrade
|
||||
disable_texture_storage
|
||||
disable_timestamp_queries
|
||||
disable_vp_auto_hdr
|
||||
disable_vp_scaling
|
||||
disable_vp_super_resolution
|
||||
disable_webgl_rgb_multisampling_usage
|
||||
|
@ -33,6 +33,7 @@ CreateDirectCompositionSurfaceSettings(
|
||||
workarounds.no_downscaled_overlay_promotion;
|
||||
settings.disable_nv12_dynamic_textures =
|
||||
workarounds.disable_nv12_dynamic_textures;
|
||||
settings.disable_vp_auto_hdr = workarounds.disable_vp_auto_hdr;
|
||||
settings.disable_vp_scaling = workarounds.disable_vp_scaling;
|
||||
settings.disable_vp_super_resolution =
|
||||
workarounds.disable_vp_super_resolution;
|
||||
|
@ -1107,15 +1107,20 @@ chromium-metrics-reviews@google.com.
|
||||
</summary>
|
||||
</histogram>
|
||||
|
||||
<histogram name="GPU.NvidiaVpSuperResolution.{State}.SetStreamExt"
|
||||
enum="Hresult" expires_after="2023-06-30">
|
||||
<histogram name="GPU.Nvidia{Extension}.{State}.SetStreamExt" enum="Hresult"
|
||||
expires_after="2023-12-31">
|
||||
<owner>magchen@chromium.org</owner>
|
||||
<owner>zmo@chromium.org</owner>
|
||||
<owner>graphics-dev@chromium.org</owner>
|
||||
<summary>
|
||||
Records HRESULT in NvidiaVpSuperResolution. This metric is recorded every
|
||||
frame when processing video streams in DirectComposition.
|
||||
Records HRESULT when setting the video processor stream extension for Nvidia
|
||||
{Extension} to {State}. This metric is recorded every frame when processing
|
||||
video streams in DirectComposition.
|
||||
</summary>
|
||||
<token key="Extension">
|
||||
<variant name="VpSuperResolution" summary="RTX SuperResolution"/>
|
||||
<variant name="VpTrueHDR" summary="RTX TrueHDR"/>
|
||||
</token>
|
||||
<token key="State">
|
||||
<variant name="Off" summary="off"/>
|
||||
<variant name="On" summary="on"/>
|
||||
@ -1466,16 +1471,20 @@ chromium-metrics-reviews@google.com.
|
||||
</summary>
|
||||
</histogram>
|
||||
|
||||
<histogram name="GPU.VideoProcessorBlt.VpSuperResolution.{State}"
|
||||
enum="Hresult" expires_after="2023-06-30">
|
||||
<histogram name="GPU.VideoProcessorBlt.{Extension}.{State}" enum="Hresult"
|
||||
expires_after="2023-12-31">
|
||||
<owner>magchen@chromium.org</owner>
|
||||
<owner>zmo@chromium.org</owner>
|
||||
<owner>graphics-dev@chromium.org</owner>
|
||||
<summary>
|
||||
Records HRESULT for VideoProcessorBlt. This metric is recorded when
|
||||
processing a video steam in DirectComposition with Video Processor Super
|
||||
Rsolution {State}.
|
||||
processing a video stream in DirectComposition with {Extension} {State}.
|
||||
</summary>
|
||||
<token key="Extension">
|
||||
<variant name="VpAutoHDR" summary="Video Processor Auto HDR"/>
|
||||
<variant name="VpSuperResolution"
|
||||
summary="Video Processor Super Resolution"/>
|
||||
</token>
|
||||
<token key="State">
|
||||
<variant name="Off" summary="off"/>
|
||||
<variant name="On" summary="on"/>
|
||||
|
@ -49,11 +49,13 @@ VideoProcessorWrapper& VideoProcessorWrapper::operator=(
|
||||
VideoProcessorWrapper&& other) = default;
|
||||
|
||||
DCLayerTree::DCLayerTree(bool disable_nv12_dynamic_textures,
|
||||
bool disable_vp_auto_hdr,
|
||||
bool disable_vp_scaling,
|
||||
bool disable_vp_super_resolution,
|
||||
bool force_dcomp_triple_buffer_video_swap_chain,
|
||||
bool no_downscaled_overlay_promotion)
|
||||
: disable_nv12_dynamic_textures_(disable_nv12_dynamic_textures),
|
||||
disable_vp_auto_hdr_(disable_vp_auto_hdr),
|
||||
disable_vp_scaling_(disable_vp_scaling),
|
||||
disable_vp_super_resolution_(disable_vp_super_resolution),
|
||||
force_dcomp_triple_buffer_video_swap_chain_(
|
||||
|
@ -70,6 +70,7 @@ class DCLayerTree {
|
||||
DCompositionInkTrailPoint>;
|
||||
|
||||
DCLayerTree(bool disable_nv12_dynamic_textures,
|
||||
bool disable_vp_auto_hdr,
|
||||
bool disable_vp_scaling,
|
||||
bool disable_vp_super_resolution,
|
||||
bool force_dcomp_triple_buffer_video_swap_chain,
|
||||
@ -103,6 +104,8 @@ class DCLayerTree {
|
||||
return disable_nv12_dynamic_textures_;
|
||||
}
|
||||
|
||||
bool disable_vp_auto_hdr() const { return disable_vp_auto_hdr_; }
|
||||
|
||||
bool disable_vp_scaling() const { return disable_vp_scaling_; }
|
||||
|
||||
bool disable_vp_super_resolution() const {
|
||||
@ -340,6 +343,7 @@ class DCLayerTree {
|
||||
gfx::Size& resource_size_in_pixels);
|
||||
|
||||
const bool disable_nv12_dynamic_textures_;
|
||||
const bool disable_vp_auto_hdr_;
|
||||
const bool disable_vp_scaling_;
|
||||
const bool disable_vp_super_resolution_;
|
||||
const bool force_dcomp_triple_buffer_video_swap_chain_;
|
||||
|
@ -51,6 +51,7 @@ DCompPresenter::DCompPresenter(
|
||||
max_pending_frames_(settings.max_pending_frames),
|
||||
layer_tree_(std::make_unique<DCLayerTree>(
|
||||
settings.disable_nv12_dynamic_textures,
|
||||
settings.disable_vp_auto_hdr,
|
||||
settings.disable_vp_scaling,
|
||||
settings.disable_vp_super_resolution,
|
||||
settings.force_dcomp_triple_buffer_video_swap_chain,
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "ui/gl/direct_composition_support.h"
|
||||
|
||||
#include <dxgi1_6.h>
|
||||
#include <set>
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/metrics/histogram_functions.h"
|
||||
@ -104,6 +105,9 @@ int g_num_monitors = 0;
|
||||
// Whether there is a HDR capable display monitor being connected.
|
||||
bool g_system_hdr_enabled = false;
|
||||
|
||||
// Per-monitor HDR capability
|
||||
std::set<HMONITOR> g_hdr_monitors = {};
|
||||
|
||||
// Global direct composition device.
|
||||
IDCompositionDevice3* g_dcomp_device = nullptr;
|
||||
// Whether swap chain present failed and direct composition should be disabled.
|
||||
@ -361,6 +365,68 @@ void UpdateOverlaySupport() {
|
||||
g_overlay_format_used_hdr = overlay_format_used_hdr;
|
||||
}
|
||||
|
||||
std::vector<DXGI_OUTPUT_DESC1> GetDirectCompositionOutputDescs() {
|
||||
std::vector<DXGI_OUTPUT_DESC1> output_descs;
|
||||
// HDR support was introduced in Windows 10 Creators Update.
|
||||
if (base::win::GetVersion() < base::win::Version::WIN10_RS2) {
|
||||
return output_descs;
|
||||
}
|
||||
|
||||
// Only direct composition surface can allocate HDR swap chains.
|
||||
if (!DirectCompositionSupported()) {
|
||||
return output_descs;
|
||||
}
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
Microsoft::WRL::ComPtr<IDXGIFactory1> factory;
|
||||
hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory));
|
||||
if (FAILED(hr)) {
|
||||
DLOG(ERROR) << "Failed to create DXGI factory.";
|
||||
return output_descs;
|
||||
}
|
||||
|
||||
for (UINT adapter_index = 0;; ++adapter_index) {
|
||||
Microsoft::WRL::ComPtr<IDXGIAdapter> adapter;
|
||||
hr = factory->EnumAdapters(adapter_index, &adapter);
|
||||
if (hr == DXGI_ERROR_NOT_FOUND) {
|
||||
break;
|
||||
}
|
||||
if (FAILED(hr)) {
|
||||
DLOG(ERROR) << "Unexpected error creating DXGI adapter.";
|
||||
break;
|
||||
}
|
||||
|
||||
for (UINT output_index = 0;; ++output_index) {
|
||||
Microsoft::WRL::ComPtr<IDXGIOutput> output;
|
||||
hr = adapter->EnumOutputs(output_index, &output);
|
||||
if (hr == DXGI_ERROR_NOT_FOUND) {
|
||||
break;
|
||||
}
|
||||
if (FAILED(hr)) {
|
||||
DLOG(ERROR) << "Unexpected error creating DXGI adapter.";
|
||||
break;
|
||||
}
|
||||
|
||||
Microsoft::WRL::ComPtr<IDXGIOutput6> output6;
|
||||
hr = output->QueryInterface(IID_PPV_ARGS(&output6));
|
||||
if (FAILED(hr)) {
|
||||
DLOG(WARNING) << "IDXGIOutput6 is required for HDR detection.";
|
||||
continue;
|
||||
}
|
||||
|
||||
DXGI_OUTPUT_DESC1 desc;
|
||||
if (FAILED(output6->GetDesc1(&desc))) {
|
||||
DLOG(ERROR) << "Unexpected error getting output descriptor.";
|
||||
continue;
|
||||
}
|
||||
|
||||
output_descs.push_back(std::move(desc));
|
||||
}
|
||||
}
|
||||
|
||||
return output_descs;
|
||||
}
|
||||
|
||||
void UpdateMonitorInfo() {
|
||||
g_num_monitors = GetSystemMetrics(SM_CMONITORS);
|
||||
|
||||
@ -372,10 +438,16 @@ void UpdateMonitorInfo() {
|
||||
} else {
|
||||
g_primary_monitor_size = gfx::Size();
|
||||
}
|
||||
|
||||
g_hdr_monitors.clear();
|
||||
g_system_hdr_enabled = false;
|
||||
auto dxgi_info = gl::GetDirectCompositionHDRMonitorDXGIInfo();
|
||||
for (const auto& output_desc : dxgi_info->output_descs)
|
||||
g_system_hdr_enabled |= output_desc->hdr_enabled;
|
||||
for (const auto& desc : GetDirectCompositionOutputDescs()) {
|
||||
if (desc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) {
|
||||
g_hdr_monitors.insert(desc.Monitor);
|
||||
g_system_hdr_enabled = true;
|
||||
}
|
||||
}
|
||||
UMA_HISTOGRAM_BOOLEAN("GPU.Output.HDR", g_system_hdr_enabled);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -563,6 +635,15 @@ bool DirectCompositionSystemHDREnabled() {
|
||||
return g_system_hdr_enabled;
|
||||
}
|
||||
|
||||
bool DirectCompositionMonitorHDREnabled(HWND window) {
|
||||
if (g_num_monitors == 0) {
|
||||
UpdateMonitorInfo();
|
||||
}
|
||||
|
||||
return g_hdr_monitors.find(MonitorFromWindow(
|
||||
window, MONITOR_DEFAULTTONEAREST)) != g_hdr_monitors.end();
|
||||
}
|
||||
|
||||
DXGI_FORMAT GetDirectCompositionSDROverlayFormat() {
|
||||
return g_overlay_format_used;
|
||||
}
|
||||
@ -593,77 +674,26 @@ void SetDirectCompositionOverlayFormatUsedForTesting(DXGI_FORMAT format) {
|
||||
|
||||
gfx::mojom::DXGIInfoPtr GetDirectCompositionHDRMonitorDXGIInfo() {
|
||||
auto result_info = gfx::mojom::DXGIInfo::New();
|
||||
// HDR support was introduced in Windows 10 Creators Update.
|
||||
if (base::win::GetVersion() < base::win::Version::WIN10_RS2)
|
||||
return result_info;
|
||||
|
||||
// Only direct composition surface can allocate HDR swap chains.
|
||||
if (!DirectCompositionSupported())
|
||||
return result_info;
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
Microsoft::WRL::ComPtr<IDXGIFactory1> factory;
|
||||
hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory));
|
||||
if (FAILED(hr)) {
|
||||
DLOG(ERROR) << "Failed to create DXGI factory.";
|
||||
return result_info;
|
||||
for (const auto& desc : GetDirectCompositionOutputDescs()) {
|
||||
auto result_output = gfx::mojom::DXGIOutputDesc::New();
|
||||
result_output->device_name = desc.DeviceName;
|
||||
result_output->hdr_enabled =
|
||||
desc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
|
||||
result_output->primaries.fRX = desc.RedPrimary[0];
|
||||
result_output->primaries.fRY = desc.RedPrimary[1];
|
||||
result_output->primaries.fGX = desc.GreenPrimary[0];
|
||||
result_output->primaries.fGY = desc.GreenPrimary[1];
|
||||
result_output->primaries.fBX = desc.BluePrimary[0];
|
||||
result_output->primaries.fBY = desc.BluePrimary[1];
|
||||
result_output->primaries.fWX = desc.WhitePoint[0];
|
||||
result_output->primaries.fWY = desc.WhitePoint[1];
|
||||
result_output->min_luminance = desc.MinLuminance;
|
||||
result_output->max_luminance = desc.MaxLuminance;
|
||||
result_output->max_full_frame_luminance = desc.MaxFullFrameLuminance;
|
||||
result_info->output_descs.push_back(std::move(result_output));
|
||||
}
|
||||
|
||||
bool hdr_monitor_found = false;
|
||||
for (UINT adapter_index = 0;; ++adapter_index) {
|
||||
Microsoft::WRL::ComPtr<IDXGIAdapter> adapter;
|
||||
hr = factory->EnumAdapters(adapter_index, &adapter);
|
||||
if (hr == DXGI_ERROR_NOT_FOUND)
|
||||
break;
|
||||
if (FAILED(hr)) {
|
||||
DLOG(ERROR) << "Unexpected error creating DXGI adapter.";
|
||||
break;
|
||||
}
|
||||
|
||||
for (UINT output_index = 0;; ++output_index) {
|
||||
Microsoft::WRL::ComPtr<IDXGIOutput> output;
|
||||
hr = adapter->EnumOutputs(output_index, &output);
|
||||
if (hr == DXGI_ERROR_NOT_FOUND)
|
||||
break;
|
||||
if (FAILED(hr)) {
|
||||
DLOG(ERROR) << "Unexpected error creating DXGI adapter.";
|
||||
break;
|
||||
}
|
||||
|
||||
Microsoft::WRL::ComPtr<IDXGIOutput6> output6;
|
||||
hr = output->QueryInterface(IID_PPV_ARGS(&output6));
|
||||
if (FAILED(hr)) {
|
||||
DLOG(WARNING) << "IDXGIOutput6 is required for HDR detection.";
|
||||
continue;
|
||||
}
|
||||
|
||||
DXGI_OUTPUT_DESC1 desc;
|
||||
if (FAILED(output6->GetDesc1(&desc))) {
|
||||
DLOG(ERROR) << "Unexpected error getting output descriptor.";
|
||||
continue;
|
||||
}
|
||||
|
||||
auto result_output = gfx::mojom::DXGIOutputDesc::New();
|
||||
result_output->device_name = desc.DeviceName;
|
||||
result_output->hdr_enabled =
|
||||
desc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
|
||||
result_output->primaries.fRX = desc.RedPrimary[0];
|
||||
result_output->primaries.fRY = desc.RedPrimary[1];
|
||||
result_output->primaries.fGX = desc.GreenPrimary[0];
|
||||
result_output->primaries.fGY = desc.GreenPrimary[1];
|
||||
result_output->primaries.fBX = desc.BluePrimary[0];
|
||||
result_output->primaries.fBY = desc.BluePrimary[1];
|
||||
result_output->primaries.fWX = desc.WhitePoint[0];
|
||||
result_output->primaries.fWY = desc.WhitePoint[1];
|
||||
result_output->min_luminance = desc.MinLuminance;
|
||||
result_output->max_luminance = desc.MaxLuminance;
|
||||
result_output->max_full_frame_luminance = desc.MaxFullFrameLuminance;
|
||||
hdr_monitor_found |= result_output->hdr_enabled;
|
||||
result_info->output_descs.push_back(std::move(result_output));
|
||||
}
|
||||
}
|
||||
|
||||
UMA_HISTOGRAM_BOOLEAN("GPU.Output.HDR", hdr_monitor_found);
|
||||
return result_info;
|
||||
}
|
||||
|
||||
|
@ -78,6 +78,9 @@ GL_EXPORT UINT GetDXGIWaitableSwapChainMaxQueuedFrames();
|
||||
// Returns true if there is an HDR capable display connected.
|
||||
GL_EXPORT bool DirectCompositionSystemHDREnabled();
|
||||
|
||||
// Returns true if the window is displayed on an HDR capable display.
|
||||
GL_EXPORT bool DirectCompositionMonitorHDREnabled(HWND window);
|
||||
|
||||
// Returns the collected DXGI information.
|
||||
GL_EXPORT gfx::mojom::DXGIInfoPtr GetDirectCompositionHDRMonitorDXGIInfo();
|
||||
|
||||
|
@ -56,6 +56,7 @@ DirectCompositionSurfaceWin::DirectCompositionSurfaceWin(
|
||||
settings.use_angle_texture_offset)),
|
||||
layer_tree_(std::make_unique<DCLayerTree>(
|
||||
settings.disable_nv12_dynamic_textures,
|
||||
settings.disable_vp_auto_hdr,
|
||||
settings.disable_vp_scaling,
|
||||
settings.disable_vp_super_resolution,
|
||||
settings.force_dcomp_triple_buffer_video_swap_chain,
|
||||
|
@ -48,6 +48,7 @@ class GL_EXPORT DirectCompositionSurfaceWin : public GLSurfaceEGL,
|
||||
|
||||
struct Settings {
|
||||
bool disable_nv12_dynamic_textures = false;
|
||||
bool disable_vp_auto_hdr = false;
|
||||
bool disable_vp_scaling = false;
|
||||
bool disable_vp_super_resolution = false;
|
||||
bool force_dcomp_triple_buffer_video_swap_chain = false;
|
||||
|
@ -232,6 +232,11 @@ BASE_FEATURE(kNvidiaVpSuperResolution,
|
||||
"NvidiaVpSuperResolution",
|
||||
base::FEATURE_ENABLED_BY_DEFAULT);
|
||||
|
||||
// Allow overlay swapchain to use NVIDIA video processor for trueHDR.
|
||||
BASE_FEATURE(kNvidiaVpTrueHDR,
|
||||
"NvidiaVpTrueHDR",
|
||||
base::FEATURE_ENABLED_BY_DEFAULT);
|
||||
|
||||
// Default to using ANGLE's OpenGL backend
|
||||
BASE_FEATURE(kDefaultANGLEOpenGL,
|
||||
"DefaultANGLEOpenGL",
|
||||
|
@ -98,6 +98,7 @@ GL_EXPORT BASE_DECLARE_FEATURE(kDirectCompositionLetterboxVideoOptimization);
|
||||
GL_EXPORT BASE_DECLARE_FEATURE(kEGLDualGPURendering);
|
||||
GL_EXPORT BASE_DECLARE_FEATURE(kIntelVpSuperResolution);
|
||||
GL_EXPORT BASE_DECLARE_FEATURE(kNvidiaVpSuperResolution);
|
||||
GL_EXPORT BASE_DECLARE_FEATURE(kNvidiaVpTrueHDR);
|
||||
GL_EXPORT BASE_DECLARE_FEATURE(kDefaultANGLEOpenGL);
|
||||
GL_EXPORT BASE_DECLARE_FEATURE(kDefaultANGLEMetal);
|
||||
GL_EXPORT BASE_DECLARE_FEATURE(kDefaultANGLEVulkan);
|
||||
|
@ -41,6 +41,21 @@ BASE_FEATURE(kFallbackBT709VideoToBT601,
|
||||
"FallbackBT709VideoToBT601",
|
||||
base::FEATURE_DISABLED_BY_DEFAULT);
|
||||
|
||||
gfx::ColorSpace GetOutputColorSpace(const gfx::ColorSpace& input_color_space,
|
||||
bool is_yuv_swapchain) {
|
||||
gfx::ColorSpace output_color_space =
|
||||
is_yuv_swapchain ? input_color_space : gfx::ColorSpace::CreateSRGB();
|
||||
if (base::FeatureList::IsEnabled(kFallbackBT709VideoToBT601) &&
|
||||
(output_color_space == gfx::ColorSpace::CreateREC709())) {
|
||||
output_color_space = gfx::ColorSpace::CreateREC601();
|
||||
}
|
||||
if (input_color_space.IsHDR()) {
|
||||
output_color_space = gfx::ColorSpace::CreateHDR10();
|
||||
}
|
||||
|
||||
return output_color_space;
|
||||
}
|
||||
|
||||
bool IsProtectedVideo(gfx::ProtectedVideoType protected_video_type) {
|
||||
return protected_video_type != gfx::ProtectedVideoType::kClear;
|
||||
}
|
||||
@ -316,6 +331,62 @@ HRESULT ToggleVpSuperResolution(UINT gpu_vendor_id,
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT ToggleNvidiaVpTrueHDR(ID3D11VideoContext* video_context,
|
||||
ID3D11VideoProcessor* video_processor,
|
||||
bool enable) {
|
||||
TRACE_EVENT1("gpu", "ToggleNvidiaVpTrueHDR", "on", enable);
|
||||
|
||||
constexpr GUID kNvidiaTrueHDRInterfaceGUID = {
|
||||
0xfdd62bb4,
|
||||
0x620b,
|
||||
0x4fd7,
|
||||
{0x9a, 0xb3, 0x1e, 0x59, 0xd0, 0xd5, 0x44, 0xb3}};
|
||||
constexpr UINT kStreamExtensionVersionV4 = 0x4;
|
||||
constexpr UINT kStreamExtensionMethodTrueHDR = 0x3;
|
||||
struct {
|
||||
UINT version;
|
||||
UINT method;
|
||||
UINT enable : 1;
|
||||
UINT reserved : 31;
|
||||
} stream_extension_info = {kStreamExtensionVersionV4,
|
||||
kStreamExtensionMethodTrueHDR, enable ? 1u : 0u,
|
||||
0u};
|
||||
|
||||
HRESULT hr = video_context->VideoProcessorSetStreamExtension(
|
||||
video_processor, 0, &kNvidiaTrueHDRInterfaceGUID,
|
||||
sizeof(stream_extension_info), &stream_extension_info);
|
||||
|
||||
base::UmaHistogramSparse(enable ? "GPU.NvidiaVpTrueHDR.On.SetStreamExt"
|
||||
: "GPU.NvidiaVpTrueHDR.Off.SetStreamExt",
|
||||
hr);
|
||||
if (FAILED(hr)) {
|
||||
DLOG(ERROR) << "VideoProcessorSetStreamExtension failed with error 0x"
|
||||
<< std::hex << hr;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT ToggleVpAutoHDR(UINT gpu_vendor_id,
|
||||
ID3D11VideoContext* video_context,
|
||||
ID3D11VideoProcessor* video_processor,
|
||||
bool enable) {
|
||||
if (gpu_vendor_id == 0x10de) {
|
||||
return ToggleNvidiaVpTrueHDR(video_context, video_processor, enable);
|
||||
}
|
||||
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
bool IsVpAutoHDREnabled(UINT gpu_vendor_id) {
|
||||
if (gpu_vendor_id == 0x10de &&
|
||||
base::FeatureList::IsEnabled(features::kNvidiaVpTrueHDR)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsWithinMargin(int i, int j) {
|
||||
constexpr int kFullScreenMargin = 10;
|
||||
return (std::abs(i - j) < kFullScreenMargin);
|
||||
@ -1343,10 +1414,19 @@ bool SwapChainPresenter::PresentToSwapChain(DCLayerOverlayParams& params,
|
||||
}
|
||||
|
||||
bool content_is_hdr = input_color_space.IsHDR();
|
||||
bool use_hdr_swap_chain = content_is_hdr && params.hdr_metadata.IsValid();
|
||||
|
||||
// Enable VideoProcessor-HDR for SDR content if the monitor and
|
||||
// GPU driver support it
|
||||
bool use_vp_auto_hdr = !content_is_hdr &&
|
||||
DirectCompositionMonitorHDREnabled(window_) &&
|
||||
enable_vp_auto_hdr_ && !is_on_battery_power_;
|
||||
|
||||
bool use_hdr_swap_chain =
|
||||
((content_is_hdr && params.hdr_metadata.IsValid()) || use_vp_auto_hdr);
|
||||
|
||||
DXGI_FORMAT swap_chain_format =
|
||||
GetSwapChainFormat(params.protected_video_type, use_hdr_swap_chain);
|
||||
|
||||
bool swap_chain_format_changed = swap_chain_format != swap_chain_format_;
|
||||
bool toggle_protected_video =
|
||||
swap_chain_protected_video_type_ != params.protected_video_type;
|
||||
@ -1414,7 +1494,7 @@ bool SwapChainPresenter::PresentToSwapChain(DCLayerOverlayParams& params,
|
||||
|
||||
if (!VideoProcessorBlt(std::move(input_texture), input_level,
|
||||
std::move(keyed_mutex), params.content_rect,
|
||||
input_color_space, content_is_hdr, stream_metadata)) {
|
||||
input_color_space, stream_metadata, use_vp_auto_hdr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1671,8 +1751,8 @@ bool SwapChainPresenter::VideoProcessorBlt(
|
||||
Microsoft::WRL::ComPtr<IDXGIKeyedMutex> keyed_mutex,
|
||||
const gfx::Rect& content_rect,
|
||||
const gfx::ColorSpace& src_color_space,
|
||||
bool content_is_hdr,
|
||||
absl::optional<DXGI_HDR_METADATA_HDR10> stream_hdr_metadata) {
|
||||
absl::optional<DXGI_HDR_METADATA_HDR10> stream_hdr_metadata,
|
||||
bool use_vp_auto_hdr) {
|
||||
TRACE_EVENT2("gpu", "SwapChainPresenter::VideoProcessorBlt", "content_rect",
|
||||
content_rect.ToString(), "swap_chain_size",
|
||||
swap_chain_size_.ToString());
|
||||
@ -1682,15 +1762,7 @@ bool SwapChainPresenter::VideoProcessorBlt(
|
||||
// doesn't need a |force_yuv| parameter (and the associated plumbing).
|
||||
bool is_yuv_swapchain = IsYUVSwapChainFormat(swap_chain_format_);
|
||||
gfx::ColorSpace output_color_space =
|
||||
is_yuv_swapchain ? src_color_space : gfx::ColorSpace::CreateSRGB();
|
||||
if (base::FeatureList::IsEnabled(kFallbackBT709VideoToBT601) &&
|
||||
(output_color_space == gfx::ColorSpace::CreateREC709())) {
|
||||
output_color_space = gfx::ColorSpace::CreateREC601();
|
||||
}
|
||||
if (content_is_hdr) {
|
||||
output_color_space = gfx::ColorSpace::CreateHDR10();
|
||||
}
|
||||
|
||||
GetOutputColorSpace(src_color_space, is_yuv_swapchain);
|
||||
VideoProcessorWrapper* video_processor_wrapper =
|
||||
layer_tree_->InitializeVideoProcessor(
|
||||
content_rect.size(), swap_chain_size_, output_color_space.IsHDR());
|
||||
@ -1716,8 +1788,12 @@ bool SwapChainPresenter::VideoProcessorBlt(
|
||||
DXGI_COLOR_SPACE_TYPE output_dxgi_color_space =
|
||||
gfx::ColorSpaceWin::GetDXGIColorSpace(output_color_space,
|
||||
/*force_yuv=*/is_yuv_swapchain);
|
||||
DXGI_COLOR_SPACE_TYPE swap_dxgi_color_space =
|
||||
use_vp_auto_hdr ? gfx::ColorSpaceWin::GetDXGIColorSpace(
|
||||
gfx::ColorSpace::CreateHDR10())
|
||||
: output_dxgi_color_space;
|
||||
|
||||
if (SUCCEEDED(swap_chain3->SetColorSpace1(output_dxgi_color_space))) {
|
||||
if (SUCCEEDED(swap_chain3->SetColorSpace1(swap_dxgi_color_space))) {
|
||||
context1->VideoProcessorSetOutputColorSpace1(video_processor.Get(),
|
||||
output_dxgi_color_space);
|
||||
}
|
||||
@ -1821,16 +1897,34 @@ bool SwapChainPresenter::VideoProcessorBlt(
|
||||
DCHECK(output_view_);
|
||||
}
|
||||
|
||||
bool use_vp_super_resolution = false;
|
||||
if (!layer_tree_->disable_vp_super_resolution() &&
|
||||
!force_vp_super_resolution_off_) {
|
||||
hr =
|
||||
ToggleVpSuperResolution(gpu_vendor_id_, video_context.Get(),
|
||||
video_processor.Get(), !is_on_battery_power_);
|
||||
if (enable_vp_auto_hdr_) {
|
||||
hr = ToggleVpAutoHDR(gpu_vendor_id_, video_context.Get(),
|
||||
video_processor.Get(), use_vp_auto_hdr);
|
||||
if (FAILED(hr)) {
|
||||
force_vp_super_resolution_off_ = true;
|
||||
enable_vp_auto_hdr_ = false;
|
||||
|
||||
if (use_vp_auto_hdr) {
|
||||
if (!RevertSwapChainToSDR(video_device, video_processor,
|
||||
video_processor_enumerator, swap_chain3,
|
||||
context1, src_color_space)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
use_vp_auto_hdr = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool use_vp_super_resolution =
|
||||
enable_vp_super_resolution_ && !is_on_battery_power_;
|
||||
if (enable_vp_super_resolution_) {
|
||||
hr = ToggleVpSuperResolution(gpu_vendor_id_, video_context.Get(),
|
||||
video_processor.Get(),
|
||||
use_vp_super_resolution);
|
||||
if (FAILED(hr)) {
|
||||
enable_vp_super_resolution_ = false;
|
||||
use_vp_super_resolution = false;
|
||||
}
|
||||
use_vp_super_resolution = !is_on_battery_power_ && SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
{
|
||||
@ -1838,46 +1932,77 @@ bool SwapChainPresenter::VideoProcessorBlt(
|
||||
hr = video_context->VideoProcessorBlt(video_processor.Get(),
|
||||
output_view_.Get(), 0, 1, &stream);
|
||||
}
|
||||
base::UmaHistogramSparse(
|
||||
(use_vp_auto_hdr ? "GPU.VideoProcessorBlt.VpAutoHDR.On"
|
||||
: "GPU.VideoProcessorBlt.VpAutoHDR.Off"),
|
||||
hr);
|
||||
base::UmaHistogramSparse(
|
||||
(use_vp_super_resolution
|
||||
? "GPU.VideoProcessorBlt.VpSuperResolution.On"
|
||||
: "GPU.VideoProcessorBlt.VpSuperResolution.Off"),
|
||||
hr);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
// Retry VideoProcessorBlt with vp super resolution off if it was on.
|
||||
if (use_vp_super_resolution) {
|
||||
DLOG(ERROR) << "Retry VideoProcessorBlt with VpSuperResolution off "
|
||||
"after it failed with error 0x"
|
||||
<< std::hex << hr;
|
||||
// Retry VideoProcessorBlt with VpSuperResolution off if it was on.
|
||||
if (FAILED(hr) && use_vp_super_resolution) {
|
||||
DLOG(ERROR) << "Retry VideoProcessorBlt with VpSuperResolution off "
|
||||
"after it failed with error 0x"
|
||||
<< std::hex << hr;
|
||||
|
||||
ToggleVpSuperResolution(gpu_vendor_id_, video_context.Get(),
|
||||
video_processor.Get(), false);
|
||||
{
|
||||
TRACE_EVENT0("gpu", "ID3D11VideoContext::VideoProcessorBlt");
|
||||
hr = video_context->VideoProcessorBlt(
|
||||
video_processor.Get(), output_view_.Get(), 0, 1, &stream);
|
||||
}
|
||||
|
||||
base::UmaHistogramSparse(
|
||||
"GPU.VideoProcessorBlt.VpSuperResolution.RetryOffAfterError", hr);
|
||||
|
||||
// We shouldn't use VpSuperResolution if it was the reason that caused
|
||||
// the VideoProcessorBlt failure.
|
||||
force_vp_super_resolution_off_ = SUCCEEDED(hr);
|
||||
ToggleVpSuperResolution(gpu_vendor_id_, video_context.Get(),
|
||||
video_processor.Get(), false);
|
||||
{
|
||||
TRACE_EVENT0("gpu", "ID3D11VideoContext::VideoProcessorBlt");
|
||||
hr = video_context->VideoProcessorBlt(
|
||||
video_processor.Get(), output_view_.Get(), 0, 1, &stream);
|
||||
}
|
||||
base::UmaHistogramSparse(
|
||||
"GPU.VideoProcessorBlt.VpSuperResolution.RetryOffAfterError", hr);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
DLOG(ERROR) << "VideoProcessorBlt failed with error 0x" << std::hex
|
||||
<< hr;
|
||||
// We shouldn't use VpSuperResolution if it was the reason that caused
|
||||
// the VideoProcessorBlt failure.
|
||||
if (SUCCEEDED(hr)) {
|
||||
enable_vp_super_resolution_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
// To prevent it from failing in all coming frames, disable overlay if
|
||||
// VideoProcessorBlt is not implemented in the GPU driver.
|
||||
if (hr == E_NOTIMPL) {
|
||||
DisableDirectCompositionOverlays();
|
||||
}
|
||||
if (FAILED(hr) && use_vp_auto_hdr) {
|
||||
DLOG(ERROR) << "Retry VideoProcessorBlt with VpAutoHDR off "
|
||||
"after it failed with error 0x"
|
||||
<< std::hex << hr;
|
||||
|
||||
ToggleVpAutoHDR(gpu_vendor_id_, video_context.Get(),
|
||||
video_processor.Get(), false);
|
||||
|
||||
if (!RevertSwapChainToSDR(video_device, video_processor,
|
||||
video_processor_enumerator, swap_chain3,
|
||||
context1, src_color_space)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
TRACE_EVENT0("gpu", "ID3D11VideoContext::VideoProcessorBlt");
|
||||
hr = video_context->VideoProcessorBlt(
|
||||
video_processor.Get(), output_view_.Get(), 0, 1, &stream);
|
||||
}
|
||||
base::UmaHistogramSparse(
|
||||
"GPU.VideoProcessorBlt.VpAutoHDR.RetryOffAfterError", hr);
|
||||
|
||||
// We shouldn't use VpAutoHDR if it was the reason that caused
|
||||
// the VideoProcessorBlt failure.
|
||||
if (SUCCEEDED(hr)) {
|
||||
enable_vp_auto_hdr_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (FAILED(hr)) {
|
||||
DLOG(ERROR) << "VideoProcessorBlt failed with error 0x" << std::hex << hr;
|
||||
|
||||
// To prevent it from failing in all coming frames, disable overlay if
|
||||
// VideoProcessorBlt is not implemented in the GPU driver.
|
||||
if (hr == E_NOTIMPL) {
|
||||
DisableDirectCompositionOverlays();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2056,6 +2181,10 @@ bool SwapChainPresenter::ReallocateSwapChain(
|
||||
DLOG(ERROR) << "Failed to get adapter desc with error 0x" << std::hex << hr;
|
||||
}
|
||||
|
||||
enable_vp_auto_hdr_ =
|
||||
!layer_tree_->disable_vp_auto_hdr() && IsVpAutoHDREnabled(gpu_vendor_id_);
|
||||
enable_vp_super_resolution_ = !layer_tree_->disable_vp_super_resolution();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2116,4 +2245,60 @@ SwapChainPresenter::GetSwapChainMedia() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool SwapChainPresenter::RevertSwapChainToSDR(
|
||||
Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device,
|
||||
Microsoft::WRL::ComPtr<ID3D11VideoProcessor> video_processor,
|
||||
Microsoft::WRL::ComPtr<ID3D11VideoProcessorEnumerator>
|
||||
video_processor_enumerator,
|
||||
Microsoft::WRL::ComPtr<IDXGISwapChain3> swap_chain3,
|
||||
Microsoft::WRL::ComPtr<ID3D11VideoContext1> context1,
|
||||
const gfx::ColorSpace& input_color_space) {
|
||||
if (!video_device || !video_processor || !video_processor_enumerator ||
|
||||
!swap_chain3 || !context1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Restore the SDR swap chain and output view
|
||||
if (!ReallocateSwapChain(
|
||||
gfx::Size(swap_chain_size_),
|
||||
GetSwapChainFormat(swap_chain_protected_video_type_, /*hdr=*/false),
|
||||
swap_chain_protected_video_type_)) {
|
||||
ReleaseSwapChainResources();
|
||||
return false;
|
||||
}
|
||||
content_ = swap_chain_.Get();
|
||||
|
||||
Microsoft::WRL::ComPtr<ID3D11Texture2D> swap_chain_buffer;
|
||||
swap_chain_->GetBuffer(0, IID_PPV_ARGS(&swap_chain_buffer));
|
||||
D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC output_desc = {};
|
||||
output_desc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D;
|
||||
output_desc.Texture2D.MipSlice = 0;
|
||||
HRESULT hr = video_device->CreateVideoProcessorOutputView(
|
||||
swap_chain_buffer.Get(), video_processor_enumerator.Get(), &output_desc,
|
||||
&output_view_);
|
||||
if (FAILED(hr)) {
|
||||
DLOG(ERROR) << "CreateVideoProcessorOutputView failed with error 0x"
|
||||
<< std::hex << hr;
|
||||
return false;
|
||||
}
|
||||
DCHECK(output_view_);
|
||||
|
||||
// Reset the output color space for the swap chain and video processor
|
||||
bool is_yuv_swapchain = IsYUVSwapChainFormat(swap_chain_format_);
|
||||
gfx::ColorSpace output_color_space =
|
||||
GetOutputColorSpace(input_color_space, is_yuv_swapchain);
|
||||
DXGI_COLOR_SPACE_TYPE output_dxgi_color_space =
|
||||
gfx::ColorSpaceWin::GetDXGIColorSpace(output_color_space,
|
||||
is_yuv_swapchain);
|
||||
context1->VideoProcessorSetOutputColorSpace1(video_processor.Get(),
|
||||
output_dxgi_color_space);
|
||||
hr = swap_chain3->SetColorSpace1(output_dxgi_color_space);
|
||||
if (FAILED(hr)) {
|
||||
DLOG(ERROR) << "SetColorSpace1 failed with error 0x" << std::hex << hr;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace gl
|
||||
|
@ -123,8 +123,8 @@ class SwapChainPresenter : public base::PowerStateObserver {
|
||||
Microsoft::WRL::ComPtr<IDXGIKeyedMutex> keyed_mutex,
|
||||
const gfx::Rect& content_rect,
|
||||
const gfx::ColorSpace& src_color_space,
|
||||
bool content_is_hdr,
|
||||
absl::optional<DXGI_HDR_METADATA_HDR10> stream_hdr_metadata);
|
||||
absl::optional<DXGI_HDR_METADATA_HDR10> stream_hdr_metadata,
|
||||
bool use_vp_auto_hdr);
|
||||
|
||||
// Get the size of the monitor on which the window handle is displayed.
|
||||
gfx::Size GetMonitorSize() const;
|
||||
@ -245,6 +245,15 @@ class SwapChainPresenter : public base::PowerStateObserver {
|
||||
// Release resources related to `PresentDCOMPSurface()`.
|
||||
void ReleaseDCOMPSurfaceResourcesIfNeeded();
|
||||
|
||||
bool RevertSwapChainToSDR(
|
||||
Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device,
|
||||
Microsoft::WRL::ComPtr<ID3D11VideoProcessor> video_processor,
|
||||
Microsoft::WRL::ComPtr<ID3D11VideoProcessorEnumerator>
|
||||
video_processor_enumerator,
|
||||
Microsoft::WRL::ComPtr<IDXGISwapChain3> swap_chain3,
|
||||
Microsoft::WRL::ComPtr<ID3D11VideoContext1> context1,
|
||||
const gfx::ColorSpace& input_color_space);
|
||||
|
||||
// The Direct Composition surface handle from MediaFoundationRenderer.
|
||||
HANDLE dcomp_surface_handle_ = INVALID_HANDLE_VALUE;
|
||||
|
||||
@ -315,7 +324,8 @@ class SwapChainPresenter : public base::PowerStateObserver {
|
||||
Microsoft::WRL::ComPtr<IDXGIDecodeSwapChain> decode_swap_chain_;
|
||||
Microsoft::WRL::ComPtr<IUnknown> decode_surface_;
|
||||
bool is_on_battery_power_;
|
||||
bool force_vp_super_resolution_off_ = false;
|
||||
bool enable_vp_auto_hdr_ = false;
|
||||
bool enable_vp_super_resolution_ = false;
|
||||
UINT gpu_vendor_id_ = 0;
|
||||
|
||||
// Number of frames per second.
|
||||
|
Reference in New Issue
Block a user