0

viz: Plumb vsync info to software output surface

Add necessary plumbing to update the begin frame source from the
software output device vsync provider.

Instantiate a VSyncProviderWin in SoftwareOutputDeviceWin.  This is the
same vsync provider used with GPU rendering, but it only uses Win32 and
DWM API and doesn't have any dependencies on D3D11, ANGLE, etc.

Verified that the above change works correctly locally by changing
monitor refresh rate to 25Hz and checking the interval in begin frames.

Change UpdateSyncParametersCallback in VSyncProvider to a OnceCallback
as a minor cleanup.

Bug: 928020
Change-Id: Iae36f69f84891af2c2ca903272034991cf488fbb
Reviewed-on: https://chromium-review.googlesource.com/c/1471451
Reviewed-by: Alexei Svitkine <asvitkine@chromium.org>
Reviewed-by: Antoine Labour <piman@chromium.org>
Commit-Queue: Sunny Sachanandani <sunnyps@chromium.org>
Cr-Commit-Position: refs/heads/master@{#632500}
This commit is contained in:
Sunny Sachanandani
2019-02-15 04:14:15 +00:00
committed by Commit Bot
parent 426ef6fb8a
commit 149fa85b99
14 changed files with 81 additions and 55 deletions

@ -98,20 +98,6 @@ void BeginFrameArgs::AsValueInto(base::trace_event::TracedValue* state) const {
state->SetBoolean("animate_only", animate_only);
}
// This is a hard-coded deadline adjustment that assumes 60Hz, to be used in
// cases where a good estimated draw time is not known. Using 1/3 of the vsync
// as the default adjustment gives the Browser the last 1/3 of a frame to
// produce output, the Renderer Impl thread the middle 1/3 of a frame to produce
// ouput, and the Renderer Main thread the first 1/3 of a frame to produce
// output.
base::TimeDelta BeginFrameArgs::DefaultEstimatedParentDrawTime() {
return base::TimeDelta::FromMicroseconds(16666 / 3);
}
base::TimeDelta BeginFrameArgs::DefaultInterval() {
return base::TimeDelta::FromMicroseconds(16666);
}
BeginFrameAck::BeginFrameAck()
: source_id(0),
sequence_number(BeginFrameArgs::kInvalidFrameNumber),

@ -80,13 +80,21 @@ struct VIZ_COMMON_EXPORT BeginFrameArgs {
base::TimeDelta interval,
BeginFrameArgsType type);
// This is the default delta that will be used to adjust the deadline when
// proper draw-time estimations are not yet available.
static base::TimeDelta DefaultEstimatedParentDrawTime();
// This is the default interval assuming 60Hz to use to avoid sprinkling the
// code with magic numbers.
static constexpr base::TimeDelta DefaultInterval() {
return base::TimeDelta::FromMicroseconds(16666);
}
// This is the default interval to use to avoid sprinkling the code with
// magic numbers.
static base::TimeDelta DefaultInterval();
// This is a hard-coded deadline adjustment that assumes 60Hz, to be used in
// cases where a good estimated draw time is not known. Using 1/3 of the vsync
// as the default adjustment gives the Browser the last 1/3 of a frame to
// produce output, the Renderer Impl thread the middle 1/3 of a frame to
// produce ouput, and the Renderer Main thread the first 1/3 of a frame to
// produce output.
static constexpr base::TimeDelta DefaultEstimatedParentDrawTime() {
return base::TimeDelta::FromMicroseconds(16666 / 3);
}
bool IsValid() const { return interval >= base::TimeDelta(); }

@ -122,7 +122,8 @@ std::unique_ptr<Display> GpuDisplayProvider::CreateDisplay(
if (!gpu_compositing) {
output_surface = std::make_unique<SoftwareOutputSurface>(
CreateSoftwareOutputDeviceForPlatform(surface_handle, display_client));
CreateSoftwareOutputDeviceForPlatform(surface_handle, display_client),
synthetic_begin_frame_source);
} else if (renderer_settings.use_skia_renderer) {
#if defined(OS_MACOSX) || defined(OS_WIN)
// TODO(penghuang): Support DDL for all platforms.

@ -19,6 +19,7 @@
#include "ui/gfx/gdi_util.h"
#include "ui/gfx/skia_util.h"
#include "ui/gfx/win/hwnd_util.h"
#include "ui/gl/vsync_provider_win.h"
namespace viz {
namespace {
@ -26,7 +27,10 @@ namespace {
// Shared base class for Windows SoftwareOutputDevice implementations.
class SoftwareOutputDeviceWinBase : public SoftwareOutputDevice {
public:
explicit SoftwareOutputDeviceWinBase(HWND hwnd) : hwnd_(hwnd) {}
explicit SoftwareOutputDeviceWinBase(HWND hwnd) : hwnd_(hwnd) {
vsync_provider_ = std::make_unique<gl::VSyncProviderWin>(hwnd);
}
~SoftwareOutputDeviceWinBase() override {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(!in_paint_);

@ -11,6 +11,7 @@
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/service/display/output_surface_client.h"
#include "components/viz/service/display/output_surface_frame.h"
#include "components/viz/service/display/software_output_device.h"
@ -21,8 +22,11 @@
namespace viz {
SoftwareOutputSurface::SoftwareOutputSurface(
std::unique_ptr<SoftwareOutputDevice> software_device)
: OutputSurface(std::move(software_device)), weak_factory_(this) {}
std::unique_ptr<SoftwareOutputDevice> software_device,
SyntheticBeginFrameSource* synthetic_begin_frame_source)
: OutputSurface(std::move(software_device)),
synthetic_begin_frame_source_(synthetic_begin_frame_source),
weak_factory_(this) {}
SoftwareOutputSurface::~SoftwareOutputSurface() = default;
@ -72,14 +76,15 @@ void SoftwareOutputSurface::SwapBuffers(OutputSurfaceFrame frame) {
<< "arrive before the previous latency info is processed.";
stored_latency_info_ = std::move(frame.latency_info);
// TODO(danakj): Update vsync params.
// gfx::VSyncProvider* vsync_provider = software_device()->GetVSyncProvider();
// if (vsync_provider)
// vsync_provider->GetVSyncParameters(update_vsync_parameters_callback_);
// Update refresh_interval_ as well.
software_device()->OnSwapBuffers(base::BindOnce(
&SoftwareOutputSurface::SwapBuffersCallback, weak_factory_.GetWeakPtr()));
gfx::VSyncProvider* vsync_provider = software_device()->GetVSyncProvider();
if (vsync_provider && synthetic_begin_frame_source_) {
vsync_provider->GetVSyncParameters(
base::BindOnce(&SoftwareOutputSurface::UpdateVSyncParametersCallback,
weak_factory_.GetWeakPtr()));
}
}
bool SoftwareOutputSurface::IsDisplayedAsOverlayPlane() const {
@ -117,8 +122,22 @@ void SoftwareOutputSurface::SwapBuffersCallback() {
client_->DidFinishLatencyInfo(stored_latency_info_);
std::vector<ui::LatencyInfo>().swap(stored_latency_info_);
client_->DidReceiveSwapBuffersAck();
base::TimeTicks now = base::TimeTicks::Now();
base::TimeDelta interval_to_next_refresh =
now.SnappedToNextTick(refresh_timebase_, refresh_interval_) - now;
client_->DidReceivePresentationFeedback(
gfx::PresentationFeedback(base::TimeTicks::Now(), refresh_interval_, 0u));
gfx::PresentationFeedback(now, interval_to_next_refresh, 0u));
}
void SoftwareOutputSurface::UpdateVSyncParametersCallback(
base::TimeTicks timebase,
base::TimeDelta interval) {
DCHECK(synthetic_begin_frame_source_);
refresh_timebase_ = timebase;
refresh_interval_ = interval;
synthetic_begin_frame_source_->OnUpdateVSyncParameters(timebase, interval);
}
#if BUILDFLAG(ENABLE_VULKAN)

@ -6,6 +6,7 @@
#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SOFTWARE_OUTPUT_SURFACE_H_
#include "base/memory/weak_ptr.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "components/viz/service/display/output_surface.h"
#include "components/viz/service/viz_service_export.h"
#include "ui/latency/latency_info.h"
@ -13,11 +14,13 @@
namespace viz {
class SoftwareOutputDevice;
class SyntheticBeginFrameSource;
class VIZ_SERVICE_EXPORT SoftwareOutputSurface : public OutputSurface {
public:
explicit SoftwareOutputSurface(
std::unique_ptr<SoftwareOutputDevice> software_device);
SoftwareOutputSurface(
std::unique_ptr<SoftwareOutputDevice> software_device,
SyntheticBeginFrameSource* synthetic_begin_frame_source);
~SoftwareOutputSurface() override;
// OutputSurface implementation.
@ -46,11 +49,18 @@ class VIZ_SERVICE_EXPORT SoftwareOutputSurface : public OutputSurface {
private:
void SwapBuffersCallback();
void UpdateVSyncParametersCallback(base::TimeTicks timebase,
base::TimeDelta interval);
OutputSurfaceClient* client_ = nullptr;
base::TimeDelta refresh_interval_;
SyntheticBeginFrameSource* const synthetic_begin_frame_source_;
base::TimeTicks refresh_timebase_;
base::TimeDelta refresh_interval_ = BeginFrameArgs::DefaultInterval();
std::vector<ui::LatencyInfo> stored_latency_info_;
ui::LatencyTracker latency_tracker_;
base::WeakPtrFactory<SoftwareOutputSurface> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(SoftwareOutputSurface);

@ -26,8 +26,8 @@ class FakeVSyncProvider : public gfx::VSyncProvider {
FakeVSyncProvider() : call_count_(0) {}
~FakeVSyncProvider() override {}
void GetVSyncParameters(const UpdateVSyncCallback& callback) override {
callback.Run(timebase_, interval_);
void GetVSyncParameters(UpdateVSyncCallback callback) override {
std::move(callback).Run(timebase_, interval_);
call_count_++;
}

@ -6,9 +6,8 @@
namespace gfx {
void FixedVSyncProvider::GetVSyncParameters(
const UpdateVSyncCallback& callback) {
callback.Run(timebase_, interval_);
void FixedVSyncProvider::GetVSyncParameters(UpdateVSyncCallback callback) {
std::move(callback).Run(timebase_, interval_);
}
bool FixedVSyncProvider::GetVSyncParametersIfAvailable(

@ -15,8 +15,8 @@ class GFX_EXPORT VSyncProvider {
public:
virtual ~VSyncProvider() {}
typedef base::Callback<
void(const base::TimeTicks timebase, const base::TimeDelta interval)>
typedef base::OnceCallback<void(const base::TimeTicks timebase,
const base::TimeDelta interval)>
UpdateVSyncCallback;
// Get the time of the most recent screen refresh, along with the time
@ -25,7 +25,7 @@ class GFX_EXPORT VSyncProvider {
// later via a PostTask to the current MessageLoop, or never (if we have
// no data source). We provide the strong guarantee that the callback will
// not be called once the instance of this class is destroyed.
virtual void GetVSyncParameters(const UpdateVSyncCallback& callback) = 0;
virtual void GetVSyncParameters(UpdateVSyncCallback callback) = 0;
// Similar to GetVSyncParameters(). It returns true, if the data is available.
// Otherwise false is returned.
@ -48,7 +48,7 @@ class GFX_EXPORT FixedVSyncProvider : public VSyncProvider {
~FixedVSyncProvider() override {}
void GetVSyncParameters(const UpdateVSyncCallback& callback) override;
void GetVSyncParameters(UpdateVSyncCallback callback) override;
bool GetVSyncParametersIfAvailable(base::TimeTicks* timebase,
base::TimeDelta* interval) override;
bool SupportGetVSyncParametersIfAvailable() const override;

@ -266,8 +266,7 @@ class SGIVideoSyncProviderThreadShim {
}
}
void GetVSyncParameters(
const gfx::VSyncProvider::UpdateVSyncCallback& callback) {
void GetVSyncParameters(gfx::VSyncProvider::UpdateVSyncCallback callback) {
base::TimeTicks now;
{
// Don't allow |window_| destruction while we're probing vsync.
@ -291,8 +290,8 @@ class SGIVideoSyncProviderThreadShim {
const base::TimeDelta kDefaultInterval =
base::TimeDelta::FromSeconds(1) / 60;
task_runner_->PostTask(FROM_HERE,
base::BindOnce(callback, now, kDefaultInterval));
task_runner_->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), now, kDefaultInterval));
}
private:
@ -344,11 +343,11 @@ class SGIVideoSyncVSyncProvider
}
void GetVSyncParameters(
const gfx::VSyncProvider::UpdateVSyncCallback& callback) override {
gfx::VSyncProvider::UpdateVSyncCallback callback) override {
// Only one outstanding request per surface.
if (!pending_callback_) {
DCHECK(callback);
pending_callback_ = callback;
pending_callback_ = std::move(callback);
vsync_thread_->task_runner()->PostTask(
FROM_HERE,
base::BindOnce(&SGIVideoSyncProviderThreadShim::GetVSyncParameters,

@ -37,11 +37,11 @@ SyncControlVSyncProvider::SyncControlVSyncProvider() : gfx::VSyncProvider() {
SyncControlVSyncProvider::~SyncControlVSyncProvider() {}
void SyncControlVSyncProvider::GetVSyncParameters(
const UpdateVSyncCallback& callback) {
UpdateVSyncCallback callback) {
base::TimeTicks timebase;
base::TimeDelta interval;
if (GetVSyncParametersIfAvailable(&timebase, &interval))
callback.Run(timebase, interval);
std::move(callback).Run(timebase, interval);
}
bool SyncControlVSyncProvider::GetVSyncParametersIfAvailable(

@ -20,7 +20,7 @@ class SyncControlVSyncProvider : public gfx::VSyncProvider {
SyncControlVSyncProvider();
~SyncControlVSyncProvider() override;
void GetVSyncParameters(const UpdateVSyncCallback& callback) override;
void GetVSyncParameters(UpdateVSyncCallback callback) override;
bool GetVSyncParametersIfAvailable(base::TimeTicks* timebase,
base::TimeDelta* interval) override;
bool SupportGetVSyncParametersIfAvailable() const override;

@ -29,11 +29,11 @@ void VSyncProviderWin::InitializeOneOff() {
::LoadLibrary(L"dwmapi.dll");
}
void VSyncProviderWin::GetVSyncParameters(const UpdateVSyncCallback& callback) {
void VSyncProviderWin::GetVSyncParameters(UpdateVSyncCallback callback) {
base::TimeTicks timebase;
base::TimeDelta interval;
if (GetVSyncParametersIfAvailable(&timebase, &interval))
callback.Run(timebase, interval);
std::move(callback).Run(timebase, interval);
}
bool VSyncProviderWin::GetVSyncParametersIfAvailable(

@ -19,7 +19,7 @@ class GL_EXPORT VSyncProviderWin : public gfx::VSyncProvider {
static void InitializeOneOff();
// gfx::VSyncProvider overrides;
void GetVSyncParameters(const UpdateVSyncCallback& callback) override;
void GetVSyncParameters(UpdateVSyncCallback callback) override;
bool GetVSyncParametersIfAvailable(base::TimeTicks* timebase,
base::TimeDelta* interval) override;
bool SupportGetVSyncParametersIfAvailable() const override;