• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GetDefaultAttribs()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 
CreateOffscreenContext(const blink::WebGraphicsContext3D::Attributes & attributes)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 
CreateContext(scoped_refptr<gpu::InProcessCommandBuffer::Service> service,gpu::GLInProcessContext * share_context)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 
WrapContext(scoped_ptr<gpu::GLInProcessContext> context)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>
WrapContextWithAttributes(scoped_ptr<gpu::GLInProcessContext> context,const blink::WebGraphicsContext3D::Attributes & attributes)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:
VideoContextProvider(scoped_ptr<gpu::GLInProcessContext> gl_in_process_context)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 
GetSurfaceTexture(uint32 stream_id)117   virtual scoped_refptr<gfx::SurfaceTexture> GetSurfaceTexture(
118       uint32 stream_id) OVERRIDE {
119     return gl_in_process_context_->GetSurfaceTexture(stream_id);
120   }
121 
ContextGL()122   virtual gpu::gles2::GLES2Interface* ContextGL() OVERRIDE {
123     return context_provider_->ContextGL();
124   }
125 
AddObserver(StreamTextureFactoryContextObserver * obs)126   virtual void AddObserver(StreamTextureFactoryContextObserver* obs) OVERRIDE {
127     observer_list_.AddObserver(obs);
128   }
129 
RemoveObserver(StreamTextureFactoryContextObserver * obs)130   virtual void RemoveObserver(
131       StreamTextureFactoryContextObserver* obs) OVERRIDE {
132     observer_list_.RemoveObserver(obs);
133   }
134 
RestoreContext()135   void RestoreContext() {
136     FOR_EACH_OBSERVER(StreamTextureFactoryContextObserver,
137                       observer_list_,
138                       ResetStreamTextureProxy());
139   }
140 
141  private:
142   friend class base::RefCountedThreadSafe<VideoContextProvider>;
~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 
SynchronousCompositorFactoryImpl()154 SynchronousCompositorFactoryImpl::SynchronousCompositorFactoryImpl()
155     : record_full_layer_(true),
156       num_hardware_compositors_(0) {
157   SynchronousCompositorFactory::SetInstance(this);
158 }
159 
~SynchronousCompositorFactoryImpl()160 SynchronousCompositorFactoryImpl::~SynchronousCompositorFactoryImpl() {}
161 
162 scoped_refptr<base::MessageLoopProxy>
GetCompositorMessageLoop()163 SynchronousCompositorFactoryImpl::GetCompositorMessageLoop() {
164   return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
165 }
166 
167 bool
RecordFullLayer()168 SynchronousCompositorFactoryImpl::RecordFullLayer() {
169   return record_full_layer_;
170 }
171 
172 scoped_ptr<cc::OutputSurface>
CreateOutputSurface(int routing_id)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*
GetInputHandlerManagerClient()180 SynchronousCompositorFactoryImpl::GetInputHandlerManagerClient() {
181   return synchronous_input_event_filter();
182 }
183 
184 scoped_refptr<ContextProviderWebContext> SynchronousCompositorFactoryImpl::
GetSharedOffscreenContextProviderForMainThread()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::
CreateOnscreenContextProviderForCompositorThread()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 
GetShareContext()216 gpu::GLInProcessContext* SynchronousCompositorFactoryImpl::GetShareContext() {
217   DCHECK(share_context_.get());
218   return share_context_.get();
219 }
220 
221 scoped_refptr<StreamTextureFactory>
CreateStreamTextureFactory(int frame_id)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*
CreateOffscreenGraphicsContext3D(const blink::WebGraphicsContext3D::Attributes & attributes)233 SynchronousCompositorFactoryImpl::CreateOffscreenGraphicsContext3D(
234     const blink::WebGraphicsContext3D::Attributes& attributes) {
235   return WrapContextWithAttributes(CreateOffscreenContext(attributes),
236                                    attributes).release();
237 }
238 
CompositorInitializedHardwareDraw()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 
CompositorReleasedHardwareDraw()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 
RestoreContextOnMainThread()257 void SynchronousCompositorFactoryImpl::RestoreContextOnMainThread() {
258   if (CanCreateMainThreadContext() && video_context_provider_ )
259     video_context_provider_->RestoreContext();
260 }
261 
CanCreateMainThreadContext()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>
TryCreateStreamTextureFactory()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 
SetDeferredGpuService(scoped_refptr<gpu::InProcessCommandBuffer::Service> service)293 void SynchronousCompositorFactoryImpl::SetDeferredGpuService(
294     scoped_refptr<gpu::InProcessCommandBuffer::Service> service) {
295   DCHECK(!service_);
296   service_ = service;
297 }
298 
SetRecordFullDocument(bool record_full_document)299 void SynchronousCompositorFactoryImpl::SetRecordFullDocument(
300     bool record_full_document) {
301   record_full_layer_ = record_full_document;
302 }
303 
304 }  // namespace content
305