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.
5 #include "content/browser/compositor/gpu_process_transport_factory.h"
10 #include "base/command_line.h"
11 #include "base/location.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/metrics/histogram.h"
14 #include "cc/output/compositor_frame.h"
15 #include "cc/output/output_surface.h"
16 #include "content/browser/compositor/browser_compositor_output_surface.h"
17 #include "content/browser/compositor/browser_compositor_output_surface_proxy.h"
18 #include "content/browser/compositor/gpu_browser_compositor_output_surface.h"
19 #include "content/browser/compositor/reflector_impl.h"
20 #include "content/browser/compositor/software_browser_compositor_output_surface.h"
21 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
22 #include "content/browser/gpu/gpu_data_manager_impl.h"
23 #include "content/browser/gpu/gpu_surface_tracker.h"
24 #include "content/browser/renderer_host/render_widget_host_impl.h"
25 #include "content/common/gpu/client/context_provider_command_buffer.h"
26 #include "content/common/gpu/client/gl_helper.h"
27 #include "content/common/gpu/client/gpu_channel_host.h"
28 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
29 #include "content/common/gpu/gpu_process_launch_causes.h"
30 #include "gpu/GLES2/gl2extchromium.h"
31 #include "gpu/command_buffer/client/gles2_interface.h"
32 #include "gpu/command_buffer/common/mailbox.h"
33 #include "third_party/khronos/GLES2/gl2.h"
34 #include "ui/compositor/compositor.h"
35 #include "ui/compositor/compositor_constants.h"
36 #include "ui/compositor/compositor_switches.h"
37 #include "ui/gfx/native_widget_types.h"
38 #include "ui/gfx/size.h"
41 #include "content/browser/compositor/software_output_device_win.h"
42 #elif defined(USE_OZONE)
43 #include "content/browser/compositor/software_output_device_ozone.h"
44 #elif defined(USE_X11)
45 #include "content/browser/compositor/software_output_device_x11.h"
48 using cc::ContextProvider
;
49 using gpu::gles2::GLES2Interface
;
53 struct GpuProcessTransportFactory::PerCompositorData
{
55 scoped_refptr
<ReflectorImpl
> reflector
;
58 class OwnedTexture
: public ui::Texture
, ImageTransportFactoryObserver
{
60 OwnedTexture(const scoped_refptr
<ContextProvider
>& provider
,
61 const gfx::Size
& size
,
62 float device_scale_factor
,
64 : ui::Texture(true, size
, device_scale_factor
),
66 texture_id_(texture_id
) {
67 ImageTransportFactory::GetInstance()->AddObserver(this);
70 // ui::Texture overrides:
71 virtual unsigned int PrepareTexture() OVERRIDE
{
72 // It's possible that we may have lost the context owning our
73 // texture but not yet fired the OnLostResources callback, so poll to see if
75 if (provider_
&& provider_
->IsContextLost())
80 // ImageTransportFactory overrides:
81 virtual void OnLostResources() OVERRIDE
{
87 virtual ~OwnedTexture() {
88 ImageTransportFactory::GetInstance()->RemoveObserver(this);
93 void DeleteTexture() {
95 provider_
->ContextGL()->DeleteTextures(1, &texture_id_
);
100 scoped_refptr
<cc::ContextProvider
> provider_
;
104 DISALLOW_COPY_AND_ASSIGN(OwnedTexture
);
107 class ImageTransportClientTexture
: public OwnedTexture
{
109 ImageTransportClientTexture(const scoped_refptr
<ContextProvider
>& provider
,
110 float device_scale_factor
,
112 : OwnedTexture(provider
,
117 virtual void Consume(const gpu::Mailbox
& mailbox
,
118 const gfx::Size
& new_size
) OVERRIDE
{
120 if (mailbox
.IsZero())
123 DCHECK(provider_
&& texture_id_
);
124 GLES2Interface
* gl
= provider_
->ContextGL();
125 gl
->BindTexture(GL_TEXTURE_2D
, texture_id_
);
126 gl
->ConsumeTextureCHROMIUM(GL_TEXTURE_2D
, mailbox
.name
);
128 gl
->ShallowFlushCHROMIUM();
131 virtual gpu::Mailbox
Produce() OVERRIDE
{ return mailbox_
; }
134 virtual ~ImageTransportClientTexture() {}
137 gpu::Mailbox mailbox_
;
138 DISALLOW_COPY_AND_ASSIGN(ImageTransportClientTexture
);
141 GpuProcessTransportFactory::GpuProcessTransportFactory()
142 : callback_factory_(this), offscreen_content_bound_to_other_thread_(false) {
143 output_surface_proxy_
= new BrowserCompositorOutputSurfaceProxy(
144 &output_surface_map_
);
147 GpuProcessTransportFactory::~GpuProcessTransportFactory() {
148 DCHECK(per_compositor_data_
.empty());
150 // Make sure the lost context callback doesn't try to run during destruction.
151 callback_factory_
.InvalidateWeakPtrs();
153 if (offscreen_compositor_contexts_
.get() &&
154 offscreen_content_bound_to_other_thread_
) {
155 // Leak shared contexts on other threads, as we can not get to the correct
156 // thread to destroy them.
157 offscreen_compositor_contexts_
->set_leak_on_destroy();
161 scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
>
162 GpuProcessTransportFactory::CreateOffscreenCommandBufferContext() {
163 return CreateContextCommon(0);
166 scoped_ptr
<cc::SoftwareOutputDevice
> CreateSoftwareOutputDevice(
167 ui::Compositor
* compositor
) {
169 return scoped_ptr
<cc::SoftwareOutputDevice
>(new SoftwareOutputDeviceWin(
171 #elif defined(USE_OZONE)
172 return scoped_ptr
<cc::SoftwareOutputDevice
>(new SoftwareOutputDeviceOzone(
174 #elif defined(USE_X11)
175 return scoped_ptr
<cc::SoftwareOutputDevice
>(new SoftwareOutputDeviceX11(
179 return scoped_ptr
<cc::SoftwareOutputDevice
>();
183 scoped_ptr
<cc::OutputSurface
> GpuProcessTransportFactory::CreateOutputSurface(
184 ui::Compositor
* compositor
, bool software_fallback
) {
185 PerCompositorData
* data
= per_compositor_data_
[compositor
];
187 data
= CreatePerCompositorData(compositor
);
189 bool create_software_renderer
= software_fallback
;
190 #if defined(OS_CHROMEOS)
191 // Software fallback does not happen on Chrome OS.
192 create_software_renderer
= false;
193 #elif defined(OS_WIN)
194 if (::GetProp(compositor
->widget(), kForceSoftwareCompositor
)) {
195 if (::RemoveProp(compositor
->widget(), kForceSoftwareCompositor
))
196 create_software_renderer
= true;
200 scoped_refptr
<ContextProviderCommandBuffer
> context_provider
;
201 if (!create_software_renderer
) {
202 context_provider
= ContextProviderCommandBuffer::Create(
203 GpuProcessTransportFactory::CreateContextCommon(data
->surface_id
),
207 UMA_HISTOGRAM_BOOLEAN("Aura.CreatedGpuBrowserCompositor", !!context_provider
);
209 if (!context_provider
.get()) {
210 if (ui::Compositor::WasInitializedWithThread()) {
211 LOG(FATAL
) << "Failed to create UI context, but can't use software"
212 " compositing with browser threaded compositing. Aborting.";
215 scoped_ptr
<SoftwareBrowserCompositorOutputSurface
> surface(
216 new SoftwareBrowserCompositorOutputSurface(
217 output_surface_proxy_
,
218 CreateSoftwareOutputDevice(compositor
),
219 per_compositor_data_
[compositor
]->surface_id
,
220 &output_surface_map_
,
221 compositor
->vsync_manager()));
222 return surface
.PassAs
<cc::OutputSurface
>();
225 scoped_refptr
<base::SingleThreadTaskRunner
> compositor_thread_task_runner
=
226 ui::Compositor::GetCompositorMessageLoop();
227 if (!compositor_thread_task_runner
.get())
228 compositor_thread_task_runner
= base::MessageLoopProxy::current();
230 // Here we know the GpuProcessHost has been set up, because we created a
232 output_surface_proxy_
->ConnectToGpuProcessHost(
233 compositor_thread_task_runner
.get());
235 scoped_ptr
<BrowserCompositorOutputSurface
> surface(
236 new GpuBrowserCompositorOutputSurface(
238 per_compositor_data_
[compositor
]->surface_id
,
239 &output_surface_map_
,
240 compositor
->vsync_manager()));
241 if (data
->reflector
.get())
242 data
->reflector
->ReattachToOutputSurfaceFromMainThread(surface
.get());
244 return surface
.PassAs
<cc::OutputSurface
>();
247 scoped_refptr
<ui::Reflector
> GpuProcessTransportFactory::CreateReflector(
248 ui::Compositor
* source
,
250 PerCompositorData
* data
= per_compositor_data_
[source
];
253 if (data
->reflector
.get())
254 RemoveObserver(data
->reflector
.get());
256 data
->reflector
= new ReflectorImpl(
257 source
, target
, &output_surface_map_
, data
->surface_id
);
258 AddObserver(data
->reflector
.get());
259 return data
->reflector
;
262 void GpuProcessTransportFactory::RemoveReflector(
263 scoped_refptr
<ui::Reflector
> reflector
) {
264 ReflectorImpl
* reflector_impl
=
265 static_cast<ReflectorImpl
*>(reflector
.get());
266 PerCompositorData
* data
=
267 per_compositor_data_
[reflector_impl
->mirrored_compositor()];
269 RemoveObserver(reflector_impl
);
270 data
->reflector
->Shutdown();
271 data
->reflector
= NULL
;
274 void GpuProcessTransportFactory::RemoveCompositor(ui::Compositor
* compositor
) {
275 PerCompositorDataMap::iterator it
= per_compositor_data_
.find(compositor
);
276 if (it
== per_compositor_data_
.end())
278 PerCompositorData
* data
= it
->second
;
280 GpuSurfaceTracker::Get()->RemoveSurface(data
->surface_id
);
282 per_compositor_data_
.erase(it
);
283 if (per_compositor_data_
.empty()) {
284 // Destroying the GLHelper may cause some async actions to be cancelled,
285 // causing things to request a new GLHelper. Due to crbug.com/176091 the
286 // GLHelper created in this case would be lost/leaked if we just reset()
287 // on the |gl_helper_| variable directly. So instead we call reset() on a
289 scoped_ptr
<GLHelper
> helper
= gl_helper_
.Pass();
291 DCHECK(!gl_helper_
) << "Destroying the GLHelper should not cause a new "
292 "GLHelper to be created.";
296 bool GpuProcessTransportFactory::DoesCreateTestContexts() { return false; }
298 ui::ContextFactory
* GpuProcessTransportFactory::AsContextFactory() {
302 gfx::GLSurfaceHandle
GpuProcessTransportFactory::GetSharedSurfaceHandle() {
303 gfx::GLSurfaceHandle handle
= gfx::GLSurfaceHandle(
304 gfx::kNullPluginWindow
, gfx::TEXTURE_TRANSPORT
);
305 handle
.parent_client_id
=
306 BrowserGpuChannelHostFactory::instance()->GetGpuChannelId();
310 scoped_refptr
<ui::Texture
> GpuProcessTransportFactory::CreateTransportClient(
311 float device_scale_factor
) {
312 scoped_refptr
<cc::ContextProvider
> provider
=
313 SharedMainThreadContextProvider();
316 GLuint texture_id
= 0;
317 provider
->ContextGL()->GenTextures(1, &texture_id
);
318 scoped_refptr
<ImageTransportClientTexture
> image(
319 new ImageTransportClientTexture(
320 provider
, device_scale_factor
, texture_id
));
324 scoped_refptr
<ui::Texture
> GpuProcessTransportFactory::CreateOwnedTexture(
325 const gfx::Size
& size
,
326 float device_scale_factor
,
327 unsigned int texture_id
) {
328 scoped_refptr
<cc::ContextProvider
> provider
=
329 SharedMainThreadContextProvider();
332 scoped_refptr
<OwnedTexture
> image(new OwnedTexture(
333 provider
, size
, device_scale_factor
, texture_id
));
337 GLHelper
* GpuProcessTransportFactory::GetGLHelper() {
338 if (!gl_helper_
&& !per_compositor_data_
.empty()) {
339 scoped_refptr
<cc::ContextProvider
> provider
=
340 SharedMainThreadContextProvider();
342 gl_helper_
.reset(new GLHelper(provider
->ContextGL(),
343 provider
->ContextSupport()));
345 return gl_helper_
.get();
348 void GpuProcessTransportFactory::AddObserver(
349 ImageTransportFactoryObserver
* observer
) {
350 observer_list_
.AddObserver(observer
);
353 void GpuProcessTransportFactory::RemoveObserver(
354 ImageTransportFactoryObserver
* observer
) {
355 observer_list_
.RemoveObserver(observer
);
358 scoped_refptr
<cc::ContextProvider
>
359 GpuProcessTransportFactory::OffscreenCompositorContextProvider() {
360 // Don't check for DestroyedOnMainThread() here. We hear about context
361 // loss for this context through the lost context callback. If the context
362 // is lost, we want to leave this ContextProvider available until the lost
363 // context notification is sent to the ImageTransportFactoryObserver clients.
364 if (offscreen_compositor_contexts_
.get())
365 return offscreen_compositor_contexts_
;
367 offscreen_compositor_contexts_
= ContextProviderCommandBuffer::Create(
368 GpuProcessTransportFactory::CreateOffscreenCommandBufferContext(),
369 "Compositor-Offscreen");
370 offscreen_content_bound_to_other_thread_
=
371 ui::Compositor::WasInitializedWithThread();
373 return offscreen_compositor_contexts_
;
376 scoped_refptr
<cc::ContextProvider
>
377 GpuProcessTransportFactory::SharedMainThreadContextProvider() {
378 if (shared_main_thread_contexts_
.get())
379 return shared_main_thread_contexts_
;
381 // In threaded compositing mode, we have to create our own context for the
382 // main thread since the compositor's context will be bound to the
383 // compositor thread. When not in threaded mode, we still need a separate
384 // context so that skia and gl_helper don't step on each other.
385 shared_main_thread_contexts_
= ContextProviderCommandBuffer::Create(
386 GpuProcessTransportFactory::CreateOffscreenCommandBufferContext(),
387 "Offscreen-MainThread");
389 if (shared_main_thread_contexts_
) {
390 shared_main_thread_contexts_
->SetLostContextCallback(
391 base::Bind(&GpuProcessTransportFactory::
392 OnLostMainThreadSharedContextInsideCallback
,
393 callback_factory_
.GetWeakPtr()));
394 if (!shared_main_thread_contexts_
->BindToCurrentThread()) {
395 shared_main_thread_contexts_
= NULL
;
396 offscreen_compositor_contexts_
= NULL
;
399 return shared_main_thread_contexts_
;
402 GpuProcessTransportFactory::PerCompositorData
*
403 GpuProcessTransportFactory::CreatePerCompositorData(
404 ui::Compositor
* compositor
) {
405 DCHECK(!per_compositor_data_
[compositor
]);
407 gfx::AcceleratedWidget widget
= compositor
->widget();
408 GpuSurfaceTracker
* tracker
= GpuSurfaceTracker::Get();
410 PerCompositorData
* data
= new PerCompositorData
;
411 data
->surface_id
= tracker
->AddSurfaceForNativeWidget(widget
);
412 tracker
->SetSurfaceHandle(
414 gfx::GLSurfaceHandle(widget
, gfx::NATIVE_DIRECT
));
416 per_compositor_data_
[compositor
] = data
;
421 scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
>
422 GpuProcessTransportFactory::CreateContextCommon(int surface_id
) {
423 if (!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor())
424 return scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
>();
425 blink::WebGraphicsContext3D::Attributes attrs
;
426 attrs
.shareResources
= true;
428 attrs
.stencil
= false;
429 attrs
.antialias
= false;
430 attrs
.noAutomaticFlushes
= true;
431 CauseForGpuLaunch cause
=
432 CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE
;
433 scoped_refptr
<GpuChannelHost
> gpu_channel_host(
434 BrowserGpuChannelHostFactory::instance()->EstablishGpuChannelSync(cause
));
435 if (!gpu_channel_host
) {
436 LOG(ERROR
) << "Failed to establish GPU channel.";
437 return scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
>();
439 GURL
url("chrome://gpu/GpuProcessTransportFactory::CreateContextCommon");
440 scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
> context(
441 new WebGraphicsContext3DCommandBufferImpl(
444 gpu_channel_host
.get(),
447 WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits(),
449 return context
.Pass();
452 void GpuProcessTransportFactory::OnLostMainThreadSharedContextInsideCallback() {
453 base::MessageLoop::current()->PostTask(
455 base::Bind(&GpuProcessTransportFactory::OnLostMainThreadSharedContext
,
456 callback_factory_
.GetWeakPtr()));
459 void GpuProcessTransportFactory::OnLostMainThreadSharedContext() {
460 LOG(ERROR
) << "Lost UI shared context.";
462 // Keep old resources around while we call the observers, but ensure that
463 // new resources are created if needed.
464 // Kill shared contexts for both threads in tandem so they are always in
465 // the same share group.
466 scoped_refptr
<cc::ContextProvider
> lost_offscreen_compositor_contexts
=
467 offscreen_compositor_contexts_
;
468 scoped_refptr
<cc::ContextProvider
> lost_shared_main_thread_contexts
=
469 shared_main_thread_contexts_
;
470 offscreen_compositor_contexts_
= NULL
;
471 shared_main_thread_contexts_
= NULL
;
473 scoped_ptr
<GLHelper
> lost_gl_helper
= gl_helper_
.Pass();
475 FOR_EACH_OBSERVER(ImageTransportFactoryObserver
,
479 // Kill things that use the shared context before killing the shared context.
480 lost_gl_helper
.reset();
481 lost_offscreen_compositor_contexts
= NULL
;
482 lost_shared_main_thread_contexts
= NULL
;
485 } // namespace content