OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "services/gfx/compositor/backend/gpu_rasterizer.h" |
| 6 |
| 7 #ifndef GL_GLEXT_PROTOTYPES |
| 8 #define GL_GLEXT_PROTOTYPES |
| 9 #endif |
| 10 |
| 11 #include <GLES2/gl2.h> |
| 12 #include <GLES2/gl2extmojo.h> |
| 13 #include <MGL/mgl.h> |
| 14 #include <MGL/mgl_onscreen.h> |
| 15 |
| 16 #include "base/bind.h" |
| 17 #include "base/location.h" |
| 18 #include "base/logging.h" |
| 19 #include "services/gfx/compositor/backend/vsync_scheduler.h" |
| 20 #include "services/gfx/compositor/render/render_frame.h" |
| 21 |
| 22 namespace compositor { |
| 23 |
| 24 GpuRasterizer::GpuRasterizer(mojo::ContextProviderPtr context_provider, |
| 25 const std::shared_ptr<VsyncScheduler>& scheduler, |
| 26 const scoped_refptr<base::TaskRunner>& task_runner, |
| 27 const base::Closure& error_callback) |
| 28 : context_provider_(context_provider.Pass()), |
| 29 scheduler_(scheduler), |
| 30 task_runner_(task_runner), |
| 31 error_callback_(error_callback), |
| 32 viewport_parameter_listener_binding_(this) { |
| 33 DCHECK(context_provider_); |
| 34 context_provider_.set_connection_error_handler( |
| 35 base::Bind(&GpuRasterizer::OnContextProviderConnectionError, |
| 36 base::Unretained(this))); |
| 37 CreateContext(); |
| 38 } |
| 39 |
| 40 GpuRasterizer::~GpuRasterizer() { |
| 41 DestroyContext(); |
| 42 } |
| 43 |
| 44 void GpuRasterizer::CreateContext() { |
| 45 mojo::ViewportParameterListenerPtr viewport_parameter_listener; |
| 46 viewport_parameter_listener_binding_.Bind( |
| 47 GetProxy(&viewport_parameter_listener)); |
| 48 context_provider_->Create( |
| 49 viewport_parameter_listener.Pass(), |
| 50 base::Bind(&GpuRasterizer::InitContext, base::Unretained(this))); |
| 51 } |
| 52 |
| 53 void GpuRasterizer::InitContext(mojo::CommandBufferPtr command_buffer) { |
| 54 DCHECK(!gl_context_); |
| 55 DCHECK(!ganesh_context_); |
| 56 DCHECK(!ganesh_surface_); |
| 57 |
| 58 if (!command_buffer) { |
| 59 LOG(ERROR) << "Could not create GL context."; |
| 60 PostErrorCallback(); |
| 61 return; |
| 62 } |
| 63 |
| 64 gl_context_ = mojo::GLContext::CreateFromCommandBuffer(command_buffer.Pass()); |
| 65 gl_context_->AddObserver(this); |
| 66 ganesh_context_.reset(new mojo::skia::GaneshContext(gl_context_)); |
| 67 |
| 68 if (current_frame_) |
| 69 Draw(); |
| 70 } |
| 71 |
| 72 void GpuRasterizer::DestroyContext() { |
| 73 if (gl_context_) { |
| 74 scheduler_->Stop(); |
| 75 |
| 76 // Release objects that belong to special scopes. |
| 77 { |
| 78 mojo::skia::GaneshContext::Scope ganesh_scope(ganesh_context_.get()); |
| 79 ganesh_surface_.reset(); |
| 80 } |
| 81 |
| 82 // Release the ganesh context before the GL context. |
| 83 ganesh_context_.reset(); |
| 84 |
| 85 // Now release the GL context. |
| 86 gl_context_->Destroy(); |
| 87 gl_context_.reset(); |
| 88 } |
| 89 } |
| 90 |
| 91 void GpuRasterizer::OnContextProviderConnectionError() { |
| 92 LOG(ERROR) << "Context provider connection lost."; |
| 93 PostErrorCallback(); |
| 94 } |
| 95 |
| 96 void GpuRasterizer::OnContextLost() { |
| 97 LOG(WARNING) << "GL context lost, recreating it."; |
| 98 DestroyContext(); |
| 99 CreateContext(); |
| 100 } |
| 101 |
| 102 void GpuRasterizer::OnVSyncParametersUpdated(int64_t timebase, |
| 103 int64_t interval) { |
| 104 DVLOG(1) << "Vsync parameters: timebase=" << timebase |
| 105 << ", interval=" << interval; |
| 106 |
| 107 if (!gl_context_) |
| 108 return; |
| 109 |
| 110 // TODO(jeffbrown): This shouldn't be hardcoded. |
| 111 // Need to do some real tuning and possibly determine values adaptively. |
| 112 int64_t update_phase = -interval; |
| 113 int64_t snapshot_phase = -interval / 8; |
| 114 int64_t presentation_phase = interval; |
| 115 if (!scheduler_->Start(timebase, interval, update_phase, snapshot_phase, |
| 116 presentation_phase)) { |
| 117 LOG(ERROR) << "Received invalid vsync parameters: timebase=" << timebase |
| 118 << ", interval=" << interval; |
| 119 PostErrorCallback(); |
| 120 } |
| 121 } |
| 122 |
| 123 void GpuRasterizer::SubmitFrame(const std::shared_ptr<RenderFrame>& frame) { |
| 124 DCHECK(frame); |
| 125 |
| 126 if (current_frame_ == frame) |
| 127 return; |
| 128 |
| 129 current_frame_ = frame; |
| 130 if (gl_context_) |
| 131 Draw(); |
| 132 } |
| 133 |
| 134 void GpuRasterizer::Draw() { |
| 135 DCHECK(gl_context_); |
| 136 DCHECK(ganesh_context_); |
| 137 DCHECK(current_frame_); |
| 138 |
| 139 gl_context_->MakeCurrent(); |
| 140 |
| 141 // Update the viewport. |
| 142 const SkRect& viewport = current_frame_->viewport(); |
| 143 bool stale_surface = false; |
| 144 if (!ganesh_surface_ || |
| 145 ganesh_surface_->surface()->width() != viewport.width() || |
| 146 ganesh_surface_->surface()->height() != viewport.height()) { |
| 147 glViewport(viewport.x(), viewport.y(), viewport.width(), viewport.height()); |
| 148 glResizeCHROMIUM(viewport.width(), viewport.height(), 1.0f); |
| 149 stale_surface = true; |
| 150 } |
| 151 |
| 152 // Paint the frame. |
| 153 { |
| 154 mojo::skia::GaneshContext::Scope ganesh_scope(ganesh_context_.get()); |
| 155 |
| 156 if (stale_surface) |
| 157 ganesh_surface_.reset( |
| 158 new mojo::skia::GaneshFramebufferSurface(ganesh_scope)); |
| 159 |
| 160 current_frame_->Paint(ganesh_surface_->canvas()); |
| 161 } |
| 162 |
| 163 // Swap buffers. |
| 164 MGLSwapBuffers(); |
| 165 } |
| 166 |
| 167 void GpuRasterizer::PostErrorCallback() { |
| 168 task_runner_->PostTask(FROM_HERE, error_callback_); |
| 169 } |
| 170 |
| 171 } // namespace compositor |
OLD | NEW |