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