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