blob: 8822e85fef1b8d616f843040ea0b4da6dbd9c2ef [file] [log] [blame]
Ben Murdoch558790d2013-07-30 15:19:42 +01001// 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.
4
5#include "content/browser/aura/gpu_process_transport_factory.h"
6
7#include <string>
8
9#include "base/bind.h"
10#include "base/command_line.h"
11#include "base/location.h"
12#include "base/message_loop/message_loop.h"
13#include "cc/output/compositor_frame.h"
14#include "cc/output/output_surface.h"
15#include "content/browser/aura/browser_compositor_output_surface.h"
16#include "content/browser/aura/browser_compositor_output_surface_proxy.h"
17#include "content/browser/aura/reflector_impl.h"
Ben Murdochbb1529c2013-08-08 10:24:53 +010018#include "content/browser/aura/software_browser_compositor_output_surface.h"
Ben Murdoch558790d2013-07-30 15:19:42 +010019#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
20#include "content/browser/gpu/gpu_data_manager_impl.h"
21#include "content/browser/gpu/gpu_surface_tracker.h"
22#include "content/browser/renderer_host/render_widget_host_impl.h"
Ben Murdochfb250652013-07-31 11:42:55 +010023#include "content/common/gpu/client/context_provider_command_buffer.h"
Ben Murdoch558790d2013-07-30 15:19:42 +010024#include "content/common/gpu/client/gl_helper.h"
25#include "content/common/gpu/client/gpu_channel_host.h"
26#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
27#include "content/common/gpu/gpu_process_launch_causes.h"
28#include "gpu/GLES2/gl2extchromium.h"
29#include "third_party/khronos/GLES2/gl2.h"
30#include "ui/compositor/compositor.h"
31#include "ui/compositor/compositor_switches.h"
32#include "ui/gfx/native_widget_types.h"
33#include "ui/gfx/size.h"
34
35#if defined(OS_WIN)
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010036#include "content/browser/aura/software_output_device_win.h"
Ben Murdoch558790d2013-07-30 15:19:42 +010037#include "ui/surface/accelerated_surface_win.h"
38#elif defined(USE_X11)
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010039#include "content/browser/aura/software_output_device_x11.h"
Ben Murdoch558790d2013-07-30 15:19:42 +010040#endif
41
42namespace content {
43
44struct GpuProcessTransportFactory::PerCompositorData {
45 int surface_id;
46 scoped_ptr<CompositorSwapClient> swap_client;
47#if defined(OS_WIN)
48 scoped_ptr<AcceleratedSurface> accelerated_surface;
49#endif
50 scoped_refptr<ReflectorImpl> reflector;
51};
52
53class OwnedTexture : public ui::Texture, ImageTransportFactoryObserver {
54 public:
55 OwnedTexture(WebKit::WebGraphicsContext3D* host_context,
56 const gfx::Size& size,
57 float device_scale_factor,
58 unsigned int texture_id)
59 : ui::Texture(true, size, device_scale_factor),
60 host_context_(host_context),
61 texture_id_(texture_id) {
62 ImageTransportFactory::GetInstance()->AddObserver(this);
63 }
64
65 // ui::Texture overrides:
66 virtual unsigned int PrepareTexture() OVERRIDE {
67 return texture_id_;
68 }
69
70 virtual WebKit::WebGraphicsContext3D* HostContext3D() OVERRIDE {
71 return host_context_;
72 }
73
74 // ImageTransportFactory overrides:
75 virtual void OnLostResources() OVERRIDE {
76 DeleteTexture();
77 }
78
79 protected:
80 virtual ~OwnedTexture() {
81 ImageTransportFactory::GetInstance()->RemoveObserver(this);
82 DeleteTexture();
83 }
84
85 protected:
86 void DeleteTexture() {
87 if (texture_id_) {
88 host_context_->deleteTexture(texture_id_);
89 texture_id_ = 0;
90 }
91 }
92
93 // A raw pointer. This |ImageTransportClientTexture| will be destroyed
94 // before the |host_context_| via
95 // |ImageTransportFactoryObserver::OnLostContext()| handlers.
96 WebKit::WebGraphicsContext3D* host_context_;
97 unsigned texture_id_;
98
99 DISALLOW_COPY_AND_ASSIGN(OwnedTexture);
100};
101
102class ImageTransportClientTexture : public OwnedTexture {
103 public:
104 ImageTransportClientTexture(
105 WebKit::WebGraphicsContext3D* host_context,
106 float device_scale_factor)
107 : OwnedTexture(host_context,
108 gfx::Size(0, 0),
109 device_scale_factor,
110 host_context->createTexture()) {
111 }
112
113 virtual void Consume(const std::string& mailbox_name,
114 const gfx::Size& new_size) OVERRIDE {
115 DCHECK(mailbox_name.size() == GL_MAILBOX_SIZE_CHROMIUM);
116 mailbox_name_ = mailbox_name;
117 if (mailbox_name.empty())
118 return;
119
120 DCHECK(host_context_ && texture_id_);
121 host_context_->bindTexture(GL_TEXTURE_2D, texture_id_);
122 host_context_->consumeTextureCHROMIUM(
123 GL_TEXTURE_2D,
124 reinterpret_cast<const signed char*>(mailbox_name.c_str()));
125 size_ = new_size;
126 host_context_->shallowFlushCHROMIUM();
127 }
128
129 virtual std::string Produce() OVERRIDE {
130 return mailbox_name_;
131 }
132
133 protected:
134 virtual ~ImageTransportClientTexture() {}
135
136 private:
137 std::string mailbox_name_;
138 DISALLOW_COPY_AND_ASSIGN(ImageTransportClientTexture);
139};
140
141class CompositorSwapClient
142 : public base::SupportsWeakPtr<CompositorSwapClient>,
143 public WebGraphicsContext3DSwapBuffersClient {
144 public:
145 CompositorSwapClient(ui::Compositor* compositor,
146 GpuProcessTransportFactory* factory)
147 : compositor_(compositor),
148 factory_(factory) {
149 }
150
151 virtual ~CompositorSwapClient() {
152 }
153
154 virtual void OnViewContextSwapBuffersPosted() OVERRIDE {
155 compositor_->OnSwapBuffersPosted();
156 }
157
158 virtual void OnViewContextSwapBuffersComplete() OVERRIDE {
159 compositor_->OnSwapBuffersComplete();
160 }
161
162 virtual void OnViewContextSwapBuffersAborted() OVERRIDE {
163 // Recreating contexts directly from here causes issues, so post a task
164 // instead.
165 // TODO(piman): Fix the underlying issues.
166 base::MessageLoop::current()->PostTask(
167 FROM_HERE,
168 base::Bind(&CompositorSwapClient::OnLostContext, this->AsWeakPtr()));
169 }
170
171 private:
172 void OnLostContext() {
173 factory_->OnLostContext(compositor_);
174 // Note: previous line destroyed this. Don't access members from now on.
175 }
176
177 ui::Compositor* compositor_;
178 GpuProcessTransportFactory* factory_;
179
180 DISALLOW_COPY_AND_ASSIGN(CompositorSwapClient);
181};
182
Ben Murdoch558790d2013-07-30 15:19:42 +0100183GpuProcessTransportFactory::GpuProcessTransportFactory()
184 : callback_factory_(this) {
Ben Murdoch558790d2013-07-30 15:19:42 +0100185 output_surface_proxy_ = new BrowserCompositorOutputSurfaceProxy(
Ben Murdochd3868032013-07-31 10:55:33 +0100186 &output_surface_map_);
Ben Murdoch558790d2013-07-30 15:19:42 +0100187}
188
189GpuProcessTransportFactory::~GpuProcessTransportFactory() {
190 DCHECK(per_compositor_data_.empty());
Ben Murdochfb250652013-07-31 11:42:55 +0100191
192 // Make sure the lost context callback doesn't try to run during destruction.
193 callback_factory_.InvalidateWeakPtrs();
Ben Murdoch558790d2013-07-30 15:19:42 +0100194}
195
196scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
197GpuProcessTransportFactory::CreateOffscreenCommandBufferContext() {
198 base::WeakPtr<WebGraphicsContext3DSwapBuffersClient> swap_client;
199 return CreateContextCommon(swap_client, 0);
200}
201
202scoped_ptr<WebKit::WebGraphicsContext3D>
203GpuProcessTransportFactory::CreateOffscreenContext() {
204 return CreateOffscreenCommandBufferContext()
205 .PassAs<WebKit::WebGraphicsContext3D>();
206}
207
Ben Murdochbb1529c2013-08-08 10:24:53 +0100208scoped_ptr<cc::SoftwareOutputDevice> CreateSoftwareOutputDevice(
209 ui::Compositor* compositor) {
210#if defined(OS_WIN)
211 return scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareOutputDeviceWin(
212 compositor));
213#elif defined(USE_X11)
214 return scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareOutputDeviceX11(
215 compositor));
216#endif
217
218 NOTREACHED();
219 return scoped_ptr<cc::SoftwareOutputDevice>();
220}
221
Ben Murdoch558790d2013-07-30 15:19:42 +0100222scoped_ptr<cc::OutputSurface> GpuProcessTransportFactory::CreateOutputSurface(
223 ui::Compositor* compositor) {
224 PerCompositorData* data = per_compositor_data_[compositor];
225 if (!data)
226 data = CreatePerCompositorData(compositor);
227
228 scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context;
229 CommandLine* command_line = CommandLine::ForCurrentProcess();
230 if (!command_line->HasSwitch(switches::kUIEnableSoftwareCompositing)) {
231 context =
232 CreateContextCommon(data->swap_client->AsWeakPtr(), data->surface_id);
233 }
Ben Murdochbb1529c2013-08-08 10:24:53 +0100234 if (!context) {
235 scoped_ptr<SoftwareBrowserCompositorOutputSurface> surface =
236 SoftwareBrowserCompositorOutputSurface::Create(
237 CreateSoftwareOutputDevice(compositor));
238 return surface.PassAs<cc::OutputSurface>();
239 }
Ben Murdoch558790d2013-07-30 15:19:42 +0100240
241 scoped_refptr<base::SingleThreadTaskRunner> compositor_thread_task_runner =
242 ui::Compositor::GetCompositorMessageLoop();
243 if (!compositor_thread_task_runner.get())
244 compositor_thread_task_runner = base::MessageLoopProxy::current();
245
246 // Here we know the GpuProcessHost has been set up, because we created a
247 // context.
248 output_surface_proxy_->ConnectToGpuProcessHost(
249 compositor_thread_task_runner.get());
250
251 scoped_ptr<BrowserCompositorOutputSurface> surface(
252 new BrowserCompositorOutputSurface(
253 context.PassAs<WebKit::WebGraphicsContext3D>(),
254 per_compositor_data_[compositor]->surface_id,
Ben Murdochd3868032013-07-31 10:55:33 +0100255 &output_surface_map_,
Ben Murdoch558790d2013-07-30 15:19:42 +0100256 base::MessageLoopProxy::current().get(),
257 compositor->AsWeakPtr()));
258 if (data->reflector.get()) {
259 data->reflector->CreateSharedTexture();
260 data->reflector->AttachToOutputSurface(surface.get());
261 }
262
263 return surface.PassAs<cc::OutputSurface>();
264}
265
266scoped_refptr<ui::Reflector> GpuProcessTransportFactory::CreateReflector(
267 ui::Compositor* source,
268 ui::Layer* target) {
269 PerCompositorData* data = per_compositor_data_[source];
270 DCHECK(data);
271
272 if (data->reflector.get())
273 RemoveObserver(data->reflector.get());
274
275 data->reflector = new ReflectorImpl(
Ben Murdochd3868032013-07-31 10:55:33 +0100276 source, target, &output_surface_map_, data->surface_id);
Ben Murdoch558790d2013-07-30 15:19:42 +0100277 AddObserver(data->reflector.get());
278 return data->reflector;
279}
280
281void GpuProcessTransportFactory::RemoveReflector(
282 scoped_refptr<ui::Reflector> reflector) {
283 ReflectorImpl* reflector_impl =
284 static_cast<ReflectorImpl*>(reflector.get());
285 PerCompositorData* data =
286 per_compositor_data_[reflector_impl->mirrored_compositor()];
287 DCHECK(data);
288 RemoveObserver(reflector_impl);
289 data->reflector->Shutdown();
290 data->reflector = NULL;
291}
292
293void GpuProcessTransportFactory::RemoveCompositor(ui::Compositor* compositor) {
294 PerCompositorDataMap::iterator it = per_compositor_data_.find(compositor);
295 if (it == per_compositor_data_.end())
296 return;
297 PerCompositorData* data = it->second;
298 DCHECK(data);
299 GpuSurfaceTracker::Get()->RemoveSurface(data->surface_id);
300 delete data;
301 per_compositor_data_.erase(it);
Ben Murdochfb250652013-07-31 11:42:55 +0100302 if (per_compositor_data_.empty())
Ben Murdoch558790d2013-07-30 15:19:42 +0100303 gl_helper_.reset();
Ben Murdoch558790d2013-07-30 15:19:42 +0100304}
305
306ui::ContextFactory* GpuProcessTransportFactory::AsContextFactory() {
307 return this;
308}
309
310gfx::GLSurfaceHandle GpuProcessTransportFactory::CreateSharedSurfaceHandle() {
311 CreateSharedContextLazy();
312 if (!shared_contexts_main_thread_ ||
313 !shared_contexts_main_thread_->Context3d())
314 return gfx::GLSurfaceHandle();
315 gfx::GLSurfaceHandle handle = gfx::GLSurfaceHandle(
316 gfx::kNullPluginWindow, gfx::TEXTURE_TRANSPORT);
317 handle.parent_gpu_process_id =
318 shared_contexts_main_thread_->Context3d()->GetGPUProcessID();
319 handle.parent_client_id =
320 shared_contexts_main_thread_->Context3d()->GetChannelID();
321 return handle;
322}
323
324void GpuProcessTransportFactory::DestroySharedSurfaceHandle(
325 gfx::GLSurfaceHandle surface) {}
326
327scoped_refptr<ui::Texture> GpuProcessTransportFactory::CreateTransportClient(
328 float device_scale_factor) {
329 if (!shared_contexts_main_thread_.get())
330 return NULL;
331 scoped_refptr<ImageTransportClientTexture> image(
332 new ImageTransportClientTexture(
333 shared_contexts_main_thread_->Context3d(),
334 device_scale_factor));
335 return image;
336}
337
338scoped_refptr<ui::Texture> GpuProcessTransportFactory::CreateOwnedTexture(
339 const gfx::Size& size,
340 float device_scale_factor,
341 unsigned int texture_id) {
342 if (!shared_contexts_main_thread_.get())
343 return NULL;
344 scoped_refptr<OwnedTexture> image(new OwnedTexture(
345 shared_contexts_main_thread_->Context3d(),
346 size,
347 device_scale_factor,
348 texture_id));
349 return image;
350}
351
352GLHelper* GpuProcessTransportFactory::GetGLHelper() {
353 if (!gl_helper_) {
354 CreateSharedContextLazy();
355 WebGraphicsContext3DCommandBufferImpl* context_for_main_thread =
356 shared_contexts_main_thread_->Context3d();
357 gl_helper_.reset(new GLHelper(context_for_main_thread));
358 }
359 return gl_helper_.get();
360}
361
362uint32 GpuProcessTransportFactory::InsertSyncPoint() {
363 if (!shared_contexts_main_thread_.get())
364 return 0;
365 return shared_contexts_main_thread_->Context3d()->insertSyncPoint();
366}
367
368void GpuProcessTransportFactory::WaitSyncPoint(uint32 sync_point) {
369 if (!shared_contexts_main_thread_.get())
370 return;
371 shared_contexts_main_thread_->Context3d()->waitSyncPoint(sync_point);
372}
373
374void GpuProcessTransportFactory::AddObserver(
375 ImageTransportFactoryObserver* observer) {
376 observer_list_.AddObserver(observer);
377}
378
379void GpuProcessTransportFactory::RemoveObserver(
380 ImageTransportFactoryObserver* observer) {
381 observer_list_.RemoveObserver(observer);
382}
383
384scoped_refptr<cc::ContextProvider>
385GpuProcessTransportFactory::OffscreenContextProviderForMainThread() {
386 if (!shared_contexts_main_thread_.get() ||
387 shared_contexts_main_thread_->DestroyedOnMainThread()) {
Ben Murdochfb250652013-07-31 11:42:55 +0100388 shared_contexts_main_thread_ = ContextProviderCommandBuffer::Create(
389 base::Bind(&GpuProcessTransportFactory::
390 CreateOffscreenCommandBufferContext,
391 base::Unretained(this)));
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100392 if (shared_contexts_main_thread_) {
393 shared_contexts_main_thread_->SetLostContextCallback(base::Bind(
394 &GpuProcessTransportFactory::
395 OnLostMainThreadSharedContextInsideCallback,
396 callback_factory_.GetWeakPtr()));
Ben Murdochfb250652013-07-31 11:42:55 +0100397
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100398 if (!shared_contexts_main_thread_->BindToCurrentThread())
399 shared_contexts_main_thread_ = NULL;
400 }
Ben Murdoch558790d2013-07-30 15:19:42 +0100401 }
402 return shared_contexts_main_thread_;
403}
404
405scoped_refptr<cc::ContextProvider>
406GpuProcessTransportFactory::OffscreenContextProviderForCompositorThread() {
407 if (!shared_contexts_compositor_thread_.get() ||
408 shared_contexts_compositor_thread_->DestroyedOnMainThread()) {
Ben Murdochfb250652013-07-31 11:42:55 +0100409 shared_contexts_compositor_thread_ = ContextProviderCommandBuffer::Create(
410 base::Bind(&GpuProcessTransportFactory::
411 CreateOffscreenCommandBufferContext,
412 base::Unretained(this)));
Ben Murdoch558790d2013-07-30 15:19:42 +0100413 }
414 return shared_contexts_compositor_thread_;
415}
416
417void GpuProcessTransportFactory::OnLostContext(ui::Compositor* compositor) {
418 LOG(ERROR) << "Lost UI compositor context.";
419 PerCompositorData* data = per_compositor_data_[compositor];
420 DCHECK(data);
421
422 // Prevent callbacks from other contexts in the same share group from
423 // calling us again.
424 data->swap_client.reset(new CompositorSwapClient(compositor, this));
425 compositor->OnSwapBuffersAborted();
426}
427
428GpuProcessTransportFactory::PerCompositorData*
429GpuProcessTransportFactory::CreatePerCompositorData(
430 ui::Compositor* compositor) {
431 DCHECK(!per_compositor_data_[compositor]);
432
433 CreateSharedContextLazy();
434
435 gfx::AcceleratedWidget widget = compositor->widget();
436 GpuSurfaceTracker* tracker = GpuSurfaceTracker::Get();
437
438 PerCompositorData* data = new PerCompositorData;
439 data->surface_id = tracker->AddSurfaceForNativeWidget(widget);
440 data->swap_client.reset(new CompositorSwapClient(compositor, this));
441#if defined(OS_WIN)
442 if (GpuDataManagerImpl::GetInstance()->IsUsingAcceleratedSurface())
443 data->accelerated_surface.reset(new AcceleratedSurface(widget));
444#endif
445 tracker->SetSurfaceHandle(
446 data->surface_id,
447 gfx::GLSurfaceHandle(widget, gfx::NATIVE_DIRECT));
448
449 per_compositor_data_[compositor] = data;
450
451 return data;
452}
453
454scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
455GpuProcessTransportFactory::CreateContextCommon(
456 const base::WeakPtr<WebGraphicsContext3DSwapBuffersClient>& swap_client,
457 int surface_id) {
458 if (!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor())
459 return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
460 WebKit::WebGraphicsContext3D::Attributes attrs;
461 attrs.shareResources = true;
462 attrs.depth = false;
463 attrs.stencil = false;
464 attrs.antialias = false;
465 attrs.noAutomaticFlushes = true;
466 GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance();
467 GURL url("chrome://gpu/GpuProcessTransportFactory::CreateContextCommon");
468 scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
469 new WebGraphicsContext3DCommandBufferImpl(
470 surface_id,
471 url,
472 factory,
473 swap_client));
474 if (!context->InitializeWithDefaultBufferSizes(
475 attrs,
476 false,
477 CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE))
478 return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
479 return context.Pass();
480}
481
Ben Murdoch558790d2013-07-30 15:19:42 +0100482void GpuProcessTransportFactory::CreateSharedContextLazy() {
483 scoped_refptr<cc::ContextProvider> provider =
484 OffscreenContextProviderForMainThread();
485}
486
Ben Murdochfb250652013-07-31 11:42:55 +0100487void GpuProcessTransportFactory::OnLostMainThreadSharedContextInsideCallback() {
488 base::MessageLoop::current()->PostTask(
489 FROM_HERE,
490 base::Bind(&GpuProcessTransportFactory::OnLostMainThreadSharedContext,
491 callback_factory_.GetWeakPtr()));
492}
493
Ben Murdoch558790d2013-07-30 15:19:42 +0100494void GpuProcessTransportFactory::OnLostMainThreadSharedContext() {
495 LOG(ERROR) << "Lost UI shared context.";
496 // Keep old resources around while we call the observers, but ensure that
497 // new resources are created if needed.
498
Ben Murdochfb250652013-07-31 11:42:55 +0100499 scoped_refptr<ContextProviderCommandBuffer> old_contexts_main_thread =
Ben Murdoch558790d2013-07-30 15:19:42 +0100500 shared_contexts_main_thread_;
501 shared_contexts_main_thread_ = NULL;
502
503 scoped_ptr<GLHelper> old_helper(gl_helper_.release());
504
505 FOR_EACH_OBSERVER(ImageTransportFactoryObserver,
506 observer_list_,
507 OnLostResources());
508}
509
510} // namespace content