Commit d332af51 authored by Maxim Kolosovskiy's avatar Maxim Kolosovskiy Committed by Commit Bot

Revert "gpu: Sync to primary monitor's vblank (windows)"

This reverts commit bd0cae50.

Reason for revert: Cause failures in DirectCompositionSurfaceTest.*
Builder: https://ci.chromium.org/p/chromium/builders/ci/Win10%20Debug%20%28NVIDIA%29?limit=200
First build: https://ci.chromium.org/p/chromium/builders/ci/Win10%20Debug%20%28NVIDIA%29/22377?blamelist=1#overview-tab

Crash example:
Test 'DirectCompositionPixelTest.DCLayersDisabled' completed with the following status(es): 'CRASH','CRASH','CRASH'

Test 'DirectCompositionPixelTest.DCLayersDisabled' had the following logs when run:

================================================================================

[ RUN      ] DirectCompositionPixelTest.DCLayersDisabled
Received fatal exception EXCEPTION_ACCESS_VIOLATION
Backtrace:
	RtlAcquireSRWLockExclusive [0x774C4188+24]
	base::internal::LockImpl::Lock [0x72EEA36A+106] (o:\base\synchronization\lock_impl_win.cc:36)
	base::Lock::Acquire [0x73AA4B5A+26] (o:\base\synchronization\lock.h:50)
	base::internal::BasicAutoLock<base::Lock>::BasicAutoLock [0x73AA4663+35] (o:\base\synchronization\lock_impl.h:84)
	gl::VSyncThreadWin::RemoveObserver [0x73B41033+51] (o:\ui\gl\vsync_thread_win.cc:84)
	gl::DirectCompositionSurfaceWin::Destroy [0x73B2089A+42] (o:\ui\gl\direct_composition_surface_win.cc:406)
	gl::DirectCompositionSurfaceWin::~DirectCompositionSurfaceWin [0x73B1DF75+37] (o:\ui\gl\direct_composition_surface_win.cc:185)
	gl::DirectCompositionSurfaceWin::~DirectCompositionSurfaceWin [0x73B217D5+37] (o:\ui\gl\direct_composition_surface_win.cc:184)
	base::RefCounted<gl::GLSurface,base::DefaultRefCountedTraits<gl::GLSurface> >::DeleteInternal<gl::GLSurface> [0x0137B3B2+50] (o:\base\memory\ref_counted.h:356)
	base::DefaultRefCountedTraits<gl::GLSurface>::Destruct [0x0137B377+23] (o:\base\memory\ref_counted.h:323)
	base::RefCounted<gl::GLSurface,base::DefaultRefCountedTraits<gl::GLSurface> >::Release [0x0137B351+49] (o:\base\memory\ref_counted.h:347)
	scoped_refptr<gl::DirectCompositionSurfaceWin>::Release [0x013BD545+21] (o:\base\memory\scoped_refptr.h:298)
	scoped_refptr<gl::DirectCompositionSurfaceWin>::~scoped_refptr [0x013BD525+37] (o:\base\memory\scoped_refptr.h:210)
	scoped_refptr<gl::DirectCompositionSurfaceWin>::operator= [0x013BD7E8+40] (o:\base\memory\scoped_refptr.h:230)
	scoped_refptr<gl::DirectCompositionSurfaceWin>::operator= [0x013BE275+69] (o:\base\memory\scoped_refptr.h:224)
	gl::`anonymous namespace'::DestroySurface [0x013BE12A+250] (o:\ui\gl\direct_composition_surface_win_unittest.cc:66)
	gl::`anonymous namespace'::DirectCompositionSurfaceTest::TearDown [0x013BBA1F+127] (o:\ui\gl\direct_composition_surface_win_unittest.cc:128)
	gl::`anonymous namespace'::DirectCompositionPixelTest::TearDown [0x013C95A3+67] (o:\ui\gl\direct_composition_surface_win_unittest.cc:602)
	testing::internal::HandleExceptionsInMethodIfSupported<testing::Test,void> [0x0141637B+107] (o:\third_party\googletest\src\googletest\src\gtest.cc:2507)
	testing::Test::Run [0x014162F1+257] (o:\third_party\googletest\src\googletest\src\gtest.cc:2532)
	testing::TestInfo::Run [0x01416DCD+253] (o:\third_party\googletest\src\googletest\src\gtest.cc:2701)
	testing::TestSuite::Run [0x01417A6D+301] (o:\third_party\googletest\src\googletest\src\gtest.cc:2827)
	testing::internal::UnitTestImpl::RunAllTests [0x01421415+1013] (o:\third_party\googletest\src\googletest\src\gtest.cc:5284)
	testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl,bool> [0x01420FF0+112] (o:\third_party\googletest\src\googletest\src\gtest.cc:2505)
	testing::UnitTest::Run [0x01420E44+292] (o:\third_party\googletest\src\googletest\src\gtest.cc:4873)
	RUN_ALL_TESTS [0x0172FC3F+15] (o:\third_party\googletest\src\googletest\include\gtest\gtest.h:2453)
	base::TestSuite::Run [0x0172F26F+143] (o:\base\test\test_suite.cc:316)
	base::internal::FunctorTraits<int (base::TestSuite::*)() __attribute__((thiscall)),void>::Invoke<int (base::TestSuite::*)() __attribute__((thiscall)),(anonymous namespace)::GlTestSuite *> [0x013DDCBC+28] (o:\base\bind_internal.h:499)
	base::internal::InvokeHelper<0,int>::MakeItSo<int (base::TestSuite::*)() __attribute__((thiscall)),(anonymous namespace)::GlTestSuite *> [0x013DDC0F+79] (o:\base\bind_internal.h:599)
	base::internal::Invoker<base::internal::BindState<int (base::TestSuite::*)() __attribute__((thiscall)),base::internal::UnretainedWrapper<(anonymous namespace)::GlTestSuite> >,int ()>::RunImpl<int (base::TestSuite::*)() __attribute__((thiscall)),std::__1:: [0x013DDB65+85] (o:\base\bind_internal.h:672)
	base::internal::Invoker<base::internal::BindState<int (base::TestSuite::*)() __attribute__((thiscall)),base::internal::UnretainedWrapper<(anonymous namespace)::GlTestSuite> >,int ()>::RunOnce [0x013DDA14+84] (o:\base\bind_internal.h:641)
	base::OnceCallback<int ()>::Run [0x01737480+80] (o:\base\callback.h:99)
	base::`anonymous namespace'::LaunchUnitTestsInternal [0x01735358+440] (o:\base\test\launcher\unit_test_launcher.cc:158)
	base::LaunchUnitTests [0x01735168+232] (o:\base\test\launcher\unit_test_launcher.cc:354)
	main [0x013DC8CB+171] (o:\ui\gl\test\run_all_unittests.cc:78)
	invoke_main [0x01839F5E+30] (d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78)
	__scrt_common_main_seh [0x0183A0C7+343] (d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288)
	__scrt_common_main [0x0183A19D+13] (d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:331)
	mainCRTStartup [0x0183A1A8+8] (d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\startup\exe_main.cpp:17)
	BaseThreadInitThunk [0x740E8654+36]
	RtlGetAppContainerNamedObjectPath [0x774E4A77+311]
	RtlGetAppContainerNamedObjectPath [0x774E4A47+263]


