Commit dd9f811b authored by Vikas Soni's avatar Vikas Soni Committed by Commit Bot

Add support for reporting EGL Timestamps via

presentation feedback.

This CL adds support for reporting egl_composite_interval and
presentation_time via the presentation feedabck.
GLSurfacePresentationHelper uses the new interface
EGLTImestampClient to query the egl timestamp info.

Bug: 790761
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel
Change-Id: I7e1f3200bba41bf3252b8acedc68393eeeb76df5
Reviewed-on: https://chromium-review.googlesource.com/1106600
Commit-Queue: vikas soni <vikassoni@chromium.org>
Reviewed-by: default avatarAntoine Labour <piman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#583360}
parent a8bdfd02
...@@ -60,6 +60,7 @@ component("gl") { ...@@ -60,6 +60,7 @@ component("gl") {
"ca_renderer_layer_params.h", "ca_renderer_layer_params.h",
"dc_renderer_layer_params.cc", "dc_renderer_layer_params.cc",
"dc_renderer_layer_params.h", "dc_renderer_layer_params.h",
"egl_timestamps.h",
"gl_bindings.cc", "gl_bindings.cc",
"gl_bindings.h", "gl_bindings.h",
"gl_bindings_autogen_gl.cc", "gl_bindings_autogen_gl.cc",
......
// Copyright (c) 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.
#ifndef UI_GL_EGL_TIMESTAMPS_H_
#define UI_GL_EGL_TIMESTAMPS_H_
#include "base/time/time.h"
#include "ui/gl/gl_export.h"
namespace gl {
// Interface to query EGL timestamps.
class GL_EXPORT EGLTimestampClient {
public:
virtual ~EGLTimestampClient() {}
// Returns whether EGL Timestamps are supported or not.
virtual bool IsEGLTimestampSupported() const = 0;
// Returns false if the egl timestamps are pending for the given frame id. If
// timestamps are pending, it means the frame is not yet done. Also returns
// the presentation time, composite interval and presentation flags for a
// frame as out parameters.
virtual bool GetFrameTimestampInfoIfAvailable(
base::TimeTicks* presentation_time,
base::TimeDelta* composite_interval,
uint32_t* presentation_flags,
int frame_id) = 0;
};
} // namespace gl
#endif // UI_GL_EGL_TIMESTAMPS_H_
...@@ -243,6 +243,10 @@ bool GLSurface::SupportsPlaneGpuFences() const { ...@@ -243,6 +243,10 @@ bool GLSurface::SupportsPlaneGpuFences() const {
return false; return false;
} }
EGLTimestampClient* GLSurface::GetEGLTimestampClient() {
return nullptr;
}
GLSurface* GLSurface::GetCurrent() { GLSurface* GLSurface::GetCurrent() {
return current_surface_.Pointer()->Get(); return current_surface_.Pointer()->Get();
} }
......
...@@ -37,6 +37,7 @@ struct DCRendererLayerParams; ...@@ -37,6 +37,7 @@ struct DCRendererLayerParams;
namespace gl { namespace gl {
class GLContext; class GLContext;
class EGLTimestampClient;
// Encapsulates a surface that can be rendered to with GL, hiding platform // Encapsulates a surface that can be rendered to with GL, hiding platform
// specific management. // specific management.
...@@ -298,6 +299,9 @@ class GL_EXPORT GLSurface : public base::RefCounted<GLSurface> { ...@@ -298,6 +299,9 @@ class GL_EXPORT GLSurface : public base::RefCounted<GLSurface> {
// triple-buffered surfaces this would return 3, etc. // triple-buffered surfaces this would return 3, etc.
virtual int GetBufferCount() const; virtual int GetBufferCount() const;
// Return the interface used for querying EGL timestamps.
virtual EGLTimestampClient* GetEGLTimestampClient();
static GLSurface* GetCurrent(); static GLSurface* GetCurrent();
protected: protected:
......
...@@ -1109,6 +1109,13 @@ void NativeViewGLSurfaceEGL::SetEnableSwapTimestamps() { ...@@ -1109,6 +1109,13 @@ void NativeViewGLSurfaceEGL::SetEnableSwapTimestamps() {
eglSurfaceAttrib(GetDisplay(), surface_, EGL_TIMESTAMPS_ANDROID, EGL_TRUE); eglSurfaceAttrib(GetDisplay(), surface_, EGL_TIMESTAMPS_ANDROID, EGL_TRUE);
// Check if egl composite interval is supported or not. If not then return.
// Else check which other timestamps are supported.
EGLint interval_name = EGL_COMPOSITE_INTERVAL_ANDROID;
if (!eglGetCompositorTimingSupportedANDROID(GetDisplay(), surface_,
interval_name))
return;
static const struct { static const struct {
EGLint egl_name; EGLint egl_name;
const char* name; const char* name;
...@@ -1131,6 +1138,25 @@ void NativeViewGLSurfaceEGL::SetEnableSwapTimestamps() { ...@@ -1131,6 +1138,25 @@ void NativeViewGLSurfaceEGL::SetEnableSwapTimestamps() {
ts.egl_name)) ts.egl_name))
continue; continue;
// For presentation feedback, prefer the actual scan out time, but fallback
// to SurfaceFlinger's composite time since some devices don't support
// the former.
switch (ts.egl_name) {
case EGL_FIRST_COMPOSITION_START_TIME_ANDROID:
// Value of presentation_feedback_index_ relies on the order of
// all_timestamps.
presentation_feedback_index_ =
static_cast<int>(supported_egl_timestamps_.size());
presentation_flags_ = 0;
break;
case EGL_DISPLAY_PRESENT_TIME_ANDROID:
presentation_feedback_index_ =
static_cast<int>(supported_egl_timestamps_.size());
presentation_flags_ = gfx::PresentationFeedback::kVSync |
gfx::PresentationFeedback::kHWCompletion;
break;
}
// Stored in separate vectors so we can pass the egl timestamps // Stored in separate vectors so we can pass the egl timestamps
// directly to the EGL functions. // directly to the EGL functions.
supported_egl_timestamps_.push_back(ts.egl_name); supported_egl_timestamps_.push_back(ts.egl_name);
...@@ -1176,21 +1202,24 @@ gfx::SwapResult NativeViewGLSurfaceEGL::SwapBuffers( ...@@ -1176,21 +1202,24 @@ gfx::SwapResult NativeViewGLSurfaceEGL::SwapBuffers(
return gfx::SwapResult::SWAP_FAILED; return gfx::SwapResult::SWAP_FAILED;
} }
EGLuint64KHR newFrameId = 0; EGLuint64KHR new_frame_id = 0;
bool newFrameIdIsValid = true; bool new_frame_id_is_valid = true;
if (use_egl_timestamps_) { if (use_egl_timestamps_) {
newFrameIdIsValid = new_frame_id_is_valid =
!!eglGetNextFrameIdANDROID(GetDisplay(), surface_, &newFrameId); !!eglGetNextFrameIdANDROID(GetDisplay(), surface_, &new_frame_id);
} }
if (!new_frame_id_is_valid)
new_frame_id = -1;
GLSurfacePresentationHelper::ScopedSwapBuffers scoped_swap_buffers( GLSurfacePresentationHelper::ScopedSwapBuffers scoped_swap_buffers(
presentation_helper_.get(), callback); presentation_helper_.get(), callback, new_frame_id);
if (!eglSwapBuffers(GetDisplay(), surface_)) { if (!eglSwapBuffers(GetDisplay(), surface_)) {
DVLOG(1) << "eglSwapBuffers failed with error " DVLOG(1) << "eglSwapBuffers failed with error "
<< GetLastEGLErrorString(); << GetLastEGLErrorString();
scoped_swap_buffers.set_result(gfx::SwapResult::SWAP_FAILED); scoped_swap_buffers.set_result(gfx::SwapResult::SWAP_FAILED);
} else if (use_egl_timestamps_) { } else if (use_egl_timestamps_) {
UpdateSwapEvents(newFrameId, newFrameIdIsValid); UpdateSwapEvents(new_frame_id, new_frame_id_is_valid);
} }
#if defined(USE_X11) #if defined(USE_X11)
...@@ -1383,6 +1412,80 @@ bool NativeViewGLSurfaceEGL::BuffersFlipped() const { ...@@ -1383,6 +1412,80 @@ bool NativeViewGLSurfaceEGL::BuffersFlipped() const {
return g_use_direct_composition; return g_use_direct_composition;
} }
EGLTimestampClient* NativeViewGLSurfaceEGL::GetEGLTimestampClient() {
// This api call is used by GLSurfacePresentationHelper class which is member
// of this class NativeViewGLSurfaceEGL. Hence its guaranteed "this" pointer
// will live longer than the GLSurfacePresentationHelper class.
return this;
}
bool NativeViewGLSurfaceEGL::IsEGLTimestampSupported() const {
return use_egl_timestamps_;
}
bool NativeViewGLSurfaceEGL::GetFrameTimestampInfoIfAvailable(
base::TimeTicks* presentation_time,
base::TimeDelta* composite_interval,
uint32_t* presentation_flags,
int frame_id) {
DCHECK(presentation_time);
DCHECK(composite_interval);
DCHECK(presentation_flags);
TRACE_EVENT1("gpu", "NativeViewGLSurfaceEGL:GetFrameTimestampInfoIfAvailable",
"frame_id", frame_id);
// Get the composite interval.
EGLint interval_name = EGL_COMPOSITE_INTERVAL_ANDROID;
EGLnsecsANDROID composite_interval_ns = 0;
*presentation_time = base::TimeTicks();
*presentation_flags = 0;
// If an error is generated, we will treat it as a frame done for timestamp
// reporting purpose.
if (!eglGetCompositorTimingANDROID(GetDisplay(), surface_, 1, &interval_name,
&composite_interval_ns)) {
*composite_interval = base::TimeDelta::FromNanoseconds(
base::TimeTicks::kNanosecondsPerSecond / 60);
return true;
}
// If the composite interval is pending, the frame is not yet done.
if (composite_interval_ns == EGL_TIMESTAMP_PENDING_ANDROID) {
return false;
}
DCHECK_GT(composite_interval_ns, 0);
*composite_interval = base::TimeDelta::FromNanoseconds(composite_interval_ns);
// Get the all available timestamps for the frame. If a frame is invalid or
// an error is generated, we will treat it as a frame done for timestamp
// reporting purpose.
std::vector<EGLnsecsANDROID> egl_timestamps(supported_egl_timestamps_.size(),
EGL_TIMESTAMP_INVALID_ANDROID);
if ((frame_id < 0) ||
!eglGetFrameTimestampsANDROID(
GetDisplay(), surface_, frame_id,
static_cast<EGLint>(supported_egl_timestamps_.size()),
supported_egl_timestamps_.data(), egl_timestamps.data())) {
return true;
}
DCHECK_GE(presentation_feedback_index_, 0);
// Get the presentation time.
EGLnsecsANDROID presentation_time_ns =
egl_timestamps[presentation_feedback_index_];
// If the presentation time is pending, the frame is not yet done.
if (presentation_time_ns == EGL_TIMESTAMP_PENDING_ANDROID) {
return false;
}
*presentation_time = base::TimeTicks() +
base::TimeDelta::FromNanoseconds(presentation_time_ns);
*presentation_flags = presentation_flags_;
return true;
}
gfx::SwapResult NativeViewGLSurfaceEGL::SwapBuffersWithDamage( gfx::SwapResult NativeViewGLSurfaceEGL::SwapBuffersWithDamage(
const std::vector<int>& rects, const std::vector<int>& rects,
const PresentationCallback& callback) { const PresentationCallback& callback) {
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "build/build_config.h" #include "build/build_config.h"
#include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size.h"
#include "ui/gfx/vsync_provider.h" #include "ui/gfx/vsync_provider.h"
#include "ui/gl/egl_timestamps.h"
#include "ui/gl/gl_bindings.h" #include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_export.h" #include "ui/gl/gl_export.h"
#include "ui/gl/gl_surface.h" #include "ui/gl/gl_surface.h"
...@@ -103,7 +104,8 @@ class GL_EXPORT GLSurfaceEGL : public GLSurface { ...@@ -103,7 +104,8 @@ class GL_EXPORT GLSurfaceEGL : public GLSurface {
}; };
// Encapsulates an EGL surface bound to a view. // Encapsulates an EGL surface bound to a view.
class GL_EXPORT NativeViewGLSurfaceEGL : public GLSurfaceEGL { class GL_EXPORT NativeViewGLSurfaceEGL : public GLSurfaceEGL,
public EGLTimestampClient {
public: public:
NativeViewGLSurfaceEGL(EGLNativeWindowType window, NativeViewGLSurfaceEGL(EGLNativeWindowType window,
std::unique_ptr<gfx::VSyncProvider> vsync_provider); std::unique_ptr<gfx::VSyncProvider> vsync_provider);
...@@ -144,6 +146,15 @@ class GL_EXPORT NativeViewGLSurfaceEGL : public GLSurfaceEGL { ...@@ -144,6 +146,15 @@ class GL_EXPORT NativeViewGLSurfaceEGL : public GLSurfaceEGL {
std::unique_ptr<gfx::GpuFence> gpu_fence) override; std::unique_ptr<gfx::GpuFence> gpu_fence) override;
bool FlipsVertically() const override; bool FlipsVertically() const override;
bool BuffersFlipped() const override; bool BuffersFlipped() const override;
EGLTimestampClient* GetEGLTimestampClient() override;
// EGLTimestampClient implementation.
bool IsEGLTimestampSupported() const override;
bool GetFrameTimestampInfoIfAvailable(base::TimeTicks* presentation_time,
base::TimeDelta* composite_interval,
uint32_t* presentation_flags,
int frame_id) override;
// Takes care of the platform dependant bits, of any, for creating the window. // Takes care of the platform dependant bits, of any, for creating the window.
virtual bool InitializeNativeWindow(); virtual bool InitializeNativeWindow();
...@@ -167,7 +178,6 @@ class GL_EXPORT NativeViewGLSurfaceEGL : public GLSurfaceEGL { ...@@ -167,7 +178,6 @@ class GL_EXPORT NativeViewGLSurfaceEGL : public GLSurfaceEGL {
// Commit the |pending_overlays_| and clear the vector. Returns false if any // Commit the |pending_overlays_| and clear the vector. Returns false if any
// fail to be committed. // fail to be committed.
bool CommitAndClearPendingOverlays(); bool CommitAndClearPendingOverlays();
void UpdateSwapEvents(EGLuint64KHR newFrameId, bool newFrameIdIsValid); void UpdateSwapEvents(EGLuint64KHR newFrameId, bool newFrameIdIsValid);
void TraceSwapEvents(EGLuint64KHR oldFrameId); void TraceSwapEvents(EGLuint64KHR oldFrameId);
...@@ -191,6 +201,10 @@ class GL_EXPORT NativeViewGLSurfaceEGL : public GLSurfaceEGL { ...@@ -191,6 +201,10 @@ class GL_EXPORT NativeViewGLSurfaceEGL : public GLSurfaceEGL {
std::vector<EGLint> supported_egl_timestamps_; std::vector<EGLint> supported_egl_timestamps_;
std::vector<const char*> supported_event_names_; std::vector<const char*> supported_event_names_;
// PresentationFeedback support.
int presentation_feedback_index_ = -1;
uint32_t presentation_flags_ = 0;
base::queue<SwapInfo> swap_info_queue_; base::queue<SwapInfo> swap_info_queue_;
bool vsync_enabled_ = true; bool vsync_enabled_ = true;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "ui/gfx/vsync_provider.h" #include "ui/gfx/vsync_provider.h"
#include "ui/gl/egl_timestamps.h"
#include "ui/gl/gl_context.h" #include "ui/gl/gl_context.h"
#include "ui/gl/gl_fence.h" #include "ui/gl/gl_fence.h"
#include "ui/gl/gpu_timing.h" #include "ui/gl/gpu_timing.h"
...@@ -16,9 +17,15 @@ namespace gl { ...@@ -16,9 +17,15 @@ namespace gl {
GLSurfacePresentationHelper::ScopedSwapBuffers::ScopedSwapBuffers( GLSurfacePresentationHelper::ScopedSwapBuffers::ScopedSwapBuffers(
GLSurfacePresentationHelper* helper, GLSurfacePresentationHelper* helper,
const GLSurface::PresentationCallback& callback) const GLSurface::PresentationCallback& callback)
: ScopedSwapBuffers(helper, callback, -1) {}
GLSurfacePresentationHelper::ScopedSwapBuffers::ScopedSwapBuffers(
GLSurfacePresentationHelper* helper,
const GLSurface::PresentationCallback& callback,
int frame_id)
: helper_(helper) { : helper_(helper) {
if (helper_) if (helper_)
helper_->PreSwapBuffers(callback); helper_->PreSwapBuffers(callback, frame_id);
} }
GLSurfacePresentationHelper::ScopedSwapBuffers::~ScopedSwapBuffers() { GLSurfacePresentationHelper::ScopedSwapBuffers::~ScopedSwapBuffers() {
...@@ -28,6 +35,11 @@ GLSurfacePresentationHelper::ScopedSwapBuffers::~ScopedSwapBuffers() { ...@@ -28,6 +35,11 @@ GLSurfacePresentationHelper::ScopedSwapBuffers::~ScopedSwapBuffers() {
GLSurfacePresentationHelper::Frame::Frame(Frame&& other) = default; GLSurfacePresentationHelper::Frame::Frame(Frame&& other) = default;
GLSurfacePresentationHelper::Frame::Frame(
int frame_id,
const GLSurface::PresentationCallback& callback)
: frame_id(frame_id), callback(callback) {}
GLSurfacePresentationHelper::Frame::Frame( GLSurfacePresentationHelper::Frame::Frame(
std::unique_ptr<GPUTimer>&& timer, std::unique_ptr<GPUTimer>&& timer,
const GLSurface::PresentationCallback& callback) const GLSurface::PresentationCallback& callback)
...@@ -47,20 +59,67 @@ GLSurfacePresentationHelper::Frame::~Frame() = default; ...@@ -47,20 +59,67 @@ GLSurfacePresentationHelper::Frame::~Frame() = default;
GLSurfacePresentationHelper::Frame& GLSurfacePresentationHelper::Frame:: GLSurfacePresentationHelper::Frame& GLSurfacePresentationHelper::Frame::
operator=(Frame&& other) = default; operator=(Frame&& other) = default;
bool GLSurfacePresentationHelper::Frame::StillPending() const { bool GLSurfacePresentationHelper::GetFrameTimestampInfoIfAvailable(
DCHECK(timer || fence); const Frame& frame,
return timer ? !timer->IsAvailable() : !fence->HasCompleted(); base::TimeTicks* timestamp,
} base::TimeDelta* interval,
uint32_t* flags) {
base::TimeTicks GLSurfacePresentationHelper::Frame::GetTimestamp() const { DCHECK(frame.timer || frame.fence || egl_timestamp_client_);
DCHECK(!StillPending());
if (timer) { if (egl_timestamp_client_) {
return egl_timestamp_client_->GetFrameTimestampInfoIfAvailable(
timestamp, interval, flags, frame.frame_id);
} else if (frame.timer) {
if (!frame.timer->IsAvailable())
return false;
int64_t start = 0; int64_t start = 0;
int64_t end = 0; int64_t end = 0;
timer->GetStartEndTimestamps(&start, &end); frame.timer->GetStartEndTimestamps(&start, &end);
return base::TimeTicks() + base::TimeDelta::FromMicroseconds(start); *timestamp = base::TimeTicks() + base::TimeDelta::FromMicroseconds(start);
} else {
if (!frame.fence->HasCompleted())
return false;
*timestamp = base::TimeTicks::Now();
} }
return base::TimeTicks::Now(); // Below logic is used to calculate final values of timestamp, interval and
// flags when using timer/fence to report the timestamps.
const bool fixed_vsync = !vsync_provider_;
const bool hw_clock = vsync_provider_ && vsync_provider_->IsHWClock();
*interval = vsync_interval_;
*flags = 0;
if (vsync_interval_.is_zero() || fixed_vsync) {
// If VSync parameters are fixed or not available, we just run
// presentation callbacks with timestamp from GPUTimers.
return true;
} else if (*timestamp < vsync_timebase_) {
// We got a VSync whose timestamp is after GPU finished rendering this
// back buffer.
*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 rendering.
*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 rendering. We have to compute the closest VSync's
// timestmp.
*timestamp =
timestamp->SnappedToNextTick(vsync_timebase_, vsync_interval_);
}
} else {
// The |vsync_timebase_| is earlier than |timestamp|, we will compute the
// next vSync's timestamp and use it to run callback.
if (!vsync_interval_.is_zero()) {
*timestamp =
timestamp->SnappedToNextTick(vsync_timebase_, vsync_interval_);
*flags = gfx::PresentationFeedback::kVSync;
}
}
return true;
} }
void GLSurfacePresentationHelper::Frame::Destroy(bool has_context) { void GLSurfacePresentationHelper::Frame::Destroy(bool has_context) {
...@@ -116,6 +175,20 @@ void GLSurfacePresentationHelper::OnMakeCurrent(GLContext* context, ...@@ -116,6 +175,20 @@ void GLSurfacePresentationHelper::OnMakeCurrent(GLContext* context,
pending_frames_.clear(); pending_frames_.clear();
gl_context_ = context; gl_context_ = context;
// Get an egl timestamp client.
egl_timestamp_client_ = surface_->GetEGLTimestampClient();
// If there is an egl timestamp client, check if egl timestamps are supported
// or not. If supported, then return as there is no need to use gpu timestamp
// client or fence.
if (egl_timestamp_client_) {
if (egl_timestamp_client_->IsEGLTimestampSupported())
return;
else
egl_timestamp_client_ = nullptr;
}
gpu_timing_client_ = context->CreateGPUTimingClient(); gpu_timing_client_ = context->CreateGPUTimingClient();
if (!gpu_timing_client_->IsAvailable()) if (!gpu_timing_client_->IsAvailable())
gpu_timing_client_ = nullptr; gpu_timing_client_ = nullptr;
...@@ -128,8 +201,11 @@ void GLSurfacePresentationHelper::OnMakeCurrent(GLContext* context, ...@@ -128,8 +201,11 @@ void GLSurfacePresentationHelper::OnMakeCurrent(GLContext* context,
} }
void GLSurfacePresentationHelper::PreSwapBuffers( void GLSurfacePresentationHelper::PreSwapBuffers(
const GLSurface::PresentationCallback& callback) { const GLSurface::PresentationCallback& callback,
if (gpu_timing_client_) { int frame_id) {
if (egl_timestamp_client_) {
pending_frames_.emplace_back(frame_id, callback);
} else if (gpu_timing_client_) {
std::unique_ptr<GPUTimer> timer; std::unique_ptr<GPUTimer> timer;
timer = gpu_timing_client_->CreateGPUTimer(false /* prefer_elapsed_time */); timer = gpu_timing_client_->CreateGPUTimer(false /* prefer_elapsed_time */);
timer->QueryTimeStamp(); timer->QueryTimeStamp();
...@@ -167,6 +243,7 @@ void GLSurfacePresentationHelper::CheckPendingFrames() { ...@@ -167,6 +243,7 @@ void GLSurfacePresentationHelper::CheckPendingFrames() {
if (!gl_context_->MakeCurrent(surface_)) { if (!gl_context_->MakeCurrent(surface_)) {
gl_context_ = nullptr; gl_context_ = nullptr;
egl_timestamp_client_ = nullptr;
gpu_timing_client_ = nullptr; gpu_timing_client_ = nullptr;
for (auto& frame : pending_frames_) for (auto& frame : pending_frames_)
frame.Destroy(); frame.Destroy();
...@@ -177,10 +254,11 @@ void GLSurfacePresentationHelper::CheckPendingFrames() { ...@@ -177,10 +254,11 @@ void GLSurfacePresentationHelper::CheckPendingFrames() {
bool need_update_vsync = false; bool need_update_vsync = false;
bool disjoint_occurred = bool disjoint_occurred =
gpu_timing_client_ && gpu_timing_client_->CheckAndResetTimerErrors(); gpu_timing_client_ && gpu_timing_client_->CheckAndResetTimerErrors();
if (disjoint_occurred || (!gpu_timing_client_ && !gl_fence_supported_)) { if (disjoint_occurred ||
// If GPUTimer and GLFence are not avaliable or disjoint occurred, we will (!egl_timestamp_client_ && !gpu_timing_client_ && !gl_fence_supported_)) {
// compute the next VSync's timestamp and use it to run presentation // If EGLTimestamps, GPUTimer and GLFence are not available or disjoint
// callback. // occurred, we will compute the next VSync's timestamp and use it to run
// presentation callback.
uint32_t flags = 0; uint32_t flags = 0;
auto timestamp = base::TimeTicks::Now(); auto timestamp = base::TimeTicks::Now();
if (!vsync_interval_.is_zero()) { if (!vsync_interval_.is_zero()) {
...@@ -206,9 +284,6 @@ void GLSurfacePresentationHelper::CheckPendingFrames() { ...@@ -206,9 +284,6 @@ void GLSurfacePresentationHelper::CheckPendingFrames() {
} }
} }
const bool fixed_vsync = !vsync_provider_;
const bool hw_clock = vsync_provider_ && vsync_provider_->IsHWClock();
while (!pending_frames_.empty()) { while (!pending_frames_.empty()) {
auto& frame = pending_frames_.front(); auto& frame = pending_frames_.front();
// Helper lambda for running the presentation callback and releasing the // Helper lambda for running the presentation callback and releasing the
...@@ -226,49 +301,16 @@ void GLSurfacePresentationHelper::CheckPendingFrames() { ...@@ -226,49 +301,16 @@ void GLSurfacePresentationHelper::CheckPendingFrames() {
continue; continue;
} }
if (frame.StillPending()) base::TimeTicks timestamp;
base::TimeDelta interval;
uint32_t flags = 0;
// Get timestamp info for a frame if available. If timestamp is not
// available, it means this frame is not yet done.
if (!GetFrameTimestampInfoIfAvailable(frame, &timestamp, &interval, &flags))
break; break;
auto timestamp = frame.GetTimestamp(); frame_presentation_callback(
gfx::PresentationFeedback(timestamp, interval, flags));
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|, we will compute the
// next vSync's timestamp and use it to run callback.
uint32_t flags = 0;
if (!vsync_interval_.is_zero()) {
timestamp =
timestamp.SnappedToNextTick(vsync_timebase_, vsync_interval_);
flags = gfx::PresentationFeedback::kVSync;
}
frame_presentation_callback(
gfx::PresentationFeedback(timestamp, vsync_interval_, flags));
}
} }
if (pending_frames_.empty() && !need_update_vsync) if (pending_frames_.empty() && !need_update_vsync)
......
...@@ -32,6 +32,9 @@ class GL_EXPORT GLSurfacePresentationHelper { ...@@ -32,6 +32,9 @@ class GL_EXPORT GLSurfacePresentationHelper {
public: public:
ScopedSwapBuffers(GLSurfacePresentationHelper* helper, ScopedSwapBuffers(GLSurfacePresentationHelper* helper,
const GLSurface::PresentationCallback& callback); const GLSurface::PresentationCallback& callback);
ScopedSwapBuffers(GLSurfacePresentationHelper* helper,
const GLSurface::PresentationCallback& callback,
int frame_id);
~ScopedSwapBuffers(); ~ScopedSwapBuffers();
void set_result(gfx::SwapResult result) { result_ = result; } void set_result(gfx::SwapResult result) { result_ = result; }
...@@ -52,12 +55,14 @@ class GL_EXPORT GLSurfacePresentationHelper { ...@@ -52,12 +55,14 @@ class GL_EXPORT GLSurfacePresentationHelper {
~GLSurfacePresentationHelper(); ~GLSurfacePresentationHelper();
void OnMakeCurrent(GLContext* context, GLSurface* surface); void OnMakeCurrent(GLContext* context, GLSurface* surface);
void PreSwapBuffers(const GLSurface::PresentationCallback& callback); void PreSwapBuffers(const GLSurface::PresentationCallback& callback,
int frame_id);
void PostSwapBuffers(gfx::SwapResult result); void PostSwapBuffers(gfx::SwapResult result);
private: private:
struct Frame { struct Frame {
Frame(Frame&& other); Frame(Frame&& other);
Frame(int frame_id, const GLSurface::PresentationCallback& callback);
Frame(std::unique_ptr<GPUTimer>&& timer, Frame(std::unique_ptr<GPUTimer>&& timer,
const GLSurface::PresentationCallback& callback); const GLSurface::PresentationCallback& callback);
Frame(std::unique_ptr<GLFence>&& fence, Frame(std::unique_ptr<GLFence>&& fence,
...@@ -66,17 +71,21 @@ class GL_EXPORT GLSurfacePresentationHelper { ...@@ -66,17 +71,21 @@ class GL_EXPORT GLSurfacePresentationHelper {
~Frame(); ~Frame();
Frame& operator=(Frame&& other); Frame& operator=(Frame&& other);
bool StillPending() const;
base::TimeTicks GetTimestamp() const;
void Destroy(bool has_context = false); void Destroy(bool has_context = false);
std::unique_ptr<GPUTimer> timer; std::unique_ptr<GPUTimer> timer;
// GLFence is used only if gpu timers are not available. // GLFence is used only if gpu timers are not available.
std::unique_ptr<GLFence> fence; std::unique_ptr<GLFence> fence;
int frame_id = -1;
GLSurface::PresentationCallback callback; GLSurface::PresentationCallback callback;
gfx::SwapResult result = gfx::SwapResult::SWAP_ACK; gfx::SwapResult result = gfx::SwapResult::SWAP_ACK;
}; };
bool GetFrameTimestampInfoIfAvailable(const Frame& frame,
base::TimeTicks* timestamp,
base::TimeDelta* interval,
uint32_t* flags);
// Check |pending_frames_| and run presentation callbacks. // Check |pending_frames_| and run presentation callbacks.
void CheckPendingFrames(); void CheckPendingFrames();
...@@ -97,6 +106,7 @@ class GL_EXPORT GLSurfacePresentationHelper { ...@@ -97,6 +106,7 @@ class GL_EXPORT GLSurfacePresentationHelper {
base::TimeDelta vsync_interval_; base::TimeDelta vsync_interval_;
bool check_pending_frame_scheduled_ = false; bool check_pending_frame_scheduled_ = false;
bool gl_fence_supported_ = false; bool gl_fence_supported_ = false;
EGLTimestampClient* egl_timestamp_client_ = nullptr;
base::WeakPtrFactory<GLSurfacePresentationHelper> weak_ptr_factory_; base::WeakPtrFactory<GLSurfacePresentationHelper> weak_ptr_factory_;
......
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