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.
4
5#include "content/browser/renderer_host/image_transport_factory_android.h"
6
7#include "base/lazy_instance.h"
8#include "base/strings/stringprintf.h"
9#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
10#include "content/common/gpu/client/gl_helper.h"
11#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
12#include "content/common/gpu/gpu_process_launch_causes.h"
13#include "gpu/command_buffer/client/gles2_implementation.h"
14#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
15#include "third_party/khronos/GLES2/gl2.h"
16#include "ui/gfx/android/device_display_info.h"
17
18namespace content {
19
20base::LazyInstance<ObserverList<ImageTransportFactoryAndroidObserver> >::Leaky
21    g_factory_observers = LAZY_INSTANCE_INITIALIZER;
22
23class GLContextLostListener
24    : public blink::WebGraphicsContext3D::WebGraphicsContextLostCallback {
25 public:
26  // WebGraphicsContextLostCallback implementation.
27  virtual void onContextLost() OVERRIDE;
28 private:
29  static void DidLoseContext();
30};
31
32namespace {
33
34static ImageTransportFactoryAndroid* g_factory = NULL;
35
36class CmdBufferImageTransportFactory : public ImageTransportFactoryAndroid {
37 public:
38  CmdBufferImageTransportFactory();
39  virtual ~CmdBufferImageTransportFactory();
40
41  virtual GLHelper* GetGLHelper() OVERRIDE;
42  virtual uint32 GetChannelID() OVERRIDE {
43    return BrowserGpuChannelHostFactory::instance()->GetGpuChannelId();
44  }
45
46 private:
47  scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context_;
48  scoped_ptr<GLHelper> gl_helper_;
49
50  DISALLOW_COPY_AND_ASSIGN(CmdBufferImageTransportFactory);
51};
52
53CmdBufferImageTransportFactory::CmdBufferImageTransportFactory() {
54  BrowserGpuChannelHostFactory* factory =
55      BrowserGpuChannelHostFactory::instance();
56  scoped_refptr<GpuChannelHost> gpu_channel_host(factory->EstablishGpuChannelSync(
57      CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE));
58  DCHECK(gpu_channel_host);
59
60  blink::WebGraphicsContext3D::Attributes attrs;
61  attrs.shareResources = true;
62  GURL url("chrome://gpu/ImageTransportFactoryAndroid");
63  static const size_t kBytesPerPixel = 4;
64  gfx::DeviceDisplayInfo display_info;
65  size_t full_screen_texture_size_in_bytes = display_info.GetDisplayHeight() *
66                                             display_info.GetDisplayWidth() *
67                                             kBytesPerPixel;
68  WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits limits;
69  limits.command_buffer_size = 64 * 1024;
70  limits.start_transfer_buffer_size = 64 * 1024;
71  limits.min_transfer_buffer_size = 64 * 1024;
72  limits.max_transfer_buffer_size = std::min(
73      3 * full_screen_texture_size_in_bytes, kDefaultMaxTransferBufferSize);
74  limits.mapped_memory_reclaim_limit =
75      WebGraphicsContext3DCommandBufferImpl::kNoLimit;
76  bool lose_context_when_out_of_memory = false;
77  context_.reset(
78      new WebGraphicsContext3DCommandBufferImpl(0,  // offscreen
79                                                url,
80                                                gpu_channel_host.get(),
81                                                attrs,
82                                                lose_context_when_out_of_memory,
83                                                limits,
84                                                NULL));
85  context_->setContextLostCallback(context_lost_listener_.get());
86  if (context_->InitializeOnCurrentThread())
87    context_->pushGroupMarkerEXT(
88        base::StringPrintf("CmdBufferImageTransportFactory-%p",
89                           context_.get()).c_str());
90}
91
92CmdBufferImageTransportFactory::~CmdBufferImageTransportFactory() {
93  context_->setContextLostCallback(NULL);
94}
95
96GLHelper* CmdBufferImageTransportFactory::GetGLHelper() {
97  if (!gl_helper_)
98    gl_helper_.reset(new GLHelper(context_->GetImplementation(),
99                                  context_->GetContextSupport()));
100
101  return gl_helper_.get();
102}
103
104}  // anonymous namespace
105
106// static
107void ImageTransportFactoryAndroid::InitializeForUnitTests(
108    scoped_ptr<ImageTransportFactoryAndroid> test_factory) {
109  DCHECK(!g_factory);
110  g_factory = test_factory.release();
111}
112
113// static
114void ImageTransportFactoryAndroid::TerminateForUnitTests() {
115  DCHECK(g_factory);
116  delete g_factory;
117  g_factory = NULL;
118}
119
120// static
121ImageTransportFactoryAndroid* ImageTransportFactoryAndroid::GetInstance() {
122  if (!g_factory)
123    g_factory = new CmdBufferImageTransportFactory();
124
125  return g_factory;
126}
127
128ImageTransportFactoryAndroid::ImageTransportFactoryAndroid()
129    : context_lost_listener_(new GLContextLostListener()) {}
130
131ImageTransportFactoryAndroid::~ImageTransportFactoryAndroid() {}
132
133void ImageTransportFactoryAndroid::AddObserver(
134    ImageTransportFactoryAndroidObserver* observer) {
135  g_factory_observers.Get().AddObserver(observer);
136}
137
138void ImageTransportFactoryAndroid::RemoveObserver(
139    ImageTransportFactoryAndroidObserver* observer) {
140  g_factory_observers.Get().RemoveObserver(observer);
141}
142
143void GLContextLostListener::onContextLost() {
144  // Need to post a task because the command buffer client cannot be deleted
145  // from within this callback.
146  LOG(ERROR) << "Context lost.";
147  base::MessageLoop::current()->PostTask(
148      FROM_HERE,
149      base::Bind(&GLContextLostListener::DidLoseContext));
150}
151
152void GLContextLostListener::DidLoseContext() {
153  delete g_factory;
154  g_factory = NULL;
155  FOR_EACH_OBSERVER(ImageTransportFactoryAndroidObserver,
156      g_factory_observers.Get(),
157      OnLostResources());
158}
159
160} // namespace content
161