Skip to content

Commit

Permalink
gpu: Plumb GPU vsync from IDXGIOutput to display compositor
Browse files Browse the repository at this point in the history
Implement a GpuVSyncBeginFrameSource that uses OutputSurface to provide
vsync updates.  GLOutputSurface implements this by plumbing vsync
requests and updates through InProcessCommandBuffer and GLSurface.  The
vsync updates are posted directly on the display compositor thread to
guard against GPU main thread contention and to minimize latency.

DirectCompositionSurfaceWin implements support for vsync updates based
on DirectCompositionGpuVSync feature flag.  Testing shows markedly
better alignment of begin frames with GPU vsync than using timer based
begin frames in ETW profiles and vastly improved regularity of frame
deltas on vsynctester.com.

Change-Id: Iaca86b3f15a6cccace168b9ac6b62a6f38c67542
Bug: 953970
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1558583
Reviewed-by: kylechar <kylechar@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: Antoine Labour <piman@chromium.org>
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
Commit-Queue: Sunny Sachanandani <sunnyps@chromium.org>
Cr-Commit-Position: refs/heads/master@{#658281}
  • Loading branch information
sunnyps authored and Commit Bot committed May 9, 2019
1 parent a52bee9 commit 04f3fcd
Show file tree
Hide file tree
Showing 34 changed files with 487 additions and 37 deletions.
1 change: 1 addition & 0 deletions components/viz/common/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ viz_component("common") {
"gpu/context_lost_reason.h",
"gpu/context_provider.cc",
"gpu/context_provider.h",
"gpu/gpu_vsync_callback.h",
"gpu/raster_context_provider.cc",
"gpu/raster_context_provider.h",
"hit_test/aggregated_hit_test_region.h",
Expand Down
9 changes: 9 additions & 0 deletions components/viz/common/frame_sinks/begin_frame_source.cc
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,10 @@ void DelayBasedBeginFrameSource::OnTimerTick() {
if (RequestCallbackOnGpuAvailable())
return;
last_begin_frame_args_ = CreateBeginFrameArgs(time_source_->LastTickTime());
TRACE_EVENT2(
"viz", "DelayBasedBeginFrameSource::OnTimerTick", "frame_time",
last_begin_frame_args_.frame_time.since_origin().InMicroseconds(),
"interval", last_begin_frame_args_.interval.InMicroseconds());
base::flat_set<BeginFrameObserver*> observers(observers_);
for (auto* obs : observers)
IssueBeginFrameToObserver(obs, last_begin_frame_args_);
Expand Down Expand Up @@ -428,6 +432,11 @@ void ExternalBeginFrameSource::OnBeginFrame(const BeginFrameArgs& args) {
return;
}

TRACE_EVENT2(
"viz", "ExternalBeginFrameSource::OnBeginFrame", "frame_time",
last_begin_frame_args_.frame_time.since_origin().InMicroseconds(),
"interval", last_begin_frame_args_.interval.InMicroseconds());

last_begin_frame_args_ = args;
base::flat_set<BeginFrameObserver*> observers(observers_);

Expand Down
19 changes: 19 additions & 0 deletions components/viz/common/gpu/gpu_vsync_callback.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_VIZ_COMMON_GPU_GPU_VSYNC_CALLBACK_H_
#define COMPONENTS_VIZ_COMMON_GPU_GPU_VSYNC_CALLBACK_H_

#include "base/callback.h"
#include "base/time/time.h"

namespace viz {

using GpuVSyncCallback =
base::RepeatingCallback<void(base::TimeTicks vsync_time,
base::TimeDelta vsync_interval)>;

} // namespace viz

#endif // COMPONENTS_VIZ_COMMON_GPU_GPU_VSYNC_CALLBACK_H_
2 changes: 2 additions & 0 deletions components/viz/service/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ viz_component("service") {
"frame_sinks/frame_sink_manager_impl.cc",
"frame_sinks/frame_sink_manager_impl.h",
"frame_sinks/frame_sink_observer.h",
"frame_sinks/gpu_vsync_begin_frame_source.cc",
"frame_sinks/gpu_vsync_begin_frame_source.h",
"frame_sinks/primary_begin_frame_source.cc",
"frame_sinks/primary_begin_frame_source.h",
"frame_sinks/root_compositor_frame_sink_impl.cc",
Expand Down
8 changes: 8 additions & 0 deletions components/viz/service/display/output_surface.cc
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,12 @@ void OutputSurface::SetNeedsSwapSizeNotifications(
DCHECK(!needs_swap_size_notifications);
}

void OutputSurface::SetGpuVSyncCallback(GpuVSyncCallback callback) {
NOTREACHED();
}

void OutputSurface::SetGpuVSyncEnabled(bool enabled) {
NOTREACHED();
}

} // namespace viz
10 changes: 10 additions & 0 deletions components/viz/service/display/output_surface.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "base/threading/thread_checker.h"
#include "components/viz/common/display/update_vsync_parameters_callback.h"
#include "components/viz/common/gpu/context_provider.h"
#include "components/viz/common/gpu/gpu_vsync_callback.h"
#include "components/viz/common/resources/returned_resource.h"
#include "components/viz/service/display/overlay_candidate_validator.h"
#include "components/viz/service/display/software_output_device.h"
Expand Down Expand Up @@ -52,6 +53,8 @@ class VIZ_SERVICE_EXPORT OutputSurface {
bool supports_stencil = false;
// Whether this OutputSurface supports post sub buffer or not.
bool supports_post_sub_buffer = false;
// Whether this OutputSurface supports gpu vsync callbacks.
bool supports_gpu_vsync = false;
};

// Constructor for skia-based compositing.
Expand Down Expand Up @@ -138,6 +141,13 @@ class VIZ_SERVICE_EXPORT OutputSurface {
virtual void SetUpdateVSyncParametersCallback(
UpdateVSyncParametersCallback callback) = 0;

// Set a callback for vsync signal from GPU service for begin frames. The
// callbacks must be received on the calling thread.
virtual void SetGpuVSyncCallback(GpuVSyncCallback callback);

// Enable or disable vsync callback based on whether begin frames are needed.
virtual void SetGpuVSyncEnabled(bool enabled);

// If set to true, the OutputSurface must deliver
// OutputSurfaceclient::DidSwapWithSize notifications to its client.
// OutputSurfaces which support delivering swap size notifications should
Expand Down
15 changes: 15 additions & 0 deletions components/viz/service/display_embedder/gl_output_surface.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,14 @@ GLOutputSurface::GLOutputSurface(
// can use.
capabilities_.max_frames_pending =
context_provider->ContextCapabilities().num_surface_buffers - 1;
capabilities_.supports_gpu_vsync =
context_provider->ContextCapabilities().gpu_vsync;
}

GLOutputSurface::~GLOutputSurface() {
viz_context_provider_->SetUpdateVSyncParametersCallback(
UpdateVSyncParametersCallback());
viz_context_provider_->SetGpuVSyncCallback(GpuVSyncCallback());
if (gpu_fence_id_ > 0)
context_provider()->ContextGL()->DestroyGpuFenceCHROMIUM(gpu_fence_id_);
}
Expand Down Expand Up @@ -205,4 +210,14 @@ void GLOutputSurface::SetUpdateVSyncParametersCallback(
viz_context_provider_->SetUpdateVSyncParametersCallback(std::move(callback));
}

void GLOutputSurface::SetGpuVSyncCallback(GpuVSyncCallback callback) {
DCHECK(capabilities_.supports_gpu_vsync);
viz_context_provider_->SetGpuVSyncCallback(std::move(callback));
}

void GLOutputSurface::SetGpuVSyncEnabled(bool enabled) {
DCHECK(capabilities_.supports_gpu_vsync);
viz_context_provider_->SetGpuVSyncEnabled(enabled);
}

} // namespace viz
3 changes: 3 additions & 0 deletions components/viz/service/display_embedder/gl_output_surface.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ class GLOutputSurface : public OutputSurface {
bool needs_swap_size_notifications) override;
void SetUpdateVSyncParametersCallback(
UpdateVSyncParametersCallback callback) override;
void SetGpuVSyncCallback(GpuVSyncCallback callback) override;
void SetGpuVSyncEnabled(bool enabled) override;

protected:
OutputSurfaceClient* client() const { return client_; }
Expand All @@ -70,6 +72,7 @@ class GLOutputSurface : public OutputSurface {
const gfx::Size& pixel_size,
const gpu::SwapBuffersCompleteParams& params);
void OnPresentation(const gfx::PresentationFeedback& feedback);
void OnGpuVSync(base::TimeTicks vsync_time, base::TimeDelta vsync_interval);

scoped_refptr<VizProcessContextProvider> viz_context_provider_;
OutputSurfaceClient* client_ = nullptr;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,9 +207,16 @@ void VizProcessContextProvider::RemoveObserver(ContextLostObserver* obs) {
}

void VizProcessContextProvider::SetUpdateVSyncParametersCallback(
const gpu::InProcessCommandBuffer::UpdateVSyncParametersCallback&
callback) {
command_buffer_->SetUpdateVSyncParametersCallback(callback);
UpdateVSyncParametersCallback callback) {
command_buffer_->SetUpdateVSyncParametersCallback(std::move(callback));
}

void VizProcessContextProvider::SetGpuVSyncCallback(GpuVSyncCallback callback) {
command_buffer_->SetGpuVSyncCallback(std::move(callback));
}

void VizProcessContextProvider::SetGpuVSyncEnabled(bool enabled) {
command_buffer_->SetGpuVSyncEnabled(enabled);
}

bool VizProcessContextProvider::UseRGB565PixelFormat() const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ class VIZ_SERVICE_EXPORT VizProcessContextProvider
void AddObserver(ContextLostObserver* obs) override;
void RemoveObserver(ContextLostObserver* obs) override;

void SetUpdateVSyncParametersCallback(
const gpu::InProcessCommandBuffer::UpdateVSyncParametersCallback&
callback);
void SetUpdateVSyncParametersCallback(UpdateVSyncParametersCallback callback);
void SetGpuVSyncCallback(GpuVSyncCallback callback);
void SetGpuVSyncEnabled(bool enabled);
bool UseRGB565PixelFormat() const;

// Provides the GL internal format that should be used when calling
Expand Down
36 changes: 36 additions & 0 deletions components/viz/service/frame_sinks/gpu_vsync_begin_frame_source.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/viz/service/frame_sinks/gpu_vsync_begin_frame_source.h"

#include "base/bind.h"
#include "components/viz/service/display/output_surface.h"

namespace viz {

GpuVSyncBeginFrameSource::GpuVSyncBeginFrameSource(
uint32_t restart_id,
OutputSurface* output_surface)
: ExternalBeginFrameSource(this, restart_id),
output_surface_(output_surface) {
DCHECK(output_surface->capabilities().supports_gpu_vsync);
output_surface->SetGpuVSyncCallback(base::BindRepeating(
&GpuVSyncBeginFrameSource::OnGpuVSync, base::Unretained(this)));
}

GpuVSyncBeginFrameSource::~GpuVSyncBeginFrameSource() = default;

void GpuVSyncBeginFrameSource::OnGpuVSync(base::TimeTicks vsync_time,
base::TimeDelta vsync_interval) {
ExternalBeginFrameSource::OnBeginFrame(BeginFrameArgs::Create(
BEGINFRAME_FROM_HERE, source_id(), next_begin_frame_sequence_number_++,
vsync_time, vsync_time + vsync_interval, vsync_interval,
BeginFrameArgs::NORMAL));
}

void GpuVSyncBeginFrameSource::OnNeedsBeginFrames(bool needs_begin_frames) {
output_surface_->SetGpuVSyncEnabled(needs_begin_frames);
}

} // namespace viz
41 changes: 41 additions & 0 deletions components/viz/service/frame_sinks/gpu_vsync_begin_frame_source.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GPU_VSYNC_BEGIN_FRAME_SOURCE_H_
#define COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GPU_VSYNC_BEGIN_FRAME_SOURCE_H_

#include "base/macros.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/service/viz_service_export.h"

namespace viz {

class OutputSurface;

// Receives begin frames via OutputSurface::SetGpuVSyncCallback(). Output
// surface must have |supports_gpu_vsync| capability. This class is not thread
// safe so the callbacks must be received on the original thread. The BFS is
// guaranteed to outlive the OutputSurface.
class VIZ_SERVICE_EXPORT GpuVSyncBeginFrameSource
: public ExternalBeginFrameSource,
public ExternalBeginFrameSourceClient {
public:
GpuVSyncBeginFrameSource(uint32_t restart_id, OutputSurface* output_surface);
~GpuVSyncBeginFrameSource() override;

// ExternalBeginFrameSourceClient implementation.
void OnNeedsBeginFrames(bool needs_begin_frames) override;

private:
void OnGpuVSync(base::TimeTicks vsync_time, base::TimeDelta vsync_interval);

OutputSurface* const output_surface_;
uint64_t next_begin_frame_sequence_number_ = 1;

DISALLOW_COPY_AND_ASSIGN(GpuVSyncBeginFrameSource);
};

} // namespace viz

#endif // COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GPU_VSYNC_BEGIN_FRAME_SOURCE_H_
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "components/viz/service/display_embedder/vsync_parameter_listener.h"
#include "components/viz/service/frame_sinks/external_begin_frame_source_mojo.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
#include "components/viz/service/frame_sinks/gpu_vsync_begin_frame_source.h"
#include "components/viz/service/hit_test/hit_test_aggregator.h"

#if defined(OS_ANDROID)
Expand Down Expand Up @@ -77,14 +78,17 @@ RootCompositorFrameSinkImpl::Create(
std::make_unique<BackToBackBeginFrameSource>(
std::make_unique<DelayBasedTimeSource>(
base::ThreadTaskRunnerHandle::Get().get()));
} else if (output_surface->capabilities().supports_gpu_vsync) {
external_begin_frame_source = std::make_unique<GpuVSyncBeginFrameSource>(
restart_id, output_surface.get());
} else {
synthetic_begin_frame_source =
std::make_unique<DelayBasedBeginFrameSource>(
std::make_unique<DelayBasedTimeSource>(
base::ThreadTaskRunnerHandle::Get().get()),
restart_id);
}
#endif
#endif // OS_ANDROID
}

BeginFrameSource* begin_frame_source = synthetic_begin_frame_source.get();
Expand Down
1 change: 1 addition & 0 deletions gpu/command_buffer/common/capabilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ struct GPU_EXPORT Capabilities {
bool dc_layers = false;
bool use_dc_overlays_for_video = false;
bool protected_video_swap_chain = false;
bool gpu_vsync = false;

// When this parameter is true, a CHROMIUM image created with RGB format will
// actually have RGBA format. The client is responsible for handling most of
Expand Down
1 change: 1 addition & 0 deletions gpu/command_buffer/service/gles2_cmd_decoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4242,6 +4242,7 @@ Capabilities GLES2DecoderImpl::GetCapabilities() {
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 =
feature_info_->feature_flags().blend_equation_advanced;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1369,6 +1369,7 @@ gpu::Capabilities GLES2DecoderPassthroughImpl::GetCapabilities() {
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();
caps.texture_npot = feature_info_->feature_flags().npot_ok;
caps.chromium_gpu_fence = feature_info_->feature_flags().chromium_gpu_fence;
caps.chromium_nonblocking_readback = true;
Expand Down
2 changes: 2 additions & 0 deletions gpu/config/gpu_finch_features.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ const base::Feature kDefaultEnableOopRasterization{
const base::Feature kDefaultPassthroughCommandDecoder{
"DefaultPassthroughCommandDecoder", base::FEATURE_DISABLED_BY_DEFAULT};

const base::Feature kDirectCompositionGpuVSync{
"DirectCompositionGpuVSync", base::FEATURE_DISABLED_BY_DEFAULT};

// Overrides preferred overlay format to NV12 instead of YUY2.
const base::Feature kDirectCompositionPreferNV12Overlays{
Expand Down
2 changes: 2 additions & 0 deletions gpu/config/gpu_finch_features.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ GPU_EXPORT extern const base::Feature kDefaultEnableOopRasterization;

GPU_EXPORT extern const base::Feature kDefaultPassthroughCommandDecoder;

GPU_EXPORT extern const base::Feature kDirectCompositionGpuVSync;

GPU_EXPORT extern const base::Feature kDirectCompositionPreferNV12Overlays;

GPU_EXPORT extern const base::Feature kDirectCompositionUnderlays;
Expand Down
2 changes: 2 additions & 0 deletions gpu/ipc/DEPS
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
include_rules = [
"+components/viz/common/features.h",
"+components/viz/common/display/update_vsync_parameters_callback.h",
"+components/viz/common/gpu/gpu_vsync_callback.h",
"+components/viz/common/resources/resource_format.h",
]

1 change: 1 addition & 0 deletions gpu/ipc/common/gpu_command_buffer_traits_multi.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ IPC_STRUCT_TRAITS_BEGIN(gpu::Capabilities)
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(disable_non_empty_post_sub_buffers)
IPC_STRUCT_TRAITS_MEMBER(avoid_stencil_buffers)
IPC_STRUCT_TRAITS_MEMBER(disable_2d_canvas_copy_on_write)
Expand Down
Loading

0 comments on commit 04f3fcd

Please sign in to comment.