0

Add support for display change in the DC overlay processor on Windows

|has_hw_overlay_support_| in the DC overlay Processor is updated after
display change. This cap is queried directly from
direct_composition_surface_win. All the other overlay_support
capabilities which are used for passing data have been removed.

|use_dc_overlays_for_video| is removed from |capabilities| of
gles2_cmd_decoder and gles2_cmd_decoder_passthrough.

|supports_dc_video_overlays| is removed from |capabilities| of
output_surface.



Bug: 1042989
Change-Id: I9fcfd0a0e9e2e19db00ea0418cfd299e17664cae
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2068920
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
Reviewed-by: Alex Gough <ajgo@chromium.org>
Reviewed-by: weiliangc <weiliangc@chromium.org>
Commit-Queue: Maggie Chen <magchen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#750268}
This commit is contained in:
Maggie Chen
2020-03-13 19:34:13 +00:00
committed by Commit Bot
parent 6df57b9ebd
commit 87d01b48ae
18 changed files with 160 additions and 71 deletions

@ -31,6 +31,9 @@ include_rules = [
"+ui/gl/android/android_surface_control_compat.h",
"+ui/gl/ca_renderer_layer_params.h",
"+ui/gl/dc_renderer_layer_params.h",
"+ui/gl/gl_utils.h",
"+ui/gl/gpu_switching_manager.h",
"+ui/gl/gpu_switching_observer.h",
"+ui/gl/trace_util.h",
"+gpu/ipc/common/vulkan_ycbcr_info.h",
"+gpu/ipc/gpu_task_scheduler_helper.h",

@ -5,6 +5,7 @@
#include "components/viz/service/display/dc_layer_overlay.h"
#include "base/metrics/histogram_macros.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "cc/base/math_util.h"
#include "components/viz/common/display/renderer_settings.h"
@ -21,6 +22,8 @@
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gl/gl_switches.h"
#include "ui/gl/gl_utils.h"
#include "ui/gl/gpu_switching_manager.h"
namespace viz {
@ -318,15 +321,41 @@ DCLayerOverlayProcessor::RenderPassData::RenderPassData(
DCLayerOverlayProcessor::RenderPassData::~RenderPassData() = default;
DCLayerOverlayProcessor::DCLayerOverlayProcessor(
const OutputSurface::Capabilities& capabilities,
const RendererSettings& settings)
: has_hw_overlay_support_(capabilities.supports_dc_video_overlays),
show_debug_borders_(settings.show_dc_layer_debug_borders) {}
: show_debug_borders_(settings.show_dc_layer_debug_borders),
viz_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
UpdateHasHwOverlaySupport();
ui::GpuSwitchingManager::GetInstance()->AddObserver(this);
}
DCLayerOverlayProcessor::DCLayerOverlayProcessor()
: has_hw_overlay_support_(true), show_debug_borders_(false) {}
DCLayerOverlayProcessor::~DCLayerOverlayProcessor() = default;
DCLayerOverlayProcessor::~DCLayerOverlayProcessor() {
ui::GpuSwitchingManager::GetInstance()->RemoveObserver(this);
}
// Called on the Viz Compositor thread
void DCLayerOverlayProcessor::UpdateHasHwOverlaySupport() {
DCHECK(viz_task_runner_->BelongsToCurrentThread());
has_hw_overlay_support_ = gl::AreOverlaysSupportedWin();
}
// Not on the Viz Compositor thread
void DCLayerOverlayProcessor::OnDisplayAdded() {
viz_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&DCLayerOverlayProcessor::UpdateHasHwOverlaySupport,
base::Unretained(this)));
}
// Not on the Viz Compositor thread
void DCLayerOverlayProcessor::OnDisplayRemoved() {
viz_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&DCLayerOverlayProcessor::UpdateHasHwOverlaySupport,
base::Unretained(this)));
}
void DCLayerOverlayProcessor::Process(
DisplayResourceProvider* resource_provider,

@ -9,14 +9,15 @@
#include "base/containers/flat_map.h"
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
#include "components/viz/common/quads/render_pass.h"
#include "components/viz/service/display/output_surface.h"
#include "components/viz/service/viz_service_export.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkMatrix44.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/video_types.h"
#include "ui/gl/gpu_switching_observer.h"
namespace viz {
class DisplayResourceProvider;
@ -80,10 +81,10 @@ class VIZ_SERVICE_EXPORT DCLayerOverlay {
typedef std::vector<DCLayerOverlay> DCLayerOverlayList;
class VIZ_SERVICE_EXPORT DCLayerOverlayProcessor {
class VIZ_SERVICE_EXPORT DCLayerOverlayProcessor
: public ui::GpuSwitchingObserver {
public:
DCLayerOverlayProcessor(const OutputSurface::Capabilities& capabilities,
const RendererSettings& settings);
explicit DCLayerOverlayProcessor(const RendererSettings& settings);
// For testing.
DCLayerOverlayProcessor();
virtual ~DCLayerOverlayProcessor();
@ -101,6 +102,11 @@ class VIZ_SERVICE_EXPORT DCLayerOverlayProcessor {
return previous_frame_overlay_rect_union_;
}
// GpuSwitchingObserver implementation.
void OnDisplayAdded() override;
void OnDisplayRemoved() override;
void UpdateHasHwOverlaySupport();
private:
// Returns an iterator to the element after |it|.
QuadList::Iterator ProcessRenderPassDrawQuad(RenderPass* render_pass,
@ -132,7 +138,7 @@ class VIZ_SERVICE_EXPORT DCLayerOverlayProcessor {
RenderPass* root_render_pass,
gfx::Rect* damage_rect);
const bool has_hw_overlay_support_;
bool has_hw_overlay_support_;
const bool show_debug_borders_;
gfx::Rect previous_frame_underlay_rect_;
@ -163,6 +169,8 @@ class VIZ_SERVICE_EXPORT DCLayerOverlayProcessor {
};
base::flat_map<RenderPassId, RenderPassData> render_pass_data_;
scoped_refptr<base::SingleThreadTaskRunner> viz_task_runner_;
DISALLOW_COPY_AND_ASSIGN(DCLayerOverlayProcessor);
};

@ -80,8 +80,6 @@ class VIZ_SERVICE_EXPORT OutputSurface {
bool supports_pre_transform = false;
// Whether this OutputSurface supports direct composition layers.
bool supports_dc_layers = false;
// Whether this OutputSurface supports direct composition video overlays.
bool supports_dc_video_overlays = false;
// Whether this OutputSurface should skip DrawAndSwap(). This is true for
// the unified display on Chrome OS. All drawing is handled by the physical
// displays so the unified display should skip that work.

@ -95,8 +95,8 @@ OverlayProcessorInterface::CreateOverlayProcessor(
enable_dc_overlay &= !capabilities.supports_surfaceless;
enable_dc_overlay &= capabilities.supports_dc_layers;
return base::WrapUnique(new OverlayProcessorWin(
enable_dc_overlay, std::make_unique<DCLayerOverlayProcessor>(
capabilities, renderer_settings)));
enable_dc_overlay,
std::make_unique<DCLayerOverlayProcessor>(renderer_settings)));
#elif defined(USE_OZONE)
bool overlay_enabled = surface_handle != gpu::kNullSurfaceHandle;
overlay_enabled &= !renderer_settings.overlay_strategies.empty();

@ -45,8 +45,6 @@ GLOutputSurface::GLOutputSurface(
context_capabilities.num_surface_buffers - 1;
capabilities_.supports_gpu_vsync = context_capabilities.gpu_vsync;
capabilities_.supports_dc_layers = context_capabilities.dc_layers;
capabilities_.supports_dc_video_overlays =
context_capabilities.use_dc_overlays_for_video;
capabilities_.supports_surfaceless = context_capabilities.surfaceless;
capabilities_.android_surface_control_feature_enabled =
context_provider->GetGpuFeatureInfo()

@ -55,7 +55,6 @@ SkiaOutputDeviceGL::SkiaOutputDeviceGL(
gl_surface_->SupportsCommitOverlayPlanes();
capabilities_.supports_gpu_vsync = gl_surface_->SupportsGpuVSync();
capabilities_.supports_dc_layers = gl_surface_->SupportsDCLayers();
capabilities_.supports_dc_video_overlays = gl_surface_->UseOverlaysForVideo();
#if defined(OS_ANDROID)
// TODO(weiliangc): This capability is used to check whether we should do
// overlay. Since currently none of the other overlay system is implemented,

@ -869,6 +869,11 @@ void GpuServiceImpl::GpuSwitched(gl::GpuPreference active_gpu_heuristic) {
}
void GpuServiceImpl::DisplayAdded() {
if (io_runner_->BelongsToCurrentThread()) {
main_runner_->PostTask(
FROM_HERE, base::BindOnce(&GpuServiceImpl::DisplayAdded, weak_ptr_));
return;
}
DVLOG(1) << "GPU: A monitor is plugged in";
if (!in_host_process())
@ -882,6 +887,11 @@ void GpuServiceImpl::DisplayAdded() {
}
void GpuServiceImpl::DisplayRemoved() {
if (io_runner_->BelongsToCurrentThread()) {
main_runner_->PostTask(
FROM_HERE, base::BindOnce(&GpuServiceImpl::DisplayRemoved, weak_ptr_));
return;
}
DVLOG(1) << "GPU: A monitor is unplugged ";
if (!in_host_process())

@ -172,7 +172,6 @@ struct GPU_EXPORT Capabilities {
bool multisample_compatibility = false;
// True if DirectComposition layers are enabled.
bool dc_layers = false;
bool use_dc_overlays_for_video = false;
bool protected_video_swap_chain = false;
bool gpu_vsync = false;
bool shared_image_swap_chain = false;

@ -4307,7 +4307,6 @@ Capabilities GLES2DecoderImpl::GetCapabilities() {
caps.multisample_compatibility =
feature_info_->feature_flags().ext_multisample_compatibility;
caps.dc_layers = supports_dc_layers_;
caps.use_dc_overlays_for_video = surface_->UseOverlaysForVideo();
caps.protected_video_swap_chain = surface_->SupportsProtectedVideo();
caps.gpu_vsync = surface_->SupportsGpuVSync();
caps.blend_equation_advanced =

@ -1598,7 +1598,6 @@ gpu::Capabilities GLES2DecoderPassthroughImpl::GetCapabilities() {
feature_info_->feature_flags().ext_multisample_compatibility;
caps.dc_layers = !offscreen_ && surface_->SupportsDCLayers();
caps.commit_overlay_planes = surface_->SupportsCommitOverlayPlanes();
caps.use_dc_overlays_for_video = surface_->UseOverlaysForVideo();
caps.protected_video_swap_chain = surface_->SupportsProtectedVideo();
caps.gpu_vsync = surface_->SupportsGpuVSync();
#if defined(OS_WIN)

@ -138,7 +138,6 @@ IPC_STRUCT_TRAITS_BEGIN(gpu::Capabilities)
IPC_STRUCT_TRAITS_MEMBER(gpu_rasterization)
IPC_STRUCT_TRAITS_MEMBER(chromium_image_rgb_emulation)
IPC_STRUCT_TRAITS_MEMBER(dc_layers)
IPC_STRUCT_TRAITS_MEMBER(use_dc_overlays_for_video)
IPC_STRUCT_TRAITS_MEMBER(protected_video_swap_chain)
IPC_STRUCT_TRAITS_MEMBER(gpu_vsync)
IPC_STRUCT_TRAITS_MEMBER(shared_image_swap_chain)

@ -12,6 +12,8 @@
#include "base/bind.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/traced_value.h"
@ -32,11 +34,36 @@
namespace gl {
namespace {
// Whether the overlay caps are valid or not.
// Whether the overlay caps are valid or not. GUARDED_BY GetOverlayLock().
bool g_overlay_caps_valid = false;
// Indicates support for either NV12 or YUY2 hardware overlays.
// Indicates support for either NV12 or YUY2 hardware overlays. GUARDED_BY
// GetOverlayLock().
bool g_supports_overlays = false;
// The lock to guard g_overlay_caps_valid and g_supports_overlays.
base::Lock& GetOverlayLock() {
static base::NoDestructor<base::Lock> overlay_lock;
return *overlay_lock;
}
bool SupportsOverlays() {
base::AutoLock auto_lock(GetOverlayLock());
return g_supports_overlays;
}
void SetSupportsOverlays(bool support) {
base::AutoLock auto_lock(GetOverlayLock());
g_supports_overlays = support;
}
bool OverlayCapsValid() {
base::AutoLock auto_lock(GetOverlayLock());
return g_overlay_caps_valid;
}
void SetOverlayCapsValid(bool valid) {
base::AutoLock auto_lock(GetOverlayLock());
g_overlay_caps_valid = valid;
}
// Used for workaround limiting overlay size to monitor size.
gfx::Size g_overlay_monitor_size;
@ -55,19 +82,17 @@ bool FlagsSupportsOverlays(UINT flags) {
DXGI_OVERLAY_SUPPORT_FLAG_SCALING));
}
void UpdateHardwareOverlaySupport() {
if (g_overlay_caps_valid)
return;
g_overlay_caps_valid = true;
bool prev_supports_overlays = g_supports_overlays;
DXGI_FORMAT prev_overlay_format_used = g_overlay_format_used;
// Reset all caps in case of early exit.
g_supports_overlays = false;
g_overlay_format_used = DXGI_FORMAT_NV12;
g_nv12_overlay_support_flags = 0;
g_yuy2_overlay_support_flags = 0;
g_overlay_monitor_size = gfx::Size();
void GetGpuDriverHardwareOverlayInfo(bool* supports_overlays,
DXGI_FORMAT* overlay_format_used,
UINT* nv12_overlay_support_flags,
UINT* yuy2_overlay_support_flags,
gfx::Size* overlay_monitor_size) {
// Initialization
*supports_overlays = false;
*overlay_format_used = DXGI_FORMAT_NV12;
*nv12_overlay_support_flags = 0;
*yuy2_overlay_support_flags = 0;
*overlay_monitor_size = gfx::Size();
// Check for DirectComposition support first to prevent likely crashes.
if (!DirectCompositionSurfaceWin::IsDirectCompositionSupported())
@ -115,10 +140,10 @@ void UpdateHardwareOverlaySupport() {
continue;
DCHECK(output3);
output3->CheckOverlaySupport(DXGI_FORMAT_NV12, d3d11_device.Get(),
&g_nv12_overlay_support_flags);
nv12_overlay_support_flags);
output3->CheckOverlaySupport(DXGI_FORMAT_YUY2, d3d11_device.Get(),
&g_yuy2_overlay_support_flags);
if (FlagsSupportsOverlays(g_nv12_overlay_support_flags) &&
yuy2_overlay_support_flags);
if (FlagsSupportsOverlays(*nv12_overlay_support_flags) &&
base::FeatureList::IsEnabled(
features::kDirectCompositionPreferNV12Overlays)) {
// NV12 format is preferred if it's supported.
@ -140,20 +165,20 @@ void UpdateHardwareOverlaySupport() {
// performing an extra scaling Blt before calling the driver. Even when
// scaled overlays aren't actually supported, presentation using the
// overlay path should be relatively efficient.
g_overlay_format_used = DXGI_FORMAT_NV12;
g_supports_overlays = true;
*overlay_format_used = DXGI_FORMAT_NV12;
*supports_overlays = true;
}
}
if (!g_supports_overlays &&
FlagsSupportsOverlays(g_yuy2_overlay_support_flags)) {
if (!*supports_overlays &&
FlagsSupportsOverlays(*yuy2_overlay_support_flags)) {
// If NV12 isn't supported, fallback to YUY2 if it's supported.
g_overlay_format_used = DXGI_FORMAT_YUY2;
g_supports_overlays = true;
*overlay_format_used = DXGI_FORMAT_YUY2;
*supports_overlays = true;
}
if (g_supports_overlays) {
if (*supports_overlays) {
DXGI_OUTPUT_DESC monitor_desc = {};
if (SUCCEEDED(output3->GetDesc(&monitor_desc))) {
g_overlay_monitor_size =
*overlay_monitor_size =
gfx::Rect(monitor_desc.DesktopCoordinates).size();
}
}
@ -163,20 +188,43 @@ void UpdateHardwareOverlaySupport() {
// https://docs.microsoft.com/en-us/windows-hardware/drivers/display/multiplane-overlay-hardware-requirements
// TODO(sunnyps): If the above is true, then we can only look at first
// output instead of iterating over all outputs.
if (g_supports_overlays)
if (*supports_overlays)
break;
}
}
if (g_supports_overlays != prev_supports_overlays ||
g_overlay_format_used != prev_overlay_format_used) {
void UpdateHardwareOverlaySupport() {
if (OverlayCapsValid())
return;
SetOverlayCapsValid(true);
bool supports_overlays = false;
DXGI_FORMAT overlay_format_used = DXGI_FORMAT_NV12;
UINT nv12_overlay_support_flags = 0;
UINT yuy2_overlay_support_flags = 0;
gfx::Size overlay_monitor_size = gfx::Size();
GetGpuDriverHardwareOverlayInfo(
&supports_overlays, &overlay_format_used, &nv12_overlay_support_flags,
&yuy2_overlay_support_flags, &overlay_monitor_size);
if (supports_overlays != SupportsOverlays() ||
overlay_format_used != g_overlay_format_used) {
// Record the new histograms
if (g_supports_overlays) {
if (supports_overlays) {
base::UmaHistogramSparse("GPU.DirectComposition.OverlayFormatUsed3",
g_overlay_format_used);
overlay_format_used);
}
UMA_HISTOGRAM_BOOLEAN("GPU.DirectComposition.OverlaysSupported",
g_supports_overlays);
supports_overlays);
}
// Update global caps
SetSupportsOverlays(supports_overlays);
g_overlay_format_used = overlay_format_used;
g_nv12_overlay_support_flags = nv12_overlay_support_flags;
g_yuy2_overlay_support_flags = yuy2_overlay_support_flags;
g_overlay_monitor_size = overlay_monitor_size;
}
bool SupportsPresentationFeedback() {
@ -300,7 +348,7 @@ bool DirectCompositionSurfaceWin::AreOverlaysSupported() {
if (command_line->HasSwitch(switches::kDisableDirectCompositionVideoOverlays))
return false;
return g_supports_overlays;
return SupportsOverlays();
}
// static
@ -315,12 +363,12 @@ bool DirectCompositionSurfaceWin::IsDecodeSwapChainSupported() {
// static
void DirectCompositionSurfaceWin::DisableOverlays() {
g_supports_overlays = false;
SetSupportsOverlays(false);
}
// static
void DirectCompositionSurfaceWin::InvalidateOverlayCaps() {
g_overlay_caps_valid = false;
SetOverlayCapsValid(false);
}
// static
@ -630,10 +678,6 @@ bool DirectCompositionSurfaceWin::SupportsDCLayers() const {
return true;
}
bool DirectCompositionSurfaceWin::UseOverlaysForVideo() const {
return AreOverlaysSupported();
}
bool DirectCompositionSurfaceWin::SupportsProtectedVideo() const {
// TODO(magchen): Check the gpu driver date (or a function) which we know this
// new support is enabled.

@ -53,6 +53,7 @@ class GL_EXPORT DirectCompositionSurfaceWin : public GLSurfaceEGL,
// Returns true if hardware video overlays are supported and should be used.
// Overridden with --enable-direct-composition-video-overlays and
// --disable-direct-composition-video-overlays.
// This function is thread safe.
static bool AreOverlaysSupported();
// Returns true if zero copy decode swap chain is supported.
@ -115,7 +116,6 @@ class GL_EXPORT DirectCompositionSurfaceWin : public GLSurfaceEGL,
bool SupportsPostSubBuffer() override;
bool OnMakeCurrent(GLContext* context) override;
bool SupportsDCLayers() const override;
bool UseOverlaysForVideo() const override;
bool SupportsProtectedVideo() const override;
bool SetDrawRectangle(const gfx::Rect& rect) override;
gfx::Vector2d GetDrawOffset() const override;

@ -192,10 +192,6 @@ bool GLSurface::SupportsDCLayers() const {
return false;
}
bool GLSurface::UseOverlaysForVideo() const {
return false;
}
bool GLSurface::SupportsProtectedVideo() const {
return false;
}
@ -464,10 +460,6 @@ bool GLSurfaceAdapter::SupportsDCLayers() const {
return surface_->SupportsDCLayers();
}
bool GLSurfaceAdapter::UseOverlaysForVideo() const {
return surface_->UseOverlaysForVideo();
}
bool GLSurfaceAdapter::SupportsProtectedVideo() const {
return surface_->SupportsProtectedVideo();
}

@ -262,8 +262,6 @@ class GL_EXPORT GLSurface : public base::RefCounted<GLSurface> {
virtual bool SupportsDCLayers() const;
virtual bool UseOverlaysForVideo() const;
virtual bool SupportsProtectedVideo() const;
// Set the rectangle that will be drawn into on the surface, returning
@ -384,7 +382,6 @@ class GL_EXPORT GLSurfaceAdapter : public GLSurface {
gfx::SurfaceOrigin GetOrigin() const override;
bool BuffersFlipped() const override;
bool SupportsDCLayers() const override;
bool UseOverlaysForVideo() const override;
bool SupportsProtectedVideo() const override;
bool SetDrawRectangle(const gfx::Rect& rect) override;
gfx::Vector2d GetDrawOffset() const override;

@ -17,6 +17,10 @@
#include "third_party/libsync/src/include/sync/sync.h"
#endif
#if defined(OS_WIN)
#include "ui/gl/direct_composition_surface_win.h"
#endif
namespace gl {
// Used by chrome://gpucrash and gpu_benchmarking_extension's
@ -76,4 +80,11 @@ bool UsePassthroughCommandDecoder(const base::CommandLine* command_line) {
features::kDefaultPassthroughCommandDecoder);
}
}
#if defined(OS_WIN)
// This function is thread safe.
bool AreOverlaysSupportedWin() {
return gl::DirectCompositionSurfaceWin::AreOverlaysSupported();
}
#endif
} // namespace gl

@ -26,6 +26,10 @@ GL_EXPORT base::ScopedFD MergeFDs(base::ScopedFD a, base::ScopedFD b);
GL_EXPORT bool UsePassthroughCommandDecoder(
const base::CommandLine* command_line);
#if defined(OS_WIN)
GL_EXPORT bool AreOverlaysSupportedWin();
#endif
} // namespace gl
#endif // UI_GL_GL_UTILS_H_