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 "base/threading/thread.h"
15 #include "cc/output/compositor_frame.h"
16 #include "cc/output/output_surface.h"
17 #include "cc/surfaces/surface_manager.h"
18 #include "content/browser/compositor/browser_compositor_output_surface.h"
19 #include "content/browser/compositor/browser_compositor_output_surface_proxy.h"
20 #include "content/browser/compositor/gpu_browser_compositor_output_surface.h"
21 #include "content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h"
22 #include "content/browser/compositor/onscreen_display_client.h"
23 #include "content/browser/compositor/reflector_impl.h"
24 #include "content/browser/compositor/software_browser_compositor_output_surface.h"
25 #include "content/browser/compositor/surface_display_output_surface.h"
26 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
27 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
28 #include "content/browser/gpu/compositor_util.h"
29 #include "content/browser/gpu/gpu_data_manager_impl.h"
30 #include "content/browser/gpu/gpu_surface_tracker.h"
31 #include "content/browser/renderer_host/render_widget_host_impl.h"
32 #include "content/common/gpu/client/context_provider_command_buffer.h"
33 #include "content/common/gpu/client/gl_helper.h"
34 #include "content/common/gpu/client/gpu_channel_host.h"
35 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
36 #include "content/common/gpu/gpu_process_launch_causes.h"
37 #include "content/common/host_shared_bitmap_manager.h"
38 #include "content/public/common/content_switches.h"
39 #include "gpu/GLES2/gl2extchromium.h"
40 #include "gpu/command_buffer/client/gles2_interface.h"
41 #include "gpu/command_buffer/common/mailbox.h"
42 #include "third_party/khronos/GLES2/gl2.h"
43 #include "ui/compositor/compositor.h"
44 #include "ui/compositor/compositor_constants.h"
45 #include "ui/compositor/compositor_switches.h"
46 #include "ui/gfx/native_widget_types.h"
47 #include "ui/gfx/size.h"
50 #include "content/browser/compositor/software_output_device_win.h"
51 #elif defined(USE_OZONE)
52 #include "content/browser/compositor/overlay_candidate_validator_ozone.h"
53 #include "content/browser/compositor/software_output_device_ozone.h"
54 #include "ui/ozone/public/surface_factory_ozone.h"
55 #elif defined(USE_X11)
56 #include "content/browser/compositor/software_output_device_x11.h"
57 #elif defined(OS_MACOSX)
58 #include "content/browser/compositor/software_output_device_mac.h"
61 using cc::ContextProvider
;
62 using gpu::gles2::GLES2Interface
;
66 struct GpuProcessTransportFactory::PerCompositorData
{
68 scoped_refptr
<ReflectorImpl
> reflector
;
69 scoped_ptr
<OnscreenDisplayClient
> display_client
;
72 GpuProcessTransportFactory::GpuProcessTransportFactory()
73 : next_surface_id_namespace_(1u),
74 callback_factory_(this) {
75 output_surface_proxy_
= new BrowserCompositorOutputSurfaceProxy(
76 &output_surface_map_
);
77 #if defined(OS_CHROMEOS)
78 bool use_thread
= !base::CommandLine::ForCurrentProcess()->HasSwitch(
79 switches::kUIDisableThreadedCompositing
);
81 bool use_thread
= false;
84 compositor_thread_
.reset(new base::Thread("Browser Compositor"));
85 compositor_thread_
->Start();
87 if (UseSurfacesEnabled())
88 surface_manager_
= make_scoped_ptr(new cc::SurfaceManager
);
91 GpuProcessTransportFactory::~GpuProcessTransportFactory() {
92 DCHECK(per_compositor_data_
.empty());
94 // Make sure the lost context callback doesn't try to run during destruction.
95 callback_factory_
.InvalidateWeakPtrs();
98 scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
>
99 GpuProcessTransportFactory::CreateOffscreenCommandBufferContext() {
100 CauseForGpuLaunch cause
=
101 CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE
;
102 scoped_refptr
<GpuChannelHost
> gpu_channel_host(
103 BrowserGpuChannelHostFactory::instance()->EstablishGpuChannelSync(cause
));
104 return CreateContextCommon(gpu_channel_host
, 0);
107 scoped_ptr
<cc::SoftwareOutputDevice
> CreateSoftwareOutputDevice(
108 ui::Compositor
* compositor
) {
110 return scoped_ptr
<cc::SoftwareOutputDevice
>(new SoftwareOutputDeviceWin(
112 #elif defined(USE_OZONE)
113 return scoped_ptr
<cc::SoftwareOutputDevice
>(new SoftwareOutputDeviceOzone(
115 #elif defined(USE_X11)
116 return scoped_ptr
<cc::SoftwareOutputDevice
>(new SoftwareOutputDeviceX11(
118 #elif defined(OS_MACOSX)
119 return scoped_ptr
<cc::SoftwareOutputDevice
>(
120 new SoftwareOutputDeviceMac(compositor
));
123 return scoped_ptr
<cc::SoftwareOutputDevice
>();
127 scoped_ptr
<cc::OverlayCandidateValidator
> CreateOverlayCandidateValidator(
128 gfx::AcceleratedWidget widget
) {
129 #if defined(USE_OZONE)
130 ui::OverlayCandidatesOzone
* overlay_candidates
=
131 ui::SurfaceFactoryOzone::GetInstance()->GetOverlayCandidates(widget
);
132 if (overlay_candidates
&&
133 base::CommandLine::ForCurrentProcess()->HasSwitch(
134 switches::kEnableHardwareOverlays
)) {
135 return scoped_ptr
<cc::OverlayCandidateValidator
>(
136 new OverlayCandidateValidatorOzone(widget
, overlay_candidates
));
139 return scoped_ptr
<cc::OverlayCandidateValidator
>();
142 void GpuProcessTransportFactory::CreateOutputSurface(
143 base::WeakPtr
<ui::Compositor
> compositor
,
144 bool software_fallback
) {
145 DCHECK(!!compositor
);
146 PerCompositorData
* data
= per_compositor_data_
[compositor
.get()];
148 data
= CreatePerCompositorData(compositor
.get());
150 bool create_software_renderer
= software_fallback
;
151 #if defined(OS_CHROMEOS)
152 // Software fallback does not happen on Chrome OS.
153 create_software_renderer
= false;
154 #elif defined(OS_WIN)
155 if (::GetProp(compositor
->widget(), kForceSoftwareCompositor
)) {
156 if (::RemoveProp(compositor
->widget(), kForceSoftwareCompositor
))
157 create_software_renderer
= true;
160 if (!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor())
161 create_software_renderer
= true;
163 if (!create_software_renderer
) {
164 CauseForGpuLaunch cause
=
165 CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE
;
166 BrowserGpuChannelHostFactory::instance()->EstablishGpuChannel(
168 base::Bind(&GpuProcessTransportFactory::EstablishedGpuChannel
,
169 callback_factory_
.GetWeakPtr(),
171 create_software_renderer
));
173 EstablishedGpuChannel(compositor
, create_software_renderer
);
177 void GpuProcessTransportFactory::EstablishedGpuChannel(
178 base::WeakPtr
<ui::Compositor
> compositor
,
179 bool create_software_renderer
) {
182 PerCompositorData
* data
= per_compositor_data_
[compositor
.get()];
184 scoped_refptr
<GpuChannelHost
> gpu_channel_host
=
185 BrowserGpuChannelHostFactory::instance()->GetGpuChannel();
186 scoped_refptr
<ContextProviderCommandBuffer
> context_provider
;
187 if (gpu_channel_host
.get() && !create_software_renderer
) {
188 context_provider
= ContextProviderCommandBuffer::Create(
189 GpuProcessTransportFactory::CreateContextCommon(gpu_channel_host
,
194 UMA_HISTOGRAM_BOOLEAN("Aura.CreatedGpuBrowserCompositor",
195 !!context_provider
.get());
197 if (context_provider
.get()) {
198 scoped_refptr
<base::SingleThreadTaskRunner
> compositor_thread_task_runner
=
199 GetCompositorMessageLoop();
200 if (!compositor_thread_task_runner
.get())
201 compositor_thread_task_runner
= base::MessageLoopProxy::current();
203 // Here we know the GpuProcessHost has been set up, because we created a
205 output_surface_proxy_
->ConnectToGpuProcessHost(
206 compositor_thread_task_runner
.get());
209 if (UseSurfacesEnabled()) {
210 // This gets a bit confusing. Here we have a ContextProvider configured to
211 // render directly to this widget. We need to make an OnscreenDisplayClient
212 // associated with this context, then return a SurfaceDisplayOutputSurface
213 // set up to draw to the display's surface.
214 cc::SurfaceManager
* manager
= surface_manager_
.get();
215 scoped_ptr
<cc::OutputSurface
> display_surface
;
216 if (!context_provider
.get()) {
218 make_scoped_ptr(new SoftwareBrowserCompositorOutputSurface(
219 output_surface_proxy_
,
220 CreateSoftwareOutputDevice(compositor
.get()),
222 &output_surface_map_
,
223 compositor
->vsync_manager()));
225 display_surface
= make_scoped_ptr(new GpuBrowserCompositorOutputSurface(
228 &output_surface_map_
,
229 compositor
->vsync_manager(),
230 CreateOverlayCandidateValidator(compositor
->widget())));
232 scoped_ptr
<OnscreenDisplayClient
> display_client(new OnscreenDisplayClient(
233 display_surface
.Pass(), manager
, compositor
->GetRendererSettings(),
234 compositor
->task_runner()));
236 scoped_ptr
<SurfaceDisplayOutputSurface
> output_surface(
237 new SurfaceDisplayOutputSurface(
238 manager
, compositor
->surface_id_allocator(), context_provider
));
239 display_client
->set_surface_output_surface(output_surface
.get());
240 output_surface
->set_display_client(display_client
.get());
241 display_client
->display()->Resize(compositor
->size());
242 data
->display_client
= display_client
.Pass();
243 compositor
->SetOutputSurface(output_surface
.Pass());
247 if (!context_provider
.get()) {
248 if (compositor_thread_
.get()) {
249 LOG(FATAL
) << "Failed to create UI context, but can't use software"
250 " compositing with browser threaded compositing. Aborting.";
253 scoped_ptr
<SoftwareBrowserCompositorOutputSurface
> surface(
254 new SoftwareBrowserCompositorOutputSurface(
255 output_surface_proxy_
,
256 CreateSoftwareOutputDevice(compositor
.get()),
258 &output_surface_map_
,
259 compositor
->vsync_manager()));
260 compositor
->SetOutputSurface(surface
.Pass());
264 scoped_ptr
<BrowserCompositorOutputSurface
> surface
;
265 #if defined(USE_OZONE)
266 if (ui::SurfaceFactoryOzone::GetInstance()->CanShowPrimaryPlaneAsOverlay()) {
267 surface
.reset(new GpuSurfacelessBrowserCompositorOutputSurface(
268 context_provider
, data
->surface_id
, &output_surface_map_
,
269 compositor
->vsync_manager(),
270 CreateOverlayCandidateValidator(compositor
->widget()), GL_RGB
,
271 compositor_thread_
!= nullptr,
272 BrowserGpuMemoryBufferManager::current()));
276 surface
.reset(new GpuBrowserCompositorOutputSurface(
279 &output_surface_map_
,
280 compositor
->vsync_manager(),
281 CreateOverlayCandidateValidator(compositor
->widget())));
283 if (data
->reflector
.get())
284 data
->reflector
->ReattachToOutputSurfaceFromMainThread(surface
.get());
286 compositor
->SetOutputSurface(surface
.Pass());
289 scoped_refptr
<ui::Reflector
> GpuProcessTransportFactory::CreateReflector(
290 ui::Compositor
* source
,
292 PerCompositorData
* data
= per_compositor_data_
[source
];
295 data
->reflector
= new ReflectorImpl(source
,
297 &output_surface_map_
,
298 GetCompositorMessageLoop(),
300 return data
->reflector
;
303 void GpuProcessTransportFactory::RemoveReflector(
304 scoped_refptr
<ui::Reflector
> reflector
) {
305 ReflectorImpl
* reflector_impl
=
306 static_cast<ReflectorImpl
*>(reflector
.get());
307 PerCompositorData
* data
=
308 per_compositor_data_
[reflector_impl
->mirrored_compositor()];
310 data
->reflector
->Shutdown();
311 data
->reflector
= NULL
;
314 void GpuProcessTransportFactory::RemoveCompositor(ui::Compositor
* compositor
) {
315 PerCompositorDataMap::iterator it
= per_compositor_data_
.find(compositor
);
316 if (it
== per_compositor_data_
.end())
318 PerCompositorData
* data
= it
->second
;
320 GpuSurfaceTracker::Get()->RemoveSurface(data
->surface_id
);
322 per_compositor_data_
.erase(it
);
323 if (per_compositor_data_
.empty()) {
324 // Destroying the GLHelper may cause some async actions to be cancelled,
325 // causing things to request a new GLHelper. Due to crbug.com/176091 the
326 // GLHelper created in this case would be lost/leaked if we just reset()
327 // on the |gl_helper_| variable directly. So instead we call reset() on a
329 scoped_ptr
<GLHelper
> helper
= gl_helper_
.Pass();
331 // If there are any observer left at this point, make sure they clean up
332 // before we destroy the GLHelper.
334 ImageTransportFactoryObserver
, observer_list_
, OnLostResources());
337 DCHECK(!gl_helper_
) << "Destroying the GLHelper should not cause a new "
338 "GLHelper to be created.";
342 bool GpuProcessTransportFactory::DoesCreateTestContexts() { return false; }
344 cc::SharedBitmapManager
* GpuProcessTransportFactory::GetSharedBitmapManager() {
345 return HostSharedBitmapManager::current();
348 gpu::GpuMemoryBufferManager
*
349 GpuProcessTransportFactory::GetGpuMemoryBufferManager() {
350 return BrowserGpuMemoryBufferManager::current();
353 ui::ContextFactory
* GpuProcessTransportFactory::GetContextFactory() {
357 base::MessageLoopProxy
* GpuProcessTransportFactory::GetCompositorMessageLoop() {
358 if (!compositor_thread_
)
360 return compositor_thread_
->message_loop_proxy().get();
363 gfx::GLSurfaceHandle
GpuProcessTransportFactory::GetSharedSurfaceHandle() {
364 gfx::GLSurfaceHandle handle
= gfx::GLSurfaceHandle(
365 gfx::kNullPluginWindow
, gfx::NULL_TRANSPORT
);
366 handle
.parent_client_id
=
367 BrowserGpuChannelHostFactory::instance()->GetGpuChannelId();
371 scoped_ptr
<cc::SurfaceIdAllocator
>
372 GpuProcessTransportFactory::CreateSurfaceIdAllocator() {
373 return make_scoped_ptr(
374 new cc::SurfaceIdAllocator(next_surface_id_namespace_
++));
377 void GpuProcessTransportFactory::ResizeDisplay(ui::Compositor
* compositor
,
378 const gfx::Size
& size
) {
379 PerCompositorDataMap::iterator it
= per_compositor_data_
.find(compositor
);
380 if (it
== per_compositor_data_
.end())
382 PerCompositorData
* data
= it
->second
;
384 if (data
->display_client
)
385 data
->display_client
->display()->Resize(size
);
388 cc::SurfaceManager
* GpuProcessTransportFactory::GetSurfaceManager() {
389 return surface_manager_
.get();
392 GLHelper
* GpuProcessTransportFactory::GetGLHelper() {
393 if (!gl_helper_
&& !per_compositor_data_
.empty()) {
394 scoped_refptr
<cc::ContextProvider
> provider
=
395 SharedMainThreadContextProvider();
397 gl_helper_
.reset(new GLHelper(provider
->ContextGL(),
398 provider
->ContextSupport()));
400 return gl_helper_
.get();
403 void GpuProcessTransportFactory::AddObserver(
404 ImageTransportFactoryObserver
* observer
) {
405 observer_list_
.AddObserver(observer
);
408 void GpuProcessTransportFactory::RemoveObserver(
409 ImageTransportFactoryObserver
* observer
) {
410 observer_list_
.RemoveObserver(observer
);
413 #if defined(OS_MACOSX)
414 void GpuProcessTransportFactory::OnSurfaceDisplayed(int surface_id
) {
415 BrowserCompositorOutputSurface
* surface
= output_surface_map_
.Lookup(
418 surface
->OnSurfaceDisplayed();
422 scoped_refptr
<cc::ContextProvider
>
423 GpuProcessTransportFactory::SharedMainThreadContextProvider() {
424 if (shared_main_thread_contexts_
.get())
425 return shared_main_thread_contexts_
;
427 // In threaded compositing mode, we have to create our own context for the
428 // main thread since the compositor's context will be bound to the
429 // compositor thread. When not in threaded mode, we still need a separate
430 // context so that skia and gl_helper don't step on each other.
431 shared_main_thread_contexts_
= ContextProviderCommandBuffer::Create(
432 GpuProcessTransportFactory::CreateOffscreenCommandBufferContext(),
433 "Offscreen-MainThread");
435 if (shared_main_thread_contexts_
.get()) {
436 shared_main_thread_contexts_
->SetLostContextCallback(
437 base::Bind(&GpuProcessTransportFactory::
438 OnLostMainThreadSharedContextInsideCallback
,
439 callback_factory_
.GetWeakPtr()));
440 if (!shared_main_thread_contexts_
->BindToCurrentThread())
441 shared_main_thread_contexts_
= NULL
;
443 return shared_main_thread_contexts_
;
446 GpuProcessTransportFactory::PerCompositorData
*
447 GpuProcessTransportFactory::CreatePerCompositorData(
448 ui::Compositor
* compositor
) {
449 DCHECK(!per_compositor_data_
[compositor
]);
451 gfx::AcceleratedWidget widget
= compositor
->widget();
452 GpuSurfaceTracker
* tracker
= GpuSurfaceTracker::Get();
454 PerCompositorData
* data
= new PerCompositorData
;
455 data
->surface_id
= tracker
->AddSurfaceForNativeWidget(widget
);
456 tracker
->SetSurfaceHandle(
458 gfx::GLSurfaceHandle(widget
, gfx::NATIVE_DIRECT
));
460 per_compositor_data_
[compositor
] = data
;
465 scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
>
466 GpuProcessTransportFactory::CreateContextCommon(
467 scoped_refptr
<GpuChannelHost
> gpu_channel_host
,
469 if (!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor())
470 return scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
>();
471 blink::WebGraphicsContext3D::Attributes attrs
;
472 attrs
.shareResources
= true;
474 attrs
.stencil
= false;
475 attrs
.antialias
= false;
476 attrs
.noAutomaticFlushes
= true;
477 bool lose_context_when_out_of_memory
= true;
478 if (!gpu_channel_host
.get()) {
479 LOG(ERROR
) << "Failed to establish GPU channel.";
480 return scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
>();
482 GURL
url("chrome://gpu/GpuProcessTransportFactory::CreateContextCommon");
483 scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
> context(
484 new WebGraphicsContext3DCommandBufferImpl(
487 gpu_channel_host
.get(),
489 lose_context_when_out_of_memory
,
490 WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits(),
492 return context
.Pass();
495 void GpuProcessTransportFactory::OnLostMainThreadSharedContextInsideCallback() {
496 base::MessageLoop::current()->PostTask(
498 base::Bind(&GpuProcessTransportFactory::OnLostMainThreadSharedContext
,
499 callback_factory_
.GetWeakPtr()));
502 void GpuProcessTransportFactory::OnLostMainThreadSharedContext() {
503 LOG(ERROR
) << "Lost UI shared context.";
505 // Keep old resources around while we call the observers, but ensure that
506 // new resources are created if needed.
507 // Kill shared contexts for both threads in tandem so they are always in
508 // the same share group.
509 scoped_refptr
<cc::ContextProvider
> lost_shared_main_thread_contexts
=
510 shared_main_thread_contexts_
;
511 shared_main_thread_contexts_
= NULL
;
513 scoped_ptr
<GLHelper
> lost_gl_helper
= gl_helper_
.Pass();
515 FOR_EACH_OBSERVER(ImageTransportFactoryObserver
,
519 // Kill things that use the shared context before killing the shared context.
520 lost_gl_helper
.reset();
521 lost_shared_main_thread_contexts
= NULL
;
524 } // namespace content