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/memory/singleton.h"
9#include "base/strings/stringprintf.h"
10#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
11#include "content/browser/renderer_host/compositor_impl_android.h"
12#include "content/common/gpu/client/gl_helper.h"
13#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
14#include "content/common/gpu/gpu_process_launch_causes.h"
15#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
16#include "third_party/khronos/GLES2/gl2.h"
17#include "ui/gfx/android/device_display_info.h"
18#include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
19
20namespace content {
21
22base::LazyInstance<ObserverList<ImageTransportFactoryAndroidObserver> >::Leaky
23    g_factory_observers = LAZY_INSTANCE_INITIALIZER;
24
25class GLContextLostListener
26    : public WebKit::WebGraphicsContext3D::WebGraphicsContextLostCallback {
27 public:
28  // WebGraphicsContextLostCallback implementation.
29  virtual void onContextLost() OVERRIDE;
30 private:
31  static void DidLoseContext();
32};
33
34namespace {
35
36using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
37
38static ImageTransportFactoryAndroid* g_factory = NULL;
39
40class DirectGLImageTransportFactory : public ImageTransportFactoryAndroid {
41 public:
42  DirectGLImageTransportFactory();
43  virtual ~DirectGLImageTransportFactory();
44
45  virtual uint32_t InsertSyncPoint() OVERRIDE { return 0; }
46  virtual void WaitSyncPoint(uint32_t sync_point) OVERRIDE {}
47  virtual uint32_t CreateTexture() OVERRIDE {
48    return context_->createTexture();
49  }
50  virtual void DeleteTexture(uint32_t id) OVERRIDE {
51    context_->deleteTexture(id);
52  }
53  virtual void AcquireTexture(
54      uint32 texture_id, const signed char* mailbox_name) OVERRIDE {}
55  virtual WebKit::WebGraphicsContext3D* GetContext3D() OVERRIDE {
56    return context_.get();
57  }
58  virtual GLHelper* GetGLHelper() OVERRIDE { return NULL; }
59
60 private:
61  scoped_ptr<WebKit::WebGraphicsContext3D> context_;
62
63  DISALLOW_COPY_AND_ASSIGN(DirectGLImageTransportFactory);
64};
65
66DirectGLImageTransportFactory::DirectGLImageTransportFactory() {
67  WebKit::WebGraphicsContext3D::Attributes attrs;
68  attrs.shareResources = true;
69  attrs.noAutomaticFlushes = true;
70  context_ = webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl::
71      CreateViewContext(attrs, NULL);
72  context_->setContextLostCallback(context_lost_listener_.get());
73  if (context_->makeContextCurrent())
74    context_->pushGroupMarkerEXT(
75        base::StringPrintf("DirectGLImageTransportFactory-%p",
76                           context_.get()).c_str());
77}
78
79DirectGLImageTransportFactory::~DirectGLImageTransportFactory() {
80  context_->setContextLostCallback(NULL);
81}
82
83class CmdBufferImageTransportFactory : public ImageTransportFactoryAndroid {
84 public:
85  CmdBufferImageTransportFactory();
86  virtual ~CmdBufferImageTransportFactory();
87
88  virtual uint32_t InsertSyncPoint() OVERRIDE;
89  virtual void WaitSyncPoint(uint32_t sync_point) OVERRIDE;
90  virtual uint32_t CreateTexture() OVERRIDE;
91  virtual void DeleteTexture(uint32_t id) OVERRIDE;
92  virtual void AcquireTexture(
93      uint32 texture_id, const signed char* mailbox_name) OVERRIDE;
94  virtual WebKit::WebGraphicsContext3D* GetContext3D() OVERRIDE {
95    return context_.get();
96  }
97  virtual GLHelper* GetGLHelper() OVERRIDE;
98
99 private:
100  scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context_;
101  scoped_ptr<GLHelper> gl_helper_;
102
103  DISALLOW_COPY_AND_ASSIGN(CmdBufferImageTransportFactory);
104};
105
106CmdBufferImageTransportFactory::CmdBufferImageTransportFactory() {
107  WebKit::WebGraphicsContext3D::Attributes attrs;
108  attrs.shareResources = true;
109  GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance();
110  GURL url("chrome://gpu/ImageTransportFactoryAndroid");
111  base::WeakPtr<WebGraphicsContext3DSwapBuffersClient> swap_client;
112  context_.reset(new WebGraphicsContext3DCommandBufferImpl(0, // offscreen
113                                                           url,
114                                                           factory,
115                                                           swap_client));
116  static const size_t kBytesPerPixel = 4;
117  gfx::DeviceDisplayInfo display_info;
118  size_t full_screen_texture_size_in_bytes =
119      display_info.GetDisplayHeight() *
120      display_info.GetDisplayWidth() *
121      kBytesPerPixel;
122  context_->setContextLostCallback(context_lost_listener_.get());
123  context_->Initialize(
124      attrs,
125      false,
126      CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE,
127      64 * 1024,  // command buffer size
128      64 * 1024,  // starting buffer size
129      64 * 1024,  // min buffer size
130      std::min(3 * full_screen_texture_size_in_bytes,
131               kDefaultMaxTransferBufferSize));
132
133  if (context_->makeContextCurrent())
134    context_->pushGroupMarkerEXT(
135        base::StringPrintf("CmdBufferImageTransportFactory-%p",
136                           context_.get()).c_str());
137}
138
139CmdBufferImageTransportFactory::~CmdBufferImageTransportFactory() {
140  context_->setContextLostCallback(NULL);
141}
142
143uint32_t CmdBufferImageTransportFactory::InsertSyncPoint() {
144  if (!context_->makeContextCurrent()) {
145    LOG(ERROR) << "Failed to make helper context current.";
146    return 0;
147  }
148  return context_->insertSyncPoint();
149}
150
151void CmdBufferImageTransportFactory::WaitSyncPoint(uint32_t sync_point) {
152  if (!context_->makeContextCurrent()) {
153    LOG(ERROR) << "Failed to make helper context current.";
154    return;
155  }
156  context_->waitSyncPoint(sync_point);
157}
158
159uint32_t CmdBufferImageTransportFactory::CreateTexture() {
160  if (!context_->makeContextCurrent()) {
161    LOG(ERROR) << "Failed to make helper context current.";
162    return false;
163  }
164  return context_->createTexture();
165}
166
167void CmdBufferImageTransportFactory::DeleteTexture(uint32_t id) {
168  if (!context_->makeContextCurrent()) {
169    LOG(ERROR) << "Failed to make helper context current.";
170    return;
171  }
172  context_->deleteTexture(id);
173}
174
175void CmdBufferImageTransportFactory::AcquireTexture(
176    uint32 texture_id, const signed char* mailbox_name) {
177  if (!context_->makeContextCurrent()) {
178    LOG(ERROR) << "Failed to make helper context current.";
179    return;
180  }
181  context_->bindTexture(GL_TEXTURE_2D, texture_id);
182  context_->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox_name);
183  context_->flush();
184}
185
186GLHelper* CmdBufferImageTransportFactory::GetGLHelper() {
187  if (!gl_helper_)
188    gl_helper_.reset(new GLHelper(context_.get()));
189
190  return gl_helper_.get();
191}
192
193}  // anonymous namespace
194
195// static
196ImageTransportFactoryAndroid* ImageTransportFactoryAndroid::GetInstance() {
197  if (!g_factory) {
198    if (CompositorImpl::UsesDirectGL())
199      g_factory = new DirectGLImageTransportFactory();
200    else
201      g_factory = new CmdBufferImageTransportFactory();
202  }
203
204  return g_factory;
205}
206
207ImageTransportFactoryAndroid::ImageTransportFactoryAndroid()
208    : context_lost_listener_(new GLContextLostListener()) {}
209
210ImageTransportFactoryAndroid::~ImageTransportFactoryAndroid() {}
211
212void ImageTransportFactoryAndroid::AddObserver(
213    ImageTransportFactoryAndroidObserver* observer) {
214  g_factory_observers.Get().AddObserver(observer);
215}
216
217void ImageTransportFactoryAndroid::RemoveObserver(
218    ImageTransportFactoryAndroidObserver* observer) {
219  g_factory_observers.Get().RemoveObserver(observer);
220}
221
222void GLContextLostListener::onContextLost() {
223  // Need to post a task because the command buffer client cannot be deleted
224  // from within this callback.
225  LOG(ERROR) << "Context lost.";
226  base::MessageLoop::current()->PostTask(
227      FROM_HERE,
228      base::Bind(&GLContextLostListener::DidLoseContext));
229}
230
231void GLContextLostListener::DidLoseContext() {
232  delete g_factory;
233  g_factory = NULL;
234  FOR_EACH_OBSERVER(ImageTransportFactoryAndroidObserver,
235      g_factory_observers.Get(),
236      OnLostResources());
237}
238
239} // namespace content
240