synchronous_compositor_output_surface.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h" 16#include "content/public/browser/browser_thread.h" 17#include "third_party/skia/include/core/SkCanvas.h" 18#include "third_party/skia/include/core/SkDevice.h" 19#include "ui/gfx/rect_conversions.h" 20#include "ui/gfx/skia_util.h" 21#include "ui/gfx/transform.h" 22#include "ui/gl/gl_context.h" 23#include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h" 24 25using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl; 26 27namespace content { 28 29namespace { 30 31// TODO(boliu): RenderThreadImpl should create in process contexts as well. 32scoped_ptr<WebKit::WebGraphicsContext3D> CreateWebGraphicsContext3D() { 33 WebKit::WebGraphicsContext3D::Attributes attributes; 34 attributes.antialias = false; 35 attributes.shareResources = true; 36 attributes.noAutomaticFlushes = true; 37 38 return scoped_ptr<WebKit::WebGraphicsContext3D>( 39 WebGraphicsContext3DInProcessCommandBufferImpl 40 ::CreateViewContext(attributes, NULL)); 41} 42 43} // namespace 44 45class SynchronousCompositorOutputSurface::SoftwareDevice 46 : public cc::SoftwareOutputDevice { 47 public: 48 SoftwareDevice(SynchronousCompositorOutputSurface* surface) 49 : surface_(surface), 50 null_device_(SkBitmap::kARGB_8888_Config, 1, 1), 51 null_canvas_(&null_device_) { 52 } 53 virtual void Resize(gfx::Size size) OVERRIDE { 54 // Intentional no-op: canvas size is controlled by the embedder. 55 } 56 virtual SkCanvas* BeginPaint(gfx::Rect damage_rect) OVERRIDE { 57 if (!surface_->current_sw_canvas_) { 58 NOTREACHED() << "BeginPaint with no canvas set"; 59 return &null_canvas_; 60 } 61 LOG_IF(WARNING, surface_->did_swap_buffer_) 62 << "Mutliple calls to BeginPaint per frame"; 63 return surface_->current_sw_canvas_; 64 } 65 virtual void EndPaint(cc::SoftwareFrameData* frame_data) OVERRIDE { 66 } 67 virtual void CopyToBitmap(gfx::Rect rect, SkBitmap* output) OVERRIDE { 68 NOTIMPLEMENTED(); 69 } 70 71 private: 72 SynchronousCompositorOutputSurface* surface_; 73 SkDevice null_device_; 74 SkCanvas null_canvas_; 75 76 DISALLOW_COPY_AND_ASSIGN(SoftwareDevice); 77}; 78 79SynchronousCompositorOutputSurface::SynchronousCompositorOutputSurface( 80 int routing_id) 81 : cc::OutputSurface( 82 scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareDevice(this))), 83 routing_id_(routing_id), 84 needs_begin_frame_(false), 85 invoking_composite_(false), 86 did_swap_buffer_(false), 87 current_sw_canvas_(NULL) { 88 capabilities_.deferred_gl_initialization = true; 89 capabilities_.adjust_deadline_for_parent = false; 90 // Cannot call out to GetDelegate() here as the output surface is not 91 // constructed on the correct thread. 92} 93 94SynchronousCompositorOutputSurface::~SynchronousCompositorOutputSurface() { 95 DCHECK(CalledOnValidThread()); 96 SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate(); 97 if (delegate) 98 delegate->DidDestroySynchronousOutputSurface(this); 99} 100 101bool SynchronousCompositorOutputSurface::ForcedDrawToSoftwareDevice() const { 102 // |current_sw_canvas_| indicates we're in a DemandDrawSw call. In addition 103 // |invoking_composite_| == false indicates an attempt to draw outside of 104 // the synchronous compositor's control: force it into SW path and hence to 105 // the null canvas (and will log a warning there). 106 return current_sw_canvas_ != NULL || !invoking_composite_; 107} 108 109bool SynchronousCompositorOutputSurface::BindToClient( 110 cc::OutputSurfaceClient* surface_client) { 111 DCHECK(CalledOnValidThread()); 112 if (!cc::OutputSurface::BindToClient(surface_client)) 113 return false; 114 SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate(); 115 if (delegate) 116 delegate->DidBindOutputSurface(this); 117 return true; 118} 119 120void SynchronousCompositorOutputSurface::Reshape( 121 gfx::Size size, float scale_factor) { 122 // Intentional no-op: surface size is controlled by the embedder. 123} 124 125void SynchronousCompositorOutputSurface::SetNeedsBeginFrame( 126 bool enable) { 127 DCHECK(CalledOnValidThread()); 128 cc::OutputSurface::SetNeedsBeginFrame(enable); 129 needs_begin_frame_ = enable; 130 SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate(); 131 if (delegate) 132 delegate->SetContinuousInvalidate(needs_begin_frame_); 133} 134 135void SynchronousCompositorOutputSurface::SwapBuffers( 136 cc::CompositorFrame* frame) { 137 if (!ForcedDrawToSoftwareDevice()) { 138 DCHECK(context3d()); 139 context3d()->shallowFlushCHROMIUM(); 140 } 141 SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate(); 142 if (delegate) 143 delegate->UpdateFrameMetaData(frame->metadata); 144 145 did_swap_buffer_ = true; 146 DidSwapBuffers(); 147} 148 149namespace { 150void AdjustTransformForClip(gfx::Transform* transform, gfx::Rect clip) { 151 // The system-provided transform translates us from the screen origin to the 152 // origin of the clip rect, but CC's draw origin starts at the clip. 153 transform->matrix().postTranslate(-clip.x(), -clip.y(), 0); 154} 155} // namespace 156 157bool SynchronousCompositorOutputSurface::InitializeHwDraw( 158 scoped_refptr<cc::ContextProvider> offscreen_context) { 159 DCHECK(CalledOnValidThread()); 160 DCHECK(HasClient()); 161 DCHECK(!context3d_); 162 163 return InitializeAndSetContext3D(CreateWebGraphicsContext3D().Pass(), 164 offscreen_context); 165} 166 167void SynchronousCompositorOutputSurface::ReleaseHwDraw() { 168 cc::OutputSurface::ReleaseGL(); 169} 170 171bool SynchronousCompositorOutputSurface::DemandDrawHw( 172 gfx::Size surface_size, 173 const gfx::Transform& transform, 174 gfx::Rect clip) { 175 DCHECK(CalledOnValidThread()); 176 DCHECK(HasClient()); 177 DCHECK(context3d()); 178 179 gfx::Transform adjusted_transform = transform; 180 AdjustTransformForClip(&adjusted_transform, clip); 181 surface_size_ = surface_size; 182 SetExternalDrawConstraints(adjusted_transform, clip); 183 InvokeComposite(clip.size()); 184 185 // TODO(boliu): Check if context is lost here. 186 187 return did_swap_buffer_; 188} 189 190bool SynchronousCompositorOutputSurface::DemandDrawSw(SkCanvas* canvas) { 191 DCHECK(CalledOnValidThread()); 192 DCHECK(canvas); 193 DCHECK(!current_sw_canvas_); 194 base::AutoReset<SkCanvas*> canvas_resetter(¤t_sw_canvas_, canvas); 195 196 SkIRect canvas_clip; 197 canvas->getClipDeviceBounds(&canvas_clip); 198 gfx::Rect clip = gfx::SkIRectToRect(canvas_clip); 199 200 gfx::Transform transform(gfx::Transform::kSkipInitialization); 201 transform.matrix() = canvas->getTotalMatrix(); // Converts 3x3 matrix to 4x4. 202 AdjustTransformForClip(&transform, clip); 203 204 surface_size_ = gfx::Size(canvas->getDeviceSize().width(), 205 canvas->getDeviceSize().height()); 206 SetExternalDrawConstraints(transform, clip); 207 208 InvokeComposite(clip.size()); 209 210 return did_swap_buffer_; 211} 212 213void SynchronousCompositorOutputSurface::InvokeComposite( 214 gfx::Size damage_size) { 215 DCHECK(!invoking_composite_); 216 base::AutoReset<bool> invoking_composite_resetter(&invoking_composite_, true); 217 did_swap_buffer_ = false; 218 SetNeedsRedrawRect(gfx::Rect(damage_size)); 219 if (needs_begin_frame_) 220 BeginFrame(cc::BeginFrameArgs::CreateForSynchronousCompositor()); 221 222 if (did_swap_buffer_) 223 OnSwapBuffersComplete(NULL); 224} 225 226void SynchronousCompositorOutputSurface::PostCheckForRetroactiveBeginFrame() { 227 // Synchronous compositor cannot perform retroactive begin frames, so 228 // intentionally no-op here. 229} 230 231// Not using base::NonThreadSafe as we want to enforce a more exacting threading 232// requirement: SynchronousCompositorOutputSurface() must only be used on the UI 233// thread. 234bool SynchronousCompositorOutputSurface::CalledOnValidThread() const { 235 return BrowserThread::CurrentlyOn(BrowserThread::UI); 236} 237 238SynchronousCompositorOutputSurfaceDelegate* 239SynchronousCompositorOutputSurface::GetDelegate() { 240 return SynchronousCompositorImpl::FromRoutingID(routing_id_); 241} 242 243} // namespace content 244