1 // Copyright (c) 2013 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 "cc/output/output_surface.h" 6 7 #include <algorithm> 8 #include <set> 9 #include <string> 10 #include <vector> 11 12 #include "base/bind.h" 13 #include "base/debug/trace_event.h" 14 #include "base/logging.h" 15 #include "base/message_loop/message_loop.h" 16 #include "base/metrics/histogram.h" 17 #include "base/strings/string_split.h" 18 #include "base/strings/string_util.h" 19 #include "cc/output/compositor_frame.h" 20 #include "cc/output/compositor_frame_ack.h" 21 #include "cc/output/managed_memory_policy.h" 22 #include "cc/output/output_surface_client.h" 23 #include "cc/scheduler/delay_based_time_source.h" 24 #include "gpu/GLES2/gl2extchromium.h" 25 #include "gpu/command_buffer/client/context_support.h" 26 #include "gpu/command_buffer/client/gles2_interface.h" 27 #include "third_party/khronos/GLES2/gl2.h" 28 #include "third_party/khronos/GLES2/gl2ext.h" 29 #include "ui/gfx/frame_time.h" 30 #include "ui/gfx/rect.h" 31 #include "ui/gfx/size.h" 32 33 using std::set; 34 using std::string; 35 using std::vector; 36 37 namespace { 38 39 const size_t kGpuLatencyHistorySize = 60; 40 const double kGpuLatencyEstimationPercentile = 100.0; 41 42 } 43 44 namespace cc { 45 46 OutputSurface::OutputSurface(scoped_refptr<ContextProvider> context_provider) 47 : client_(NULL), 48 context_provider_(context_provider), 49 device_scale_factor_(-1), 50 external_stencil_test_enabled_(false), 51 weak_ptr_factory_(this), 52 gpu_latency_history_(kGpuLatencyHistorySize) { 53 } 54 55 OutputSurface::OutputSurface(scoped_ptr<SoftwareOutputDevice> software_device) 56 : client_(NULL), 57 software_device_(software_device.Pass()), 58 device_scale_factor_(-1), 59 external_stencil_test_enabled_(false), 60 weak_ptr_factory_(this), 61 gpu_latency_history_(kGpuLatencyHistorySize) { 62 } 63 64 OutputSurface::OutputSurface(scoped_refptr<ContextProvider> context_provider, 65 scoped_ptr<SoftwareOutputDevice> software_device) 66 : client_(NULL), 67 context_provider_(context_provider), 68 software_device_(software_device.Pass()), 69 device_scale_factor_(-1), 70 external_stencil_test_enabled_(false), 71 weak_ptr_factory_(this), 72 gpu_latency_history_(kGpuLatencyHistorySize) { 73 } 74 75 void OutputSurface::CommitVSyncParameters(base::TimeTicks timebase, 76 base::TimeDelta interval) { 77 TRACE_EVENT2("cc", 78 "OutputSurface::CommitVSyncParameters", 79 "timebase", 80 (timebase - base::TimeTicks()).InSecondsF(), 81 "interval", 82 interval.InSecondsF()); 83 client_->CommitVSyncParameters(timebase, interval); 84 } 85 86 // Forwarded to OutputSurfaceClient 87 void OutputSurface::SetNeedsRedrawRect(const gfx::Rect& damage_rect) { 88 TRACE_EVENT0("cc", "OutputSurface::SetNeedsRedrawRect"); 89 client_->SetNeedsRedrawRect(damage_rect); 90 } 91 92 void OutputSurface::ReclaimResources(const CompositorFrameAck* ack) { 93 client_->ReclaimResources(ack); 94 } 95 96 void OutputSurface::DidLoseOutputSurface() { 97 TRACE_EVENT0("cc", "OutputSurface::DidLoseOutputSurface"); 98 pending_gpu_latency_query_ids_.clear(); 99 available_gpu_latency_query_ids_.clear(); 100 client_->DidLoseOutputSurface(); 101 } 102 103 void OutputSurface::SetExternalStencilTest(bool enabled) { 104 external_stencil_test_enabled_ = enabled; 105 } 106 107 void OutputSurface::SetExternalDrawConstraints( 108 const gfx::Transform& transform, 109 const gfx::Rect& viewport, 110 const gfx::Rect& clip, 111 const gfx::Rect& viewport_rect_for_tile_priority, 112 const gfx::Transform& transform_for_tile_priority, 113 bool resourceless_software_draw) { 114 client_->SetExternalDrawConstraints(transform, 115 viewport, 116 clip, 117 viewport_rect_for_tile_priority, 118 transform_for_tile_priority, 119 resourceless_software_draw); 120 } 121 122 OutputSurface::~OutputSurface() { 123 ResetContext3d(); 124 } 125 126 bool OutputSurface::HasExternalStencilTest() const { 127 return external_stencil_test_enabled_; 128 } 129 130 bool OutputSurface::BindToClient(OutputSurfaceClient* client) { 131 DCHECK(client); 132 client_ = client; 133 bool success = true; 134 135 if (context_provider_) { 136 success = context_provider_->BindToCurrentThread(); 137 if (success) 138 SetUpContext3d(); 139 } 140 141 if (!success) 142 client_ = NULL; 143 144 return success; 145 } 146 147 bool OutputSurface::InitializeAndSetContext3d( 148 scoped_refptr<ContextProvider> context_provider) { 149 DCHECK(!context_provider_); 150 DCHECK(context_provider); 151 DCHECK(client_); 152 153 bool success = false; 154 if (context_provider->BindToCurrentThread()) { 155 context_provider_ = context_provider; 156 SetUpContext3d(); 157 client_->DeferredInitialize(); 158 success = true; 159 } 160 161 if (!success) 162 ResetContext3d(); 163 164 return success; 165 } 166 167 void OutputSurface::ReleaseGL() { 168 DCHECK(client_); 169 DCHECK(context_provider_); 170 client_->ReleaseGL(); 171 DCHECK(!context_provider_); 172 } 173 174 void OutputSurface::SetUpContext3d() { 175 DCHECK(context_provider_); 176 DCHECK(client_); 177 178 context_provider_->SetLostContextCallback( 179 base::Bind(&OutputSurface::DidLoseOutputSurface, 180 base::Unretained(this))); 181 context_provider_->ContextSupport()->SetSwapBuffersCompleteCallback( 182 base::Bind(&OutputSurface::OnSwapBuffersComplete, 183 base::Unretained(this))); 184 context_provider_->SetMemoryPolicyChangedCallback( 185 base::Bind(&OutputSurface::SetMemoryPolicy, 186 base::Unretained(this))); 187 } 188 189 void OutputSurface::ReleaseContextProvider() { 190 DCHECK(client_); 191 DCHECK(context_provider_); 192 ResetContext3d(); 193 } 194 195 void OutputSurface::ResetContext3d() { 196 if (context_provider_.get()) { 197 while (!pending_gpu_latency_query_ids_.empty()) { 198 unsigned query_id = pending_gpu_latency_query_ids_.front(); 199 pending_gpu_latency_query_ids_.pop_front(); 200 context_provider_->ContextGL()->DeleteQueriesEXT(1, &query_id); 201 } 202 while (!available_gpu_latency_query_ids_.empty()) { 203 unsigned query_id = available_gpu_latency_query_ids_.front(); 204 available_gpu_latency_query_ids_.pop_front(); 205 context_provider_->ContextGL()->DeleteQueriesEXT(1, &query_id); 206 } 207 context_provider_->SetLostContextCallback( 208 ContextProvider::LostContextCallback()); 209 context_provider_->SetMemoryPolicyChangedCallback( 210 ContextProvider::MemoryPolicyChangedCallback()); 211 if (gpu::ContextSupport* support = context_provider_->ContextSupport()) 212 support->SetSwapBuffersCompleteCallback(base::Closure()); 213 } 214 context_provider_ = NULL; 215 } 216 217 void OutputSurface::EnsureBackbuffer() { 218 if (software_device_) 219 software_device_->EnsureBackbuffer(); 220 } 221 222 void OutputSurface::DiscardBackbuffer() { 223 if (context_provider_) 224 context_provider_->ContextGL()->DiscardBackbufferCHROMIUM(); 225 if (software_device_) 226 software_device_->DiscardBackbuffer(); 227 } 228 229 void OutputSurface::Reshape(const gfx::Size& size, float scale_factor) { 230 if (size == surface_size_ && scale_factor == device_scale_factor_) 231 return; 232 233 surface_size_ = size; 234 device_scale_factor_ = scale_factor; 235 if (context_provider_) { 236 context_provider_->ContextGL()->ResizeCHROMIUM( 237 size.width(), size.height(), scale_factor); 238 } 239 if (software_device_) 240 software_device_->Resize(size, scale_factor); 241 } 242 243 gfx::Size OutputSurface::SurfaceSize() const { 244 return surface_size_; 245 } 246 247 void OutputSurface::BindFramebuffer() { 248 DCHECK(context_provider_); 249 context_provider_->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, 0); 250 } 251 252 void OutputSurface::SwapBuffers(CompositorFrame* frame) { 253 if (frame->software_frame_data) { 254 PostSwapBuffersComplete(); 255 client_->DidSwapBuffers(); 256 return; 257 } 258 259 DCHECK(context_provider_); 260 DCHECK(frame->gl_frame_data); 261 262 UpdateAndMeasureGpuLatency(); 263 if (frame->gl_frame_data->sub_buffer_rect == 264 gfx::Rect(frame->gl_frame_data->size)) { 265 context_provider_->ContextSupport()->Swap(); 266 } else { 267 context_provider_->ContextSupport()->PartialSwapBuffers( 268 frame->gl_frame_data->sub_buffer_rect); 269 } 270 271 client_->DidSwapBuffers(); 272 } 273 274 base::TimeDelta OutputSurface::GpuLatencyEstimate() { 275 if (context_provider_ && !capabilities_.adjust_deadline_for_parent) 276 return gpu_latency_history_.Percentile(kGpuLatencyEstimationPercentile); 277 else 278 return base::TimeDelta(); 279 } 280 281 void OutputSurface::UpdateAndMeasureGpuLatency() { 282 // http://crbug.com/306690 tracks re-enabling latency queries. 283 #if 0 284 // We only care about GPU latency for surfaces that do not have a parent 285 // compositor, since surfaces that do have a parent compositor can use 286 // mailboxes or delegated rendering to send frames to their parent without 287 // incurring GPU latency. 288 if (capabilities_.adjust_deadline_for_parent) 289 return; 290 291 while (pending_gpu_latency_query_ids_.size()) { 292 unsigned query_id = pending_gpu_latency_query_ids_.front(); 293 unsigned query_complete = 1; 294 context_provider_->ContextGL()->GetQueryObjectuivEXT( 295 query_id, GL_QUERY_RESULT_AVAILABLE_EXT, &query_complete); 296 if (!query_complete) 297 break; 298 299 unsigned value = 0; 300 context_provider_->ContextGL()->GetQueryObjectuivEXT( 301 query_id, GL_QUERY_RESULT_EXT, &value); 302 pending_gpu_latency_query_ids_.pop_front(); 303 available_gpu_latency_query_ids_.push_back(query_id); 304 305 base::TimeDelta latency = base::TimeDelta::FromMicroseconds(value); 306 base::TimeDelta latency_estimate = GpuLatencyEstimate(); 307 gpu_latency_history_.InsertSample(latency); 308 309 base::TimeDelta latency_overestimate; 310 base::TimeDelta latency_underestimate; 311 if (latency > latency_estimate) 312 latency_underestimate = latency - latency_estimate; 313 else 314 latency_overestimate = latency_estimate - latency; 315 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatency", 316 latency, 317 base::TimeDelta::FromMilliseconds(1), 318 base::TimeDelta::FromMilliseconds(100), 319 50); 320 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatencyUnderestimate", 321 latency_underestimate, 322 base::TimeDelta::FromMilliseconds(1), 323 base::TimeDelta::FromMilliseconds(100), 324 50); 325 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatencyOverestimate", 326 latency_overestimate, 327 base::TimeDelta::FromMilliseconds(1), 328 base::TimeDelta::FromMilliseconds(100), 329 50); 330 } 331 332 unsigned gpu_latency_query_id; 333 if (available_gpu_latency_query_ids_.size()) { 334 gpu_latency_query_id = available_gpu_latency_query_ids_.front(); 335 available_gpu_latency_query_ids_.pop_front(); 336 } else { 337 context_provider_->ContextGL()->GenQueriesEXT(1, &gpu_latency_query_id); 338 } 339 340 context_provider_->ContextGL()->BeginQueryEXT(GL_LATENCY_QUERY_CHROMIUM, 341 gpu_latency_query_id); 342 context_provider_->ContextGL()->EndQueryEXT(GL_LATENCY_QUERY_CHROMIUM); 343 pending_gpu_latency_query_ids_.push_back(gpu_latency_query_id); 344 #endif 345 } 346 347 void OutputSurface::PostSwapBuffersComplete() { 348 base::MessageLoop::current()->PostTask( 349 FROM_HERE, 350 base::Bind(&OutputSurface::OnSwapBuffersComplete, 351 weak_ptr_factory_.GetWeakPtr())); 352 } 353 354 // We don't post tasks bound to the client directly since they might run 355 // after the OutputSurface has been destroyed. 356 void OutputSurface::OnSwapBuffersComplete() { 357 client_->DidSwapBuffersComplete(); 358 } 359 360 void OutputSurface::SetMemoryPolicy(const ManagedMemoryPolicy& policy) { 361 TRACE_EVENT1("cc", "OutputSurface::SetMemoryPolicy", 362 "bytes_limit_when_visible", policy.bytes_limit_when_visible); 363 // Just ignore the memory manager when it says to set the limit to zero 364 // bytes. This will happen when the memory manager thinks that the renderer 365 // is not visible (which the renderer knows better). 366 if (policy.bytes_limit_when_visible) 367 client_->SetMemoryPolicy(policy); 368 } 369 370 } // namespace cc 371