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 25namespace content { 26 27namespace { 28 29void DidActivatePendingTree(int routing_id) { 30 SynchronousCompositorOutputSurfaceDelegate* delegate = 31 SynchronousCompositorImpl::FromRoutingID(routing_id); 32 if (delegate) 33 delegate->DidActivatePendingTree(); 34} 35 36} // namespace 37 38class 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 70SynchronousCompositorOutputSurface::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 94SynchronousCompositorOutputSurface::~SynchronousCompositorOutputSurface() { 95 DCHECK(CalledOnValidThread()); 96 SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate(); 97 if (delegate) 98 delegate->DidDestroySynchronousOutputSurface(this); 99} 100 101bool 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 119void SynchronousCompositorOutputSurface::Reshape( 120 const gfx::Size& size, float scale_factor) { 121 // Intentional no-op: surface size is controlled by the embedder. 122} 123 124void 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 132void 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 142namespace { 143void 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 149bool 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 158void SynchronousCompositorOutputSurface::ReleaseHwDraw() { 159 DCHECK(CalledOnValidThread()); 160 cc::OutputSurface::ReleaseGL(); 161} 162 163scoped_ptr<cc::CompositorFrame> 164SynchronousCompositorOutputSurface::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 186scoped_ptr<cc::CompositorFrame> 187SynchronousCompositorOutputSurface::DemandDrawSw(SkCanvas* canvas) { 188 DCHECK(CalledOnValidThread()); 189 DCHECK(canvas); 190 DCHECK(!current_sw_canvas_); 191 base::AutoReset<SkCanvas*> canvas_resetter(¤t_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 216void 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 266void SynchronousCompositorOutputSurface::ReturnResources( 267 const cc::CompositorFrameAck& frame_ack) { 268 ReclaimResources(&frame_ack); 269} 270 271void 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 281void 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. 292bool SynchronousCompositorOutputSurface::CalledOnValidThread() const { 293 return BrowserThread::CurrentlyOn(BrowserThread::UI); 294} 295 296SynchronousCompositorOutputSurfaceDelegate* 297SynchronousCompositorOutputSurface::GetDelegate() { 298 return SynchronousCompositorImpl::FromRoutingID(routing_id_); 299} 300 301} // namespace content 302