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/WebKit/public/platform/WebGraphicsContext3D.h"
     28 #include "third_party/khronos/GLES2/gl2.h"
     29 #include "third_party/khronos/GLES2/gl2ext.h"
     30 #include "ui/gfx/frame_time.h"
     31 #include "ui/gfx/rect.h"
     32 #include "ui/gfx/size.h"
     33 
     34 using std::set;
     35 using std::string;
     36 using std::vector;
     37 
     38 namespace {
     39 
     40 const size_t kGpuLatencyHistorySize = 60;
     41 const double kGpuLatencyEstimationPercentile = 100.0;
     42 
     43 }
     44 
     45 namespace cc {
     46 
     47 OutputSurface::OutputSurface(scoped_refptr<ContextProvider> context_provider)
     48     : context_provider_(context_provider),
     49       device_scale_factor_(-1),
     50       max_frames_pending_(0),
     51       pending_swap_buffers_(0),
     52       needs_begin_impl_frame_(false),
     53       client_ready_for_begin_impl_frame_(true),
     54       client_(NULL),
     55       check_for_retroactive_begin_impl_frame_pending_(false),
     56       external_stencil_test_enabled_(false),
     57       weak_ptr_factory_(this),
     58       gpu_latency_history_(kGpuLatencyHistorySize) {}
     59 
     60 OutputSurface::OutputSurface(scoped_ptr<SoftwareOutputDevice> software_device)
     61     : software_device_(software_device.Pass()),
     62       device_scale_factor_(-1),
     63       max_frames_pending_(0),
     64       pending_swap_buffers_(0),
     65       needs_begin_impl_frame_(false),
     66       client_ready_for_begin_impl_frame_(true),
     67       client_(NULL),
     68       check_for_retroactive_begin_impl_frame_pending_(false),
     69       external_stencil_test_enabled_(false),
     70       weak_ptr_factory_(this),
     71       gpu_latency_history_(kGpuLatencyHistorySize) {}
     72 
     73 OutputSurface::OutputSurface(scoped_refptr<ContextProvider> context_provider,
     74                              scoped_ptr<SoftwareOutputDevice> software_device)
     75     : context_provider_(context_provider),
     76       software_device_(software_device.Pass()),
     77       device_scale_factor_(-1),
     78       max_frames_pending_(0),
     79       pending_swap_buffers_(0),
     80       needs_begin_impl_frame_(false),
     81       client_ready_for_begin_impl_frame_(true),
     82       client_(NULL),
     83       check_for_retroactive_begin_impl_frame_pending_(false),
     84       external_stencil_test_enabled_(false),
     85       weak_ptr_factory_(this),
     86       gpu_latency_history_(kGpuLatencyHistorySize) {}
     87 
     88 void OutputSurface::InitializeBeginImplFrameEmulation(
     89     base::SingleThreadTaskRunner* task_runner,
     90     bool throttle_frame_production,
     91     base::TimeDelta interval) {
     92   if (throttle_frame_production) {
     93     scoped_refptr<DelayBasedTimeSource> time_source;
     94     if (gfx::FrameTime::TimestampsAreHighRes())
     95       time_source = DelayBasedTimeSourceHighRes::Create(interval, task_runner);
     96     else
     97       time_source = DelayBasedTimeSource::Create(interval, task_runner);
     98     frame_rate_controller_.reset(new FrameRateController(time_source));
     99   } else {
    100     frame_rate_controller_.reset(new FrameRateController(task_runner));
    101   }
    102 
    103   frame_rate_controller_->SetClient(this);
    104   frame_rate_controller_->SetMaxSwapsPending(max_frames_pending_);
    105   frame_rate_controller_->SetDeadlineAdjustment(
    106       capabilities_.adjust_deadline_for_parent ?
    107           BeginFrameArgs::DefaultDeadlineAdjustment() : base::TimeDelta());
    108 
    109   // The new frame rate controller will consume the swap acks of the old
    110   // frame rate controller, so we set that expectation up here.
    111   for (int i = 0; i < pending_swap_buffers_; i++)
    112     frame_rate_controller_->DidSwapBuffers();
    113 }
    114 
    115 void OutputSurface::SetMaxFramesPending(int max_frames_pending) {
    116   if (frame_rate_controller_)
    117     frame_rate_controller_->SetMaxSwapsPending(max_frames_pending);
    118   max_frames_pending_ = max_frames_pending;
    119 }
    120 
    121 void OutputSurface::OnVSyncParametersChanged(base::TimeTicks timebase,
    122                                              base::TimeDelta interval) {
    123   TRACE_EVENT2("cc", "OutputSurface::OnVSyncParametersChanged",
    124                "timebase", (timebase - base::TimeTicks()).InSecondsF(),
    125                "interval", interval.InSecondsF());
    126   if (frame_rate_controller_)
    127     frame_rate_controller_->SetTimebaseAndInterval(timebase, interval);
    128 }
    129 
    130 void OutputSurface::FrameRateControllerTick(bool throttled,
    131                                             const BeginFrameArgs& args) {
    132   DCHECK(frame_rate_controller_);
    133   if (throttled)
    134     skipped_begin_impl_frame_args_ = args;
    135   else
    136     BeginImplFrame(args);
    137 }
    138 
    139 // Forwarded to OutputSurfaceClient
    140 void OutputSurface::SetNeedsRedrawRect(gfx::Rect damage_rect) {
    141   TRACE_EVENT0("cc", "OutputSurface::SetNeedsRedrawRect");
    142   client_->SetNeedsRedrawRect(damage_rect);
    143 }
    144 
    145 void OutputSurface::SetNeedsBeginImplFrame(bool enable) {
    146   TRACE_EVENT1("cc", "OutputSurface::SetNeedsBeginImplFrame", "enable", enable);
    147   needs_begin_impl_frame_ = enable;
    148   client_ready_for_begin_impl_frame_ = true;
    149   if (frame_rate_controller_) {
    150     BeginFrameArgs skipped = frame_rate_controller_->SetActive(enable);
    151     if (skipped.IsValid())
    152       skipped_begin_impl_frame_args_ = skipped;
    153   }
    154   if (needs_begin_impl_frame_)
    155     PostCheckForRetroactiveBeginImplFrame();
    156 }
    157 
    158 void OutputSurface::BeginImplFrame(const BeginFrameArgs& args) {
    159   TRACE_EVENT2("cc", "OutputSurface::BeginImplFrame",
    160                "client_ready_for_begin_impl_frame_",
    161                client_ready_for_begin_impl_frame_,
    162                "pending_swap_buffers_", pending_swap_buffers_);
    163   if (!needs_begin_impl_frame_ || !client_ready_for_begin_impl_frame_ ||
    164       (pending_swap_buffers_ >= max_frames_pending_ &&
    165        max_frames_pending_ > 0)) {
    166     skipped_begin_impl_frame_args_ = args;
    167   } else {
    168     client_ready_for_begin_impl_frame_ = false;
    169     client_->BeginImplFrame(args);
    170     // args might be an alias for skipped_begin_impl_frame_args_.
    171     // Do not reset it before calling BeginImplFrame!
    172     skipped_begin_impl_frame_args_ = BeginFrameArgs();
    173   }
    174 }
    175 
    176 base::TimeTicks OutputSurface::RetroactiveBeginImplFrameDeadline() {
    177   // TODO(brianderson): Remove the alternative deadline once we have better
    178   // deadline estimations.
    179   base::TimeTicks alternative_deadline =
    180       skipped_begin_impl_frame_args_.frame_time +
    181       BeginFrameArgs::DefaultRetroactiveBeginFramePeriod();
    182   return std::max(skipped_begin_impl_frame_args_.deadline,
    183                   alternative_deadline);
    184 }
    185 
    186 void OutputSurface::PostCheckForRetroactiveBeginImplFrame() {
    187   if (!skipped_begin_impl_frame_args_.IsValid() ||
    188       check_for_retroactive_begin_impl_frame_pending_)
    189     return;
    190 
    191   base::MessageLoop::current()->PostTask(
    192      FROM_HERE,
    193      base::Bind(&OutputSurface::CheckForRetroactiveBeginImplFrame,
    194                 weak_ptr_factory_.GetWeakPtr()));
    195   check_for_retroactive_begin_impl_frame_pending_ = true;
    196 }
    197 
    198 void OutputSurface::CheckForRetroactiveBeginImplFrame() {
    199   TRACE_EVENT0("cc", "OutputSurface::CheckForRetroactiveBeginImplFrame");
    200   check_for_retroactive_begin_impl_frame_pending_ = false;
    201   if (gfx::FrameTime::Now() < RetroactiveBeginImplFrameDeadline())
    202     BeginImplFrame(skipped_begin_impl_frame_args_);
    203 }
    204 
    205 void OutputSurface::DidSwapBuffers() {
    206   pending_swap_buffers_++;
    207   TRACE_EVENT1("cc", "OutputSurface::DidSwapBuffers",
    208                "pending_swap_buffers_", pending_swap_buffers_);
    209   client_->DidSwapBuffers();
    210   if (frame_rate_controller_)
    211     frame_rate_controller_->DidSwapBuffers();
    212   PostCheckForRetroactiveBeginImplFrame();
    213 }
    214 
    215 void OutputSurface::OnSwapBuffersComplete() {
    216   pending_swap_buffers_--;
    217   TRACE_EVENT1("cc", "OutputSurface::OnSwapBuffersComplete",
    218                "pending_swap_buffers_", pending_swap_buffers_);
    219   client_->OnSwapBuffersComplete();
    220   if (frame_rate_controller_)
    221     frame_rate_controller_->DidSwapBuffersComplete();
    222   PostCheckForRetroactiveBeginImplFrame();
    223 }
    224 
    225 void OutputSurface::ReclaimResources(const CompositorFrameAck* ack) {
    226   client_->ReclaimResources(ack);
    227 }
    228 
    229 void OutputSurface::DidLoseOutputSurface() {
    230   TRACE_EVENT0("cc", "OutputSurface::DidLoseOutputSurface");
    231   client_ready_for_begin_impl_frame_ = true;
    232   pending_swap_buffers_ = 0;
    233   skipped_begin_impl_frame_args_ = BeginFrameArgs();
    234   if (frame_rate_controller_)
    235     frame_rate_controller_->SetActive(false);
    236   pending_gpu_latency_query_ids_.clear();
    237   available_gpu_latency_query_ids_.clear();
    238   client_->DidLoseOutputSurface();
    239 }
    240 
    241 void OutputSurface::SetExternalStencilTest(bool enabled) {
    242   external_stencil_test_enabled_ = enabled;
    243 }
    244 
    245 void OutputSurface::SetExternalDrawConstraints(const gfx::Transform& transform,
    246                                                gfx::Rect viewport,
    247                                                gfx::Rect clip,
    248                                                bool valid_for_tile_management) {
    249   client_->SetExternalDrawConstraints(
    250       transform, viewport, clip, valid_for_tile_management);
    251 }
    252 
    253 OutputSurface::~OutputSurface() {
    254   if (frame_rate_controller_)
    255     frame_rate_controller_->SetActive(false);
    256   ResetContext3d();
    257 }
    258 
    259 bool OutputSurface::HasExternalStencilTest() const {
    260   return external_stencil_test_enabled_;
    261 }
    262 
    263 bool OutputSurface::ForcedDrawToSoftwareDevice() const { return false; }
    264 
    265 bool OutputSurface::BindToClient(OutputSurfaceClient* client) {
    266   DCHECK(client);
    267   client_ = client;
    268   bool success = true;
    269 
    270   if (context_provider_) {
    271     success = context_provider_->BindToCurrentThread();
    272     if (success)
    273       SetUpContext3d();
    274   }
    275 
    276   if (!success)
    277     client_ = NULL;
    278 
    279   return success;
    280 }
    281 
    282 bool OutputSurface::InitializeAndSetContext3d(
    283     scoped_refptr<ContextProvider> context_provider,
    284     scoped_refptr<ContextProvider> offscreen_context_provider) {
    285   DCHECK(!context_provider_);
    286   DCHECK(context_provider);
    287   DCHECK(client_);
    288 
    289   bool success = false;
    290   if (context_provider->BindToCurrentThread()) {
    291     context_provider_ = context_provider;
    292     SetUpContext3d();
    293     if (client_->DeferredInitialize(offscreen_context_provider))
    294       success = true;
    295   }
    296 
    297   if (!success)
    298     ResetContext3d();
    299 
    300   return success;
    301 }
    302 
    303 void OutputSurface::ReleaseGL() {
    304   DCHECK(client_);
    305   DCHECK(context_provider_);
    306   client_->ReleaseGL();
    307   ResetContext3d();
    308 }
    309 
    310 void OutputSurface::SetUpContext3d() {
    311   DCHECK(context_provider_);
    312   DCHECK(client_);
    313 
    314   context_provider_->SetLostContextCallback(
    315       base::Bind(&OutputSurface::DidLoseOutputSurface,
    316                  base::Unretained(this)));
    317   context_provider_->ContextSupport()->SetSwapBuffersCompleteCallback(
    318       base::Bind(&OutputSurface::OnSwapBuffersComplete,
    319                  base::Unretained(this)));
    320   context_provider_->SetMemoryPolicyChangedCallback(
    321       base::Bind(&OutputSurface::SetMemoryPolicy,
    322                  base::Unretained(this)));
    323 }
    324 
    325 void OutputSurface::ResetContext3d() {
    326   if (context_provider_.get()) {
    327     while (!pending_gpu_latency_query_ids_.empty()) {
    328       unsigned query_id = pending_gpu_latency_query_ids_.front();
    329       pending_gpu_latency_query_ids_.pop_front();
    330       context_provider_->Context3d()->deleteQueryEXT(query_id);
    331     }
    332     while (!available_gpu_latency_query_ids_.empty()) {
    333       unsigned query_id = available_gpu_latency_query_ids_.front();
    334       available_gpu_latency_query_ids_.pop_front();
    335       context_provider_->Context3d()->deleteQueryEXT(query_id);
    336     }
    337     context_provider_->SetLostContextCallback(
    338         ContextProvider::LostContextCallback());
    339     context_provider_->SetMemoryPolicyChangedCallback(
    340         ContextProvider::MemoryPolicyChangedCallback());
    341     if (gpu::ContextSupport* support = context_provider_->ContextSupport())
    342       support->SetSwapBuffersCompleteCallback(base::Closure());
    343   }
    344   context_provider_ = NULL;
    345 }
    346 
    347 void OutputSurface::EnsureBackbuffer() {
    348   if (software_device_)
    349     software_device_->EnsureBackbuffer();
    350 }
    351 
    352 void OutputSurface::DiscardBackbuffer() {
    353   if (context_provider_)
    354     context_provider_->ContextGL()->DiscardBackbufferCHROMIUM();
    355   if (software_device_)
    356     software_device_->DiscardBackbuffer();
    357 }
    358 
    359 void OutputSurface::Reshape(gfx::Size size, float scale_factor) {
    360   if (size == surface_size_ && scale_factor == device_scale_factor_)
    361     return;
    362 
    363   surface_size_ = size;
    364   device_scale_factor_ = scale_factor;
    365   if (context_provider_) {
    366     context_provider_->Context3d()->reshapeWithScaleFactor(
    367         size.width(), size.height(), scale_factor);
    368   }
    369   if (software_device_)
    370     software_device_->Resize(size);
    371 }
    372 
    373 gfx::Size OutputSurface::SurfaceSize() const {
    374   return surface_size_;
    375 }
    376 
    377 void OutputSurface::BindFramebuffer() {
    378   DCHECK(context_provider_);
    379   context_provider_->Context3d()->bindFramebuffer(GL_FRAMEBUFFER, 0);
    380 }
    381 
    382 void OutputSurface::SwapBuffers(CompositorFrame* frame) {
    383   if (frame->software_frame_data) {
    384     PostSwapBuffersComplete();
    385     DidSwapBuffers();
    386     return;
    387   }
    388 
    389   DCHECK(context_provider_);
    390   DCHECK(frame->gl_frame_data);
    391 
    392   UpdateAndMeasureGpuLatency();
    393   if (frame->gl_frame_data->sub_buffer_rect ==
    394       gfx::Rect(frame->gl_frame_data->size)) {
    395     context_provider_->ContextSupport()->Swap();
    396   } else {
    397     context_provider_->ContextSupport()->PartialSwapBuffers(
    398         frame->gl_frame_data->sub_buffer_rect);
    399   }
    400 
    401   DidSwapBuffers();
    402 }
    403 
    404 base::TimeDelta OutputSurface::GpuLatencyEstimate() {
    405   if (context_provider_ && !capabilities_.adjust_deadline_for_parent)
    406     return gpu_latency_history_.Percentile(kGpuLatencyEstimationPercentile);
    407   else
    408     return base::TimeDelta();
    409 }
    410 
    411 void OutputSurface::UpdateAndMeasureGpuLatency() {
    412   return;  // http://crbug.com/306690  tracks re-enabling latency queries.
    413 
    414   // We only care about GPU latency for surfaces that do not have a parent
    415   // compositor, since surfaces that do have a parent compositor can use
    416   // mailboxes or delegated rendering to send frames to their parent without
    417   // incurring GPU latency.
    418   if (capabilities_.adjust_deadline_for_parent)
    419     return;
    420 
    421   while (pending_gpu_latency_query_ids_.size()) {
    422     unsigned query_id = pending_gpu_latency_query_ids_.front();
    423     unsigned query_complete = 1;
    424     context_provider_->Context3d()->getQueryObjectuivEXT(
    425         query_id, GL_QUERY_RESULT_AVAILABLE_EXT, &query_complete);
    426     if (!query_complete)
    427       break;
    428 
    429     unsigned value = 0;
    430     context_provider_->Context3d()->getQueryObjectuivEXT(
    431         query_id, GL_QUERY_RESULT_EXT, &value);
    432     pending_gpu_latency_query_ids_.pop_front();
    433     available_gpu_latency_query_ids_.push_back(query_id);
    434 
    435     base::TimeDelta latency = base::TimeDelta::FromMicroseconds(value);
    436     base::TimeDelta latency_estimate = GpuLatencyEstimate();
    437     gpu_latency_history_.InsertSample(latency);
    438 
    439     base::TimeDelta latency_overestimate;
    440     base::TimeDelta latency_underestimate;
    441     if (latency > latency_estimate)
    442       latency_underestimate = latency - latency_estimate;
    443     else
    444       latency_overestimate = latency_estimate - latency;
    445     UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatency",
    446                                latency,
    447                                base::TimeDelta::FromMilliseconds(1),
    448                                base::TimeDelta::FromMilliseconds(100),
    449                                50);
    450     UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatencyUnderestimate",
    451                                latency_underestimate,
    452                                base::TimeDelta::FromMilliseconds(1),
    453                                base::TimeDelta::FromMilliseconds(100),
    454                                50);
    455     UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatencyOverestimate",
    456                                latency_overestimate,
    457                                base::TimeDelta::FromMilliseconds(1),
    458                                base::TimeDelta::FromMilliseconds(100),
    459                                50);
    460   }
    461 
    462   unsigned gpu_latency_query_id;
    463   if (available_gpu_latency_query_ids_.size()) {
    464     gpu_latency_query_id = available_gpu_latency_query_ids_.front();
    465     available_gpu_latency_query_ids_.pop_front();
    466   } else {
    467     gpu_latency_query_id = context_provider_->Context3d()->createQueryEXT();
    468   }
    469 
    470   context_provider_->Context3d()->beginQueryEXT(GL_LATENCY_QUERY_CHROMIUM,
    471                                                 gpu_latency_query_id);
    472   context_provider_->Context3d()->endQueryEXT(GL_LATENCY_QUERY_CHROMIUM);
    473   pending_gpu_latency_query_ids_.push_back(gpu_latency_query_id);
    474 }
    475 
    476 void OutputSurface::PostSwapBuffersComplete() {
    477   base::MessageLoop::current()->PostTask(
    478       FROM_HERE,
    479       base::Bind(&OutputSurface::OnSwapBuffersComplete,
    480                  weak_ptr_factory_.GetWeakPtr()));
    481 }
    482 
    483 void OutputSurface::SetMemoryPolicy(const ManagedMemoryPolicy& policy) {
    484   TRACE_EVENT1("cc", "OutputSurface::SetMemoryPolicy",
    485                "bytes_limit_when_visible", policy.bytes_limit_when_visible);
    486   // Just ignore the memory manager when it says to set the limit to zero
    487   // bytes. This will happen when the memory manager thinks that the renderer
    488   // is not visible (which the renderer knows better).
    489   if (policy.bytes_limit_when_visible)
    490     client_->SetMemoryPolicy(policy);
    491 }
    492 
    493 }  // namespace cc
    494