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
GetDefaultAttribs()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
CreateOffscreenContext(const blink::WebGraphicsContext3D::Attributes & attributes)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
CreateContext(scoped_refptr<gpu::InProcessCommandBuffer::Service> service,const gpu::GLInProcessContextSharedMemoryLimits & mem_limits)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
WrapContext(scoped_ptr<gpu::GLInProcessContext> context)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>
WrapContextWithAttributes(scoped_ptr<gpu::GLInProcessContext> context,const blink::WebGraphicsContext3D::Attributes & attributes)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:
VideoContextProvider(scoped_ptr<gpu::GLInProcessContext> gl_in_process_context)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
GetSurfaceTexture(uint32 stream_id)122 virtual scoped_refptr<gfx::SurfaceTexture> GetSurfaceTexture(
123 uint32 stream_id) OVERRIDE {
124 return gl_in_process_context_->GetSurfaceTexture(stream_id);
125 }
126
ContextGL()127 virtual gpu::gles2::GLES2Interface* ContextGL() OVERRIDE {
128 return context_provider_->ContextGL();
129 }
130
AddObserver(StreamTextureFactoryContextObserver * obs)131 virtual void AddObserver(StreamTextureFactoryContextObserver* obs) OVERRIDE {
132 observer_list_.AddObserver(obs);
133 }
134
RemoveObserver(StreamTextureFactoryContextObserver * obs)135 virtual void RemoveObserver(
136 StreamTextureFactoryContextObserver* obs) OVERRIDE {
137 observer_list_.RemoveObserver(obs);
138 }
139
RestoreContext()140 void RestoreContext() {
141 FOR_EACH_OBSERVER(StreamTextureFactoryContextObserver,
142 observer_list_,
143 ResetStreamTextureProxy());
144 }
145
146 private:
147 friend class base::RefCountedThreadSafe<VideoContextProvider>;
~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
SynchronousCompositorFactoryImpl()159 SynchronousCompositorFactoryImpl::SynchronousCompositorFactoryImpl()
160 : record_full_layer_(true),
161 num_hardware_compositors_(0) {
162 SynchronousCompositorFactory::SetInstance(this);
163 }
164
~SynchronousCompositorFactoryImpl()165 SynchronousCompositorFactoryImpl::~SynchronousCompositorFactoryImpl() {}
166
167 scoped_refptr<base::MessageLoopProxy>
GetCompositorMessageLoop()168 SynchronousCompositorFactoryImpl::GetCompositorMessageLoop() {
169 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
170 }
171
172 bool
RecordFullLayer()173 SynchronousCompositorFactoryImpl::RecordFullLayer() {
174 return record_full_layer_;
175 }
176
177 scoped_ptr<cc::OutputSurface>
CreateOutputSurface(int routing_id,scoped_refptr<content::FrameSwapMessageQueue> frame_swap_message_queue)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*
GetInputHandlerManagerClient()188 SynchronousCompositorFactoryImpl::GetInputHandlerManagerClient() {
189 return synchronous_input_event_filter();
190 }
191
192 scoped_refptr<ContextProviderWebContext>
CreateOffscreenContextProvider(const blink::WebGraphicsContext3D::Attributes & attributes,const std::string & debug_name)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::
CreateOnscreenContextProviderForCompositorThread()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>
CreateStreamTextureFactory(int frame_id)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*
CreateOffscreenGraphicsContext3D(const blink::WebGraphicsContext3D::Attributes & attributes)227 SynchronousCompositorFactoryImpl::CreateOffscreenGraphicsContext3D(
228 const blink::WebGraphicsContext3D::Attributes& attributes) {
229 return WrapContextWithAttributes(CreateOffscreenContext(attributes),
230 attributes).release();
231 }
232
CompositorInitializedHardwareDraw()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
CompositorReleasedHardwareDraw()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
RestoreContextOnMainThread()251 void SynchronousCompositorFactoryImpl::RestoreContextOnMainThread() {
252 if (CanCreateMainThreadContext() && video_context_provider_ )
253 video_context_provider_->RestoreContext();
254 }
255
CanCreateMainThreadContext()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>
TryCreateStreamTextureFactory()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
SetDeferredGpuService(scoped_refptr<gpu::InProcessCommandBuffer::Service> service)287 void SynchronousCompositorFactoryImpl::SetDeferredGpuService(
288 scoped_refptr<gpu::InProcessCommandBuffer::Service> service) {
289 DCHECK(!service_);
290 service_ = service;
291 }
292
SetRecordFullDocument(bool record_full_document)293 void SynchronousCompositorFactoryImpl::SetRecordFullDocument(
294 bool record_full_document) {
295 record_full_layer_ = record_full_document;
296 }
297
298 } // namespace content
299