Original change's description:
> gpu: Sync to primary monitor's vblank (windows)
> 
> DWM composition is limited to primary monitor's refresh rate.  Prior to
> GPU vsync we would use DWM composition rate to drive begin frames.
> 
> With GPU vsync we started using per monitor vblank to limit begin frames
> in case primary monitor had higher refresh rate, but this might be
> causing draw duration and omnibar latency regressions.  MS platform team
> also suggested syncing to primary monitor only.  In any case the correct
> approach would be to further limit begin frames based on event queries
> from 2 frames back.
> 
> This CL makes the GPU vsync begin frames sync to primary monitor, and
> also makes the vsync thread a singleton since it doesn't have per-window
> state any more.
> 
> Bug: 953970
> Change-Id: Id3d3f043cb847172b1d6ba4bd38b087ceb2d8631
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1711215
> Reviewed-by: Zhenyao Mo <zmo@chromium.org>
> Commit-Queue: Sunny Sachanandani <sunnyps@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#679832}

TBR=zmo@chromium.org,sunnyps@chromium.org

Change-Id: If4a762325952dd33283bf41a13321e759de51025
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 953970
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1713510Reviewed-by: default avatarMaxim Kolosovskiy <kolos@chromium.org>
Commit-Queue: Maxim Kolosovskiy <kolos@chromium.org>
Cr-Commit-Position: refs/heads/master@{#679915}
parent 1d5018b0
...@@ -307,7 +307,6 @@ jumbo_component("gl") { ...@@ -307,7 +307,6 @@ jumbo_component("gl") {
"gl_wgl_api_implementation.h", "gl_wgl_api_implementation.h",
"swap_chain_presenter.cc", "swap_chain_presenter.cc",
"swap_chain_presenter.h", "swap_chain_presenter.h",
"vsync_observer.h",
"vsync_provider_win.cc", "vsync_provider_win.cc",
"vsync_provider_win.h", "vsync_provider_win.h",
"vsync_thread_win.cc", "vsync_thread_win.cc",
......
...@@ -107,9 +107,7 @@ bool DirectCompositionChildSurfaceWin::UseSwapChainFrameStatistics() { ...@@ -107,9 +107,7 @@ bool DirectCompositionChildSurfaceWin::UseSwapChainFrameStatistics() {
return base::FeatureList::IsEnabled(features::kSwapChainFrameStatistics); return base::FeatureList::IsEnabled(features::kSwapChainFrameStatistics);
} }
DirectCompositionChildSurfaceWin::DirectCompositionChildSurfaceWin( DirectCompositionChildSurfaceWin::DirectCompositionChildSurfaceWin() {}
gfx::VSyncProvider* vsync_provider)
: vsync_provider_(vsync_provider) {}
DirectCompositionChildSurfaceWin::~DirectCompositionChildSurfaceWin() { DirectCompositionChildSurfaceWin::~DirectCompositionChildSurfaceWin() {
Destroy(); Destroy();
...@@ -260,8 +258,6 @@ gfx::SwapResult DirectCompositionChildSurfaceWin::SwapBuffers( ...@@ -260,8 +258,6 @@ gfx::SwapResult DirectCompositionChildSurfaceWin::SwapBuffers(
bool succeeded = ReleaseDrawTexture(false /* will_discard */); bool succeeded = ReleaseDrawTexture(false /* will_discard */);
if (UseSwapChainFrameStatistics()) { if (UseSwapChainFrameStatistics()) {
vsync_provider_->GetVSyncParametersIfAvailable(&last_vsync_time_,
&last_vsync_interval_);
CheckPendingFrames(); CheckPendingFrames();
// Enqueue callback after retiring previous callbacks so that it's called // Enqueue callback after retiring previous callbacks so that it's called
// after SwapBuffers() returns. // after SwapBuffers() returns.
...@@ -507,6 +503,17 @@ bool DirectCompositionChildSurfaceWin::SetEnableDCLayers(bool enable) { ...@@ -507,6 +503,17 @@ bool DirectCompositionChildSurfaceWin::SetEnableDCLayers(bool enable) {
return true; return true;
} }
void DirectCompositionChildSurfaceWin::UpdateVSyncParameters(
base::TimeTicks vsync_time,
base::TimeDelta vsync_interval) {
last_vsync_time_ = vsync_time;
last_vsync_interval_ = vsync_interval;
}
bool DirectCompositionChildSurfaceWin::HasPendingFrames() const {
return !pending_frames_.empty();
}
void DirectCompositionChildSurfaceWin::CheckPendingFrames() { void DirectCompositionChildSurfaceWin::CheckPendingFrames() {
DCHECK(UseSwapChainFrameStatistics()); DCHECK(UseSwapChainFrameStatistics());
......
...@@ -12,15 +12,11 @@ ...@@ -12,15 +12,11 @@
#include "ui/gl/gl_surface_egl.h" #include "ui/gl/gl_surface_egl.h"
namespace gfx {
class VSyncProvider;
} // namespace gfx
namespace gl { namespace gl {
class DirectCompositionChildSurfaceWin : public GLSurfaceEGL { class DirectCompositionChildSurfaceWin : public GLSurfaceEGL {
public: public:
explicit DirectCompositionChildSurfaceWin(gfx::VSyncProvider* vsync_provider); DirectCompositionChildSurfaceWin();
static bool UseSwapChainFrameStatistics(); static bool UseSwapChainFrameStatistics();
...@@ -44,6 +40,11 @@ class DirectCompositionChildSurfaceWin : public GLSurfaceEGL { ...@@ -44,6 +40,11 @@ class DirectCompositionChildSurfaceWin : public GLSurfaceEGL {
bool has_alpha) override; bool has_alpha) override;
bool SetEnableDCLayers(bool enable) override; bool SetEnableDCLayers(bool enable) override;
void UpdateVSyncParameters(base::TimeTicks vsync_time,
base::TimeDelta vsync_interval);
bool HasPendingFrames() const;
void CheckPendingFrames();
const Microsoft::WRL::ComPtr<IDCompositionSurface>& dcomp_surface() const { const Microsoft::WRL::ComPtr<IDCompositionSurface>& dcomp_surface() const {
return dcomp_surface_; return dcomp_surface_;
} }
...@@ -75,7 +76,6 @@ class DirectCompositionChildSurfaceWin : public GLSurfaceEGL { ...@@ -75,7 +76,6 @@ class DirectCompositionChildSurfaceWin : public GLSurfaceEGL {
// Presentation callback enqueued in SwapBuffers(). // Presentation callback enqueued in SwapBuffers().
PresentationCallback callback; PresentationCallback callback;
}; };
void CheckPendingFrames();
void EnqueuePendingFrame(PresentationCallback callback); void EnqueuePendingFrame(PresentationCallback callback);
void ClearPendingFrames(); void ClearPendingFrames();
...@@ -109,7 +109,6 @@ class DirectCompositionChildSurfaceWin : public GLSurfaceEGL { ...@@ -109,7 +109,6 @@ class DirectCompositionChildSurfaceWin : public GLSurfaceEGL {
// be called on the device. // be called on the device.
uint64_t dcomp_surface_serial_ = 0; uint64_t dcomp_surface_serial_ = 0;
gfx::VSyncProvider* const vsync_provider_;
base::TimeTicks last_vsync_time_; base::TimeTicks last_vsync_time_;
base::TimeDelta last_vsync_interval_ = base::TimeDelta::FromSecondsD(1. / 60); base::TimeDelta last_vsync_interval_ = base::TimeDelta::FromSecondsD(1. / 60);
......
...@@ -172,14 +172,15 @@ DirectCompositionSurfaceWin::DirectCompositionSurfaceWin( ...@@ -172,14 +172,15 @@ DirectCompositionSurfaceWin::DirectCompositionSurfaceWin(
: GLSurfaceEGL(), : GLSurfaceEGL(),
child_window_(parent_window), child_window_(parent_window),
task_runner_(base::ThreadTaskRunnerHandle::Get()), task_runner_(base::ThreadTaskRunnerHandle::Get()),
root_surface_(new DirectCompositionChildSurfaceWin(vsync_provider.get())), root_surface_(new DirectCompositionChildSurfaceWin()),
layer_tree_(std::make_unique<DCLayerTree>( layer_tree_(std::make_unique<DCLayerTree>(
settings.disable_nv12_dynamic_textures, settings.disable_nv12_dynamic_textures,
settings.disable_larger_than_screen_overlays)), settings.disable_larger_than_screen_overlays)),
presentation_helper_(
std::make_unique<GLSurfacePresentationHelper>(vsync_provider.get())),
vsync_provider_(std::move(vsync_provider)), vsync_provider_(std::move(vsync_provider)),
vsync_callback_(std::move(vsync_callback)) {} vsync_callback_(std::move(vsync_callback)),
presentation_helper_(
std::make_unique<GLSurfacePresentationHelper>(vsync_provider_.get())),
weak_ptr_factory_(this) {}
DirectCompositionSurfaceWin::~DirectCompositionSurfaceWin() { DirectCompositionSurfaceWin::~DirectCompositionSurfaceWin() {
Destroy(); Destroy();
...@@ -395,17 +396,27 @@ bool DirectCompositionSurfaceWin::Initialize(GLSurfaceFormat format) { ...@@ -395,17 +396,27 @@ bool DirectCompositionSurfaceWin::Initialize(GLSurfaceFormat format) {
if (!root_surface_->Initialize(GLSurfaceFormat())) if (!root_surface_->Initialize(GLSurfaceFormat()))
return false; return false;
if (SupportsGpuVSync() && vsync_callback_) if (root_surface_->UseSwapChainFrameStatistics()) {
vsync_thread_ = VSyncThreadWin::GetInstance(); // Save weak ptr on main thread before any use on vsync thread.
main_thread_vsync_callback_ = base::BindRepeating(
&DirectCompositionSurfaceWin::HandleVSyncOnMainThread,
weak_ptr_factory_.GetWeakPtr());
}
if ((SupportsGpuVSync() && vsync_callback_) || main_thread_vsync_callback_) {
vsync_thread_ = std::make_unique<VSyncThreadWin>(
window_, d3d11_device_,
base::BindRepeating(
&DirectCompositionSurfaceWin::HandleVSyncOnVSyncThread,
base::Unretained(this)));
}
return true; return true;
} }
void DirectCompositionSurfaceWin::Destroy() { void DirectCompositionSurfaceWin::Destroy() {
if (vsync_thread_) { // Destroy vsync thread because joining it could issue callbacks.
vsync_thread_->RemoveObserver(this); vsync_thread_ = nullptr;
vsync_thread_ = nullptr;
}
// Destroy presentation helper first because its dtor calls GetHandle. // Destroy presentation helper first because its dtor calls GetHandle.
presentation_helper_ = nullptr; presentation_helper_ = nullptr;
root_surface_->Destroy(); root_surface_->Destroy();
...@@ -448,11 +459,14 @@ gfx::SwapResult DirectCompositionSurfaceWin::SwapBuffers( ...@@ -448,11 +459,14 @@ gfx::SwapResult DirectCompositionSurfaceWin::SwapBuffers(
callback.Reset(); callback.Reset();
} }
gfx::SwapResult swap_result; gfx::SwapResult swap_result = root_surface_->SwapBuffers(std::move(callback));
if (root_surface_->SwapBuffers(std::move(callback)) ==
gfx::SwapResult::SWAP_ACK && if (swap_result == gfx::SwapResult::SWAP_ACK &&
layer_tree_->CommitAndClearPendingOverlays(root_surface_.get())) { layer_tree_->CommitAndClearPendingOverlays(root_surface_.get())) {
swap_result = gfx::SwapResult::SWAP_ACK; if (vsync_thread_) {
vsync_thread_->SetEnabled(root_surface_->HasPendingFrames() ||
vsync_callback_enabled_);
}
} else { } else {
swap_result = gfx::SwapResult::SWAP_FAILED; swap_result = gfx::SwapResult::SWAP_FAILED;
} }
...@@ -533,17 +547,34 @@ bool DirectCompositionSurfaceWin::SupportsGpuVSync() const { ...@@ -533,17 +547,34 @@ bool DirectCompositionSurfaceWin::SupportsGpuVSync() const {
void DirectCompositionSurfaceWin::SetGpuVSyncEnabled(bool enabled) { void DirectCompositionSurfaceWin::SetGpuVSyncEnabled(bool enabled) {
DCHECK(vsync_thread_); DCHECK(vsync_thread_);
if (enabled) { if (vsync_callback_enabled_ == enabled)
vsync_thread_->AddObserver(this); return;
} else { vsync_callback_enabled_ = enabled;
vsync_thread_->RemoveObserver(this); vsync_thread_->SetEnabled(root_surface_->HasPendingFrames() ||
vsync_callback_enabled_);
}
void DirectCompositionSurfaceWin::HandleVSyncOnVSyncThread(
base::TimeTicks vsync_time,
base::TimeDelta vsync_interval) {
if (vsync_callback_)
vsync_callback_.Run(vsync_time, vsync_interval);
if (main_thread_vsync_callback_) {
task_runner_->PostTask(
FROM_HERE, base::BindOnce(main_thread_vsync_callback_, vsync_time,
vsync_interval));
} }
} }
void DirectCompositionSurfaceWin::OnVSync(base::TimeTicks vsync_time, void DirectCompositionSurfaceWin::HandleVSyncOnMainThread(
base::TimeDelta interval) { base::TimeTicks vsync_time,
DCHECK(vsync_callback_); base::TimeDelta vsync_interval) {
vsync_callback_.Run(vsync_time, interval); // Check pending frames in root surface in case client stops issuing swaps.
root_surface_->UpdateVSyncParameters(vsync_time, vsync_interval);
root_surface_->CheckPendingFrames();
vsync_thread_->SetEnabled(root_surface_->HasPendingFrames() ||
vsync_callback_enabled_);
} }
scoped_refptr<base::TaskRunner> scoped_refptr<base::TaskRunner>
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
#include "ui/gl/child_window_win.h" #include "ui/gl/child_window_win.h"
#include "ui/gl/gl_export.h" #include "ui/gl/gl_export.h"
#include "ui/gl/gl_surface_egl.h" #include "ui/gl/gl_surface_egl.h"
#include "ui/gl/vsync_observer.h"
namespace gl { namespace gl {
class DCLayerTree; class DCLayerTree;
...@@ -24,8 +23,7 @@ class DirectCompositionChildSurfaceWin; ...@@ -24,8 +23,7 @@ class DirectCompositionChildSurfaceWin;
class GLSurfacePresentationHelper; class GLSurfacePresentationHelper;
class VSyncThreadWin; class VSyncThreadWin;
class GL_EXPORT DirectCompositionSurfaceWin : public GLSurfaceEGL, class GL_EXPORT DirectCompositionSurfaceWin : public GLSurfaceEGL {
public VSyncObserver {
public: public:
using VSyncCallback = using VSyncCallback =
base::RepeatingCallback<void(base::TimeTicks, base::TimeDelta)>; base::RepeatingCallback<void(base::TimeTicks, base::TimeDelta)>;
...@@ -107,6 +105,7 @@ class GL_EXPORT DirectCompositionSurfaceWin : public GLSurfaceEGL, ...@@ -107,6 +105,7 @@ class GL_EXPORT DirectCompositionSurfaceWin : public GLSurfaceEGL,
gfx::Vector2d GetDrawOffset() const override; gfx::Vector2d GetDrawOffset() const override;
bool SupportsGpuVSync() const override; bool SupportsGpuVSync() const override;
void SetGpuVSyncEnabled(bool enabled) override; void SetGpuVSyncEnabled(bool enabled) override;
// This schedules an overlay plane to be displayed on the next SwapBuffers // This schedules an overlay plane to be displayed on the next SwapBuffers
// or PostSubBuffer call. Overlay planes must be scheduled before every swap // or PostSubBuffer call. Overlay planes must be scheduled before every swap
// to remain in the layer tree. This surface's backbuffer doesn't have to be // to remain in the layer tree. This surface's backbuffer doesn't have to be
...@@ -114,9 +113,6 @@ class GL_EXPORT DirectCompositionSurfaceWin : public GLSurfaceEGL, ...@@ -114,9 +113,6 @@ class GL_EXPORT DirectCompositionSurfaceWin : public GLSurfaceEGL,
// tree at z-order 0. // tree at z-order 0.
bool ScheduleDCLayer(const ui::DCRendererLayerParams& params) override; bool ScheduleDCLayer(const ui::DCRendererLayerParams& params) override;
// VSyncObserver implementation.
void OnVSync(base::TimeTicks vsync_time, base::TimeDelta interval) override;
HWND window() const { return window_; } HWND window() const { return window_; }
scoped_refptr<base::TaskRunner> GetWindowTaskRunnerForTesting(); scoped_refptr<base::TaskRunner> GetWindowTaskRunnerForTesting();
...@@ -131,21 +127,33 @@ class GL_EXPORT DirectCompositionSurfaceWin : public GLSurfaceEGL, ...@@ -131,21 +127,33 @@ class GL_EXPORT DirectCompositionSurfaceWin : public GLSurfaceEGL,
~DirectCompositionSurfaceWin() override; ~DirectCompositionSurfaceWin() override;
private: private:
void HandleVSyncOnVSyncThread(base::TimeTicks vsync_time,
base::TimeDelta vsync_interval);
void HandleVSyncOnMainThread(base::TimeTicks vsync_time,
base::TimeDelta vsync_interval);
HWND window_ = nullptr; HWND window_ = nullptr;
ChildWindowWin child_window_; ChildWindowWin child_window_;
scoped_refptr<base::SequencedTaskRunner> task_runner_; scoped_refptr<base::SequencedTaskRunner> task_runner_;
scoped_refptr<DirectCompositionChildSurfaceWin> root_surface_; scoped_refptr<DirectCompositionChildSurfaceWin> root_surface_;
std::unique_ptr<DCLayerTree> layer_tree_; std::unique_ptr<DCLayerTree> layer_tree_;
std::unique_ptr<GLSurfacePresentationHelper> presentation_helper_;
std::unique_ptr<VSyncThreadWin> vsync_thread_;
std::unique_ptr<gfx::VSyncProvider> vsync_provider_; std::unique_ptr<gfx::VSyncProvider> vsync_provider_;
const VSyncCallback vsync_callback_; const VSyncCallback vsync_callback_;
VSyncThreadWin* vsync_thread_; bool vsync_callback_enabled_ = false;
std::unique_ptr<GLSurfacePresentationHelper> presentation_helper_;
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device_; Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device_;
Microsoft::WRL::ComPtr<IDCompositionDevice2> dcomp_device_; Microsoft::WRL::ComPtr<IDCompositionDevice2> dcomp_device_;
VSyncCallback main_thread_vsync_callback_;
base::WeakPtrFactory<DirectCompositionSurfaceWin> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(DirectCompositionSurfaceWin); DISALLOW_COPY_AND_ASSIGN(DirectCompositionSurfaceWin);
}; };
......
// 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 UI_GL_VSYNC_OBSERVER_H_
#define UI_GL_VSYNC_OBSERVER_H_
namespace gl {
class GL_EXPORT VSyncObserver {
public:
// Called on vsync thread.
virtual void OnVSync(base::TimeTicks vsync_time,
base::TimeDelta interval) = 0;
protected:
virtual ~VSyncObserver() {}
};
} // namespace gl
#endif // UI_GL_VSYNC_OBSERVER_H_
...@@ -5,10 +5,6 @@ ...@@ -5,10 +5,6 @@
#include "ui/gl/vsync_thread_win.h" #include "ui/gl/vsync_thread_win.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/memory/singleton.h"
#include "base/stl_util.h"
#include "ui/gl/gl_angle_util_win.h"
#include "ui/gl/vsync_observer.h"
namespace gl { namespace gl {
namespace { namespace {
...@@ -47,51 +43,45 @@ Microsoft::WRL::ComPtr<IDXGIOutput> DXGIOutputFromMonitor( ...@@ -47,51 +43,45 @@ Microsoft::WRL::ComPtr<IDXGIOutput> DXGIOutputFromMonitor(
} }
} // namespace } // namespace
// static VSyncThreadWin::VSyncThreadWin(
VSyncThreadWin* VSyncThreadWin::GetInstance() { HWND window,
return base::Singleton<VSyncThreadWin>::get(); Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device,
} VSyncCallback callback)
VSyncThreadWin::VSyncThreadWin()
: vsync_thread_("GpuVSyncThread"), : vsync_thread_("GpuVSyncThread"),
d3d11_device_(QueryD3D11DeviceObjectFromANGLE()) { window_(window),
DCHECK(d3d11_device_); d3d11_device_(std::move(d3d11_device)),
callback_(std::move(callback)) {
DCHECK(window_);
DCHECK(callback_);
base::Thread::Options options; base::Thread::Options options;
options.priority = base::ThreadPriority::DISPLAY; // Inherit priority from GPU main thread which depends on finch flags.
options.priority = base::PlatformThread::GetCurrentThreadPriority();
vsync_thread_.StartWithOptions(std::move(options)); vsync_thread_.StartWithOptions(std::move(options));
} }
VSyncThreadWin::~VSyncThreadWin() { VSyncThreadWin::~VSyncThreadWin() {
{ SetEnabled(false);
base::AutoLock auto_lock(lock_);
observers_.clear();
}
vsync_thread_.Stop(); vsync_thread_.Stop();
} }
void VSyncThreadWin::AddObserver(VSyncObserver* obs) { void VSyncThreadWin::SetEnabled(bool enabled) {
base::AutoLock auto_lock(lock_); base::AutoLock auto_lock(lock_);
observers_.insert(obs); if (enabled_ == enabled)
if (is_idle_) { return;
is_idle_ = false; enabled_ = enabled;
if (enabled_ && !started_) {
started_ = true;
vsync_thread_.task_runner()->PostTask( vsync_thread_.task_runner()->PostTask(
FROM_HERE, FROM_HERE,
base::BindOnce(&VSyncThreadWin::WaitForVSync, base::Unretained(this))); base::BindOnce(&VSyncThreadWin::WaitForVSync, base::Unretained(this)));
} }
} }
void VSyncThreadWin::RemoveObserver(VSyncObserver* obs) {
base::AutoLock auto_lock(lock_);
observers_.erase(obs);
}
void VSyncThreadWin::WaitForVSync() { void VSyncThreadWin::WaitForVSync() {
// From Raymond Chen's blog "How do I get a handle to the primary monitor?" HMONITOR monitor = MonitorFromWindow(window_, MONITOR_DEFAULTTONEAREST);
// https://devblogs.microsoft.com/oldnewthing/20141106-00/?p=43683 if (window_monitor_ != monitor) {
HMONITOR monitor = MonitorFromWindow(nullptr, MONITOR_DEFAULTTOPRIMARY); window_monitor_ = monitor;
if (primary_monitor_ != monitor) { window_output_ = DXGIOutputFromMonitor(monitor, d3d11_device_);
primary_monitor_ = monitor;
primary_output_ = DXGIOutputFromMonitor(monitor, d3d11_device_);
} }
base::TimeDelta interval = base::TimeDelta::FromSecondsD(1.0 / 60); base::TimeDelta interval = base::TimeDelta::FromSecondsD(1.0 / 60);
...@@ -112,13 +102,13 @@ void VSyncThreadWin::WaitForVSync() { ...@@ -112,13 +102,13 @@ void VSyncThreadWin::WaitForVSync() {
base::TimeTicks wait_for_vblank_start_time = base::TimeTicks::Now(); base::TimeTicks wait_for_vblank_start_time = base::TimeTicks::Now();
bool wait_for_vblank_succeeded = bool wait_for_vblank_succeeded =
primary_output_ && SUCCEEDED(primary_output_->WaitForVBlank()); window_output_ && SUCCEEDED(window_output_->WaitForVBlank());
// WaitForVBlank returns very early instead of waiting until vblank when the // WaitForVBlank returns very early instead of waiting until vblank when the
// monitor goes to sleep. We use 1ms as a threshold for the duration of // monitor goes to sleep. We use 1ms as a threshold for the duration of
// WaitForVBlank and fallback to Sleep() if it returns before that. This // WaitForVBlank and fallback to Sleep() if it returns before that. This
// could happen during normal operation for the first call after the vsync // could happen during normal operation for the first call after the vsync
// thread becomes non-idle, but it shouldn't happen often. // callback is enabled, but it shouldn't happen often.
const auto kVBlankIntervalThreshold = base::TimeDelta::FromMilliseconds(1); const auto kVBlankIntervalThreshold = base::TimeDelta::FromMilliseconds(1);
base::TimeDelta wait_for_vblank_elapsed_time = base::TimeDelta wait_for_vblank_elapsed_time =
base::TimeTicks::Now() - wait_for_vblank_start_time; base::TimeTicks::Now() - wait_for_vblank_start_time;
...@@ -129,15 +119,17 @@ void VSyncThreadWin::WaitForVSync() { ...@@ -129,15 +119,17 @@ void VSyncThreadWin::WaitForVSync() {
} }
base::AutoLock auto_lock(lock_); base::AutoLock auto_lock(lock_);
if (!observers_.empty()) { DCHECK(started_);
if (enabled_) {
vsync_thread_.task_runner()->PostTask( vsync_thread_.task_runner()->PostTask(
FROM_HERE, FROM_HERE,
base::BindOnce(&VSyncThreadWin::WaitForVSync, base::Unretained(this))); base::BindOnce(&VSyncThreadWin::WaitForVSync, base::Unretained(this)));
base::TimeTicks vsync_time = base::TimeTicks::Now(); // Release lock before running callback to guard against any reentracny
for (auto* obs : observers_) // deadlock.
obs->OnVSync(vsync_time, interval); base::AutoUnlock auto_unlock(lock_);
callback_.Run(base::TimeTicks::Now(), interval);
} else { } else {
is_idle_ = true; started_ = false;
} }
} }
......
...@@ -9,53 +9,48 @@ ...@@ -9,53 +9,48 @@
#include <windows.h> #include <windows.h>
#include <wrl/client.h> #include <wrl/client.h>
#include "base/containers/flat_set.h"
#include "base/threading/thread.h" #include "base/threading/thread.h"
#include "ui/gl/gl_export.h" #include "ui/gl/gl_export.h"
namespace base {
template <typename T>
struct DefaultSingletonTraits;
} // namespace base
namespace gl { namespace gl {
class VSyncObserver;
// Helper singleton that wraps a thread for calling IDXGIOutput::WaitForVBlank() // Helper class that manages a thread for calling IDXGIOutput::WaitForVBlank()
// for the primary monitor, and notifies observers on the same thread. Observers // for the output corresponding to the given |window|, and runs |callback| on
// can be added or removed on the main thread, and the vsync thread goes to // the same thread. The callback can be enabled or disabled via SetEnabled().
// sleep if there are no observers. This is used by DirectCompositionSurfaceWin // This is used by DirectCompositionSurfaceWin to plumb vsync signal back to the
// to plumb vsync signal back to the display compositor's BeginFrameSource. // display compositor's BeginFrameSource.
class GL_EXPORT VSyncThreadWin { class GL_EXPORT VSyncThreadWin {
public: public:
static VSyncThreadWin* GetInstance(); using VSyncCallback =
base::RepeatingCallback<void(base::TimeTicks, base::TimeDelta)>;
VSyncThreadWin(HWND window,
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device,
VSyncCallback callback);
~VSyncThreadWin();
// These methods are not rentrancy safe, and shouldn't be called inside void SetEnabled(bool enabled);
// VSyncObserver::OnVSync. It's safe to assume that these can be called only
// from the main thread.
void AddObserver(VSyncObserver* obs);
void RemoveObserver(VSyncObserver* obs);
private: private:
friend struct base::DefaultSingletonTraits<VSyncThreadWin>;
VSyncThreadWin();
~VSyncThreadWin();
void WaitForVSync(); void WaitForVSync();
base::Thread vsync_thread_; base::Thread vsync_thread_;
// Used on vsync thread only after initialization. // Used on vsync thread only after initialization.
const HWND window_;
const Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device_; const Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device_;
HMONITOR primary_monitor_ = nullptr; const VSyncCallback callback_;
Microsoft::WRL::ComPtr<IDXGIOutput> primary_output_;
// Used on vsync thread exclusively.
HMONITOR window_monitor_ = nullptr;
Microsoft::WRL::ComPtr<IDXGIOutput> window_output_;
base::Lock lock_; base::Lock lock_;
bool GUARDED_BY(lock_) is_idle_ = true; bool GUARDED_BY(lock_) enabled_ = false;
base::flat_set<VSyncObserver*> GUARDED_BY(lock_) observers_; bool GUARDED_BY(lock_) started_ = false;
DISALLOW_COPY_AND_ASSIGN(VSyncThreadWin); DISALLOW_COPY_AND_ASSIGN(VSyncThreadWin);
}; };
} // namespace gl } // namespace gl
#endif // UI_GL_VSYNC_THREAD_WIN_H_ #endif // UI_GL_VSYNC_THREAD_WIN_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment