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