Index: services/gfx/compositor/backend/gpu_rasterizer.cc |
diff --git a/services/gfx/compositor/backend/gpu_rasterizer.cc b/services/gfx/compositor/backend/gpu_rasterizer.cc |
index 4625490a7f2f32916705af021074a5f0dfb9e698..85c555360abadc96568e78fb0265f365edcf91d8 100644 |
--- a/services/gfx/compositor/backend/gpu_rasterizer.cc |
+++ b/services/gfx/compositor/backend/gpu_rasterizer.cc |
@@ -13,7 +13,6 @@ |
#include <MGL/mgl.h> |
#include <MGL/mgl_echo.h> |
#include <MGL/mgl_onscreen.h> |
-#include <MGL/mgl_signal_sync_point.h> |
#include "base/bind.h" |
#include "base/location.h" |
@@ -21,29 +20,27 @@ |
#include "base/message_loop/message_loop.h" |
#include "base/time/time.h" |
#include "base/trace_event/trace_event.h" |
-#include "services/gfx/compositor/backend/vsync_scheduler.h" |
#include "services/gfx/compositor/render/render_frame.h" |
namespace compositor { |
namespace { |
+// Timeout for receiving initial viewport parameters from the GPU service. |
constexpr int64_t kViewportParameterTimeoutMs = 1000; |
+ |
+// Default vsync interval when the GPU service failed to provide viewport |
+// parameters promptly. |
constexpr int64_t kDefaultVsyncIntervalUs = 100000; // deliberately sluggish |
} |
GpuRasterizer::GpuRasterizer(mojo::ContextProviderPtr context_provider, |
- const scoped_refptr<VsyncScheduler>& scheduler, |
- const scoped_refptr<base::TaskRunner>& task_runner, |
- const base::Closure& error_callback) |
+ Callbacks* callbacks) |
: context_provider_(context_provider.Pass()), |
- scheduler_(scheduler), |
- task_runner_(task_runner), |
- error_callback_(error_callback), |
+ callbacks_(callbacks), |
viewport_parameter_listener_binding_(this), |
viewport_parameter_timeout_(false, false), |
weak_ptr_factory_(this) { |
DCHECK(context_provider_); |
- DCHECK(scheduler_); |
- DCHECK(task_runner_); |
+ DCHECK(callbacks_); |
context_provider_.set_connection_error_handler( |
base::Bind(&GpuRasterizer::OnContextProviderConnectionError, |
@@ -76,12 +73,13 @@ void GpuRasterizer::InitContext( |
if (!command_buffer) { |
LOG(ERROR) << "Could not create GL context."; |
- PostErrorCallback(); |
+ callbacks_->OnRasterizerError(); |
return; |
} |
gl_context_ = mojo::GLContext::CreateFromCommandBuffer( |
mojo::CommandBufferPtr::Create(std::move(command_buffer))); |
+ DCHECK(!gl_context_->is_lost()); |
gl_context_->AddObserver(this); |
ganesh_context_ = new mojo::skia::GaneshContext(gl_context_); |
@@ -94,19 +92,20 @@ void GpuRasterizer::InitContext( |
base::Bind(&GpuRasterizer::OnViewportParameterTimeout, |
base::Unretained(this))); |
} |
- |
- if (frame_) |
- Draw(); |
} |
void GpuRasterizer::AbandonContext() { |
- if (gl_context_) |
- scheduler_->Stop(); |
- |
if (viewport_parameter_listener_binding_.is_bound()) { |
viewport_parameter_timeout_.Stop(); |
viewport_parameter_listener_binding_.Close(); |
} |
+ |
+ if (ready_) { |
+ while (frames_in_progress_) |
+ DrawFinished(false /*presented*/); |
+ ready_ = false; |
+ callbacks_->OnRasterizerSuspended(); |
+ } |
} |
void GpuRasterizer::DestroyContext() { |
@@ -124,15 +123,14 @@ void GpuRasterizer::DestroyContext() { |
void GpuRasterizer::OnContextProviderConnectionError() { |
LOG(ERROR) << "Context provider connection lost."; |
- PostErrorCallback(); |
+ |
+ callbacks_->OnRasterizerError(); |
} |
void GpuRasterizer::OnContextLost() { |
LOG(WARNING) << "GL context lost!"; |
AbandonContext(); |
- frames_pending_ = 0u; |
- |
base::MessageLoop::current()->PostTask( |
FROM_HERE, base::Bind(&GpuRasterizer::RecreateContextAfterLoss, |
weak_ptr_factory_.GetWeakPtr())); |
@@ -167,71 +165,33 @@ void GpuRasterizer::OnVSyncParametersUpdated(int64_t timebase, |
} |
vsync_timebase_ = timebase; |
vsync_interval_ = interval; |
- |
- if (gl_context_ && !gl_context_->is_lost()) |
- ApplyViewportParameters(); |
+ ApplyViewportParameters(); |
} |
void GpuRasterizer::ApplyViewportParameters() { |
DCHECK(have_viewport_parameters_); |
- DCHECK(gl_context_); |
- // TODO(jeffbrown): This shouldn't be hardcoded. |
- // Need to do some real tuning and possibly determine values adaptively. |
- int64_t update_phase = -vsync_interval_; |
- int64_t snapshot_phase = -vsync_interval_ / 6; |
- int64_t presentation_phase = vsync_interval_; |
- if (!scheduler_->Start(vsync_timebase_, vsync_interval_, update_phase, |
- snapshot_phase, presentation_phase)) { |
- LOG(ERROR) << "Received invalid vsync parameters: timebase=" |
- << vsync_timebase_ << ", interval=" << vsync_interval_; |
- PostErrorCallback(); |
+ if (gl_context_ && !gl_context_->is_lost()) { |
+ ready_ = true; |
+ callbacks_->OnRasterizerReady(vsync_timebase_, vsync_interval_); |
} |
} |
-constexpr uint32_t kMaxFramesPending = 2; |
- |
-void GpuRasterizer::SubmitFrame(const scoped_refptr<RenderFrame>& frame, |
- const FrameCallback& frame_callback) { |
- TRACE_EVENT0("gfx", "GpuRasterizer::SubmitFrame"); |
+void GpuRasterizer::DrawFrame(const scoped_refptr<RenderFrame>& frame) { |
DCHECK(frame); |
- |
- if (frame_ && !frame_callback_.is_null()) |
- frame_callback_.Run(false); // frame discarded |
- |
- frame_ = frame; |
- frame_callback_ = frame_callback; |
- |
- if (gl_context_ && !gl_context_->is_lost()) { |
- if (frames_pending_ == kMaxFramesPending) { |
- TRACE_EVENT_INSTANT0("gfx", "GpuRasterizer dropping", |
- TRACE_EVENT_SCOPE_THREAD); |
- LOG(ERROR) << "too many frames pending, dropping"; |
- frame_callback_.Run(false); |
- return; |
- } |
- Draw(); |
- } else |
- frame_callback_.Run(false); |
-} |
- |
-static void DidEcho(void* context) { |
- TRACE_EVENT_ASYNC_END0("gfx", "SwapBuffers Echo", context); |
- auto cb = static_cast<base::Closure*>(context); |
- cb->Run(); |
- delete cb; |
-} |
- |
-void GpuRasterizer::Draw() { |
- TRACE_EVENT0("gfx", "GpuRasterizer::Draw"); |
+ DCHECK(ready_); |
DCHECK(gl_context_); |
+ DCHECK(!gl_context_->is_lost()); |
DCHECK(ganesh_context_); |
- DCHECK(frame_); |
+ |
+ uint32_t frame_number = total_frames_++; |
+ frames_in_progress_++; |
+ TRACE_EVENT1("gfx", "GpuRasterizer::DrawFrame", "num", frame_number); |
mojo::GLContext::Scope gl_scope(gl_context_); |
// Update the viewport. |
- const SkIRect& viewport = frame_->viewport(); |
+ const SkIRect& viewport = frame->viewport(); |
bool stale_surface = false; |
if (!ganesh_surface_ || |
ganesh_surface_->surface()->width() != viewport.width() || |
@@ -241,7 +201,7 @@ void GpuRasterizer::Draw() { |
stale_surface = true; |
} |
- // Paint the frame. |
+ // Draw the frame content. |
{ |
mojo::skia::GaneshContext::Scope ganesh_scope(ganesh_context_); |
@@ -250,38 +210,36 @@ void GpuRasterizer::Draw() { |
new mojo::skia::GaneshFramebufferSurface(ganesh_scope)); |
} |
- frame_->Paint(ganesh_surface_->canvas()); |
+ frame->Draw(ganesh_surface_->canvas()); |
} |
- // Swap buffers and listen for completion. |
- // TODO: Investigate using |MGLSignalSyncPoint| to wait for completion. |
+ // Swap buffers. |
{ |
TRACE_EVENT0("gfx", "MGLSwapBuffers"); |
MGLSwapBuffers(); |
} |
- base::Closure* echo_callback = new base::Closure( |
- base::Bind(&GpuRasterizer::DidEchoCallback, |
- weak_ptr_factory_.GetWeakPtr(), frame_callback_)); |
- frame_callback_.Reset(); |
- TRACE_EVENT_ASYNC_BEGIN0("gfx", "SwapBuffers Echo", echo_callback); |
- MGLEcho(DidEcho, echo_callback); |
- frames_pending_++; |
- TRACE_COUNTER1("gfx", "GpuRasterizer::frames_pending_", frames_pending_); |
+ |
+ // Listen for completion. |
+ TRACE_EVENT_ASYNC_BEGIN0("gfx", "MGLEcho", frame_number); |
+ MGLEcho(&GpuRasterizer::OnMGLEchoReply, this); |
} |
-void GpuRasterizer::DidEchoCallback(FrameCallback frame_callback) { |
- frames_pending_--; |
- TRACE_COUNTER1("gfx", "GpuRasterizer::frames_pending_", frames_pending_); |
- TRACE_EVENT0("gfx", "GpuRasterizer::DidEchoCallback"); |
- // Signal pending callback for backpressure. |
- if (!frame_callback.is_null()) { |
- frame_callback.Run(true); |
- frame_callback.Reset(); |
- } |
+void GpuRasterizer::DrawFinished(bool presented) { |
+ DCHECK(frames_in_progress_); |
+ |
+ uint32_t frame_number = total_frames_ - frames_in_progress_; |
+ frames_in_progress_--; |
+ TRACE_EVENT2("gfx", "GpuRasterizer::DrawFinished", "num", frame_number, |
+ "presented", presented); |
+ TRACE_EVENT_ASYNC_END0("gfx", "MGLEcho", frame_number); |
+ |
+ callbacks_->OnRasterizerFinishedDraw(presented); |
} |
-void GpuRasterizer::PostErrorCallback() { |
- task_runner_->PostTask(FROM_HERE, error_callback_); |
+void GpuRasterizer::OnMGLEchoReply(void* context) { |
+ auto rasterizer = static_cast<GpuRasterizer*>(context); |
+ if (rasterizer->ready_) |
+ rasterizer->DrawFinished(true /*presented*/); |
} |
} // namespace compositor |