1 // Copyright 2014 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_factory_impl.h" 6 7 #include "base/observer_list.h" 8 #include "content/browser/android/in_process/synchronous_compositor_output_surface.h" 9 #include "content/public/browser/browser_thread.h" 10 #include "content/renderer/gpu/frame_swap_message_queue.h" 11 #include "gpu/command_buffer/client/gl_in_process_context.h" 12 #include "gpu/command_buffer/common/gles2_cmd_utils.h" 13 #include "ui/gl/android/surface_texture.h" 14 #include "ui/gl/gl_surface.h" 15 #include "ui/gl/gl_surface_stub.h" 16 #include "webkit/common/gpu/context_provider_in_process.h" 17 #include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h" 18 19 using webkit::gpu::ContextProviderWebContext; 20 21 namespace content { 22 23 namespace { 24 25 blink::WebGraphicsContext3D::Attributes GetDefaultAttribs() { 26 blink::WebGraphicsContext3D::Attributes attributes; 27 attributes.antialias = false; 28 attributes.depth = false; 29 attributes.stencil = false; 30 attributes.shareResources = true; 31 attributes.noAutomaticFlushes = true; 32 33 return attributes; 34 } 35 36 using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl; 37 using webkit::gpu::WebGraphicsContext3DImpl; 38 39 scoped_ptr<gpu::GLInProcessContext> CreateOffscreenContext( 40 const blink::WebGraphicsContext3D::Attributes& attributes) { 41 const gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu; 42 43 gpu::gles2::ContextCreationAttribHelper in_process_attribs; 44 WebGraphicsContext3DImpl::ConvertAttributes( 45 attributes, &in_process_attribs); 46 in_process_attribs.lose_context_when_out_of_memory = true; 47 48 scoped_ptr<gpu::GLInProcessContext> context(gpu::GLInProcessContext::Create( 49 NULL /* service */, 50 NULL /* surface */, 51 true /* is_offscreen */, 52 gfx::kNullAcceleratedWidget, 53 gfx::Size(1, 1), 54 NULL /* share_context */, 55 true, // TODO(sievers): Use attributes.shareResources. crbug/443464. 56 in_process_attribs, 57 gpu_preference, 58 gpu::GLInProcessContextSharedMemoryLimits())); 59 return context.Pass(); 60 } 61 62 scoped_ptr<gpu::GLInProcessContext> CreateContext( 63 scoped_refptr<gpu::InProcessCommandBuffer::Service> service, 64 const gpu::GLInProcessContextSharedMemoryLimits& mem_limits) { 65 const gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu; 66 gpu::gles2::ContextCreationAttribHelper in_process_attribs; 67 WebGraphicsContext3DImpl::ConvertAttributes( 68 GetDefaultAttribs(), &in_process_attribs); 69 in_process_attribs.lose_context_when_out_of_memory = true; 70 71 scoped_ptr<gpu::GLInProcessContext> context(gpu::GLInProcessContext::Create( 72 service, 73 NULL /* surface */, 74 false /* is_offscreen */, 75 gfx::kNullAcceleratedWidget, 76 gfx::Size(1, 1), 77 NULL /* share_context */, 78 false /* share_resources */, 79 in_process_attribs, 80 gpu_preference, 81 mem_limits)); 82 return context.Pass(); 83 } 84 85 scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> WrapContext( 86 scoped_ptr<gpu::GLInProcessContext> context) { 87 if (!context.get()) 88 return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>(); 89 90 return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>( 91 WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext( 92 context.Pass(), GetDefaultAttribs())); 93 } 94 95 scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> 96 WrapContextWithAttributes( 97 scoped_ptr<gpu::GLInProcessContext> context, 98 const blink::WebGraphicsContext3D::Attributes& attributes) { 99 if (!context.get()) 100 return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>(); 101 102 return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>( 103 WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext( 104 context.Pass(), attributes)); 105 } 106 107 } // namespace 108 109 class SynchronousCompositorFactoryImpl::VideoContextProvider 110 : public StreamTextureFactorySynchronousImpl::ContextProvider { 111 public: 112 VideoContextProvider( 113 scoped_ptr<gpu::GLInProcessContext> gl_in_process_context) 114 : gl_in_process_context_(gl_in_process_context.get()) { 115 116 context_provider_ = webkit::gpu::ContextProviderInProcess::Create( 117 WrapContext(gl_in_process_context.Pass()), 118 "Video-Offscreen-main-thread"); 119 context_provider_->BindToCurrentThread(); 120 } 121 122 virtual scoped_refptr<gfx::SurfaceTexture> GetSurfaceTexture( 123 uint32 stream_id) OVERRIDE { 124 return gl_in_process_context_->GetSurfaceTexture(stream_id); 125 } 126 127 virtual gpu::gles2::GLES2Interface* ContextGL() OVERRIDE { 128 return context_provider_->ContextGL(); 129 } 130 131 virtual void AddObserver(StreamTextureFactoryContextObserver* obs) OVERRIDE { 132 observer_list_.AddObserver(obs); 133 } 134 135 virtual void RemoveObserver( 136 StreamTextureFactoryContextObserver* obs) OVERRIDE { 137 observer_list_.RemoveObserver(obs); 138 } 139 140 void RestoreContext() { 141 FOR_EACH_OBSERVER(StreamTextureFactoryContextObserver, 142 observer_list_, 143 ResetStreamTextureProxy()); 144 } 145 146 private: 147 friend class base::RefCountedThreadSafe<VideoContextProvider>; 148 virtual ~VideoContextProvider() {} 149 150 scoped_refptr<cc::ContextProvider> context_provider_; 151 gpu::GLInProcessContext* gl_in_process_context_; 152 ObserverList<StreamTextureFactoryContextObserver> observer_list_; 153 154 DISALLOW_COPY_AND_ASSIGN(VideoContextProvider); 155 }; 156 157 using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl; 158 159 SynchronousCompositorFactoryImpl::SynchronousCompositorFactoryImpl() 160 : record_full_layer_(true), 161 num_hardware_compositors_(0) { 162 SynchronousCompositorFactory::SetInstance(this); 163 } 164 165 SynchronousCompositorFactoryImpl::~SynchronousCompositorFactoryImpl() {} 166 167 scoped_refptr<base::MessageLoopProxy> 168 SynchronousCompositorFactoryImpl::GetCompositorMessageLoop() { 169 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI); 170 } 171 172 bool 173 SynchronousCompositorFactoryImpl::RecordFullLayer() { 174 return record_full_layer_; 175 } 176 177 scoped_ptr<cc::OutputSurface> 178 SynchronousCompositorFactoryImpl::CreateOutputSurface( 179 int routing_id, 180 scoped_refptr<content::FrameSwapMessageQueue> frame_swap_message_queue) { 181 scoped_ptr<SynchronousCompositorOutputSurface> output_surface( 182 new SynchronousCompositorOutputSurface(routing_id, 183 frame_swap_message_queue)); 184 return output_surface.PassAs<cc::OutputSurface>(); 185 } 186 187 InputHandlerManagerClient* 188 SynchronousCompositorFactoryImpl::GetInputHandlerManagerClient() { 189 return synchronous_input_event_filter(); 190 } 191 192 scoped_refptr<ContextProviderWebContext> 193 SynchronousCompositorFactoryImpl::CreateOffscreenContextProvider( 194 const blink::WebGraphicsContext3D::Attributes& attributes, 195 const std::string& debug_name) { 196 scoped_ptr<gpu::GLInProcessContext> context = 197 CreateOffscreenContext(attributes); 198 return webkit::gpu::ContextProviderInProcess::Create( 199 WrapContext(context.Pass()), debug_name); 200 } 201 202 scoped_refptr<cc::ContextProvider> SynchronousCompositorFactoryImpl:: 203 CreateOnscreenContextProviderForCompositorThread() { 204 DCHECK(service_); 205 206 gpu::GLInProcessContextSharedMemoryLimits mem_limits; 207 // This is half of what RenderWidget uses because synchronous compositor 208 // pipeline is only one frame deep. 209 mem_limits.mapped_memory_reclaim_limit = 6 * 1024 * 1024; 210 return webkit::gpu::ContextProviderInProcess::Create( 211 WrapContext(CreateContext(service_, mem_limits)), 212 "Child-Compositor"); 213 } 214 215 scoped_refptr<StreamTextureFactory> 216 SynchronousCompositorFactoryImpl::CreateStreamTextureFactory(int frame_id) { 217 scoped_refptr<StreamTextureFactorySynchronousImpl> factory( 218 StreamTextureFactorySynchronousImpl::Create( 219 base::Bind( 220 &SynchronousCompositorFactoryImpl::TryCreateStreamTextureFactory, 221 base::Unretained(this)), 222 frame_id)); 223 return factory; 224 } 225 226 webkit::gpu::WebGraphicsContext3DImpl* 227 SynchronousCompositorFactoryImpl::CreateOffscreenGraphicsContext3D( 228 const blink::WebGraphicsContext3D::Attributes& attributes) { 229 return WrapContextWithAttributes(CreateOffscreenContext(attributes), 230 attributes).release(); 231 } 232 233 void SynchronousCompositorFactoryImpl::CompositorInitializedHardwareDraw() { 234 base::AutoLock lock(num_hardware_compositor_lock_); 235 num_hardware_compositors_++; 236 if (num_hardware_compositors_ == 1 && main_thread_proxy_) { 237 main_thread_proxy_->PostTask( 238 FROM_HERE, 239 base::Bind( 240 &SynchronousCompositorFactoryImpl::RestoreContextOnMainThread, 241 base::Unretained(this))); 242 } 243 } 244 245 void SynchronousCompositorFactoryImpl::CompositorReleasedHardwareDraw() { 246 base::AutoLock lock(num_hardware_compositor_lock_); 247 DCHECK_GT(num_hardware_compositors_, 0u); 248 num_hardware_compositors_--; 249 } 250 251 void SynchronousCompositorFactoryImpl::RestoreContextOnMainThread() { 252 if (CanCreateMainThreadContext() && video_context_provider_ ) 253 video_context_provider_->RestoreContext(); 254 } 255 256 bool SynchronousCompositorFactoryImpl::CanCreateMainThreadContext() { 257 base::AutoLock lock(num_hardware_compositor_lock_); 258 return num_hardware_compositors_ > 0; 259 } 260 261 scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider> 262 SynchronousCompositorFactoryImpl::TryCreateStreamTextureFactory() { 263 { 264 base::AutoLock lock(num_hardware_compositor_lock_); 265 main_thread_proxy_ = base::MessageLoopProxy::current(); 266 } 267 268 // Always fail creation even if |video_context_provider_| is not NULL. 269 // This is to avoid synchronous calls that may deadlock. Setting 270 // |video_context_provider_| to null is also not safe since it makes 271 // synchronous destruction uncontrolled and possibly deadlock. 272 if (!CanCreateMainThreadContext()) { 273 return 274 scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>(); 275 } 276 277 if (!video_context_provider_) { 278 DCHECK(service_); 279 280 video_context_provider_ = new VideoContextProvider( 281 CreateContext(service_, 282 gpu::GLInProcessContextSharedMemoryLimits())); 283 } 284 return video_context_provider_; 285 } 286 287 void SynchronousCompositorFactoryImpl::SetDeferredGpuService( 288 scoped_refptr<gpu::InProcessCommandBuffer::Service> service) { 289 DCHECK(!service_); 290 service_ = service; 291 } 292 293 void SynchronousCompositorFactoryImpl::SetRecordFullDocument( 294 bool record_full_document) { 295 record_full_layer_ = record_full_document; 296 } 297 298 } // namespace content 299