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/gpu_browser_compositor_output_surface.h"
19 #include "content/browser/aura/reflector_impl.h"
20 #include "content/browser/aura/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 "third_party/khronos/GLES2/gl2.h"
33 #include "ui/compositor/compositor.h"
34 #include "ui/compositor/compositor_switches.h"
35 #include "ui/gfx/native_widget_types.h"
36 #include "ui/gfx/size.h"
39 #include "content/browser/aura/software_output_device_win.h"
40 #include "ui/surface/accelerated_surface_win.h"
41 #elif defined(USE_OZONE)
42 #include "content/browser/aura/software_output_device_ozone.h"
43 #elif defined(USE_X11)
44 #include "content/browser/aura/software_output_device_x11.h"
47 using cc::ContextProvider
;
48 using gpu::gles2::GLES2Interface
;
52 struct GpuProcessTransportFactory::PerCompositorData
{
55 scoped_ptr
<AcceleratedSurface
> accelerated_surface
;
57 scoped_refptr
<ReflectorImpl
> reflector
;
60 class OwnedTexture
: public ui::Texture
, ImageTransportFactoryObserver
{
62 OwnedTexture(const scoped_refptr
<ContextProvider
>& provider
,
63 const gfx::Size
& size
,
64 float device_scale_factor
,
66 : ui::Texture(true, size
, device_scale_factor
),
68 texture_id_(texture_id
) {
69 ImageTransportFactory::GetInstance()->AddObserver(this);
72 // ui::Texture overrides:
73 virtual unsigned int PrepareTexture() OVERRIDE
{
74 // It's possible that we may have lost the context owning our
75 // texture but not yet fired the OnLostResources callback, so poll to see if
77 if (provider_
&& provider_
->IsContextLost())
82 // ImageTransportFactory overrides:
83 virtual void OnLostResources() OVERRIDE
{
89 virtual ~OwnedTexture() {
90 ImageTransportFactory::GetInstance()->RemoveObserver(this);
95 void DeleteTexture() {
97 provider_
->ContextGL()->DeleteTextures(1, &texture_id_
);
102 scoped_refptr
<cc::ContextProvider
> provider_
;
106 DISALLOW_COPY_AND_ASSIGN(OwnedTexture
);
109 class ImageTransportClientTexture
: public OwnedTexture
{
111 ImageTransportClientTexture(const scoped_refptr
<ContextProvider
>& provider
,
112 float device_scale_factor
,
114 : OwnedTexture(provider
,
119 virtual void Consume(const std::string
& mailbox_name
,
120 const gfx::Size
& new_size
) OVERRIDE
{
121 DCHECK(mailbox_name
.size() == GL_MAILBOX_SIZE_CHROMIUM
);
122 mailbox_name_
= mailbox_name
;
123 if (mailbox_name
.empty())
126 DCHECK(provider_
&& texture_id_
);
127 GLES2Interface
* gl
= provider_
->ContextGL();
128 gl
->BindTexture(GL_TEXTURE_2D
, texture_id_
);
129 gl
->ConsumeTextureCHROMIUM(
130 GL_TEXTURE_2D
, reinterpret_cast<const GLbyte
*>(mailbox_name
.c_str()));
132 gl
->ShallowFlushCHROMIUM();
135 virtual std::string
Produce() OVERRIDE
{ return mailbox_name_
; }
138 virtual ~ImageTransportClientTexture() {}
141 std::string mailbox_name_
;
142 DISALLOW_COPY_AND_ASSIGN(ImageTransportClientTexture
);
145 GpuProcessTransportFactory::GpuProcessTransportFactory()
146 : callback_factory_(this) {
147 output_surface_proxy_
= new BrowserCompositorOutputSurfaceProxy(
148 &output_surface_map_
);
151 GpuProcessTransportFactory::~GpuProcessTransportFactory() {
152 DCHECK(per_compositor_data_
.empty());
154 // Make sure the lost context callback doesn't try to run during destruction.
155 callback_factory_
.InvalidateWeakPtrs();
158 scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
>
159 GpuProcessTransportFactory::CreateOffscreenCommandBufferContext() {
160 return CreateContextCommon(0);
163 scoped_ptr
<cc::SoftwareOutputDevice
> CreateSoftwareOutputDevice(
164 ui::Compositor
* compositor
) {
166 return scoped_ptr
<cc::SoftwareOutputDevice
>(new SoftwareOutputDeviceWin(
168 #elif defined(USE_OZONE)
169 return scoped_ptr
<cc::SoftwareOutputDevice
>(new SoftwareOutputDeviceOzone(
171 #elif defined(USE_X11)
172 return scoped_ptr
<cc::SoftwareOutputDevice
>(new SoftwareOutputDeviceX11(
177 return scoped_ptr
<cc::SoftwareOutputDevice
>();
180 scoped_ptr
<cc::OutputSurface
> GpuProcessTransportFactory::CreateOutputSurface(
181 ui::Compositor
* compositor
, bool software_fallback
) {
182 PerCompositorData
* data
= per_compositor_data_
[compositor
];
184 data
= CreatePerCompositorData(compositor
);
186 scoped_refptr
<ContextProviderCommandBuffer
> context_provider
;
188 // Software fallback does not happen on Chrome OS.
189 #if defined(OS_CHROMEOS)
190 software_fallback
= false;
193 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
194 if (!command_line
->HasSwitch(switches::kUIEnableSoftwareCompositing
) &&
195 !software_fallback
) {
196 context_provider
= ContextProviderCommandBuffer::Create(
197 GpuProcessTransportFactory::CreateContextCommon(data
->surface_id
),
201 UMA_HISTOGRAM_BOOLEAN("Aura.CreatedGpuBrowserCompositor", !!context_provider
);
203 if (!context_provider
.get()) {
204 if (ui::Compositor::WasInitializedWithThread()) {
205 LOG(FATAL
) << "Failed to create UI context, but can't use software"
206 " compositing with browser threaded compositing. Aborting.";
209 scoped_ptr
<SoftwareBrowserCompositorOutputSurface
> surface(
210 new SoftwareBrowserCompositorOutputSurface(
211 output_surface_proxy_
,
212 CreateSoftwareOutputDevice(compositor
),
213 per_compositor_data_
[compositor
]->surface_id
,
214 &output_surface_map_
,
215 base::MessageLoopProxy::current().get(),
216 compositor
->AsWeakPtr()));
217 return surface
.PassAs
<cc::OutputSurface
>();
220 scoped_refptr
<base::SingleThreadTaskRunner
> compositor_thread_task_runner
=
221 ui::Compositor::GetCompositorMessageLoop();
222 if (!compositor_thread_task_runner
.get())
223 compositor_thread_task_runner
= base::MessageLoopProxy::current();
225 // Here we know the GpuProcessHost has been set up, because we created a
227 output_surface_proxy_
->ConnectToGpuProcessHost(
228 compositor_thread_task_runner
.get());
230 scoped_ptr
<BrowserCompositorOutputSurface
> surface(
231 new GpuBrowserCompositorOutputSurface(
233 per_compositor_data_
[compositor
]->surface_id
,
234 &output_surface_map_
,
235 base::MessageLoopProxy::current().get(),
236 compositor
->AsWeakPtr()));
237 if (data
->reflector
.get()) {
238 data
->reflector
->CreateSharedTexture();
239 data
->reflector
->AttachToOutputSurface(surface
.get());
242 return surface
.PassAs
<cc::OutputSurface
>();
245 scoped_refptr
<ui::Reflector
> GpuProcessTransportFactory::CreateReflector(
246 ui::Compositor
* source
,
248 PerCompositorData
* data
= per_compositor_data_
[source
];
251 if (data
->reflector
.get())
252 RemoveObserver(data
->reflector
.get());
254 data
->reflector
= new ReflectorImpl(
255 source
, target
, &output_surface_map_
, data
->surface_id
);
256 AddObserver(data
->reflector
.get());
257 return data
->reflector
;
260 void GpuProcessTransportFactory::RemoveReflector(
261 scoped_refptr
<ui::Reflector
> reflector
) {
262 ReflectorImpl
* reflector_impl
=
263 static_cast<ReflectorImpl
*>(reflector
.get());
264 PerCompositorData
* data
=
265 per_compositor_data_
[reflector_impl
->mirrored_compositor()];
267 RemoveObserver(reflector_impl
);
268 data
->reflector
->Shutdown();
269 data
->reflector
= NULL
;
272 void GpuProcessTransportFactory::RemoveCompositor(ui::Compositor
* compositor
) {
273 PerCompositorDataMap::iterator it
= per_compositor_data_
.find(compositor
);
274 if (it
== per_compositor_data_
.end())
276 PerCompositorData
* data
= it
->second
;
278 GpuSurfaceTracker::Get()->RemoveSurface(data
->surface_id
);
280 per_compositor_data_
.erase(it
);
281 if (per_compositor_data_
.empty())
285 bool GpuProcessTransportFactory::DoesCreateTestContexts() { return false; }
287 ui::ContextFactory
* GpuProcessTransportFactory::AsContextFactory() {
291 gfx::GLSurfaceHandle
GpuProcessTransportFactory::CreateSharedSurfaceHandle() {
292 scoped_refptr
<cc::ContextProvider
> provider
=
293 SharedMainThreadContextProvider();
295 return gfx::GLSurfaceHandle();
296 ContextProviderCommandBuffer
* provider_command_buffer
=
297 static_cast<ContextProviderCommandBuffer
*>(provider
.get());
298 gfx::GLSurfaceHandle handle
= gfx::GLSurfaceHandle(
299 gfx::kNullPluginWindow
, gfx::TEXTURE_TRANSPORT
);
300 handle
.parent_gpu_process_id
= provider_command_buffer
->GetGPUProcessID();
301 handle
.parent_client_id
=
302 BrowserGpuChannelHostFactory::instance()->GetGpuChannelId();
306 void GpuProcessTransportFactory::DestroySharedSurfaceHandle(
307 gfx::GLSurfaceHandle surface
) {}
309 scoped_refptr
<ui::Texture
> GpuProcessTransportFactory::CreateTransportClient(
310 float device_scale_factor
) {
311 scoped_refptr
<cc::ContextProvider
> provider
=
312 SharedMainThreadContextProvider();
315 GLuint texture_id
= 0;
316 provider
->ContextGL()->GenTextures(1, &texture_id
);
317 scoped_refptr
<ImageTransportClientTexture
> image(
318 new ImageTransportClientTexture(
319 provider
, device_scale_factor
, texture_id
));
323 scoped_refptr
<ui::Texture
> GpuProcessTransportFactory::CreateOwnedTexture(
324 const gfx::Size
& size
,
325 float device_scale_factor
,
326 unsigned int texture_id
) {
327 scoped_refptr
<cc::ContextProvider
> provider
=
328 SharedMainThreadContextProvider();
331 scoped_refptr
<OwnedTexture
> image(new OwnedTexture(
332 provider
, size
, device_scale_factor
, texture_id
));
336 GLHelper
* GpuProcessTransportFactory::GetGLHelper() {
338 scoped_refptr
<cc::ContextProvider
> provider
=
339 SharedMainThreadContextProvider();
341 gl_helper_
.reset(new GLHelper(provider
->ContextGL(),
342 provider
->ContextSupport()));
344 return gl_helper_
.get();
347 void GpuProcessTransportFactory::AddObserver(
348 ImageTransportFactoryObserver
* observer
) {
349 observer_list_
.AddObserver(observer
);
352 void GpuProcessTransportFactory::RemoveObserver(
353 ImageTransportFactoryObserver
* observer
) {
354 observer_list_
.RemoveObserver(observer
);
357 scoped_refptr
<cc::ContextProvider
>
358 GpuProcessTransportFactory::OffscreenCompositorContextProvider() {
359 // Don't check for DestroyedOnMainThread() here. We hear about context
360 // loss for this context through the lost context callback. If the context
361 // is lost, we want to leave this ContextProvider available until the lost
362 // context notification is sent to the ImageTransportFactoryObserver clients.
363 if (offscreen_compositor_contexts_
.get())
364 return offscreen_compositor_contexts_
;
366 offscreen_compositor_contexts_
= ContextProviderCommandBuffer::Create(
367 GpuProcessTransportFactory::CreateOffscreenCommandBufferContext(),
368 "Compositor-Offscreen");
370 return offscreen_compositor_contexts_
;
373 scoped_refptr
<cc::ContextProvider
>
374 GpuProcessTransportFactory::SharedMainThreadContextProvider() {
375 if (shared_main_thread_contexts_
.get())
376 return shared_main_thread_contexts_
;
378 if (ui::Compositor::WasInitializedWithThread()) {
379 // In threaded compositing mode, we have to create our own context for the
380 // main thread since the compositor's context will be bound to the
381 // compositor thread.
382 shared_main_thread_contexts_
= ContextProviderCommandBuffer::Create(
383 GpuProcessTransportFactory::CreateOffscreenCommandBufferContext(),
384 "Offscreen-MainThread");
386 // In single threaded compositing mode, we can just reuse the compositor's
388 shared_main_thread_contexts_
=
389 static_cast<ContextProviderCommandBuffer
*>(
390 OffscreenCompositorContextProvider().get());
393 if (shared_main_thread_contexts_
) {
394 shared_main_thread_contexts_
->SetLostContextCallback(
395 base::Bind(&GpuProcessTransportFactory::
396 OnLostMainThreadSharedContextInsideCallback
,
397 callback_factory_
.GetWeakPtr()));
398 if (!shared_main_thread_contexts_
->BindToCurrentThread()) {
399 shared_main_thread_contexts_
= NULL
;
400 offscreen_compositor_contexts_
= NULL
;
403 return shared_main_thread_contexts_
;
406 GpuProcessTransportFactory::PerCompositorData
*
407 GpuProcessTransportFactory::CreatePerCompositorData(
408 ui::Compositor
* compositor
) {
409 DCHECK(!per_compositor_data_
[compositor
]);
411 gfx::AcceleratedWidget widget
= compositor
->widget();
412 GpuSurfaceTracker
* tracker
= GpuSurfaceTracker::Get();
414 PerCompositorData
* data
= new PerCompositorData
;
415 data
->surface_id
= tracker
->AddSurfaceForNativeWidget(widget
);
417 if (GpuDataManagerImpl::GetInstance()->IsUsingAcceleratedSurface())
418 data
->accelerated_surface
.reset(new AcceleratedSurface(widget
));
420 tracker
->SetSurfaceHandle(
422 gfx::GLSurfaceHandle(widget
, gfx::NATIVE_DIRECT
));
424 per_compositor_data_
[compositor
] = data
;
429 scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
>
430 GpuProcessTransportFactory::CreateContextCommon(int surface_id
) {
431 if (!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor())
432 return scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
>();
433 blink::WebGraphicsContext3D::Attributes attrs
;
434 attrs
.shareResources
= true;
436 attrs
.stencil
= false;
437 attrs
.antialias
= false;
438 attrs
.noAutomaticFlushes
= true;
439 CauseForGpuLaunch cause
=
440 CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE
;
441 scoped_refptr
<GpuChannelHost
> gpu_channel_host(
442 BrowserGpuChannelHostFactory::instance()->EstablishGpuChannelSync(cause
));
443 if (!gpu_channel_host
)
444 return scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
>();
445 GURL
url("chrome://gpu/GpuProcessTransportFactory::CreateContextCommon");
446 scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
> context(
447 new WebGraphicsContext3DCommandBufferImpl(
450 gpu_channel_host
.get(),
453 WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits()));
454 return context
.Pass();
457 void GpuProcessTransportFactory::OnLostMainThreadSharedContextInsideCallback() {
458 base::MessageLoop::current()->PostTask(
460 base::Bind(&GpuProcessTransportFactory::OnLostMainThreadSharedContext
,
461 callback_factory_
.GetWeakPtr()));
464 void GpuProcessTransportFactory::OnLostMainThreadSharedContext() {
465 LOG(ERROR
) << "Lost UI shared context.";
467 // Keep old resources around while we call the observers, but ensure that
468 // new resources are created if needed.
469 // Kill shared contexts for both threads in tandem so they are always in
470 // the same share group.
471 scoped_refptr
<cc::ContextProvider
> lost_offscreen_compositor_contexts
=
472 offscreen_compositor_contexts_
;
473 scoped_refptr
<cc::ContextProvider
> lost_shared_main_thread_contexts
=
474 shared_main_thread_contexts_
;
475 offscreen_compositor_contexts_
= NULL
;
476 shared_main_thread_contexts_
= NULL
;
478 scoped_ptr
<GLHelper
> lost_gl_helper
= gl_helper_
.Pass();
480 FOR_EACH_OBSERVER(ImageTransportFactoryObserver
,
484 // Kill things that use the shared context before killing the shared context.
485 lost_gl_helper
.reset();
486 lost_offscreen_compositor_contexts
= NULL
;
487 lost_shared_main_thread_contexts
= NULL
;
490 } // namespace content