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 "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