Aura: Keep shared GL context around for factory lifetime.
[chromium-blink-merge.git] / content / browser / renderer_host / image_transport_factory.cc
blob98b8c6f55e9134046646149b274d9071cbfbdea4
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"
7 #include <algorithm>
8 #include <map>
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"
39 #if defined(OS_WIN)
40 #include "ui/surface/accelerated_surface_win.h"
41 #endif
43 namespace content {
44 namespace {
46 ImageTransportFactory* g_factory;
48 class DefaultTransportFactory
49 : public ui::DefaultContextFactory,
50 public ImageTransportFactory {
51 public:
52 DefaultTransportFactory() {
53 ui::DefaultContextFactory::Initialize();
56 virtual ui::ContextFactory* AsContextFactory() OVERRIDE {
57 return this;
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 {
72 return NULL;
75 virtual scoped_refptr<ui::Texture> CreateOwnedTexture(
76 const gfx::Size& size,
77 float device_scale_factor,
78 unsigned int texture_id) OVERRIDE {
79 return NULL;
82 virtual GLHelper* GetGLHelper() OVERRIDE {
83 return NULL;
86 virtual uint32 InsertSyncPoint() OVERRIDE {
87 return 0;
90 // We don't generate lost context events, so we don't need to keep track of
91 // observers
92 virtual void AddObserver(ImageTransportFactoryObserver* observer) OVERRIDE {
95 virtual void RemoveObserver(
96 ImageTransportFactoryObserver* observer) OVERRIDE {
99 private:
100 DISALLOW_COPY_AND_ASSIGN(DefaultTransportFactory);
103 class OwnedTexture : public ui::Texture, ImageTransportFactoryObserver {
104 public:
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 {
117 return texture_id_;
120 virtual WebKit::WebGraphicsContext3D* HostContext3D() OVERRIDE {
121 return host_context_;
124 // ImageTransportFactory overrides:
125 virtual void OnLostResources() OVERRIDE {
126 DeleteTexture();
129 protected:
130 virtual ~OwnedTexture() {
131 ImageTransportFactory::GetInstance()->RemoveObserver(this);
132 DeleteTexture();
135 protected:
136 void DeleteTexture() {
137 if (texture_id_) {
138 host_context_->deleteTexture(texture_id_);
139 texture_id_ = 0;
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 {
153 public:
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,
160 size,
161 device_scale_factor,
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())
169 return;
171 DCHECK(host_context_ && texture_id_);
172 host_context_->bindTexture(GL_TEXTURE_2D, texture_id_);
173 host_context_->consumeTextureCHROMIUM(
174 GL_TEXTURE_2D,
175 reinterpret_cast<const signed char*>(mailbox_name_.c_str()));
176 size_ = new_size;
177 host_context_->flush();
180 virtual void Produce() OVERRIDE {
181 if (!mailbox_name_.length())
182 return;
184 DCHECK(host_context_ && texture_id_);
185 host_context_->bindTexture(GL_TEXTURE_2D, texture_id_);
186 host_context_->produceTextureCHROMIUM(
187 GL_TEXTURE_2D,
188 reinterpret_cast<const signed char*>(mailbox_name_.c_str()));
191 protected:
192 virtual ~ImageTransportClientTexture() {}
194 private:
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 {
204 public:
205 CompositorSwapClient(ui::Compositor* compositor,
206 GpuProcessTransportFactory* factory)
207 : compositor_(compositor),
208 factory_(factory) {
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
224 // instead.
225 // TODO(piman): Fix the underlying issues.
226 MessageLoop::current()->PostTask(FROM_HERE,
227 base::Bind(&CompositorSwapClient::OnLostContext, this->AsWeakPtr()));
230 private:
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> {
243 public:
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(
252 messages_to_filter,
253 arraysize(messages_to_filter),
254 base::Bind(&BrowserCompositorOutputSurfaceProxy::OnMessageReceived,
255 this),
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);
266 private:
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);
278 friend class
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 {
294 public:
295 explicit BrowserCompositorOutputSurface(
296 WebGraphicsContext3DCommandBufferImpl* context,
297 int surface_id,
298 BrowserCompositorOutputSurfaceProxy* output_surface_proxy)
299 : context3D_(context),
300 surface_id_(surface_id),
301 client_(NULL),
302 output_surface_proxy_(output_surface_proxy) {
303 DetachFromThread();
306 virtual ~BrowserCompositorOutputSurface() {
307 DCHECK(CalledOnValidThread());
308 if (!client_)
309 return;
310 output_surface_proxy_->RemoveSurface(surface_id_);
313 virtual bool bindToClient(
314 WebKit::WebCompositorOutputSurfaceClient* client) OVERRIDE {
315 DCHECK(CalledOnValidThread());
316 DCHECK(client);
317 DCHECK(!client_);
318 if (context3D_.get()) {
319 if (!context3D_->makeContextCurrent())
320 return false;
323 client_ = client;
324 output_surface_proxy_->AddSurface(this, surface_id_);
325 return true;
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());
345 DCHECK(client_);
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);
353 private:
354 scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context3D_;
355 int surface_id_;
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);
364 if (surface)
365 surface->OnUpdateVSyncParameters(timebase, interval);
368 class GpuProcessTransportFactory :
369 public ui::ContextFactory,
370 public ImageTransportFactory,
371 public WebKit::WebGraphicsContext3D::WebGraphicsContextLostCallback {
372 public:
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()
383 OVERRIDE {
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];
391 if (!data)
392 data = CreatePerCompositorData(compositor);
393 WebGraphicsContext3DCommandBufferImpl* context =
394 CreateContextCommon(data->swap_client->AsWeakPtr(),
395 data->surface_id);
396 return new BrowserCompositorOutputSurface(
397 context,
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())
405 return;
406 PerCompositorData* data = it->second;
407 DCHECK(data);
408 GpuSurfaceTracker::Get()->RemoveSurface(data->surface_id);
409 delete data;
410 per_compositor_data_.erase(it);
411 if (per_compositor_data_.empty()) {
412 gl_helper_.reset();
413 callback_factory_.InvalidateWeakPtrs();
417 virtual ui::ContextFactory* AsContextFactory() OVERRIDE {
418 return this;
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();
427 return handle;
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())
439 return NULL;
440 scoped_refptr<ImageTransportClientTexture> image(
441 new ImageTransportClientTexture(shared_context_.get(),
442 size, device_scale_factor,
443 mailbox_name));
444 return image;
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())
452 return NULL;
453 scoped_refptr<OwnedTexture> image(
454 new OwnedTexture(shared_context_.get(), size, device_scale_factor,
455 texture_id));
456 return image;
459 virtual GLHelper* GetGLHelper() {
460 if (!gl_helper_.get()) {
461 CreateSharedContextLazy();
462 WebKit::WebGraphicsContext3D* context_for_thread =
463 CreateOffscreenContext();
464 if (!context_for_thread)
465 return NULL;
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())
474 return 0;
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
487 // context.
488 virtual void onContextLost() {
489 MessageLoop::current()->PostTask(
490 FROM_HERE,
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];
498 DCHECK(data);
500 // Prevent callbacks from other contexts in the same share group from
501 // calling us again.
502 data->swap_client.reset(new CompositorSwapClient(compositor, this));
503 compositor->OnSwapBuffersAborted();
506 private:
507 struct PerCompositorData {
508 int surface_id;
509 scoped_ptr<CompositorSwapClient> swap_client;
510 #if defined(OS_WIN)
511 scoped_ptr<AcceleratedSurface> accelerated_surface;
512 #endif
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));
526 #if defined(OS_WIN)
527 if (GpuDataManagerImpl::GetInstance()->IsUsingAcceleratedSurface())
528 data->accelerated_surface.reset(new AcceleratedSurface(widget));
529 #endif
530 tracker->SetSurfaceHandle(
531 data->surface_id,
532 gfx::GLSurfaceHandle(widget, false));
534 per_compositor_data_[compositor] = data;
536 return data;
539 WebGraphicsContext3DCommandBufferImpl* CreateContextCommon(
540 const base::WeakPtr<WebGraphicsContext3DSwapBuffersClient>& swap_client,
541 int surface_id) {
542 WebKit::WebGraphicsContext3D::Attributes attrs;
543 attrs.shareResources = true;
544 attrs.depth = false;
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(
552 surface_id,
553 url,
554 factory,
555 swap_client));
556 if (!context->Initialize(
557 attrs,
558 false,
559 CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE))
560 return NULL;
561 return context.release();
564 void CreateSharedContextLazy() {
565 if (shared_context_.get())
566 return;
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,
590 observer_list_,
591 OnLostResources());
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();
614 return test_context;
617 } // anonymous namespace
619 // static
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(
628 CreateTestContext);
629 } else {
630 g_factory = new GpuProcessTransportFactory();
632 ui::ContextFactory::SetInstance(g_factory->AsContextFactory());
635 // static
636 void ImageTransportFactory::Terminate() {
637 ui::ContextFactory::SetInstance(NULL);
638 delete g_factory;
639 g_factory = NULL;
642 // static
643 ImageTransportFactory* ImageTransportFactory::GetInstance() {
644 return g_factory;
647 } // namespace content