1 // Copyright (c) 2012 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/renderer_host/image_transport_factory.h"
10 #include "base/bind.h"
11 #include "base/command_line.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/observer_list.h"
15 #include "base/threading/non_thread_safe.h"
16 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
17 #include "content/browser/gpu/gpu_data_manager_impl.h"
18 #include "content/browser/gpu/gpu_process_host.h"
19 #include "content/browser/gpu/gpu_surface_tracker.h"
20 #include "content/common/gpu/client/gl_helper.h"
21 #include "content/common/gpu/client/gpu_channel_host.h"
22 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
23 #include "content/common/gpu/gpu_messages.h"
24 #include "content/common/gpu/gpu_process_launch_causes.h"
25 #include "content/common/webkitplatformsupport_impl.h"
26 #include "content/public/common/content_switches.h"
27 #include "gpu/ipc/command_buffer_proxy.h"
28 #include "third_party/WebKit/Source/Platform/chromium/public/WebCompositorOutputSurface.h"
29 #include "third_party/WebKit/Source/Platform/chromium/public/WebCompositorOutputSurfaceClient.h"
30 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebGraphicsContext3D.h"
31 #include "third_party/khronos/GLES2/gl2.h"
32 #include "third_party/khronos/GLES2/gl2ext.h"
33 #include "ui/compositor/compositor.h"
34 #include "ui/compositor/compositor_setup.h"
35 #include "ui/compositor/test_web_graphics_context_3d.h"
36 #include "ui/gfx/native_widget_types.h"
37 #include "ui/gfx/size.h"
40 #include "ui/surface/accelerated_surface_win.h"
46 ImageTransportFactory
* g_factory
;
48 class DefaultTransportFactory
49 : public ui::DefaultContextFactory
,
50 public ImageTransportFactory
{
52 DefaultTransportFactory() {
53 ui::DefaultContextFactory::Initialize();
56 virtual ui::ContextFactory
* AsContextFactory() OVERRIDE
{
60 virtual gfx::GLSurfaceHandle
CreateSharedSurfaceHandle() OVERRIDE
{
61 return gfx::GLSurfaceHandle();
64 virtual void DestroySharedSurfaceHandle(
65 gfx::GLSurfaceHandle surface
) OVERRIDE
{
68 virtual scoped_refptr
<ui::Texture
> CreateTransportClient(
69 const gfx::Size
& size
,
70 float device_scale_factor
,
71 const std::string
& mailbox_name
) OVERRIDE
{
75 virtual scoped_refptr
<ui::Texture
> CreateOwnedTexture(
76 const gfx::Size
& size
,
77 float device_scale_factor
,
78 unsigned int texture_id
) OVERRIDE
{
82 virtual GLHelper
* GetGLHelper() OVERRIDE
{
86 virtual uint32
InsertSyncPoint() OVERRIDE
{
90 // We don't generate lost context events, so we don't need to keep track of
92 virtual void AddObserver(ImageTransportFactoryObserver
* observer
) OVERRIDE
{
95 virtual void RemoveObserver(
96 ImageTransportFactoryObserver
* observer
) OVERRIDE
{
100 DISALLOW_COPY_AND_ASSIGN(DefaultTransportFactory
);
103 class OwnedTexture
: public ui::Texture
, ImageTransportFactoryObserver
{
105 OwnedTexture(WebKit::WebGraphicsContext3D
* host_context
,
106 const gfx::Size
& size
,
107 float device_scale_factor
,
108 unsigned int texture_id
)
109 : ui::Texture(true, size
, device_scale_factor
),
110 host_context_(host_context
),
111 texture_id_(texture_id
) {
112 ImageTransportFactory::GetInstance()->AddObserver(this);
115 // ui::Texture overrides:
116 virtual unsigned int PrepareTexture() OVERRIDE
{
120 virtual WebKit::WebGraphicsContext3D
* HostContext3D() OVERRIDE
{
121 return host_context_
;
124 // ImageTransportFactory overrides:
125 virtual void OnLostResources() OVERRIDE
{
130 virtual ~OwnedTexture() {
131 ImageTransportFactory::GetInstance()->RemoveObserver(this);
136 void DeleteTexture() {
138 host_context_
->deleteTexture(texture_id_
);
143 // A raw pointer. This |ImageTransportClientTexture| will be destroyed
144 // before the |host_context_| via
145 // |ImageTransportFactoryObserver::OnLostContext()| handlers.
146 WebKit::WebGraphicsContext3D
* host_context_
;
147 unsigned texture_id_
;
149 DISALLOW_COPY_AND_ASSIGN(OwnedTexture
);
152 class ImageTransportClientTexture
: public OwnedTexture
{
154 ImageTransportClientTexture(
155 WebKit::WebGraphicsContext3D
* host_context
,
156 const gfx::Size
& size
,
157 float device_scale_factor
,
158 const std::string
& mailbox_name
)
159 : OwnedTexture(host_context
,
162 host_context
->createTexture()),
163 mailbox_name_(mailbox_name
) {
164 DCHECK(mailbox_name
.size() == GL_MAILBOX_SIZE_CHROMIUM
);
167 virtual void Consume(const gfx::Size
& new_size
) OVERRIDE
{
168 if (!mailbox_name_
.length())
171 DCHECK(host_context_
&& texture_id_
);
172 host_context_
->bindTexture(GL_TEXTURE_2D
, texture_id_
);
173 host_context_
->consumeTextureCHROMIUM(
175 reinterpret_cast<const signed char*>(mailbox_name_
.c_str()));
177 host_context_
->flush();
180 virtual void Produce() OVERRIDE
{
181 if (!mailbox_name_
.length())
184 DCHECK(host_context_
&& texture_id_
);
185 host_context_
->bindTexture(GL_TEXTURE_2D
, texture_id_
);
186 host_context_
->produceTextureCHROMIUM(
188 reinterpret_cast<const signed char*>(mailbox_name_
.c_str()));
192 virtual ~ImageTransportClientTexture() {}
195 std::string mailbox_name_
;
196 DISALLOW_COPY_AND_ASSIGN(ImageTransportClientTexture
);
199 class GpuProcessTransportFactory
;
201 class CompositorSwapClient
202 : public base::SupportsWeakPtr
<CompositorSwapClient
>,
203 public WebGraphicsContext3DSwapBuffersClient
{
205 CompositorSwapClient(ui::Compositor
* compositor
,
206 GpuProcessTransportFactory
* factory
)
207 : compositor_(compositor
),
211 ~CompositorSwapClient() {
214 virtual void OnViewContextSwapBuffersPosted() OVERRIDE
{
215 compositor_
->OnSwapBuffersPosted();
218 virtual void OnViewContextSwapBuffersComplete() OVERRIDE
{
219 compositor_
->OnSwapBuffersComplete();
222 virtual void OnViewContextSwapBuffersAborted() OVERRIDE
{
223 // Recreating contexts directly from here causes issues, so post a task
225 // TODO(piman): Fix the underlying issues.
226 MessageLoop::current()->PostTask(FROM_HERE
,
227 base::Bind(&CompositorSwapClient::OnLostContext
, this->AsWeakPtr()));
231 void OnLostContext();
232 ui::Compositor
* compositor_
;
233 GpuProcessTransportFactory
* factory_
;
235 DISALLOW_COPY_AND_ASSIGN(CompositorSwapClient
);
238 class BrowserCompositorOutputSurface
;
240 // Directs vsync updates to the appropriate BrowserCompositorOutputSurface.
241 class BrowserCompositorOutputSurfaceProxy
:
242 public base::RefCountedThreadSafe
<BrowserCompositorOutputSurfaceProxy
> {
244 BrowserCompositorOutputSurfaceProxy()
245 : message_handler_set_(false) {
248 void AddSurface(BrowserCompositorOutputSurface
* surface
, int surface_id
) {
249 if (!message_handler_set_
) {
250 uint32 messages_to_filter
[] = {GpuHostMsg_UpdateVSyncParameters::ID
};
251 BrowserGpuChannelHostFactory::instance()->SetHandlerForControlMessages(
253 arraysize(messages_to_filter
),
254 base::Bind(&BrowserCompositorOutputSurfaceProxy::OnMessageReceived
,
256 MessageLoop::current()->message_loop_proxy());
257 message_handler_set_
= true;
259 surface_map_
.AddWithID(surface
, surface_id
);
262 void RemoveSurface(int surface_id
) {
263 surface_map_
.Remove(surface_id
);
267 void OnMessageReceived(const IPC::Message
& message
) {
268 IPC_BEGIN_MESSAGE_MAP(BrowserCompositorOutputSurfaceProxy
, message
)
269 IPC_MESSAGE_HANDLER(GpuHostMsg_UpdateVSyncParameters
,
270 OnUpdateVSyncParameters
);
271 IPC_END_MESSAGE_MAP()
274 void OnUpdateVSyncParameters(int surface_id
,
275 base::TimeTicks timebase
,
276 base::TimeDelta interval
);
279 base::RefCountedThreadSafe
<BrowserCompositorOutputSurfaceProxy
>;
280 ~BrowserCompositorOutputSurfaceProxy() {}
281 IDMap
<BrowserCompositorOutputSurface
> surface_map_
;
282 bool message_handler_set_
;
284 DISALLOW_COPY_AND_ASSIGN(BrowserCompositorOutputSurfaceProxy
);
288 // Adapts a WebGraphicsContext3DCommandBufferImpl into a
289 // WebCompositorOutputSurface that also handles vsync parameter updates
290 // arriving from the GPU process.
291 class BrowserCompositorOutputSurface
:
292 public WebKit::WebCompositorOutputSurface
,
293 public base::NonThreadSafe
{
295 explicit BrowserCompositorOutputSurface(
296 WebGraphicsContext3DCommandBufferImpl
* context
,
298 BrowserCompositorOutputSurfaceProxy
* output_surface_proxy
)
299 : context3D_(context
),
300 surface_id_(surface_id
),
302 output_surface_proxy_(output_surface_proxy
) {
306 virtual ~BrowserCompositorOutputSurface() {
307 DCHECK(CalledOnValidThread());
310 output_surface_proxy_
->RemoveSurface(surface_id_
);
313 virtual bool bindToClient(
314 WebKit::WebCompositorOutputSurfaceClient
* client
) OVERRIDE
{
315 DCHECK(CalledOnValidThread());
318 if (context3D_
.get()) {
319 if (!context3D_
->makeContextCurrent())
324 output_surface_proxy_
->AddSurface(this, surface_id_
);
328 virtual const Capabilities
& capabilities() const OVERRIDE
{
329 DCHECK(CalledOnValidThread());
330 return capabilities_
;
333 virtual WebKit::WebGraphicsContext3D
* context3D() const OVERRIDE
{
334 DCHECK(CalledOnValidThread());
335 return context3D_
.get();
338 virtual void sendFrameToParentCompositor(
339 const WebKit::WebCompositorFrame
&) OVERRIDE
{
342 void OnUpdateVSyncParameters(
343 base::TimeTicks timebase
, base::TimeDelta interval
) {
344 DCHECK(CalledOnValidThread());
346 double monotonicTimebase
= timebase
.ToInternalValue() /
347 static_cast<double>(base::Time::kMicrosecondsPerSecond
);
348 double intervalInSeconds
= interval
.ToInternalValue() /
349 static_cast<double>(base::Time::kMicrosecondsPerSecond
);
350 client_
->onVSyncParametersChanged(monotonicTimebase
, intervalInSeconds
);
354 scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
> context3D_
;
356 Capabilities capabilities_
;
357 WebKit::WebCompositorOutputSurfaceClient
* client_
;
358 scoped_refptr
<BrowserCompositorOutputSurfaceProxy
> output_surface_proxy_
;
361 void BrowserCompositorOutputSurfaceProxy::OnUpdateVSyncParameters(
362 int surface_id
, base::TimeTicks timebase
, base::TimeDelta interval
) {
363 BrowserCompositorOutputSurface
* surface
= surface_map_
.Lookup(surface_id
);
365 surface
->OnUpdateVSyncParameters(timebase
, interval
);
368 class GpuProcessTransportFactory
:
369 public ui::ContextFactory
,
370 public ImageTransportFactory
,
371 public WebKit::WebGraphicsContext3D::WebGraphicsContextLostCallback
{
373 GpuProcessTransportFactory()
374 : ALLOW_THIS_IN_INITIALIZER_LIST(callback_factory_(this)) {
375 output_surface_proxy_
= new BrowserCompositorOutputSurfaceProxy();
378 virtual ~GpuProcessTransportFactory() {
379 DCHECK(per_compositor_data_
.empty());
382 virtual WebGraphicsContext3DCommandBufferImpl
* CreateOffscreenContext()
384 base::WeakPtr
<WebGraphicsContext3DSwapBuffersClient
> swap_client
;
385 return CreateContextCommon(swap_client
, 0);
388 virtual WebKit::WebCompositorOutputSurface
* CreateOutputSurface(
389 ui::Compositor
* compositor
) OVERRIDE
{
390 PerCompositorData
* data
= per_compositor_data_
[compositor
];
392 data
= CreatePerCompositorData(compositor
);
393 WebGraphicsContext3DCommandBufferImpl
* context
=
394 CreateContextCommon(data
->swap_client
->AsWeakPtr(),
396 return new BrowserCompositorOutputSurface(
398 per_compositor_data_
[compositor
]->surface_id
,
399 output_surface_proxy_
);
402 virtual void RemoveCompositor(ui::Compositor
* compositor
) OVERRIDE
{
403 PerCompositorDataMap::iterator it
= per_compositor_data_
.find(compositor
);
404 if (it
== per_compositor_data_
.end())
406 PerCompositorData
* data
= it
->second
;
408 GpuSurfaceTracker::Get()->RemoveSurface(data
->surface_id
);
410 per_compositor_data_
.erase(it
);
411 if (per_compositor_data_
.empty()) {
413 callback_factory_
.InvalidateWeakPtrs();
417 virtual ui::ContextFactory
* AsContextFactory() OVERRIDE
{
421 virtual gfx::GLSurfaceHandle
CreateSharedSurfaceHandle() OVERRIDE
{
422 CreateSharedContextLazy();
423 gfx::GLSurfaceHandle handle
= gfx::GLSurfaceHandle(
424 gfx::kNullPluginWindow
, true);
425 handle
.parent_gpu_process_id
= shared_context_
->GetGPUProcessID();
430 virtual void DestroySharedSurfaceHandle(
431 gfx::GLSurfaceHandle surface
) OVERRIDE
{
434 virtual scoped_refptr
<ui::Texture
> CreateTransportClient(
435 const gfx::Size
& size
,
436 float device_scale_factor
,
437 const std::string
& mailbox_name
) {
438 if (!shared_context_
.get())
440 scoped_refptr
<ImageTransportClientTexture
> image(
441 new ImageTransportClientTexture(shared_context_
.get(),
442 size
, device_scale_factor
,
447 virtual scoped_refptr
<ui::Texture
> CreateOwnedTexture(
448 const gfx::Size
& size
,
449 float device_scale_factor
,
450 unsigned int texture_id
) OVERRIDE
{
451 if (!shared_context_
.get())
453 scoped_refptr
<OwnedTexture
> image(
454 new OwnedTexture(shared_context_
.get(), size
, device_scale_factor
,
459 virtual GLHelper
* GetGLHelper() {
460 if (!gl_helper_
.get()) {
461 CreateSharedContextLazy();
462 WebKit::WebGraphicsContext3D
* context_for_thread
=
463 CreateOffscreenContext();
464 if (!context_for_thread
)
466 gl_helper_
.reset(new GLHelper(shared_context_
.get(),
467 context_for_thread
));
469 return gl_helper_
.get();
472 virtual uint32
InsertSyncPoint() OVERRIDE
{
473 if (!shared_context_
.get())
475 return shared_context_
->insertSyncPoint();
478 virtual void AddObserver(ImageTransportFactoryObserver
* observer
) {
479 observer_list_
.AddObserver(observer
);
482 virtual void RemoveObserver(ImageTransportFactoryObserver
* observer
) {
483 observer_list_
.RemoveObserver(observer
);
486 // WebGraphicsContextLostCallback implementation, called for the shared
488 virtual void onContextLost() {
489 MessageLoop::current()->PostTask(
491 base::Bind(&GpuProcessTransportFactory::OnLostSharedContext
,
492 callback_factory_
.GetWeakPtr()));
495 void OnLostContext(ui::Compositor
* compositor
) {
496 LOG(ERROR
) << "Lost UI compositor context.";
497 PerCompositorData
* data
= per_compositor_data_
[compositor
];
500 // Prevent callbacks from other contexts in the same share group from
502 data
->swap_client
.reset(new CompositorSwapClient(compositor
, this));
503 compositor
->OnSwapBuffersAborted();
507 struct PerCompositorData
{
509 scoped_ptr
<CompositorSwapClient
> swap_client
;
511 scoped_ptr
<AcceleratedSurface
> accelerated_surface
;
515 PerCompositorData
* CreatePerCompositorData(ui::Compositor
* compositor
) {
516 DCHECK(!per_compositor_data_
[compositor
]);
518 CreateSharedContextLazy();
520 gfx::AcceleratedWidget widget
= compositor
->widget();
521 GpuSurfaceTracker
* tracker
= GpuSurfaceTracker::Get();
523 PerCompositorData
* data
= new PerCompositorData
;
524 data
->surface_id
= tracker
->AddSurfaceForNativeWidget(widget
);
525 data
->swap_client
.reset(new CompositorSwapClient(compositor
, this));
527 if (GpuDataManagerImpl::GetInstance()->IsUsingAcceleratedSurface())
528 data
->accelerated_surface
.reset(new AcceleratedSurface(widget
));
530 tracker
->SetSurfaceHandle(
532 gfx::GLSurfaceHandle(widget
, false));
534 per_compositor_data_
[compositor
] = data
;
539 WebGraphicsContext3DCommandBufferImpl
* CreateContextCommon(
540 const base::WeakPtr
<WebGraphicsContext3DSwapBuffersClient
>& swap_client
,
542 WebKit::WebGraphicsContext3D::Attributes attrs
;
543 attrs
.shareResources
= true;
545 attrs
.stencil
= false;
546 attrs
.antialias
= false;
547 attrs
.noAutomaticFlushes
= true;
548 GpuChannelHostFactory
* factory
= BrowserGpuChannelHostFactory::instance();
549 GURL
url("chrome://gpu/GpuProcessTransportFactory::CreateContextCommon");
550 scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
> context(
551 new WebGraphicsContext3DCommandBufferImpl(
556 if (!context
->Initialize(
559 CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE
))
561 return context
.release();
564 void CreateSharedContextLazy() {
565 if (shared_context_
.get())
568 shared_context_
.reset(CreateOffscreenContext());
569 if (!shared_context_
.get()) {
570 // If we can't recreate contexts, we won't be able to show the UI. Better
571 // crash at this point.
572 LOG(FATAL
) << "Failed to initialize UI shared context.";
574 if (!shared_context_
->makeContextCurrent()) {
575 // If we can't recreate contexts, we won't be able to show the UI. Better
576 // crash at this point.
577 LOG(FATAL
) << "Failed to make UI shared context current.";
579 shared_context_
->setContextLostCallback(this);
582 void OnLostSharedContext() {
583 // Keep old resources around while we call the observers, but ensure that
584 // new resources are created if needed.
585 scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
> old_shared_context(
586 shared_context_
.release());
587 scoped_ptr
<GLHelper
> old_helper(gl_helper_
.release());
589 FOR_EACH_OBSERVER(ImageTransportFactoryObserver
,
594 typedef std::map
<ui::Compositor
*, PerCompositorData
*> PerCompositorDataMap
;
595 PerCompositorDataMap per_compositor_data_
;
596 scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
> shared_context_
;
597 scoped_ptr
<GLHelper
> gl_helper_
;
598 ObserverList
<ImageTransportFactoryObserver
> observer_list_
;
599 base::WeakPtrFactory
<GpuProcessTransportFactory
> callback_factory_
;
600 scoped_refptr
<BrowserCompositorOutputSurfaceProxy
> output_surface_proxy_
;
602 DISALLOW_COPY_AND_ASSIGN(GpuProcessTransportFactory
);
605 void CompositorSwapClient::OnLostContext() {
606 factory_
->OnLostContext(compositor_
);
607 // Note: previous line destroyed this. Don't access members from now on.
610 WebKit::WebGraphicsContext3D
* CreateTestContext() {
611 ui::TestWebGraphicsContext3D
* test_context
=
612 new ui::TestWebGraphicsContext3D();
613 test_context
->Initialize();
617 } // anonymous namespace
620 void ImageTransportFactory::Initialize() {
621 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
622 if (command_line
->HasSwitch(switches::kTestCompositor
)) {
623 ui::SetupTestCompositor();
625 if (ui::IsTestCompositorEnabled()) {
626 g_factory
= new DefaultTransportFactory();
627 WebKitPlatformSupportImpl::SetOffscreenContextFactoryForTest(
630 g_factory
= new GpuProcessTransportFactory();
632 ui::ContextFactory::SetInstance(g_factory
->AsContextFactory());
636 void ImageTransportFactory::Terminate() {
637 ui::ContextFactory::SetInstance(NULL
);
643 ImageTransportFactory
* ImageTransportFactory::GetInstance() {
647 } // namespace content