Respond with QuotaExceededError when IndexedDB has no disk space on open.
[chromium-blink-merge.git] / content / browser / aura / gpu_process_transport_factory.cc
blob959210deceaa6f5e519b127524ecb2b48b6fe6f1
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/aura/gpu_process_transport_factory.h"
7 #include <string>
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 "base/metrics/histogram.h"
14 #include "cc/output/compositor_frame.h"
15 #include "cc/output/output_surface.h"
16 #include "content/browser/aura/browser_compositor_output_surface.h"
17 #include "content/browser/aura/browser_compositor_output_surface_proxy.h"
18 #include "content/browser/aura/reflector_impl.h"
19 #include "content/browser/aura/software_browser_compositor_output_surface.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_surface_tracker.h"
23 #include "content/browser/renderer_host/render_widget_host_impl.h"
24 #include "content/common/gpu/client/context_provider_command_buffer.h"
25 #include "content/common/gpu/client/gl_helper.h"
26 #include "content/common/gpu/client/gpu_channel_host.h"
27 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
28 #include "content/common/gpu/gpu_process_launch_causes.h"
29 #include "gpu/GLES2/gl2extchromium.h"
30 #include "third_party/khronos/GLES2/gl2.h"
31 #include "ui/compositor/compositor.h"
32 #include "ui/compositor/compositor_switches.h"
33 #include "ui/gfx/native_widget_types.h"
34 #include "ui/gfx/size.h"
36 #if defined(OS_WIN)
37 #include "content/browser/aura/software_output_device_win.h"
38 #include "ui/surface/accelerated_surface_win.h"
39 #elif defined(USE_X11)
40 #include "content/browser/aura/software_output_device_x11.h"
41 #endif
43 namespace content {
45 struct GpuProcessTransportFactory::PerCompositorData {
46 int surface_id;
47 scoped_ptr<CompositorSwapClient> swap_client;
48 #if defined(OS_WIN)
49 scoped_ptr<AcceleratedSurface> accelerated_surface;
50 #endif
51 scoped_refptr<ReflectorImpl> reflector;
54 class OwnedTexture : public ui::Texture, ImageTransportFactoryObserver {
55 public:
56 OwnedTexture(WebKit::WebGraphicsContext3D* host_context,
57 const gfx::Size& size,
58 float device_scale_factor,
59 unsigned int texture_id)
60 : ui::Texture(true, size, device_scale_factor),
61 host_context_(host_context),
62 texture_id_(texture_id) {
63 ImageTransportFactory::GetInstance()->AddObserver(this);
66 // ui::Texture overrides:
67 virtual unsigned int PrepareTexture() OVERRIDE {
68 return texture_id_;
71 virtual WebKit::WebGraphicsContext3D* HostContext3D() OVERRIDE {
72 return host_context_;
75 // ImageTransportFactory overrides:
76 virtual void OnLostResources() OVERRIDE {
77 DeleteTexture();
78 host_context_ = NULL;
81 protected:
82 virtual ~OwnedTexture() {
83 ImageTransportFactory::GetInstance()->RemoveObserver(this);
84 DeleteTexture();
87 protected:
88 void DeleteTexture() {
89 if (texture_id_) {
90 host_context_->deleteTexture(texture_id_);
91 texture_id_ = 0;
95 // The OnLostResources() callback will happen before this context
96 // pointer is destroyed.
97 WebKit::WebGraphicsContext3D* host_context_;
98 unsigned texture_id_;
100 DISALLOW_COPY_AND_ASSIGN(OwnedTexture);
103 class ImageTransportClientTexture : public OwnedTexture {
104 public:
105 ImageTransportClientTexture(
106 WebKit::WebGraphicsContext3D* host_context,
107 float device_scale_factor)
108 : OwnedTexture(host_context,
109 gfx::Size(0, 0),
110 device_scale_factor,
111 host_context->createTexture()) {
114 virtual void Consume(const std::string& mailbox_name,
115 const gfx::Size& new_size) OVERRIDE {
116 DCHECK(mailbox_name.size() == GL_MAILBOX_SIZE_CHROMIUM);
117 mailbox_name_ = mailbox_name;
118 if (mailbox_name.empty())
119 return;
121 DCHECK(host_context_ && texture_id_);
122 host_context_->bindTexture(GL_TEXTURE_2D, texture_id_);
123 host_context_->consumeTextureCHROMIUM(
124 GL_TEXTURE_2D,
125 reinterpret_cast<const signed char*>(mailbox_name.c_str()));
126 size_ = new_size;
127 host_context_->shallowFlushCHROMIUM();
130 virtual std::string Produce() OVERRIDE {
131 return mailbox_name_;
134 protected:
135 virtual ~ImageTransportClientTexture() {}
137 private:
138 std::string mailbox_name_;
139 DISALLOW_COPY_AND_ASSIGN(ImageTransportClientTexture);
142 class CompositorSwapClient
143 : public base::SupportsWeakPtr<CompositorSwapClient>,
144 public WebGraphicsContext3DSwapBuffersClient {
145 public:
146 CompositorSwapClient(ui::Compositor* compositor,
147 GpuProcessTransportFactory* factory)
148 : compositor_(compositor),
149 factory_(factory) {
152 virtual ~CompositorSwapClient() {
155 virtual void OnViewContextSwapBuffersPosted() OVERRIDE {
156 compositor_->OnSwapBuffersPosted();
159 virtual void OnViewContextSwapBuffersComplete() OVERRIDE {
160 compositor_->OnSwapBuffersComplete();
163 virtual void OnViewContextSwapBuffersAborted() OVERRIDE {
164 // Recreating contexts directly from here causes issues, so post a task
165 // instead.
166 // TODO(piman): Fix the underlying issues.
167 base::MessageLoop::current()->PostTask(
168 FROM_HERE,
169 base::Bind(&CompositorSwapClient::OnLostContext, this->AsWeakPtr()));
172 private:
173 void OnLostContext() {
174 factory_->OnLostContext(compositor_);
175 // Note: previous line destroyed this. Don't access members from now on.
178 ui::Compositor* compositor_;
179 GpuProcessTransportFactory* factory_;
181 DISALLOW_COPY_AND_ASSIGN(CompositorSwapClient);
184 GpuProcessTransportFactory::GpuProcessTransportFactory()
185 : callback_factory_(this) {
186 output_surface_proxy_ = new BrowserCompositorOutputSurfaceProxy(
187 &output_surface_map_);
190 GpuProcessTransportFactory::~GpuProcessTransportFactory() {
191 DCHECK(per_compositor_data_.empty());
193 // Make sure the lost context callback doesn't try to run during destruction.
194 callback_factory_.InvalidateWeakPtrs();
197 scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
198 GpuProcessTransportFactory::CreateOffscreenCommandBufferContext() {
199 base::WeakPtr<WebGraphicsContext3DSwapBuffersClient> swap_client;
200 return CreateContextCommon(swap_client, 0);
203 scoped_ptr<cc::SoftwareOutputDevice> CreateSoftwareOutputDevice(
204 ui::Compositor* compositor) {
205 #if defined(OS_WIN)
206 return scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareOutputDeviceWin(
207 compositor));
208 #elif defined(USE_X11)
209 return scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareOutputDeviceX11(
210 compositor));
211 #endif
213 NOTREACHED();
214 return scoped_ptr<cc::SoftwareOutputDevice>();
217 scoped_ptr<cc::OutputSurface> GpuProcessTransportFactory::CreateOutputSurface(
218 ui::Compositor* compositor) {
219 PerCompositorData* data = per_compositor_data_[compositor];
220 if (!data)
221 data = CreatePerCompositorData(compositor);
223 scoped_refptr<ContextProviderCommandBuffer> context_provider;
225 CommandLine* command_line = CommandLine::ForCurrentProcess();
226 if (!command_line->HasSwitch(switches::kUIEnableSoftwareCompositing)) {
227 context_provider = ContextProviderCommandBuffer::Create(
228 GpuProcessTransportFactory::CreateContextCommon(
229 data->swap_client->AsWeakPtr(),
230 data->surface_id),
231 "Compositor");
234 UMA_HISTOGRAM_BOOLEAN("Aura.CreatedGpuBrowserCompositor", !!context_provider);
236 if (!context_provider.get()) {
237 if (ui::Compositor::WasInitializedWithThread()) {
238 LOG(FATAL) << "Failed to create UI context, but can't use software"
239 " compositing with browser threaded compositing. Aborting.";
242 scoped_ptr<SoftwareBrowserCompositorOutputSurface> surface =
243 SoftwareBrowserCompositorOutputSurface::Create(
244 CreateSoftwareOutputDevice(compositor));
245 return surface.PassAs<cc::OutputSurface>();
248 scoped_refptr<base::SingleThreadTaskRunner> compositor_thread_task_runner =
249 ui::Compositor::GetCompositorMessageLoop();
250 if (!compositor_thread_task_runner.get())
251 compositor_thread_task_runner = base::MessageLoopProxy::current();
253 // Here we know the GpuProcessHost has been set up, because we created a
254 // context.
255 output_surface_proxy_->ConnectToGpuProcessHost(
256 compositor_thread_task_runner.get());
258 scoped_ptr<BrowserCompositorOutputSurface> surface(
259 new BrowserCompositorOutputSurface(
260 context_provider,
261 per_compositor_data_[compositor]->surface_id,
262 &output_surface_map_,
263 base::MessageLoopProxy::current().get(),
264 compositor->AsWeakPtr()));
265 if (data->reflector.get()) {
266 data->reflector->CreateSharedTexture();
267 data->reflector->AttachToOutputSurface(surface.get());
270 return surface.PassAs<cc::OutputSurface>();
273 scoped_refptr<ui::Reflector> GpuProcessTransportFactory::CreateReflector(
274 ui::Compositor* source,
275 ui::Layer* target) {
276 PerCompositorData* data = per_compositor_data_[source];
277 DCHECK(data);
279 if (data->reflector.get())
280 RemoveObserver(data->reflector.get());
282 data->reflector = new ReflectorImpl(
283 source, target, &output_surface_map_, data->surface_id);
284 AddObserver(data->reflector.get());
285 return data->reflector;
288 void GpuProcessTransportFactory::RemoveReflector(
289 scoped_refptr<ui::Reflector> reflector) {
290 ReflectorImpl* reflector_impl =
291 static_cast<ReflectorImpl*>(reflector.get());
292 PerCompositorData* data =
293 per_compositor_data_[reflector_impl->mirrored_compositor()];
294 DCHECK(data);
295 RemoveObserver(reflector_impl);
296 data->reflector->Shutdown();
297 data->reflector = NULL;
300 void GpuProcessTransportFactory::RemoveCompositor(ui::Compositor* compositor) {
301 PerCompositorDataMap::iterator it = per_compositor_data_.find(compositor);
302 if (it == per_compositor_data_.end())
303 return;
304 PerCompositorData* data = it->second;
305 DCHECK(data);
306 GpuSurfaceTracker::Get()->RemoveSurface(data->surface_id);
307 delete data;
308 per_compositor_data_.erase(it);
309 if (per_compositor_data_.empty())
310 gl_helper_.reset();
313 bool GpuProcessTransportFactory::DoesCreateTestContexts() { return false; }
315 ui::ContextFactory* GpuProcessTransportFactory::AsContextFactory() {
316 return this;
319 gfx::GLSurfaceHandle GpuProcessTransportFactory::CreateSharedSurfaceHandle() {
320 CreateSharedContextLazy();
321 if (!shared_contexts_main_thread_ ||
322 !shared_contexts_main_thread_->Context3d())
323 return gfx::GLSurfaceHandle();
324 gfx::GLSurfaceHandle handle = gfx::GLSurfaceHandle(
325 gfx::kNullPluginWindow, gfx::TEXTURE_TRANSPORT);
326 handle.parent_gpu_process_id =
327 shared_contexts_main_thread_->Context3d()->GetGPUProcessID();
328 handle.parent_client_id =
329 shared_contexts_main_thread_->Context3d()->GetChannelID();
330 return handle;
333 void GpuProcessTransportFactory::DestroySharedSurfaceHandle(
334 gfx::GLSurfaceHandle surface) {}
336 scoped_refptr<ui::Texture> GpuProcessTransportFactory::CreateTransportClient(
337 float device_scale_factor) {
338 if (!shared_contexts_main_thread_.get())
339 return NULL;
340 scoped_refptr<ImageTransportClientTexture> image(
341 new ImageTransportClientTexture(
342 shared_contexts_main_thread_->Context3d(),
343 device_scale_factor));
344 return image;
347 scoped_refptr<ui::Texture> GpuProcessTransportFactory::CreateOwnedTexture(
348 const gfx::Size& size,
349 float device_scale_factor,
350 unsigned int texture_id) {
351 if (!shared_contexts_main_thread_.get())
352 return NULL;
353 scoped_refptr<OwnedTexture> image(new OwnedTexture(
354 shared_contexts_main_thread_->Context3d(),
355 size,
356 device_scale_factor,
357 texture_id));
358 return image;
361 GLHelper* GpuProcessTransportFactory::GetGLHelper() {
362 if (!gl_helper_) {
363 CreateSharedContextLazy();
364 WebGraphicsContext3DCommandBufferImpl* context_for_main_thread =
365 shared_contexts_main_thread_->Context3d();
366 gl_helper_.reset(new GLHelper(context_for_main_thread));
368 return gl_helper_.get();
371 uint32 GpuProcessTransportFactory::InsertSyncPoint() {
372 if (!shared_contexts_main_thread_.get())
373 return 0;
374 return shared_contexts_main_thread_->Context3d()->insertSyncPoint();
377 void GpuProcessTransportFactory::WaitSyncPoint(uint32 sync_point) {
378 if (!shared_contexts_main_thread_.get())
379 return;
380 shared_contexts_main_thread_->Context3d()->waitSyncPoint(sync_point);
383 void GpuProcessTransportFactory::AddObserver(
384 ImageTransportFactoryObserver* observer) {
385 observer_list_.AddObserver(observer);
388 void GpuProcessTransportFactory::RemoveObserver(
389 ImageTransportFactoryObserver* observer) {
390 observer_list_.RemoveObserver(observer);
393 scoped_refptr<cc::ContextProvider>
394 GpuProcessTransportFactory::OffscreenContextProviderForMainThread() {
395 // Don't check for DestroyedOnMainThread() here. We hear about context
396 // loss for this context through the lost context callback. If the context
397 // is lost, we want to leave this ContextProvider available until the lost
398 // context notification is sent to the ImageTransportFactoryObserver clients.
399 if (!shared_contexts_main_thread_.get()) {
400 shared_contexts_main_thread_ = ContextProviderCommandBuffer::Create(
401 GpuProcessTransportFactory::CreateOffscreenCommandBufferContext(),
402 "Compositor-Offscreen-MainThread");
403 if (shared_contexts_main_thread_) {
404 shared_contexts_main_thread_->SetLostContextCallback(base::Bind(
405 &GpuProcessTransportFactory::
406 OnLostMainThreadSharedContextInsideCallback,
407 callback_factory_.GetWeakPtr()));
409 if (!shared_contexts_main_thread_->BindToCurrentThread())
410 shared_contexts_main_thread_ = NULL;
413 return shared_contexts_main_thread_;
416 scoped_refptr<cc::ContextProvider>
417 GpuProcessTransportFactory::OffscreenContextProviderForCompositorThread() {
418 // The lifetime of this context is tied to the main thread context so that
419 // they are always in the same share group. So do not check for
420 // DestroyedOnMainThread().
421 if (!shared_contexts_compositor_thread_.get()) {
422 shared_contexts_compositor_thread_ = ContextProviderCommandBuffer::Create(
423 GpuProcessTransportFactory::CreateOffscreenCommandBufferContext(),
424 "Compositor-Offscreen");
426 return shared_contexts_compositor_thread_;
429 void GpuProcessTransportFactory::OnLostContext(ui::Compositor* compositor) {
430 LOG(ERROR) << "Lost UI compositor context.";
431 PerCompositorData* data = per_compositor_data_[compositor];
432 DCHECK(data);
434 // Prevent callbacks from other contexts in the same share group from
435 // calling us again.
436 data->swap_client.reset(new CompositorSwapClient(compositor, this));
437 compositor->OnSwapBuffersAborted();
440 GpuProcessTransportFactory::PerCompositorData*
441 GpuProcessTransportFactory::CreatePerCompositorData(
442 ui::Compositor* compositor) {
443 DCHECK(!per_compositor_data_[compositor]);
445 CreateSharedContextLazy();
447 gfx::AcceleratedWidget widget = compositor->widget();
448 GpuSurfaceTracker* tracker = GpuSurfaceTracker::Get();
450 PerCompositorData* data = new PerCompositorData;
451 data->surface_id = tracker->AddSurfaceForNativeWidget(widget);
452 data->swap_client.reset(new CompositorSwapClient(compositor, this));
453 #if defined(OS_WIN)
454 if (GpuDataManagerImpl::GetInstance()->IsUsingAcceleratedSurface())
455 data->accelerated_surface.reset(new AcceleratedSurface(widget));
456 #endif
457 tracker->SetSurfaceHandle(
458 data->surface_id,
459 gfx::GLSurfaceHandle(widget, gfx::NATIVE_DIRECT));
461 per_compositor_data_[compositor] = data;
463 return data;
466 scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
467 GpuProcessTransportFactory::CreateContextCommon(
468 const base::WeakPtr<WebGraphicsContext3DSwapBuffersClient>& swap_client,
469 int surface_id) {
470 if (!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor())
471 return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
472 WebKit::WebGraphicsContext3D::Attributes attrs;
473 attrs.shareResources = true;
474 attrs.depth = false;
475 attrs.stencil = false;
476 attrs.antialias = false;
477 attrs.noAutomaticFlushes = true;
478 GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance();
479 GURL url("chrome://gpu/GpuProcessTransportFactory::CreateContextCommon");
480 scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
481 new WebGraphicsContext3DCommandBufferImpl(
482 surface_id,
483 url,
484 factory,
485 swap_client));
486 if (!context->InitializeWithDefaultBufferSizes(
487 attrs,
488 false,
489 CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE))
490 return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
491 return context.Pass();
494 void GpuProcessTransportFactory::CreateSharedContextLazy() {
495 scoped_refptr<cc::ContextProvider> provider =
496 OffscreenContextProviderForMainThread();
499 void GpuProcessTransportFactory::OnLostMainThreadSharedContextInsideCallback() {
500 base::MessageLoop::current()->PostTask(
501 FROM_HERE,
502 base::Bind(&GpuProcessTransportFactory::OnLostMainThreadSharedContext,
503 callback_factory_.GetWeakPtr()));
506 void GpuProcessTransportFactory::OnLostMainThreadSharedContext() {
507 LOG(ERROR) << "Lost UI shared context.";
509 // Keep old resources around while we call the observers, but ensure that
510 // new resources are created if needed.
511 // Kill shared contexts for both threads in tandem so they are always in
512 // the same share group.
514 scoped_refptr<cc::ContextProvider> lost_shared_contexts_main_thread =
515 shared_contexts_main_thread_;
516 scoped_refptr<cc::ContextProvider> lost_shared_contexts_compositor_thread =
517 shared_contexts_compositor_thread_;
518 shared_contexts_main_thread_ = NULL;
519 shared_contexts_compositor_thread_ = NULL;
521 scoped_ptr<GLHelper> lost_gl_helper = gl_helper_.Pass();
523 FOR_EACH_OBSERVER(ImageTransportFactoryObserver,
524 observer_list_,
525 OnLostResources());
527 // Kill things that use the shared context before killing the shared context.
528 lost_gl_helper.reset();
529 lost_shared_contexts_main_thread = NULL;
530 lost_shared_contexts_compositor_thread = NULL;
533 } // namespace content