Commit 56c883db authored by Peng Huang's avatar Peng Huang Committed by Commit Bot

GLX: implement GLSurface PresentationCallback

This CL implements GLSurface PresentationCallback for GLX. It uses
OpenGL GpuTimer to query the |timestamp| for GPU finishes renderering
the back buffer, and use the closest VSync after the |timestamp| to
run presentation callback.

Bug: 776877
Cq-Include-Trybots: master.tryserver.chromium.android:android_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel
Change-Id: I87f40022555b988e9cbe5cd628979c15f6043f0d
Reviewed-on: https://chromium-review.googlesource.com/809704Reviewed-by: default avatardanakj <danakj@chromium.org>
Reviewed-by: default avatarAntoine Labour <piman@chromium.org>
Reviewed-by: default avatarDaniel Nicoara <dnicoara@chromium.org>
Commit-Queue: Peng Huang <penghuang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#523646}
parent 5822c72b
......@@ -216,4 +216,14 @@ void SoftwareOutputDeviceMac::GetVSyncParameters(
update_vsync_callback_ = callback;
}
bool SoftwareOutputDeviceMac::GetVSyncParametersIfAvailable(
base::TimeTicks* timebase,
base::TimeDelta* interval) {
return false;
}
bool SoftwareOutputDeviceMac::SupportGetVSyncParametersIfAvailable() {
return false;
}
} // namespace viz
......@@ -38,6 +38,9 @@ class VIZ_SERVICE_EXPORT SoftwareOutputDeviceMac : public SoftwareOutputDevice,
// gfx::VSyncProvider implementation.
void GetVSyncParameters(
const gfx::VSyncProvider::UpdateVSyncCallback& callback) override;
bool GetVSyncParametersIfAvailable(base::TimeTicks* timebase,
base::TimeDelta* interval) override;
bool SupportGetVSyncParametersIfAvailable() override;
// Testing methods.
SkRegion LastCopyRegionForTesting() const {
......
......@@ -31,6 +31,13 @@ class FakeVSyncProvider : public gfx::VSyncProvider {
call_count_++;
}
bool GetVSyncParametersIfAvailable(base::TimeTicks* timebase,
base::TimeDelta* interval) override {
return false;
}
bool SupportGetVSyncParametersIfAvailable() override { return false; }
int call_count() const { return call_count_; }
void set_timebase(base::TimeTicks timebase) { timebase_ = timebase; }
......
......@@ -663,6 +663,16 @@ void GpuVSyncProviderWin::GetVSyncParameters(
// thread.
}
bool GpuVSyncProviderWin::GetVSyncParametersIfAvailable(
base::TimeTicks* timebase,
base::TimeDelta* interval) {
return false;
}
bool GpuVSyncProviderWin::SupportGetVSyncParametersIfAvailable() {
return false;
}
void GpuVSyncProviderWin::OnVSync(base::TimeTicks timestamp,
base::TimeDelta interval) {
DCHECK(vsync_worker_->BelongsToWorkerThread());
......
......@@ -31,6 +31,9 @@ class GPU_EXPORT GpuVSyncProviderWin : public gfx::VSyncProvider {
// This class ignores this method and updates VSync directly via a
// worker thread IPC call.
void GetVSyncParameters(const UpdateVSyncCallback& callback) override;
bool GetVSyncParametersIfAvailable(base::TimeTicks* timebase,
base::TimeDelta* interval) override;
bool SupportGetVSyncParametersIfAvailable() override;
private:
void OnVSync(base::TimeTicks timestamp, base::TimeDelta interval);
......
......@@ -11,4 +11,16 @@ void FixedVSyncProvider::GetVSyncParameters(
callback.Run(timebase_, interval_);
}
bool FixedVSyncProvider::GetVSyncParametersIfAvailable(
base::TimeTicks* timebase,
base::TimeDelta* interval) {
*timebase = timebase_;
*interval = interval_;
return true;
}
bool FixedVSyncProvider::SupportGetVSyncParametersIfAvailable() {
return true;
}
} // namespace gfx
......@@ -26,6 +26,14 @@ class GFX_EXPORT VSyncProvider {
// 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;
// Similar to GetVSyncParameters(). It returns true, if the data is available.
// Otherwise false is returned.
virtual bool GetVSyncParametersIfAvailable(base::TimeTicks* timebase,
base::TimeDelta* interval) = 0;
// Returns true, if GetVSyncParametersIfAvailable is supported.
virtual bool SupportGetVSyncParametersIfAvailable() = 0;
};
// Provides a constant timebase and interval.
......@@ -38,6 +46,9 @@ class GFX_EXPORT FixedVSyncProvider : public VSyncProvider {
~FixedVSyncProvider() override {}
void GetVSyncParameters(const UpdateVSyncCallback& callback) override;
bool GetVSyncParametersIfAvailable(base::TimeTicks* timebase,
base::TimeDelta* interval) override;
bool SupportGetVSyncParametersIfAvailable() override;
private:
base::TimeTicks timebase_;
......
......@@ -26,6 +26,7 @@
#include "ui/gfx/x/x11_connection.h"
#include "ui/gfx/x/x11_types.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_visual_picker_glx.h"
#include "ui/gl/sync_control_vsync_provider.h"
......@@ -288,7 +289,7 @@ class SGIVideoSyncProviderThreadShim {
base::TimeDelta::FromSeconds(1) / 60;
task_runner_->PostTask(FROM_HERE,
base::Bind(callback, now, kDefaultInterval));
base::BindOnce(callback, now, kDefaultInterval));
}
private:
......@@ -325,7 +326,7 @@ class SGIVideoSyncVSyncProvider
cancel_vsync_flag_(shim_->cancel_vsync_flag()),
vsync_lock_(shim_->vsync_lock()) {
vsync_thread_->task_runner()->PostTask(
FROM_HERE, base::Bind(&SGIVideoSyncProviderThreadShim::Initialize,
FROM_HERE, base::BindOnce(&SGIVideoSyncProviderThreadShim::Initialize,
base::Unretained(shim_.get())));
}
......@@ -347,14 +348,21 @@ class SGIVideoSyncVSyncProvider
new gfx::VSyncProvider::UpdateVSyncCallback(callback));
vsync_thread_->task_runner()->PostTask(
FROM_HERE,
base::Bind(
&SGIVideoSyncProviderThreadShim::GetVSyncParameters,
base::BindOnce(&SGIVideoSyncProviderThreadShim::GetVSyncParameters,
base::Unretained(shim_.get()),
base::Bind(&SGIVideoSyncVSyncProvider::PendingCallbackRunner,
base::BindRepeating(
&SGIVideoSyncVSyncProvider::PendingCallbackRunner,
AsWeakPtr())));
}
}
bool GetVSyncParametersIfAvailable(base::TimeTicks* timebase,
base::TimeDelta* interval) override {
return false;
}
bool SupportGetVSyncParametersIfAvailable() override { return false; }
private:
void PendingCallbackRunner(const base::TimeTicks timebase,
const base::TimeDelta interval) {
......@@ -558,11 +566,9 @@ NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX(gfx::AcceleratedWidget window)
window_(0),
glx_window_(0),
config_(nullptr),
visual_id_(CopyFromParent) {}
GLXDrawable NativeViewGLSurfaceGLX::GetDrawableHandle() const {
return glx_window_;
}
visual_id_(CopyFromParent),
waiting_for_vsync_parameters_(false),
weak_ptr_factory_(this) {}
bool NativeViewGLSurfaceGLX::Initialize(GLSurfaceFormat format) {
XWindowAttributes attributes;
......@@ -619,12 +625,23 @@ bool NativeViewGLSurfaceGLX::Initialize(GLSurfaceFormat format) {
base::TimeDelta::FromSeconds(1) / 59.9;
vsync_provider_.reset(
new gfx::FixedVSyncProvider(kDefaultTimebase, kDefaultInterval));
vsync_timebase_ = kDefaultTimebase;
vsync_interval_ = kDefaultInterval;
}
return true;
}
void NativeViewGLSurfaceGLX::Destroy() {
// Discard pending frames and run presentation callback with empty
// PresentationFeedback.
for (auto& frame : pending_frames_) {
bool has_context = gl_context_->IsCurrent(this);
frame.timer->Destroy(has_context);
frame.callback.Run(gfx::PresentationFeedback());
}
pending_frames_.clear();
vsync_provider_.reset();
if (glx_window_) {
glXDestroyWindow(g_display, glx_window_);
......@@ -655,10 +672,11 @@ bool NativeViewGLSurfaceGLX::IsOffscreen() {
gfx::SwapResult NativeViewGLSurfaceGLX::SwapBuffers(
const PresentationCallback& callback) {
// TODO(penghuang): Provide presentation feedback. https://crbug.com/776877
TRACE_EVENT2("gpu", "NativeViewGLSurfaceGLX:RealSwapBuffers", "width",
GetSize().width(), "height", GetSize().height());
PreSwapBuffers(callback);
glXSwapBuffers(g_display, GetDrawableHandle());
PostSwapBuffers();
return gfx::SwapResult::SWAP_ACK;
}
......@@ -670,6 +688,10 @@ void* NativeViewGLSurfaceGLX::GetHandle() {
return reinterpret_cast<void*>(GetDrawableHandle());
}
bool NativeViewGLSurfaceGLX::SupportsPresentationCallback() {
return true;
}
bool NativeViewGLSurfaceGLX::SupportsPostSubBuffer() {
return g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer;
}
......@@ -694,12 +716,36 @@ gfx::SwapResult NativeViewGLSurfaceGLX::PostSubBuffer(
int width,
int height,
const PresentationCallback& callback) {
// TODO(penghuang): Provide presentation feedback. https://crbug.com/776877
DCHECK(g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer);
PreSwapBuffers(callback);
glXCopySubBufferMESA(g_display, GetDrawableHandle(), x, y, width, height);
PostSwapBuffers();
return gfx::SwapResult::SWAP_ACK;
}
bool NativeViewGLSurfaceGLX::OnMakeCurrent(GLContext* context) {
if (context == gl_context_)
return GLSurfaceGLX::OnMakeCurrent(context);
// If context is changed, we assume SwapBuffers issued for previous context
// will be discarded.
if (gpu_timing_client_) {
gpu_timing_client_ = nullptr;
for (auto& frame : pending_frames_) {
frame.timer->Destroy(false /* has_context */);
frame.callback.Run(gfx::PresentationFeedback());
}
pending_frames_.clear();
}
gl_context_ = context;
gpu_timing_client_ = context->CreateGPUTimingClient();
if (!gpu_timing_client_->IsAvailable())
gpu_timing_client_ = nullptr;
return GLSurfaceGLX::OnMakeCurrent(context);
}
gfx::VSyncProvider* NativeViewGLSurfaceGLX::GetVSyncProvider() {
return vsync_provider_.get();
}
......@@ -721,6 +767,180 @@ bool NativeViewGLSurfaceGLX::CanHandleEvent(XEvent* event) {
event->xexpose.window == static_cast<Window>(window_);
}
GLXDrawable NativeViewGLSurfaceGLX::GetDrawableHandle() const {
return glx_window_;
}
void NativeViewGLSurfaceGLX::PreSwapBuffers(
const PresentationCallback& callback) {
std::unique_ptr<GPUTimer> timer;
if (gpu_timing_client_) {
timer = gpu_timing_client_->CreateGPUTimer(false /* prefer_elapsed_time */);
timer->QueryTimeStamp();
}
pending_frames_.push_back(Frame(std::move(timer), callback));
}
void NativeViewGLSurfaceGLX::PostSwapBuffers() {
if (!waiting_for_vsync_parameters_)
CheckPendingFrames();
}
void NativeViewGLSurfaceGLX::CheckPendingFrames() {
DCHECK(gl_context_ || pending_frames_.empty());
// VSync parameters are fixed.
bool fixed_vsync =
!(g_glx_oml_sync_control_supported || g_glx_sgi_video_sync_supported);
// VSyncProvier::GetVSyncParameters returns VSync parameters via callback
// immediatelly.
bool get_vsync_parameters_return_immediately =
vsync_provider_->SupportGetVSyncParametersIfAvailable();
// The VSync timestamp is from the driver.
bool hw_clock = g_glx_oml_sync_control_supported;
if (get_vsync_parameters_return_immediately && !fixed_vsync) {
if (!vsync_provider_->GetVSyncParametersIfAvailable(&vsync_timebase_,
&vsync_interval_)) {
vsync_timebase_ = base::TimeTicks();
vsync_interval_ = base::TimeDelta();
LOG(ERROR) << "GetVSyncParametersIfAvailable() failed!";
}
}
if (pending_frames_.empty())
return;
bool disjoint_occurred =
gpu_timing_client_ && gpu_timing_client_->CheckAndResetTimerErrors();
if (disjoint_occurred || !gpu_timing_client_) {
// If GPUTimer is not avaliable or disjoint occurred, we just run
// presentation callback with current system time.
for (auto& frame : pending_frames_) {
frame.callback.Run(gfx::PresentationFeedback(
base::TimeTicks::Now(), vsync_interval_, 0 /* flags */));
}
pending_frames_.clear();
return;
}
bool need_update_vsync = false;
while (!pending_frames_.empty()) {
auto& frame = pending_frames_.front();
if (!frame.timer->IsAvailable())
break;
int64_t start = 0;
int64_t end = 0;
frame.timer->GetStartEndTimestamps(&start, &end);
auto timestamp =
base::TimeTicks() + base::TimeDelta::FromMicroseconds(start);
// Helper lambda for running the presentation callback and releasing the
// frame.
auto frame_presentation_callback =
[this, &frame](const gfx::PresentationFeedback& feedback) {
frame.timer->Destroy(true /* has_context */);
frame.callback.Run(feedback);
pending_frames_.pop_front();
};
if (vsync_interval_.is_zero() || fixed_vsync) {
// If VSync parameters are fixed or not avaliable, we just run
// presentation callbacks with timestamp from GPUTimers.
frame_presentation_callback(
gfx::PresentationFeedback(timestamp, vsync_interval_, 0 /* flags */));
} else if (timestamp < vsync_timebase_) {
// We got a VSync whose timestamp is after GPU finished renderering this
// back buffer.
uint32_t flags = gfx::PresentationFeedback::kVSync |
gfx::PresentationFeedback::kHWCompletion;
auto delta = vsync_timebase_ - timestamp;
if (delta < vsync_interval_) {
// The |vsync_timebase_| is the closest VSync's timestamp after the GPU
// finished renderering.
timestamp = vsync_timebase_;
if (hw_clock)
flags |= gfx::PresentationFeedback::kHWClock;
} else {
// The |vsync_timebase_| isn't the closest VSync's timestamp after the
// GPU finished renderering. We have to compute the closest VSync's
// timestmp.
timestamp =
timestamp.SnappedToNextTick(vsync_timebase_, vsync_interval_);
}
frame_presentation_callback(
gfx::PresentationFeedback(timestamp, vsync_interval_, flags));
} else {
// The |vsync_timebase_| is earlier than |timestamp| of the current
// pending frame. We need update vsync parameters.
need_update_vsync = true;
// We compute the next VSync's timestamp and use it to run
// callback.
auto delta = timestamp - vsync_timebase_;
auto offset = delta % vsync_interval_;
timestamp += vsync_interval_ - offset;
uint32_t flags = gfx::PresentationFeedback::kVSync;
frame_presentation_callback(
gfx::PresentationFeedback(timestamp, vsync_interval_, flags));
}
}
if (waiting_for_vsync_parameters_ || !need_update_vsync ||
pending_frames_.empty())
return;
waiting_for_vsync_parameters_ = true;
if (!get_vsync_parameters_return_immediately) {
// In this case, the |vsync_provider_| will call the callback when the next
// VSync is received.
vsync_provider_->GetVSyncParameters(
base::BindRepeating(&NativeViewGLSurfaceGLX::UpdateVSyncCallback,
weak_ptr_factory_.GetWeakPtr()));
return;
}
// If the |vsync_provider_| can not notify us for the next VSync
// asynchronically, we have to compute the next VSync time and post a delayed
// task so we can check the VSync later.
base::TimeDelta interval = vsync_interval_.is_zero()
? base::TimeDelta::FromSeconds(1) / 60
: vsync_interval_;
auto now = base::TimeTicks::Now();
auto next_vsync = now.SnappedToNextTick(vsync_timebase_, interval);
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&NativeViewGLSurfaceGLX::CheckPendingFramesCallback,
weak_ptr_factory_.GetWeakPtr()),
next_vsync - now);
} // namespace gl
void NativeViewGLSurfaceGLX::CheckPendingFramesCallback() {
DCHECK(waiting_for_vsync_parameters_);
waiting_for_vsync_parameters_ = false;
CheckPendingFrames();
}
void NativeViewGLSurfaceGLX::UpdateVSyncCallback(
const base::TimeTicks timebase,
const base::TimeDelta interval) {
DCHECK(waiting_for_vsync_parameters_);
waiting_for_vsync_parameters_ = false;
vsync_timebase_ = timebase;
vsync_interval_ = interval;
CheckPendingFrames();
}
NativeViewGLSurfaceGLX::Frame::Frame(Frame&& other) = default;
NativeViewGLSurfaceGLX::Frame::Frame(std::unique_ptr<GPUTimer>&& timer,
const PresentationCallback& callback)
: timer(std::move(timer)), callback(callback) {}
NativeViewGLSurfaceGLX::Frame::~Frame() = default;
NativeViewGLSurfaceGLX::Frame& NativeViewGLSurfaceGLX::Frame::operator=(
Frame&& other) = default;
UnmappedNativeViewGLSurfaceGLX::UnmappedNativeViewGLSurfaceGLX(
const gfx::Size& size)
: size_(size), config_(nullptr), window_(0), glx_window_(0) {
......
......@@ -11,13 +11,16 @@
#include <string>
#include "base/compiler_specific.h"
#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/vsync_provider.h"
#include "ui/gfx/x/x11_types.h"
#include "ui/gl/gl_export.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/gpu_timing.h"
namespace gl {
......@@ -76,6 +79,7 @@ class GL_EXPORT NativeViewGLSurfaceGLX : public GLSurfaceGLX {
gfx::SwapResult SwapBuffers(const PresentationCallback& callback) override;
gfx::Size GetSize() override;
void* GetHandle() override;
bool SupportsPresentationCallback() override;
bool SupportsPostSubBuffer() override;
void* GetConfig() override;
GLSurfaceFormat GetFormat() override;
......@@ -85,6 +89,7 @@ class GL_EXPORT NativeViewGLSurfaceGLX : public GLSurfaceGLX {
int width,
int height,
const PresentationCallback& callback) override;
bool OnMakeCurrent(GLContext* context) override;
gfx::VSyncProvider* GetVSyncProvider() override;
VisualID GetVisualID() const { return visual_id_; }
......@@ -103,10 +108,23 @@ class GL_EXPORT NativeViewGLSurfaceGLX : public GLSurfaceGLX {
bool CanHandleEvent(XEvent* xevent);
gfx::AcceleratedWidget window() const { return window_; }
private:
// The handle for the drawable to make current or swap.
GLXDrawable GetDrawableHandle() const;
void PreSwapBuffers(const PresentationCallback& callback);
void PostSwapBuffers();
// Check |pending_frames_| and run presentation callbacks.
void CheckPendingFrames();
// Callback used by PostDelayedTask for running CheckPendingFrames().
void CheckPendingFramesCallback();
void UpdateVSyncCallback(const base::TimeTicks timebase,
const base::TimeDelta interval);
// Window passed in at creation. Always valid.
gfx::AcceleratedWidget parent_window_;
......@@ -122,6 +140,26 @@ class GL_EXPORT NativeViewGLSurfaceGLX : public GLSurfaceGLX {
std::unique_ptr<gfx::VSyncProvider> vsync_provider_;
scoped_refptr<GLContext> gl_context_;
scoped_refptr<GPUTimingClient> gpu_timing_client_;
struct Frame {
Frame(Frame&& other);
Frame(std::unique_ptr<GPUTimer>&& timer,
const PresentationCallback& callback);
~Frame();
Frame& operator=(Frame&& other);
std::unique_ptr<GPUTimer> timer;
PresentationCallback callback;
};
base::circular_deque<Frame> pending_frames_;
base::TimeTicks vsync_timebase_;
base::TimeDelta vsync_interval_;
bool waiting_for_vsync_parameters_;
base::WeakPtrFactory<NativeViewGLSurfaceGLX> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceGLX);
};
......
......@@ -136,7 +136,7 @@ class GL_EXPORT GPUTimingClient
// CheckAndResetTimerErrors has to be called before reading timestamps
// from GPUTimers instances and after making sure all the timers
// were available.
// If the returned value is false, all the previous timers should be
// If the returned value is true, all the previous timers should be
// discarded.
bool CheckAndResetTimerErrors();
......
......@@ -38,6 +38,15 @@ SyncControlVSyncProvider::~SyncControlVSyncProvider() {}
void SyncControlVSyncProvider::GetVSyncParameters(
const UpdateVSyncCallback& callback) {
base::TimeTicks timebase;
base::TimeDelta interval;
if (GetVSyncParametersIfAvailable(&timebase, &interval))
callback.Run(timebase, interval);
}
bool SyncControlVSyncProvider::GetVSyncParametersIfAvailable(
base::TimeTicks* timebase_out,
base::TimeDelta* interval_out) {
TRACE_EVENT0("gpu", "SyncControlVSyncProvider::GetVSyncParameters");
#if defined(OS_LINUX)
// The actual clock used for the system time returned by glXGetSyncValuesOML
......@@ -51,7 +60,7 @@ void SyncControlVSyncProvider::GetVSyncParameters(
int64_t media_stream_counter;
int64_t swap_buffer_counter;
if (!GetSyncValues(&system_time, &media_stream_counter, &swap_buffer_counter))
return;
return false;
// Both Intel and Mali drivers will return TRUE for GetSyncValues
// but a value of 0 for MSC if they cannot access the CRTC data structure
......@@ -61,7 +70,7 @@ void SyncControlVSyncProvider::GetVSyncParameters(
if (invalid_msc_) {
LOG_IF(ERROR, !prev_invalid_msc) << "glXGetSyncValuesOML "
"should not return TRUE with a media stream counter of 0.";
return;
return false;
}
struct timespec real_time;
......@@ -90,7 +99,7 @@ void SyncControlVSyncProvider::GetVSyncParameters(
// Return if |system_time| is more than 1 frames in the future.
int64_t interval_in_microseconds = last_good_interval_.InMicroseconds();
if (system_time > monotonic_time_in_microseconds + interval_in_microseconds)
return;
return false;
// If |system_time| is slightly in the future, adjust it to the previous
// frame and use the last frame counter to prevent issues in the callback.
......@@ -100,7 +109,7 @@ void SyncControlVSyncProvider::GetVSyncParameters(
}
if (monotonic_time_in_microseconds - system_time >
base::Time::kMicrosecondsPerSecond)
return;
return false;
const base::TimeTicks timebase =
base::TimeTicks() + base::TimeDelta::FromMicroseconds(system_time);
......@@ -154,8 +163,20 @@ void SyncControlVSyncProvider::GetVSyncParameters(
last_timebase_ = timebase;
last_media_stream_counter_ = media_stream_counter;
callback.Run(timebase, last_good_interval_);
*timebase_out = timebase;
*interval_out = last_good_interval_;
return true;
#else
return false;
#endif // defined(OS_LINUX)
}
bool SyncControlVSyncProvider::SupportGetVSyncParametersIfAvailable() {
#if defined(OS_LINUX)
return true;
#else
return false;
#endif
}
} // namespace gl
......@@ -21,6 +21,9 @@ class SyncControlVSyncProvider : public gfx::VSyncProvider {
~SyncControlVSyncProvider() override;
void GetVSyncParameters(const UpdateVSyncCallback& callback) override;
bool GetVSyncParametersIfAvailable(base::TimeTicks* timebase,
base::TimeDelta* interval) override;
bool SupportGetVSyncParametersIfAvailable() override;
static constexpr bool IsSupported() {
#if defined(OS_LINUX)
......
......@@ -30,6 +30,15 @@ void VSyncProviderWin::InitializeOneOff() {
}
void VSyncProviderWin::GetVSyncParameters(const UpdateVSyncCallback& callback) {
base::TimeTicks timebase;
base::TimeDelta interval;
if (GetVSyncParametersIfAvailable(&timebase, &interval))
callback.Run(timebase, interval);
}
bool VSyncProviderWin::GetVSyncParametersIfAvailable(
base::TimeTicks* out_timebase,
base::TimeDelta* out_interval) {
TRACE_EVENT0("gpu", "WinVSyncProvider::GetVSyncParameters");
base::TimeTicks timebase;
......@@ -105,9 +114,16 @@ void VSyncProviderWin::GetVSyncParameters(const UpdateVSyncCallback& callback) {
}
}
if (!interval.is_zero()) {
callback.Run(timebase, interval);
}
if (interval.is_zero())
return false;
*out_timebase = timebase;
*out_interval = interval;
return true;
}
bool VSyncProviderWin::SupportGetVSyncParametersIfAvailable() {
return true;
}
} // namespace gl
......@@ -20,6 +20,9 @@ class GL_EXPORT VSyncProviderWin : public gfx::VSyncProvider {
// gfx::VSyncProvider overrides;
void GetVSyncParameters(const UpdateVSyncCallback& callback) override;
bool GetVSyncParametersIfAvailable(base::TimeTicks* timebase,
base::TimeDelta* interval) override;
bool SupportGetVSyncParametersIfAvailable() override;
private:
gfx::AcceleratedWidget window_;
......
......@@ -17,4 +17,14 @@ void DrmVSyncProvider::GetVSyncParameters(const UpdateVSyncCallback& callback) {
window_->GetVSyncParameters(callback);
}
bool DrmVSyncProvider::GetVSyncParametersIfAvailable(
base::TimeTicks* timebase,
base::TimeDelta* interval) {
return false;
}
bool DrmVSyncProvider::SupportGetVSyncParametersIfAvailable() {
return false;
}
} // namespace ui
......@@ -19,6 +19,9 @@ class DrmVSyncProvider : public gfx::VSyncProvider {
~DrmVSyncProvider() override;
void GetVSyncParameters(const UpdateVSyncCallback& callback) override;
bool GetVSyncParametersIfAvailable(base::TimeTicks* timebase,
base::TimeDelta* interval) override;
bool SupportGetVSyncParametersIfAvailable() override;
private:
DrmWindowProxy* window_;
......
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