Home | History | Annotate | Download | only in in_process
      1 // Copyright 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 "content/browser/android/in_process/synchronous_compositor_output_surface.h"
      6 
      7 #include "base/auto_reset.h"
      8 #include "base/logging.h"
      9 #include "cc/output/begin_frame_args.h"
     10 #include "cc/output/compositor_frame.h"
     11 #include "cc/output/context_provider.h"
     12 #include "cc/output/output_surface_client.h"
     13 #include "cc/output/software_output_device.h"
     14 #include "content/browser/android/in_process/synchronous_compositor_impl.h"
     15 #include "content/browser/gpu/compositor_util.h"
     16 #include "content/public/browser/browser_thread.h"
     17 #include "gpu/command_buffer/client/gles2_interface.h"
     18 #include "gpu/command_buffer/common/gpu_memory_allocation.h"
     19 #include "third_party/skia/include/core/SkCanvas.h"
     20 #include "ui/gfx/rect_conversions.h"
     21 #include "ui/gfx/skia_util.h"
     22 #include "ui/gfx/transform.h"
     23 
     24 namespace content {
     25 
     26 namespace {
     27 
     28 void DidActivatePendingTree(int routing_id) {
     29   SynchronousCompositorOutputSurfaceDelegate* delegate =
     30       SynchronousCompositorImpl::FromRoutingID(routing_id);
     31   if (delegate)
     32     delegate->DidActivatePendingTree();
     33 }
     34 
     35 } // namespace
     36 
     37 class SynchronousCompositorOutputSurface::SoftwareDevice
     38   : public cc::SoftwareOutputDevice {
     39  public:
     40   SoftwareDevice(SynchronousCompositorOutputSurface* surface)
     41     : surface_(surface) {
     42   }
     43   virtual void Resize(const gfx::Size& pixel_size,
     44                       float scale_factor) OVERRIDE {
     45     // Intentional no-op: canvas size is controlled by the embedder.
     46   }
     47   virtual SkCanvas* BeginPaint(const gfx::Rect& damage_rect) OVERRIDE {
     48     if (!surface_->current_sw_canvas_) {
     49       NOTREACHED() << "BeginPaint with no canvas set";
     50       return &null_canvas_;
     51     }
     52     LOG_IF(WARNING, surface_->frame_holder_.get())
     53         << "Mutliple calls to BeginPaint per frame";
     54     return surface_->current_sw_canvas_;
     55   }
     56   virtual void EndPaint(cc::SoftwareFrameData* frame_data) OVERRIDE {
     57   }
     58   virtual void CopyToPixels(const gfx::Rect& rect, void* pixels) OVERRIDE {
     59     NOTIMPLEMENTED();
     60   }
     61 
     62  private:
     63   SynchronousCompositorOutputSurface* surface_;
     64   SkCanvas null_canvas_;
     65 
     66   DISALLOW_COPY_AND_ASSIGN(SoftwareDevice);
     67 };
     68 
     69 SynchronousCompositorOutputSurface::SynchronousCompositorOutputSurface(
     70     int routing_id)
     71     : cc::OutputSurface(
     72           scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareDevice(this))),
     73       routing_id_(routing_id),
     74       needs_begin_frame_(false),
     75       invoking_composite_(false),
     76       current_sw_canvas_(NULL),
     77       memory_policy_(0),
     78       output_surface_client_(NULL) {
     79   capabilities_.deferred_gl_initialization = true;
     80   capabilities_.draw_and_swap_full_viewport_every_frame = true;
     81   capabilities_.adjust_deadline_for_parent = false;
     82   capabilities_.delegated_rendering = true;
     83   capabilities_.max_frames_pending = 1;
     84   // Cannot call out to GetDelegate() here as the output surface is not
     85   // constructed on the correct thread.
     86 
     87   memory_policy_.priority_cutoff_when_visible =
     88       gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE;
     89 }
     90 
     91 SynchronousCompositorOutputSurface::~SynchronousCompositorOutputSurface() {
     92   DCHECK(CalledOnValidThread());
     93   SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
     94   if (delegate)
     95     delegate->DidDestroySynchronousOutputSurface(this);
     96 }
     97 
     98 bool SynchronousCompositorOutputSurface::BindToClient(
     99     cc::OutputSurfaceClient* surface_client) {
    100   DCHECK(CalledOnValidThread());
    101   if (!cc::OutputSurface::BindToClient(surface_client))
    102     return false;
    103 
    104   output_surface_client_ = surface_client;
    105   output_surface_client_->SetTreeActivationCallback(
    106       base::Bind(&DidActivatePendingTree, routing_id_));
    107   output_surface_client_->SetMemoryPolicy(memory_policy_);
    108 
    109   SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
    110   if (delegate)
    111     delegate->DidBindOutputSurface(this);
    112 
    113   return true;
    114 }
    115 
    116 void SynchronousCompositorOutputSurface::Reshape(
    117     const gfx::Size& size, float scale_factor) {
    118   // Intentional no-op: surface size is controlled by the embedder.
    119 }
    120 
    121 void SynchronousCompositorOutputSurface::SetNeedsBeginFrame(bool enable) {
    122   DCHECK(CalledOnValidThread());
    123   needs_begin_frame_ = enable;
    124   SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
    125   if (delegate && !invoking_composite_)
    126     delegate->SetContinuousInvalidate(needs_begin_frame_);
    127 }
    128 
    129 void SynchronousCompositorOutputSurface::SwapBuffers(
    130     cc::CompositorFrame* frame) {
    131   DCHECK(CalledOnValidThread());
    132 
    133   frame_holder_.reset(new cc::CompositorFrame);
    134   frame->AssignTo(frame_holder_.get());
    135 
    136   client_->DidSwapBuffers();
    137 }
    138 
    139 namespace {
    140 void AdjustTransform(gfx::Transform* transform, gfx::Rect viewport) {
    141   // CC's draw origin starts at the viewport.
    142   transform->matrix().postTranslate(-viewport.x(), -viewport.y(), 0);
    143 }
    144 } // namespace
    145 
    146 bool SynchronousCompositorOutputSurface::InitializeHwDraw(
    147     scoped_refptr<cc::ContextProvider> onscreen_context_provider) {
    148   DCHECK(CalledOnValidThread());
    149   DCHECK(HasClient());
    150   DCHECK(!context_provider_);
    151 
    152   return InitializeAndSetContext3d(onscreen_context_provider);
    153 }
    154 
    155 void SynchronousCompositorOutputSurface::ReleaseHwDraw() {
    156   DCHECK(CalledOnValidThread());
    157   cc::OutputSurface::ReleaseGL();
    158 }
    159 
    160 scoped_ptr<cc::CompositorFrame>
    161 SynchronousCompositorOutputSurface::DemandDrawHw(
    162     gfx::Size surface_size,
    163     const gfx::Transform& transform,
    164     gfx::Rect viewport,
    165     gfx::Rect clip,
    166     gfx::Rect viewport_rect_for_tile_priority,
    167     const gfx::Transform& transform_for_tile_priority) {
    168   DCHECK(CalledOnValidThread());
    169   DCHECK(HasClient());
    170   DCHECK(context_provider_);
    171 
    172   surface_size_ = surface_size;
    173   InvokeComposite(transform,
    174                   viewport,
    175                   clip,
    176                   viewport_rect_for_tile_priority,
    177                   transform_for_tile_priority,
    178                   true);
    179 
    180   return frame_holder_.Pass();
    181 }
    182 
    183 scoped_ptr<cc::CompositorFrame>
    184 SynchronousCompositorOutputSurface::DemandDrawSw(SkCanvas* canvas) {
    185   DCHECK(CalledOnValidThread());
    186   DCHECK(canvas);
    187   DCHECK(!current_sw_canvas_);
    188   base::AutoReset<SkCanvas*> canvas_resetter(&current_sw_canvas_, canvas);
    189 
    190   SkIRect canvas_clip;
    191   canvas->getClipDeviceBounds(&canvas_clip);
    192   gfx::Rect clip = gfx::SkIRectToRect(canvas_clip);
    193 
    194   gfx::Transform transform(gfx::Transform::kSkipInitialization);
    195   transform.matrix() = canvas->getTotalMatrix();  // Converts 3x3 matrix to 4x4.
    196 
    197   surface_size_ = gfx::Size(canvas->getDeviceSize().width(),
    198                             canvas->getDeviceSize().height());
    199 
    200   // Resourceless software draw does not need viewport_for_tiling.
    201   gfx::Rect empty;
    202   InvokeComposite(transform, clip, clip, empty, gfx::Transform(), false);
    203 
    204   return frame_holder_.Pass();
    205 }
    206 
    207 void SynchronousCompositorOutputSurface::InvokeComposite(
    208     const gfx::Transform& transform,
    209     gfx::Rect viewport,
    210     gfx::Rect clip,
    211     gfx::Rect viewport_rect_for_tile_priority,
    212     gfx::Transform transform_for_tile_priority,
    213     bool hardware_draw) {
    214   DCHECK(!invoking_composite_);
    215   DCHECK(!frame_holder_.get());
    216   base::AutoReset<bool> invoking_composite_resetter(&invoking_composite_, true);
    217 
    218   gfx::Transform adjusted_transform = transform;
    219   AdjustTransform(&adjusted_transform, viewport);
    220   SetExternalDrawConstraints(adjusted_transform,
    221                              viewport,
    222                              clip,
    223                              viewport_rect_for_tile_priority,
    224                              transform_for_tile_priority,
    225                              !hardware_draw);
    226   SetNeedsRedrawRect(gfx::Rect(viewport.size()));
    227   client_->BeginFrame(cc::BeginFrameArgs::CreateForSynchronousCompositor());
    228 
    229   // After software draws (which might move the viewport arbitrarily), restore
    230   // the previous hardware viewport to allow CC's tile manager to prioritize
    231   // properly.
    232   if (hardware_draw) {
    233     cached_hw_transform_ = adjusted_transform;
    234     cached_hw_viewport_ = viewport;
    235     cached_hw_clip_ = clip;
    236     cached_hw_viewport_rect_for_tile_priority_ =
    237         viewport_rect_for_tile_priority;
    238     cached_hw_transform_for_tile_priority_ = transform_for_tile_priority;
    239   } else {
    240     bool resourceless_software_draw = false;
    241     SetExternalDrawConstraints(cached_hw_transform_,
    242                                cached_hw_viewport_,
    243                                cached_hw_clip_,
    244                                cached_hw_viewport_rect_for_tile_priority_,
    245                                cached_hw_transform_for_tile_priority_,
    246                                resourceless_software_draw);
    247   }
    248 
    249   if (frame_holder_.get())
    250     client_->DidSwapBuffersComplete();
    251 
    252   SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
    253   if (delegate)
    254     delegate->SetContinuousInvalidate(needs_begin_frame_);
    255 }
    256 
    257 void SynchronousCompositorOutputSurface::ReturnResources(
    258     const cc::CompositorFrameAck& frame_ack) {
    259   ReclaimResources(&frame_ack);
    260 }
    261 
    262 void SynchronousCompositorOutputSurface::SetMemoryPolicy(
    263     const SynchronousCompositorMemoryPolicy& policy) {
    264   DCHECK(CalledOnValidThread());
    265   memory_policy_.bytes_limit_when_visible = policy.bytes_limit;
    266   memory_policy_.num_resources_limit = policy.num_resources_limit;
    267 
    268   if (output_surface_client_)
    269     output_surface_client_->SetMemoryPolicy(memory_policy_);
    270 }
    271 
    272 // Not using base::NonThreadSafe as we want to enforce a more exacting threading
    273 // requirement: SynchronousCompositorOutputSurface() must only be used on the UI
    274 // thread.
    275 bool SynchronousCompositorOutputSurface::CalledOnValidThread() const {
    276   return BrowserThread::CurrentlyOn(BrowserThread::UI);
    277 }
    278 
    279 SynchronousCompositorOutputSurfaceDelegate*
    280 SynchronousCompositorOutputSurface::GetDelegate() {
    281   return SynchronousCompositorImpl::FromRoutingID(routing_id_);
    282 }
    283 
    284 }  // namespace content
    285