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