Save errno for logging before potentially overwriting it.
[chromium-blink-merge.git] / content / browser / renderer_host / image_transport_factory.cc
blobf1c31424cda99626cb8384fdd49ac8ef5dcc7929
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/strings/string_number_conversions.h"
16 #include "base/threading/non_thread_safe.h"
17 #include "cc/output/compositor_frame.h"
18 #include "cc/output/output_surface.h"
19 #include "cc/output/output_surface_client.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_process_host.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_messages.h"
30 #include "content/common/gpu/gpu_process_launch_causes.h"
31 #include "content/public/common/content_switches.h"
32 #include "gpu/GLES2/gl2extchromium.h"
33 #include "gpu/ipc/command_buffer_proxy.h"
34 #include "third_party/khronos/GLES2/gl2.h"
35 #include "third_party/khronos/GLES2/gl2ext.h"
36 #include "ui/compositor/compositor.h"
37 #include "ui/compositor/compositor_setup.h"
38 #include "ui/compositor/compositor_switches.h"
39 #include "ui/compositor/layer.h"
40 #include "ui/compositor/test_web_graphics_context_3d.h"
41 #include "ui/gfx/native_widget_types.h"
42 #include "ui/gfx/size.h"
44 #if defined(OS_WIN)
45 #include "content/browser/renderer_host/software_output_device_win.h"
46 #include "ui/surface/accelerated_surface_win.h"
47 #elif defined(USE_X11)
48 #include "content/browser/renderer_host/software_output_device_x11.h"
49 #endif
51 namespace content {
52 namespace {
54 ImageTransportFactory* g_factory;
56 // An ImageTransportFactory that disables transport.
57 class NoTransportFactory : public ImageTransportFactory {
58 public:
59 explicit NoTransportFactory(ui::ContextFactory* context_factory)
60 : context_factory_(context_factory) {
63 virtual ui::ContextFactory* AsContextFactory() OVERRIDE {
64 return context_factory_.get();
67 virtual gfx::GLSurfaceHandle CreateSharedSurfaceHandle() OVERRIDE {
68 return gfx::GLSurfaceHandle();
71 virtual void DestroySharedSurfaceHandle(
72 gfx::GLSurfaceHandle surface) OVERRIDE {
75 virtual scoped_refptr<ui::Texture> CreateTransportClient(
76 float device_scale_factor) OVERRIDE {
77 return NULL;
80 virtual scoped_refptr<ui::Texture> CreateOwnedTexture(
81 const gfx::Size& size,
82 float device_scale_factor,
83 unsigned int texture_id) OVERRIDE {
84 return NULL;
87 virtual GLHelper* GetGLHelper() OVERRIDE {
88 return NULL;
91 virtual uint32 InsertSyncPoint() OVERRIDE {
92 return 0;
95 virtual void WaitSyncPoint(uint32 sync_point) OVERRIDE {
98 // We don't generate lost context events, so we don't need to keep track of
99 // observers
100 virtual void AddObserver(ImageTransportFactoryObserver* observer) OVERRIDE {
103 virtual void RemoveObserver(
104 ImageTransportFactoryObserver* observer) OVERRIDE {
107 private:
108 scoped_ptr<ui::ContextFactory> context_factory_;
109 DISALLOW_COPY_AND_ASSIGN(NoTransportFactory);
112 class OwnedTexture : public ui::Texture, ImageTransportFactoryObserver {
113 public:
114 OwnedTexture(WebKit::WebGraphicsContext3D* host_context,
115 const gfx::Size& size,
116 float device_scale_factor,
117 unsigned int texture_id)
118 : ui::Texture(true, size, device_scale_factor),
119 host_context_(host_context),
120 texture_id_(texture_id) {
121 ImageTransportFactory::GetInstance()->AddObserver(this);
124 // ui::Texture overrides:
125 virtual unsigned int PrepareTexture() OVERRIDE {
126 return texture_id_;
129 virtual WebKit::WebGraphicsContext3D* HostContext3D() OVERRIDE {
130 return host_context_;
133 // ImageTransportFactory overrides:
134 virtual void OnLostResources() OVERRIDE {
135 DeleteTexture();
138 protected:
139 virtual ~OwnedTexture() {
140 ImageTransportFactory::GetInstance()->RemoveObserver(this);
141 DeleteTexture();
144 protected:
145 void DeleteTexture() {
146 if (texture_id_) {
147 host_context_->deleteTexture(texture_id_);
148 texture_id_ = 0;
152 // A raw pointer. This |ImageTransportClientTexture| will be destroyed
153 // before the |host_context_| via
154 // |ImageTransportFactoryObserver::OnLostContext()| handlers.
155 WebKit::WebGraphicsContext3D* host_context_;
156 unsigned texture_id_;
158 DISALLOW_COPY_AND_ASSIGN(OwnedTexture);
161 class ImageTransportClientTexture : public OwnedTexture {
162 public:
163 ImageTransportClientTexture(
164 WebKit::WebGraphicsContext3D* host_context,
165 float device_scale_factor)
166 : OwnedTexture(host_context,
167 gfx::Size(0, 0),
168 device_scale_factor,
169 host_context->createTexture()) {
172 virtual void Consume(const std::string& mailbox_name,
173 const gfx::Size& new_size) OVERRIDE {
174 DCHECK(mailbox_name.size() == GL_MAILBOX_SIZE_CHROMIUM);
175 mailbox_name_ = mailbox_name;
176 if (mailbox_name.empty())
177 return;
179 DCHECK(host_context_ && texture_id_);
180 host_context_->bindTexture(GL_TEXTURE_2D, texture_id_);
181 host_context_->consumeTextureCHROMIUM(
182 GL_TEXTURE_2D,
183 reinterpret_cast<const signed char*>(mailbox_name.c_str()));
184 size_ = new_size;
185 host_context_->shallowFlushCHROMIUM();
188 virtual std::string Produce() OVERRIDE {
189 return mailbox_name_;
192 protected:
193 virtual ~ImageTransportClientTexture() {}
195 private:
196 std::string mailbox_name_;
197 DISALLOW_COPY_AND_ASSIGN(ImageTransportClientTexture);
200 class GpuProcessTransportFactory;
202 class CompositorSwapClient
203 : public base::SupportsWeakPtr<CompositorSwapClient>,
204 public WebGraphicsContext3DSwapBuffersClient {
205 public:
206 CompositorSwapClient(ui::Compositor* compositor,
207 GpuProcessTransportFactory* factory)
208 : compositor_(compositor),
209 factory_(factory) {
212 virtual ~CompositorSwapClient() {
215 virtual void OnViewContextSwapBuffersPosted() OVERRIDE {
216 compositor_->OnSwapBuffersPosted();
219 virtual void OnViewContextSwapBuffersComplete() OVERRIDE {
220 compositor_->OnSwapBuffersComplete();
223 virtual void OnViewContextSwapBuffersAborted() OVERRIDE {
224 // Recreating contexts directly from here causes issues, so post a task
225 // instead.
226 // TODO(piman): Fix the underlying issues.
227 base::MessageLoop::current()->PostTask(
228 FROM_HERE,
229 base::Bind(&CompositorSwapClient::OnLostContext, this->AsWeakPtr()));
232 private:
233 void OnLostContext();
234 ui::Compositor* compositor_;
235 GpuProcessTransportFactory* factory_;
237 DISALLOW_COPY_AND_ASSIGN(CompositorSwapClient);
240 class BrowserCompositorOutputSurface;
242 // Directs vsync updates to the appropriate BrowserCompositorOutputSurface.
243 class BrowserCompositorOutputSurfaceProxy
244 : public base::RefCountedThreadSafe<BrowserCompositorOutputSurfaceProxy> {
245 public:
246 BrowserCompositorOutputSurfaceProxy()
247 : message_handler_set_(false) {
250 void AddSurface(BrowserCompositorOutputSurface* surface, int surface_id) {
251 if (!message_handler_set_) {
252 uint32 messages_to_filter[] = {GpuHostMsg_UpdateVSyncParameters::ID};
253 BrowserGpuChannelHostFactory::instance()->SetHandlerForControlMessages(
254 messages_to_filter,
255 arraysize(messages_to_filter),
256 base::Bind(&BrowserCompositorOutputSurfaceProxy::OnMessageReceived,
257 this),
258 base::MessageLoop::current()->message_loop_proxy());
259 message_handler_set_ = true;
261 surface_map_.AddWithID(surface, surface_id);
264 BrowserCompositorOutputSurface* GetOutputSurface(int surface_id) {
265 return surface_map_.Lookup(surface_id);
268 void RemoveSurface(int surface_id) {
269 surface_map_.Remove(surface_id);
272 private:
273 void OnMessageReceived(const IPC::Message& message) {
274 IPC_BEGIN_MESSAGE_MAP(BrowserCompositorOutputSurfaceProxy, message)
275 IPC_MESSAGE_HANDLER(GpuHostMsg_UpdateVSyncParameters,
276 OnUpdateVSyncParameters);
277 IPC_END_MESSAGE_MAP()
280 void OnUpdateVSyncParameters(int surface_id,
281 base::TimeTicks timebase,
282 base::TimeDelta interval);
284 friend class
285 base::RefCountedThreadSafe<BrowserCompositorOutputSurfaceProxy>;
286 ~BrowserCompositorOutputSurfaceProxy() {}
287 IDMap<BrowserCompositorOutputSurface> surface_map_;
288 bool message_handler_set_;
290 DISALLOW_COPY_AND_ASSIGN(BrowserCompositorOutputSurfaceProxy);
293 // A reflector implementation that copies the framebuffer content
294 // to the texture, then draw it onto the mirroring compositor.
295 class ReflectorImpl : public ImageTransportFactoryObserver,
296 public base::SupportsWeakPtr<ReflectorImpl>,
297 public ui::Reflector {
298 public:
299 ReflectorImpl(ui::Compositor* mirrored_compositor,
300 ui::Layer* mirroring_layer,
301 BrowserCompositorOutputSurfaceProxy* output_surface_proxy,
302 int surface_id)
303 : texture_id_(0),
304 texture_size_(mirrored_compositor->size()),
305 output_surface_proxy_(output_surface_proxy),
306 mirrored_compositor_(mirrored_compositor),
307 mirroring_compositor_(mirroring_layer->GetCompositor()),
308 mirroring_layer_(mirroring_layer),
309 impl_message_loop_(ui::Compositor::GetCompositorMessageLoop()),
310 main_message_loop_(base::MessageLoopProxy::current()),
311 surface_id_(surface_id) {
312 CreateSharedTexture();
313 impl_message_loop_->PostTask(
314 FROM_HERE,
315 base::Bind(&ReflectorImpl::InitOnImplThread,
316 this));
319 ui::Compositor* mirrored_compositor() {
320 return mirrored_compositor_;
323 void InitOnImplThread();
325 void Shutdown() {
326 mirroring_compositor_ = NULL;
327 mirroring_layer_ = NULL;
328 shared_texture_ = NULL;
329 impl_message_loop_->PostTask(
330 FROM_HERE,
331 base::Bind(&ReflectorImpl::ShutdownOnImplThread,
332 this));
335 void ShutdownOnImplThread();
337 // This must be called on ImplThread, or before the surface is passed to
338 // ImplThread.
339 void AttachToOutputSurface(BrowserCompositorOutputSurface* surface);
341 // ui::Reflector overrides:
342 virtual void OnMirroringCompositorResized() OVERRIDE {
343 mirroring_compositor_->ScheduleFullRedraw();
346 // ImageTransportFactoryObsever overrides:
347 virtual void OnLostResources() OVERRIDE {
348 shared_texture_ = NULL;
349 mirroring_layer_->SetExternalTexture(NULL);
352 // Called when the output surface's size has changed.
353 // This must be called on ImplThread.
354 void OnReshape(gfx::Size size) {
355 if (texture_size_ == size)
356 return;
357 texture_size_ = size;
358 DCHECK(texture_id_);
359 gl_helper_->ResizeTexture(texture_id_, size);
360 main_message_loop_->PostTask(
361 FROM_HERE,
362 base::Bind(&ReflectorImpl::UpdateTextureSizeOnMainThread,
363 this->AsWeakPtr(),
364 texture_size_));
367 // Called in |BrowserCompositorOutputSurface::SwapBuffers| to copy
368 // the full screen image to the |texture_id_|. This must be called
369 // on ImplThread.
370 void OnSwapBuffers() {
371 DCHECK(texture_id_);
372 gl_helper_->CopyTextureFullImage(texture_id_, texture_size_);
373 main_message_loop_->PostTask(
374 FROM_HERE,
375 base::Bind(&ReflectorImpl::FullRedrawOnMainThread,
376 this->AsWeakPtr(),
377 texture_size_));
380 // Called in |BrowserCompositorOutputSurface::PostSubBuffer| copy
381 // the sub image given by |rect| to the texture.This must be called
382 // on ImplThread.
383 void OnPostSubBuffer(gfx::Rect rect) {
384 DCHECK(texture_id_);
385 gl_helper_->CopyTextureSubImage(texture_id_, rect);
386 main_message_loop_->PostTask(
387 FROM_HERE,
388 base::Bind(&ReflectorImpl::UpdateSubBufferOnMainThread,
389 this->AsWeakPtr(),
390 texture_size_,
391 rect));
394 // Create a shared texture that will be used to copy the content of
395 // mirrored compositor to the mirroring compositor. This must be
396 // called before the reflector is attached to OutputSurface to avoid
397 // race with ImplThread accessing |texture_id_|.
398 void CreateSharedTexture() {
399 texture_id_ = ImageTransportFactory::GetInstance()->GetGLHelper()->
400 CreateTexture();
401 shared_texture_ = ImageTransportFactory::GetInstance()->
402 CreateOwnedTexture(texture_size_, 1.0f, texture_id_);
403 mirroring_layer_->SetExternalTexture(shared_texture_.get());
406 private:
407 virtual ~ReflectorImpl() {
408 // Make sure the reflector is deleted on main thread.
409 DCHECK_EQ(main_message_loop_.get(),
410 base::MessageLoopProxy::current().get());
413 void UpdateTextureSizeOnMainThread(gfx::Size size) {
414 if (!mirroring_layer_)
415 return;
416 mirroring_layer_->SetBounds(gfx::Rect(size));
419 // Request full redraw on mirroring compositor.
420 void FullRedrawOnMainThread(gfx::Size size) {
421 if (!mirroring_compositor_)
422 return;
423 UpdateTextureSizeOnMainThread(size);
424 mirroring_compositor_->ScheduleFullRedraw();
427 void UpdateSubBufferOnMainThread(gfx::Size size,
428 gfx::Rect rect) {
429 if (!mirroring_compositor_)
430 return;
431 UpdateTextureSizeOnMainThread(size);
432 // Flip the coordinates to compositor's one.
433 int y = size.height() - rect.y() - rect.height();
434 gfx::Rect new_rect(rect.x(), y, rect.width(), rect.height());
435 mirroring_layer_->SchedulePaint(new_rect);
438 // Request full redraw on mirrored compositor so that
439 // the full content will be copied to mirroring compositor.
440 void FullRedrawContentOnMainThread() {
441 mirrored_compositor_->ScheduleFullRedraw();
444 static void DeleteOnMainThread(ReflectorImpl* reflector) {
445 // reflector gets deleted when the function returns.
448 // These variables are initialized on MainThread before
449 // the reflector is attached to the output surface. Once
450 // attached, they must be accessed only on ImplThraed unless
451 // the context is lost. When the context is lost, these
452 // will be re-ininitiailzed when the new output-surface
453 // is created on MainThread.
454 int texture_id_;
455 gfx::Size texture_size_;
457 // Must be accessed only on ImplThread.
458 scoped_refptr<BrowserCompositorOutputSurfaceProxy> output_surface_proxy_;
459 scoped_ptr<GLHelper> gl_helper_;
461 // Must be accessed only on MainThread.
462 ui::Compositor* mirrored_compositor_;
463 ui::Compositor* mirroring_compositor_;
464 ui::Layer* mirroring_layer_;
465 scoped_refptr<ui::Texture> shared_texture_;
466 scoped_refptr<base::MessageLoopProxy> impl_message_loop_;
467 scoped_refptr<base::MessageLoopProxy> main_message_loop_;
468 int surface_id_;
471 // Adapts a WebGraphicsContext3DCommandBufferImpl into a
472 // cc::OutputSurface that also handles vsync parameter updates
473 // arriving from the GPU process.
474 class BrowserCompositorOutputSurface
475 : public cc::OutputSurface,
476 public base::NonThreadSafe {
477 public:
478 BrowserCompositorOutputSurface(
479 scoped_ptr<WebKit::WebGraphicsContext3D> context,
480 int surface_id,
481 BrowserCompositorOutputSurfaceProxy* output_surface_proxy,
482 base::MessageLoopProxy* compositor_message_loop,
483 base::WeakPtr<ui::Compositor> compositor)
484 : OutputSurface(context.Pass()),
485 surface_id_(surface_id),
486 output_surface_proxy_(output_surface_proxy),
487 compositor_message_loop_(compositor_message_loop),
488 compositor_(compositor) {
489 CommandLine* command_line = CommandLine::ForCurrentProcess();
490 if (command_line->HasSwitch(switches::kUIMaxFramesPending)) {
491 std::string string_value = command_line->GetSwitchValueASCII(
492 switches::kUIMaxFramesPending);
493 int int_value;
494 if (base::StringToInt(string_value, &int_value))
495 capabilities_.max_frames_pending = int_value;
496 else
497 LOG(ERROR) << "Trouble parsing --" << switches::kUIMaxFramesPending;
499 capabilities_.adjust_deadline_for_parent = false;
500 DetachFromThread();
503 virtual ~BrowserCompositorOutputSurface() {
504 DCHECK(CalledOnValidThread());
505 if (!HasClient())
506 return;
507 output_surface_proxy_->RemoveSurface(surface_id_);
510 virtual bool BindToClient(
511 cc::OutputSurfaceClient* client) OVERRIDE {
512 DCHECK(CalledOnValidThread());
514 if (!OutputSurface::BindToClient(client))
515 return false;
517 output_surface_proxy_->AddSurface(this, surface_id_);
518 return true;
521 void OnUpdateVSyncParameters(
522 base::TimeTicks timebase, base::TimeDelta interval) {
523 DCHECK(CalledOnValidThread());
524 DCHECK(HasClient());
525 OnVSyncParametersChanged(timebase, interval);
526 compositor_message_loop_->PostTask(
527 FROM_HERE,
528 base::Bind(&ui::Compositor::OnUpdateVSyncParameters,
529 compositor_, timebase, interval));
532 virtual void Reshape(gfx::Size size, float scale_factor) OVERRIDE {
533 OutputSurface::Reshape(size, scale_factor);
534 if (reflector_.get())
535 reflector_->OnReshape(size);
538 virtual void SwapBuffers(cc::CompositorFrame* frame) OVERRIDE {
539 DCHECK(frame->gl_frame_data);
541 WebGraphicsContext3DCommandBufferImpl* command_buffer =
542 static_cast<WebGraphicsContext3DCommandBufferImpl*>(context3d());
543 CommandBufferProxyImpl* command_buffer_proxy =
544 command_buffer->GetCommandBufferProxy();
545 DCHECK(command_buffer_proxy);
546 context3d()->shallowFlushCHROMIUM();
547 command_buffer_proxy->SetLatencyInfo(frame->metadata.latency_info);
549 if (reflector_.get()) {
550 if (frame->gl_frame_data->sub_buffer_rect ==
551 gfx::Rect(frame->gl_frame_data->size))
552 reflector_->OnSwapBuffers();
553 else
554 reflector_->OnPostSubBuffer(frame->gl_frame_data->sub_buffer_rect);
557 OutputSurface::SwapBuffers(frame);
560 void SetReflector(ReflectorImpl* reflector) {
561 reflector_ = reflector;
564 private:
565 int surface_id_;
566 scoped_refptr<BrowserCompositorOutputSurfaceProxy> output_surface_proxy_;
568 scoped_refptr<base::MessageLoopProxy> compositor_message_loop_;
569 base::WeakPtr<ui::Compositor> compositor_;
570 scoped_refptr<ReflectorImpl> reflector_;
573 void BrowserCompositorOutputSurfaceProxy::OnUpdateVSyncParameters(
574 int surface_id, base::TimeTicks timebase, base::TimeDelta interval) {
575 BrowserCompositorOutputSurface* surface = surface_map_.Lookup(surface_id);
576 if (surface)
577 surface->OnUpdateVSyncParameters(timebase, interval);
580 void ReflectorImpl::AttachToOutputSurface(
581 BrowserCompositorOutputSurface* output_surface) {
582 gl_helper_.reset(new GLHelper(output_surface->context3d()));
583 output_surface->SetReflector(this);
586 void ReflectorImpl::InitOnImplThread() {
587 AttachToOutputSurface(output_surface_proxy_->GetOutputSurface(surface_id_));
588 gl_helper_->CopyTextureFullImage(texture_id_, texture_size_);
589 // The shared texture doesn't have the data, so invokes full redraw
590 // now.
591 main_message_loop_->PostTask(
592 FROM_HERE,
593 base::Bind(&ReflectorImpl::FullRedrawContentOnMainThread,
594 scoped_refptr<ReflectorImpl>(this)));
597 void ReflectorImpl::ShutdownOnImplThread() {
598 BrowserCompositorOutputSurface* output_surface =
599 output_surface_proxy_->GetOutputSurface(surface_id_);
600 output_surface->SetReflector(NULL);
601 gl_helper_.reset();
602 // The instance must be deleted on main thread.
603 main_message_loop_->PostTask(
604 FROM_HERE,
605 base::Bind(&ReflectorImpl::DeleteOnMainThread,
606 scoped_refptr<ReflectorImpl>(this)));
609 class GpuProcessTransportFactory
610 : public ui::ContextFactory,
611 public ImageTransportFactory {
612 public:
613 GpuProcessTransportFactory()
614 : callback_factory_(this) {
615 output_surface_proxy_ = new BrowserCompositorOutputSurfaceProxy();
618 virtual ~GpuProcessTransportFactory() {
619 DCHECK(per_compositor_data_.empty());
622 scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
623 CreateOffscreenCommandBufferContext() {
624 base::WeakPtr<WebGraphicsContext3DSwapBuffersClient> swap_client;
625 return CreateContextCommon(swap_client, 0);
628 virtual scoped_ptr<WebKit::WebGraphicsContext3D> CreateOffscreenContext()
629 OVERRIDE {
630 return CreateOffscreenCommandBufferContext()
631 .PassAs<WebKit::WebGraphicsContext3D>();
634 virtual cc::OutputSurface* CreateOutputSurface(
635 ui::Compositor* compositor) OVERRIDE {
636 PerCompositorData* data = per_compositor_data_[compositor];
637 if (!data)
638 data = CreatePerCompositorData(compositor);
639 BrowserCompositorOutputSurface* surface =
640 new BrowserCompositorOutputSurface(
641 CreateContextCommon(data->swap_client->AsWeakPtr(),
642 data->surface_id)
643 .PassAs<WebKit::WebGraphicsContext3D>(),
644 per_compositor_data_[compositor]->surface_id,
645 output_surface_proxy_.get(),
646 base::MessageLoopProxy::current(),
647 compositor->AsWeakPtr());
648 if (data->reflector.get()) {
649 data->reflector->CreateSharedTexture();
650 data->reflector->AttachToOutputSurface(surface);
652 return surface;
655 virtual scoped_refptr<ui::Reflector> CreateReflector(
656 ui::Compositor* source,
657 ui::Layer* target) OVERRIDE {
658 PerCompositorData* data = per_compositor_data_[source];
659 DCHECK(data);
661 if (data->reflector.get())
662 RemoveObserver(data->reflector.get());
664 data->reflector = new ReflectorImpl(
665 source, target, output_surface_proxy_.get(), data->surface_id);
666 AddObserver(data->reflector.get());
667 return data->reflector;
670 virtual void RemoveReflector(
671 scoped_refptr<ui::Reflector> reflector) OVERRIDE {
672 ReflectorImpl* reflector_impl =
673 static_cast<ReflectorImpl*>(reflector.get());
674 PerCompositorData* data =
675 per_compositor_data_[reflector_impl->mirrored_compositor()];
676 DCHECK(data);
677 RemoveObserver(reflector_impl);
678 data->reflector->Shutdown();
679 data->reflector = NULL;
682 virtual void RemoveCompositor(ui::Compositor* compositor) OVERRIDE {
683 PerCompositorDataMap::iterator it = per_compositor_data_.find(compositor);
684 if (it == per_compositor_data_.end())
685 return;
686 PerCompositorData* data = it->second;
687 DCHECK(data);
688 GpuSurfaceTracker::Get()->RemoveSurface(data->surface_id);
689 delete data;
690 per_compositor_data_.erase(it);
691 if (per_compositor_data_.empty()) {
692 gl_helper_.reset();
693 callback_factory_.InvalidateWeakPtrs();
697 virtual ui::ContextFactory* AsContextFactory() OVERRIDE {
698 return this;
701 virtual gfx::GLSurfaceHandle CreateSharedSurfaceHandle() OVERRIDE {
702 CreateSharedContextLazy();
703 gfx::GLSurfaceHandle handle = gfx::GLSurfaceHandle(
704 gfx::kNullPluginWindow, gfx::TEXTURE_TRANSPORT);
705 handle.parent_gpu_process_id =
706 shared_contexts_main_thread_->Context3d()->GetGPUProcessID();
707 handle.parent_client_id =
708 shared_contexts_main_thread_->Context3d()->GetChannelID();
709 return handle;
712 virtual void DestroySharedSurfaceHandle(
713 gfx::GLSurfaceHandle surface) OVERRIDE {
716 virtual scoped_refptr<ui::Texture> CreateTransportClient(
717 float device_scale_factor) OVERRIDE {
718 if (!shared_contexts_main_thread_.get())
719 return NULL;
720 scoped_refptr<ImageTransportClientTexture> image(
721 new ImageTransportClientTexture(
722 shared_contexts_main_thread_->Context3d(),
723 device_scale_factor));
724 return image;
727 virtual scoped_refptr<ui::Texture> CreateOwnedTexture(
728 const gfx::Size& size,
729 float device_scale_factor,
730 unsigned int texture_id) OVERRIDE {
731 if (!shared_contexts_main_thread_.get())
732 return NULL;
733 scoped_refptr<OwnedTexture> image(new OwnedTexture(
734 shared_contexts_main_thread_->Context3d(),
735 size,
736 device_scale_factor,
737 texture_id));
738 return image;
741 virtual GLHelper* GetGLHelper() OVERRIDE {
742 if (!gl_helper_) {
743 CreateSharedContextLazy();
744 WebGraphicsContext3DCommandBufferImpl* context_for_main_thread =
745 shared_contexts_main_thread_->Context3d();
746 gl_helper_.reset(new GLHelper(context_for_main_thread));
748 return gl_helper_.get();
751 virtual uint32 InsertSyncPoint() OVERRIDE {
752 if (!shared_contexts_main_thread_.get())
753 return 0;
754 return shared_contexts_main_thread_->Context3d()->insertSyncPoint();
757 virtual void WaitSyncPoint(uint32 sync_point) OVERRIDE {
758 if (!shared_contexts_main_thread_.get())
759 return;
760 shared_contexts_main_thread_->Context3d()->waitSyncPoint(sync_point);
763 virtual void AddObserver(ImageTransportFactoryObserver* observer) OVERRIDE {
764 observer_list_.AddObserver(observer);
767 virtual void RemoveObserver(
768 ImageTransportFactoryObserver* observer) OVERRIDE {
769 observer_list_.RemoveObserver(observer);
772 void OnLostContext(ui::Compositor* compositor) {
773 LOG(ERROR) << "Lost UI compositor context.";
774 PerCompositorData* data = per_compositor_data_[compositor];
775 DCHECK(data);
777 // Prevent callbacks from other contexts in the same share group from
778 // calling us again.
779 data->swap_client.reset(new CompositorSwapClient(compositor, this));
780 compositor->OnSwapBuffersAborted();
783 private:
784 struct PerCompositorData {
785 int surface_id;
786 scoped_ptr<CompositorSwapClient> swap_client;
787 #if defined(OS_WIN)
788 scoped_ptr<AcceleratedSurface> accelerated_surface;
789 #endif
790 scoped_refptr<ReflectorImpl> reflector;
793 PerCompositorData* CreatePerCompositorData(ui::Compositor* compositor) {
794 DCHECK(!per_compositor_data_[compositor]);
796 CreateSharedContextLazy();
798 gfx::AcceleratedWidget widget = compositor->widget();
799 GpuSurfaceTracker* tracker = GpuSurfaceTracker::Get();
801 PerCompositorData* data = new PerCompositorData;
802 data->surface_id = tracker->AddSurfaceForNativeWidget(widget);
803 data->swap_client.reset(new CompositorSwapClient(compositor, this));
804 #if defined(OS_WIN)
805 if (GpuDataManagerImpl::GetInstance()->IsUsingAcceleratedSurface())
806 data->accelerated_surface.reset(new AcceleratedSurface(widget));
807 #endif
808 tracker->SetSurfaceHandle(
809 data->surface_id,
810 gfx::GLSurfaceHandle(widget, gfx::NATIVE_DIRECT));
812 per_compositor_data_[compositor] = data;
814 return data;
817 scoped_ptr<WebGraphicsContext3DCommandBufferImpl> CreateContextCommon(
818 const base::WeakPtr<WebGraphicsContext3DSwapBuffersClient>& swap_client,
819 int surface_id) {
820 WebKit::WebGraphicsContext3D::Attributes attrs;
821 attrs.shareResources = true;
822 attrs.depth = false;
823 attrs.stencil = false;
824 attrs.antialias = false;
825 attrs.noAutomaticFlushes = true;
826 GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance();
827 GURL url("chrome://gpu/GpuProcessTransportFactory::CreateContextCommon");
828 scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
829 new WebGraphicsContext3DCommandBufferImpl(
830 surface_id,
831 url,
832 factory,
833 swap_client));
834 if (!context->InitializeWithDefaultBufferSizes(
835 attrs,
836 false,
837 CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE))
838 return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
839 return context.Pass();
842 // Crash given that we are unable to show any UI whatsoever. On Windows we
843 // also trigger code in breakpad causes a system process to show message box.
844 // In all cases a crash dump is generated.
845 void FatalGPUError(const char* message) {
846 #if defined(OS_WIN)
847 // 0xC01E0200 corresponds to STATUS_GRAPHICS_GPU_EXCEPTION_ON_DEVICE.
848 ::RaiseException(0xC01E0200, EXCEPTION_NONCONTINUABLE, 0, NULL);
849 #else
850 LOG(FATAL) << message;
851 #endif
854 class MainThreadContextProvider : public ContextProviderCommandBuffer {
855 public:
856 static scoped_refptr<MainThreadContextProvider> Create(
857 GpuProcessTransportFactory* factory) {
858 scoped_refptr<MainThreadContextProvider> provider =
859 new MainThreadContextProvider(factory);
860 if (!provider->InitializeOnMainThread())
861 return NULL;
862 return provider;
865 protected:
866 explicit MainThreadContextProvider(GpuProcessTransportFactory* factory)
867 : factory_(factory) {}
868 virtual ~MainThreadContextProvider() {}
870 virtual scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
871 CreateOffscreenContext3d() OVERRIDE {
872 return factory_->CreateOffscreenCommandBufferContext();
875 virtual void OnLostContext() OVERRIDE {
876 base::MessageLoop::current()->PostTask(
877 FROM_HERE,
878 base::Bind(&GpuProcessTransportFactory::OnLostMainThreadSharedContext,
879 factory_->callback_factory_.GetWeakPtr()));
882 private:
883 GpuProcessTransportFactory* factory_;
886 virtual scoped_refptr<cc::ContextProvider>
887 OffscreenContextProviderForMainThread() OVERRIDE {
888 if (!shared_contexts_main_thread_.get() ||
889 shared_contexts_main_thread_->DestroyedOnMainThread()) {
890 shared_contexts_main_thread_ = MainThreadContextProvider::Create(this);
891 if (shared_contexts_main_thread_.get() &&
892 !shared_contexts_main_thread_->BindToCurrentThread())
893 shared_contexts_main_thread_ = NULL;
895 return shared_contexts_main_thread_;
898 class CompositorThreadContextProvider : public ContextProviderCommandBuffer {
899 public:
900 static scoped_refptr<CompositorThreadContextProvider> Create(
901 GpuProcessTransportFactory* factory) {
902 scoped_refptr<CompositorThreadContextProvider> provider =
903 new CompositorThreadContextProvider(factory);
904 if (!provider->InitializeOnMainThread())
905 return NULL;
906 return provider;
909 protected:
910 explicit CompositorThreadContextProvider(
911 GpuProcessTransportFactory* factory) : factory_(factory) {}
912 virtual ~CompositorThreadContextProvider() {}
914 virtual scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
915 CreateOffscreenContext3d() OVERRIDE {
916 return factory_->CreateOffscreenCommandBufferContext();
919 private:
920 GpuProcessTransportFactory* factory_;
923 virtual scoped_refptr<cc::ContextProvider>
924 OffscreenContextProviderForCompositorThread() OVERRIDE {
925 if (!shared_contexts_compositor_thread_.get() ||
926 shared_contexts_compositor_thread_->DestroyedOnMainThread()) {
927 shared_contexts_compositor_thread_ =
928 CompositorThreadContextProvider::Create(this);
930 return shared_contexts_compositor_thread_;
933 void CreateSharedContextLazy() {
934 scoped_refptr<cc::ContextProvider> provider =
935 OffscreenContextProviderForMainThread();
936 if (!provider.get()) {
937 // If we can't recreate contexts, we won't be able to show the UI.
938 // Better crash at this point.
939 FatalGPUError("Failed to initialize UI shared context.");
943 void OnLostMainThreadSharedContext() {
944 LOG(ERROR) << "Lost UI shared context.";
945 // Keep old resources around while we call the observers, but ensure that
946 // new resources are created if needed.
948 scoped_refptr<MainThreadContextProvider> old_contexts_main_thread =
949 shared_contexts_main_thread_;
950 shared_contexts_main_thread_ = NULL;
952 scoped_ptr<GLHelper> old_helper(gl_helper_.release());
954 FOR_EACH_OBSERVER(ImageTransportFactoryObserver,
955 observer_list_,
956 OnLostResources());
959 typedef std::map<ui::Compositor*, PerCompositorData*> PerCompositorDataMap;
960 PerCompositorDataMap per_compositor_data_;
961 scoped_refptr<MainThreadContextProvider> shared_contexts_main_thread_;
962 scoped_refptr<CompositorThreadContextProvider>
963 shared_contexts_compositor_thread_;
964 scoped_ptr<GLHelper> gl_helper_;
965 ObserverList<ImageTransportFactoryObserver> observer_list_;
966 base::WeakPtrFactory<GpuProcessTransportFactory> callback_factory_;
967 scoped_refptr<BrowserCompositorOutputSurfaceProxy> output_surface_proxy_;
969 DISALLOW_COPY_AND_ASSIGN(GpuProcessTransportFactory);
972 void CompositorSwapClient::OnLostContext() {
973 factory_->OnLostContext(compositor_);
974 // Note: previous line destroyed this. Don't access members from now on.
977 class SoftwareOutputSurface : public cc::OutputSurface {
978 public:
979 explicit SoftwareOutputSurface(
980 scoped_ptr<cc::SoftwareOutputDevice> software_device)
981 : cc::OutputSurface(software_device.Pass()) {}
983 virtual void SwapBuffers(cc::CompositorFrame* frame) OVERRIDE {
984 ui::LatencyInfo latency_info = frame->metadata.latency_info;
985 latency_info.swap_timestamp = base::TimeTicks::HighResNow();
986 RenderWidgetHostImpl::CompositorFrameDrawn(latency_info);
987 cc::OutputSurface::SwapBuffers(frame);
991 class SoftwareContextFactory : public ui::ContextFactory {
992 public:
993 SoftwareContextFactory() {}
994 virtual ~SoftwareContextFactory() {}
995 virtual scoped_ptr<WebKit::WebGraphicsContext3D> CreateOffscreenContext()
996 OVERRIDE {
997 return scoped_ptr<WebKit::WebGraphicsContext3D>();
999 virtual cc::OutputSurface* CreateOutputSurface(
1000 ui::Compositor* compositor) OVERRIDE {
1001 #if defined(OS_WIN)
1002 scoped_ptr<SoftwareOutputDeviceWin> software_device(
1003 new SoftwareOutputDeviceWin(compositor));
1004 return new SoftwareOutputSurface(
1005 software_device.PassAs<cc::SoftwareOutputDevice>());
1006 #elif defined(USE_X11)
1007 scoped_ptr<SoftwareOutputDeviceX11> software_device(
1008 new SoftwareOutputDeviceX11(compositor));
1009 return new SoftwareOutputSurface(
1010 software_device.PassAs<cc::SoftwareOutputDevice>());
1011 #else
1012 NOTIMPLEMENTED();
1013 return NULL;
1014 #endif
1017 virtual scoped_refptr<ui::Reflector> CreateReflector(
1018 ui::Compositor* source,
1019 ui::Layer* target) OVERRIDE {
1020 return NULL;
1022 virtual void RemoveReflector(
1023 scoped_refptr<ui::Reflector> reflector) OVERRIDE {}
1025 virtual void RemoveCompositor(ui::Compositor* compositor) OVERRIDE {}
1027 virtual scoped_refptr<cc::ContextProvider>
1028 OffscreenContextProviderForMainThread() OVERRIDE {
1029 return NULL;
1032 virtual scoped_refptr<cc::ContextProvider>
1033 OffscreenContextProviderForCompositorThread() OVERRIDE {
1034 return NULL;
1037 private:
1038 DISALLOW_COPY_AND_ASSIGN(SoftwareContextFactory);
1041 } // anonymous namespace
1043 // static
1044 void ImageTransportFactory::Initialize() {
1045 CommandLine* command_line = CommandLine::ForCurrentProcess();
1046 if (command_line->HasSwitch(switches::kTestCompositor)) {
1047 ui::SetupTestCompositor();
1049 if (ui::IsTestCompositorEnabled()) {
1050 g_factory = new NoTransportFactory(new ui::TestContextFactory);
1051 } else if (command_line->HasSwitch(switches::kUIEnableSoftwareCompositing)) {
1052 g_factory = new NoTransportFactory(new SoftwareContextFactory);
1053 } else {
1054 g_factory = new GpuProcessTransportFactory;
1056 ui::ContextFactory::SetInstance(g_factory->AsContextFactory());
1059 // static
1060 void ImageTransportFactory::Terminate() {
1061 ui::ContextFactory::SetInstance(NULL);
1062 delete g_factory;
1063 g_factory = NULL;
1066 // static
1067 ImageTransportFactory* ImageTransportFactory::GetInstance() {
1068 return g_factory;
1071 } // namespace content