1 // Copyright (c) 2013 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/aura/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/aura/browser_compositor_output_surface.h"
17 #include "content/browser/aura/browser_compositor_output_surface_proxy.h"
18 #include "content/browser/aura/reflector_impl.h"
19 #include "content/browser/aura/software_browser_compositor_output_surface.h"
20 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
21 #include "content/browser/gpu/gpu_data_manager_impl.h"
22 #include "content/browser/gpu/gpu_surface_tracker.h"
23 #include "content/browser/renderer_host/render_widget_host_impl.h"
24 #include "content/common/gpu/client/context_provider_command_buffer.h"
25 #include "content/common/gpu/client/gl_helper.h"
26 #include "content/common/gpu/client/gpu_channel_host.h"
27 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
28 #include "content/common/gpu/gpu_process_launch_causes.h"
29 #include "gpu/GLES2/gl2extchromium.h"
30 #include "third_party/khronos/GLES2/gl2.h"
31 #include "ui/compositor/compositor.h"
32 #include "ui/compositor/compositor_switches.h"
33 #include "ui/gfx/native_widget_types.h"
34 #include "ui/gfx/size.h"
37 #include "content/browser/aura/software_output_device_win.h"
38 #include "ui/surface/accelerated_surface_win.h"
39 #elif defined(USE_X11)
40 #include "content/browser/aura/software_output_device_x11.h"
45 struct GpuProcessTransportFactory::PerCompositorData
{
47 scoped_ptr
<CompositorSwapClient
> swap_client
;
49 scoped_ptr
<AcceleratedSurface
> accelerated_surface
;
51 scoped_refptr
<ReflectorImpl
> reflector
;
54 class OwnedTexture
: public ui::Texture
, ImageTransportFactoryObserver
{
56 OwnedTexture(WebKit::WebGraphicsContext3D
* host_context
,
57 const gfx::Size
& size
,
58 float device_scale_factor
,
59 unsigned int texture_id
)
60 : ui::Texture(true, size
, device_scale_factor
),
61 host_context_(host_context
),
62 texture_id_(texture_id
) {
63 ImageTransportFactory::GetInstance()->AddObserver(this);
66 // ui::Texture overrides:
67 virtual unsigned int PrepareTexture() OVERRIDE
{
71 virtual WebKit::WebGraphicsContext3D
* HostContext3D() OVERRIDE
{
75 // ImageTransportFactory overrides:
76 virtual void OnLostResources() OVERRIDE
{
82 virtual ~OwnedTexture() {
83 ImageTransportFactory::GetInstance()->RemoveObserver(this);
88 void DeleteTexture() {
90 host_context_
->deleteTexture(texture_id_
);
95 // The OnLostResources() callback will happen before this context
96 // pointer is destroyed.
97 WebKit::WebGraphicsContext3D
* host_context_
;
100 DISALLOW_COPY_AND_ASSIGN(OwnedTexture
);
103 class ImageTransportClientTexture
: public OwnedTexture
{
105 ImageTransportClientTexture(
106 WebKit::WebGraphicsContext3D
* host_context
,
107 float device_scale_factor
)
108 : OwnedTexture(host_context
,
111 host_context
->createTexture()) {
114 virtual void Consume(const std::string
& mailbox_name
,
115 const gfx::Size
& new_size
) OVERRIDE
{
116 DCHECK(mailbox_name
.size() == GL_MAILBOX_SIZE_CHROMIUM
);
117 mailbox_name_
= mailbox_name
;
118 if (mailbox_name
.empty())
121 DCHECK(host_context_
&& texture_id_
);
122 host_context_
->bindTexture(GL_TEXTURE_2D
, texture_id_
);
123 host_context_
->consumeTextureCHROMIUM(
125 reinterpret_cast<const signed char*>(mailbox_name
.c_str()));
127 host_context_
->shallowFlushCHROMIUM();
130 virtual std::string
Produce() OVERRIDE
{
131 return mailbox_name_
;
135 virtual ~ImageTransportClientTexture() {}
138 std::string mailbox_name_
;
139 DISALLOW_COPY_AND_ASSIGN(ImageTransportClientTexture
);
142 class CompositorSwapClient
143 : public base::SupportsWeakPtr
<CompositorSwapClient
>,
144 public WebGraphicsContext3DSwapBuffersClient
{
146 CompositorSwapClient(ui::Compositor
* compositor
,
147 GpuProcessTransportFactory
* factory
)
148 : compositor_(compositor
),
152 virtual ~CompositorSwapClient() {
155 virtual void OnViewContextSwapBuffersPosted() OVERRIDE
{
156 compositor_
->OnSwapBuffersPosted();
159 virtual void OnViewContextSwapBuffersComplete() OVERRIDE
{
160 compositor_
->OnSwapBuffersComplete();
163 virtual void OnViewContextSwapBuffersAborted() OVERRIDE
{
164 // Recreating contexts directly from here causes issues, so post a task
166 // TODO(piman): Fix the underlying issues.
167 base::MessageLoop::current()->PostTask(
169 base::Bind(&CompositorSwapClient::OnLostContext
, this->AsWeakPtr()));
173 void OnLostContext() {
174 factory_
->OnLostContext(compositor_
);
175 // Note: previous line destroyed this. Don't access members from now on.
178 ui::Compositor
* compositor_
;
179 GpuProcessTransportFactory
* factory_
;
181 DISALLOW_COPY_AND_ASSIGN(CompositorSwapClient
);
184 GpuProcessTransportFactory::GpuProcessTransportFactory()
185 : callback_factory_(this) {
186 output_surface_proxy_
= new BrowserCompositorOutputSurfaceProxy(
187 &output_surface_map_
);
190 GpuProcessTransportFactory::~GpuProcessTransportFactory() {
191 DCHECK(per_compositor_data_
.empty());
193 // Make sure the lost context callback doesn't try to run during destruction.
194 callback_factory_
.InvalidateWeakPtrs();
197 scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
>
198 GpuProcessTransportFactory::CreateOffscreenCommandBufferContext() {
199 base::WeakPtr
<WebGraphicsContext3DSwapBuffersClient
> swap_client
;
200 return CreateContextCommon(swap_client
, 0);
203 scoped_ptr
<cc::SoftwareOutputDevice
> CreateSoftwareOutputDevice(
204 ui::Compositor
* compositor
) {
206 return scoped_ptr
<cc::SoftwareOutputDevice
>(new SoftwareOutputDeviceWin(
208 #elif defined(USE_X11)
209 return scoped_ptr
<cc::SoftwareOutputDevice
>(new SoftwareOutputDeviceX11(
214 return scoped_ptr
<cc::SoftwareOutputDevice
>();
217 scoped_ptr
<cc::OutputSurface
> GpuProcessTransportFactory::CreateOutputSurface(
218 ui::Compositor
* compositor
) {
219 PerCompositorData
* data
= per_compositor_data_
[compositor
];
221 data
= CreatePerCompositorData(compositor
);
223 scoped_refptr
<ContextProviderCommandBuffer
> context_provider
;
225 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
226 if (!command_line
->HasSwitch(switches::kUIEnableSoftwareCompositing
)) {
227 context_provider
= ContextProviderCommandBuffer::Create(
228 GpuProcessTransportFactory::CreateContextCommon(
229 data
->swap_client
->AsWeakPtr(),
234 UMA_HISTOGRAM_BOOLEAN("Aura.CreatedGpuBrowserCompositor", !!context_provider
);
236 if (!context_provider
.get()) {
237 if (ui::Compositor::WasInitializedWithThread()) {
238 LOG(FATAL
) << "Failed to create UI context, but can't use software"
239 " compositing with browser threaded compositing. Aborting.";
242 scoped_ptr
<SoftwareBrowserCompositorOutputSurface
> surface
=
243 SoftwareBrowserCompositorOutputSurface::Create(
244 CreateSoftwareOutputDevice(compositor
));
245 return surface
.PassAs
<cc::OutputSurface
>();
248 scoped_refptr
<base::SingleThreadTaskRunner
> compositor_thread_task_runner
=
249 ui::Compositor::GetCompositorMessageLoop();
250 if (!compositor_thread_task_runner
.get())
251 compositor_thread_task_runner
= base::MessageLoopProxy::current();
253 // Here we know the GpuProcessHost has been set up, because we created a
255 output_surface_proxy_
->ConnectToGpuProcessHost(
256 compositor_thread_task_runner
.get());
258 scoped_ptr
<BrowserCompositorOutputSurface
> surface(
259 new BrowserCompositorOutputSurface(
261 per_compositor_data_
[compositor
]->surface_id
,
262 &output_surface_map_
,
263 base::MessageLoopProxy::current().get(),
264 compositor
->AsWeakPtr()));
265 if (data
->reflector
.get()) {
266 data
->reflector
->CreateSharedTexture();
267 data
->reflector
->AttachToOutputSurface(surface
.get());
270 return surface
.PassAs
<cc::OutputSurface
>();
273 scoped_refptr
<ui::Reflector
> GpuProcessTransportFactory::CreateReflector(
274 ui::Compositor
* source
,
276 PerCompositorData
* data
= per_compositor_data_
[source
];
279 if (data
->reflector
.get())
280 RemoveObserver(data
->reflector
.get());
282 data
->reflector
= new ReflectorImpl(
283 source
, target
, &output_surface_map_
, data
->surface_id
);
284 AddObserver(data
->reflector
.get());
285 return data
->reflector
;
288 void GpuProcessTransportFactory::RemoveReflector(
289 scoped_refptr
<ui::Reflector
> reflector
) {
290 ReflectorImpl
* reflector_impl
=
291 static_cast<ReflectorImpl
*>(reflector
.get());
292 PerCompositorData
* data
=
293 per_compositor_data_
[reflector_impl
->mirrored_compositor()];
295 RemoveObserver(reflector_impl
);
296 data
->reflector
->Shutdown();
297 data
->reflector
= NULL
;
300 void GpuProcessTransportFactory::RemoveCompositor(ui::Compositor
* compositor
) {
301 PerCompositorDataMap::iterator it
= per_compositor_data_
.find(compositor
);
302 if (it
== per_compositor_data_
.end())
304 PerCompositorData
* data
= it
->second
;
306 GpuSurfaceTracker::Get()->RemoveSurface(data
->surface_id
);
308 per_compositor_data_
.erase(it
);
309 if (per_compositor_data_
.empty())
313 bool GpuProcessTransportFactory::DoesCreateTestContexts() { return false; }
315 ui::ContextFactory
* GpuProcessTransportFactory::AsContextFactory() {
319 gfx::GLSurfaceHandle
GpuProcessTransportFactory::CreateSharedSurfaceHandle() {
320 CreateSharedContextLazy();
321 if (!shared_contexts_main_thread_
||
322 !shared_contexts_main_thread_
->Context3d())
323 return gfx::GLSurfaceHandle();
324 gfx::GLSurfaceHandle handle
= gfx::GLSurfaceHandle(
325 gfx::kNullPluginWindow
, gfx::TEXTURE_TRANSPORT
);
326 handle
.parent_gpu_process_id
=
327 shared_contexts_main_thread_
->Context3d()->GetGPUProcessID();
328 handle
.parent_client_id
=
329 shared_contexts_main_thread_
->Context3d()->GetChannelID();
333 void GpuProcessTransportFactory::DestroySharedSurfaceHandle(
334 gfx::GLSurfaceHandle surface
) {}
336 scoped_refptr
<ui::Texture
> GpuProcessTransportFactory::CreateTransportClient(
337 float device_scale_factor
) {
338 if (!shared_contexts_main_thread_
.get())
340 scoped_refptr
<ImageTransportClientTexture
> image(
341 new ImageTransportClientTexture(
342 shared_contexts_main_thread_
->Context3d(),
343 device_scale_factor
));
347 scoped_refptr
<ui::Texture
> GpuProcessTransportFactory::CreateOwnedTexture(
348 const gfx::Size
& size
,
349 float device_scale_factor
,
350 unsigned int texture_id
) {
351 if (!shared_contexts_main_thread_
.get())
353 scoped_refptr
<OwnedTexture
> image(new OwnedTexture(
354 shared_contexts_main_thread_
->Context3d(),
361 GLHelper
* GpuProcessTransportFactory::GetGLHelper() {
363 CreateSharedContextLazy();
364 WebGraphicsContext3DCommandBufferImpl
* context_for_main_thread
=
365 shared_contexts_main_thread_
->Context3d();
366 gl_helper_
.reset(new GLHelper(context_for_main_thread
));
368 return gl_helper_
.get();
371 uint32
GpuProcessTransportFactory::InsertSyncPoint() {
372 if (!shared_contexts_main_thread_
.get())
374 return shared_contexts_main_thread_
->Context3d()->insertSyncPoint();
377 void GpuProcessTransportFactory::WaitSyncPoint(uint32 sync_point
) {
378 if (!shared_contexts_main_thread_
.get())
380 shared_contexts_main_thread_
->Context3d()->waitSyncPoint(sync_point
);
383 void GpuProcessTransportFactory::AddObserver(
384 ImageTransportFactoryObserver
* observer
) {
385 observer_list_
.AddObserver(observer
);
388 void GpuProcessTransportFactory::RemoveObserver(
389 ImageTransportFactoryObserver
* observer
) {
390 observer_list_
.RemoveObserver(observer
);
393 scoped_refptr
<cc::ContextProvider
>
394 GpuProcessTransportFactory::OffscreenContextProviderForMainThread() {
395 // Don't check for DestroyedOnMainThread() here. We hear about context
396 // loss for this context through the lost context callback. If the context
397 // is lost, we want to leave this ContextProvider available until the lost
398 // context notification is sent to the ImageTransportFactoryObserver clients.
399 if (!shared_contexts_main_thread_
.get()) {
400 shared_contexts_main_thread_
= ContextProviderCommandBuffer::Create(
401 GpuProcessTransportFactory::CreateOffscreenCommandBufferContext(),
402 "Compositor-Offscreen-MainThread");
403 if (shared_contexts_main_thread_
) {
404 shared_contexts_main_thread_
->SetLostContextCallback(base::Bind(
405 &GpuProcessTransportFactory::
406 OnLostMainThreadSharedContextInsideCallback
,
407 callback_factory_
.GetWeakPtr()));
409 if (!shared_contexts_main_thread_
->BindToCurrentThread())
410 shared_contexts_main_thread_
= NULL
;
413 return shared_contexts_main_thread_
;
416 scoped_refptr
<cc::ContextProvider
>
417 GpuProcessTransportFactory::OffscreenContextProviderForCompositorThread() {
418 // The lifetime of this context is tied to the main thread context so that
419 // they are always in the same share group. So do not check for
420 // DestroyedOnMainThread().
421 if (!shared_contexts_compositor_thread_
.get()) {
422 shared_contexts_compositor_thread_
= ContextProviderCommandBuffer::Create(
423 GpuProcessTransportFactory::CreateOffscreenCommandBufferContext(),
424 "Compositor-Offscreen");
426 return shared_contexts_compositor_thread_
;
429 void GpuProcessTransportFactory::OnLostContext(ui::Compositor
* compositor
) {
430 LOG(ERROR
) << "Lost UI compositor context.";
431 PerCompositorData
* data
= per_compositor_data_
[compositor
];
434 // Prevent callbacks from other contexts in the same share group from
436 data
->swap_client
.reset(new CompositorSwapClient(compositor
, this));
437 compositor
->OnSwapBuffersAborted();
440 GpuProcessTransportFactory::PerCompositorData
*
441 GpuProcessTransportFactory::CreatePerCompositorData(
442 ui::Compositor
* compositor
) {
443 DCHECK(!per_compositor_data_
[compositor
]);
445 CreateSharedContextLazy();
447 gfx::AcceleratedWidget widget
= compositor
->widget();
448 GpuSurfaceTracker
* tracker
= GpuSurfaceTracker::Get();
450 PerCompositorData
* data
= new PerCompositorData
;
451 data
->surface_id
= tracker
->AddSurfaceForNativeWidget(widget
);
452 data
->swap_client
.reset(new CompositorSwapClient(compositor
, this));
454 if (GpuDataManagerImpl::GetInstance()->IsUsingAcceleratedSurface())
455 data
->accelerated_surface
.reset(new AcceleratedSurface(widget
));
457 tracker
->SetSurfaceHandle(
459 gfx::GLSurfaceHandle(widget
, gfx::NATIVE_DIRECT
));
461 per_compositor_data_
[compositor
] = data
;
466 scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
>
467 GpuProcessTransportFactory::CreateContextCommon(
468 const base::WeakPtr
<WebGraphicsContext3DSwapBuffersClient
>& swap_client
,
470 if (!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor())
471 return scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
>();
472 WebKit::WebGraphicsContext3D::Attributes attrs
;
473 attrs
.shareResources
= true;
475 attrs
.stencil
= false;
476 attrs
.antialias
= false;
477 attrs
.noAutomaticFlushes
= true;
478 GpuChannelHostFactory
* factory
= BrowserGpuChannelHostFactory::instance();
479 GURL
url("chrome://gpu/GpuProcessTransportFactory::CreateContextCommon");
480 scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
> context(
481 new WebGraphicsContext3DCommandBufferImpl(
486 if (!context
->InitializeWithDefaultBufferSizes(
489 CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE
))
490 return scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
>();
491 return context
.Pass();
494 void GpuProcessTransportFactory::CreateSharedContextLazy() {
495 scoped_refptr
<cc::ContextProvider
> provider
=
496 OffscreenContextProviderForMainThread();
499 void GpuProcessTransportFactory::OnLostMainThreadSharedContextInsideCallback() {
500 base::MessageLoop::current()->PostTask(
502 base::Bind(&GpuProcessTransportFactory::OnLostMainThreadSharedContext
,
503 callback_factory_
.GetWeakPtr()));
506 void GpuProcessTransportFactory::OnLostMainThreadSharedContext() {
507 LOG(ERROR
) << "Lost UI shared context.";
509 // Keep old resources around while we call the observers, but ensure that
510 // new resources are created if needed.
511 // Kill shared contexts for both threads in tandem so they are always in
512 // the same share group.
514 scoped_refptr
<cc::ContextProvider
> lost_shared_contexts_main_thread
=
515 shared_contexts_main_thread_
;
516 scoped_refptr
<cc::ContextProvider
> lost_shared_contexts_compositor_thread
=
517 shared_contexts_compositor_thread_
;
518 shared_contexts_main_thread_
= NULL
;
519 shared_contexts_compositor_thread_
= NULL
;
521 scoped_ptr
<GLHelper
> lost_gl_helper
= gl_helper_
.Pass();
523 FOR_EACH_OBSERVER(ImageTransportFactoryObserver
,
527 // Kill things that use the shared context before killing the shared context.
528 lost_gl_helper
.reset();
529 lost_shared_contexts_main_thread
= NULL
;
530 lost_shared_contexts_compositor_thread
= NULL
;
533 } // namespace content