[go: nahoru, domu]

Android: SurfaceTexture-based image transport

This is an interim solution for where the embedder cannot use a command buffer context running on the gpu thread for frontend rendering (i.e. for the browser compositor), for example draw functor/callback based UI drawing.
On Android, sharing GL resources across threads is not a given and SurfaceTexture is therefore the only compatible option.

TBR=jam@chromium.org for .gyp change

BUG=161409

Review URL: https://codereview.chromium.org/11343058

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@168332 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index bed4799..442e752 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -23,8 +23,11 @@
 #include "third_party/khronos/GLES2/gl2ext.h"
 #include "third_party/WebKit/Source/Platform/chromium/public/WebCompositorOutputSurface.h"
 #include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3D.h"
+#include "third_party/WebKit/Source/Platform/chromium/public/WebSolidColorLayer.h"
 #include "ui/gfx/android/java_bitmap.h"
 #include "webkit/compositor_bindings/web_compositor_support_impl.h"
+#include "webkit/glue/webthread_impl.h"
+#include "webkit/gpu/webgraphicscontext3d_in_process_impl.h"
 
 using webkit::WebCompositorSupportImpl;
 
@@ -37,6 +40,8 @@
 static bool g_initialized = false;
 static base::LazyInstance<WebCompositorSupportImpl> g_compositor_support =
     LAZY_INSTANCE_INITIALIZER;
+static WebKit::WebThread* g_impl_thread = NULL;
+static bool g_use_direct_gl = false;
 
 // Adapts a pure WebGraphicsContext3D into a WebCompositorOutputSurface.
 class WebGraphicsContextToOutputSurfaceAdapter :
@@ -91,11 +96,20 @@
 
 // static
 void Compositor::Initialize() {
-  g_compositor_support.Get().initialize(NULL);
+  DCHECK(!CompositorImpl::IsInitialized());
+  g_compositor_support.Get().initialize(g_impl_thread);
   g_initialized = true;
 }
 
 // static
+void Compositor::InitializeWithFlags(uint32 flags) {
+  g_use_direct_gl = flags & DIRECT_CONTEXT_ON_DRAW_THREAD;
+  if (flags & ENABLE_COMPOSITOR_THREAD)
+    g_impl_thread = new webkit_glue::WebThreadImpl("Browser Compositor");
+  Compositor::Initialize();
+}
+
+// static
 WebCompositorSupportImpl* CompositorImpl::CompositorSupport() {
   DCHECK(g_initialized);
   return g_compositor_support.Pointer();
@@ -106,6 +120,11 @@
   return g_initialized;
 }
 
+// static
+bool CompositorImpl::UsesDirectGL() {
+  return g_use_direct_gl;
+}
+
 CompositorImpl::CompositorImpl(Compositor::Client* client)
     : window_(NULL),
       surface_id_(0),
@@ -135,7 +154,7 @@
     ANativeWindow_release(window_);
     window_ = NULL;
     surface_id_ = 0;
-    host_.reset();
+    SetVisible(false);
   }
 
   if (window) {
@@ -145,8 +164,14 @@
     tracker->SetSurfaceHandle(
         surface_id_,
         gfx::GLSurfaceHandle(gfx::kDummyPluginWindow, false));
+    SetVisible(true);
+  }
+}
 
-    DCHECK(!host_.get());
+void CompositorImpl::SetVisible(bool visible) {
+  if (!visible) {
+    host_.reset();
+  } else if (!host_.get()) {
     WebKit::WebLayerTreeView::Settings settings;
     settings.refreshRate = 60.0;
     host_.reset(g_compositor_support.Get().createLayerTreeView(
@@ -243,28 +268,38 @@
 }
 
 WebKit::WebCompositorOutputSurface* CompositorImpl::createOutputSurface() {
-  DCHECK(window_ && surface_id_);
-  WebKit::WebGraphicsContext3D::Attributes attrs;
-  attrs.shareResources = true;
-  attrs.noAutomaticFlushes = true;
-  GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance();
-  GURL url("chrome://gpu/Compositor::createContext3D");
-  base::WeakPtr<WebGraphicsContext3DSwapBuffersClient> swap_client;
-  scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
-      new WebGraphicsContext3DCommandBufferImpl(
-          surface_id_,
-          url,
-          factory,
-          swap_client));
-  if (!context->Initialize(
-      attrs,
-      false,
-      CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE)) {
-    LOG(ERROR) << "Failed to create 3D context for compositor.";
-    return NULL;
+  if (g_use_direct_gl) {
+    WebKit::WebGraphicsContext3D::Attributes attrs;
+    attrs.shareResources = false;
+    attrs.noAutomaticFlushes = true;
+    scoped_ptr<webkit::gpu::WebGraphicsContext3DInProcessImpl> context(
+        webkit::gpu::WebGraphicsContext3DInProcessImpl::CreateForWindow(
+            attrs,
+            window_,
+            NULL));
+    return new WebGraphicsContextToOutputSurfaceAdapter(context.release());
+  } else {
+    DCHECK(window_ && surface_id_);
+    WebKit::WebGraphicsContext3D::Attributes attrs;
+    attrs.shareResources = true;
+    attrs.noAutomaticFlushes = true;
+    GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance();
+    GURL url("chrome://gpu/Compositor::createContext3D");
+    base::WeakPtr<WebGraphicsContext3DSwapBuffersClient> swap_client;
+    scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
+        new WebGraphicsContext3DCommandBufferImpl(surface_id_,
+                                                  url,
+                                                  factory,
+                                                  swap_client));
+    if (!context->Initialize(
+        attrs,
+        false,
+        CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE)) {
+      LOG(ERROR) << "Failed to create 3D context for compositor.";
+      return NULL;
+    }
+    return new WebGraphicsContextToOutputSurfaceAdapter(context.release());
   }
-
-  return new WebGraphicsContextToOutputSurfaceAdapter(context.release());
 }
 
 void CompositorImpl::didRecreateOutputSurface(bool success) {
diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h
index 379145a0..eebc6d1 100644
--- a/content/browser/renderer_host/compositor_impl_android.h
+++ b/content/browser/renderer_host/compositor_impl_android.h
@@ -35,9 +35,13 @@
   static webkit::WebCompositorSupportImpl* CompositorSupport();
   static bool IsInitialized();
 
+  // Returns true if initialized with DIRECT_CONTEXT_ON_DRAW_THREAD.
+  static bool UsesDirectGL();
+
   // Compositor implementation.
   virtual void SetRootLayer(WebKit::WebLayer* root) OVERRIDE;
   virtual void SetWindowSurface(ANativeWindow* window) OVERRIDE;
+  virtual void SetVisible(bool visible) OVERRIDE;
   virtual void SetWindowBounds(const gfx::Size& size) OVERRIDE;
   virtual bool CompositeAndReadback(
       void *pixels, const gfx::Rect& rect) OVERRIDE;
diff --git a/content/browser/renderer_host/image_transport_factory_android.cc b/content/browser/renderer_host/image_transport_factory_android.cc
index deef500..a2b8f10e 100644
--- a/content/browser/renderer_host/image_transport_factory_android.cc
+++ b/content/browser/renderer_host/image_transport_factory_android.cc
@@ -6,40 +6,97 @@
 
 #include "base/memory/singleton.h"
 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
+#include "content/browser/renderer_host/compositor_impl_android.h"
 #include "content/common/gpu/gpu_process_launch_causes.h"
 #include "content/common/gpu/client/gl_helper.h"
 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
 #include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3D.h"
+#include "webkit/gpu/webgraphicscontext3d_in_process_impl.h"
 
 namespace content {
 
-// static
-ImageTransportFactoryAndroid* ImageTransportFactoryAndroid::GetInstance() {
-  return Singleton<ImageTransportFactoryAndroid>::get();
+namespace {
+
+static ImageTransportFactoryAndroid* g_factory = NULL;
+
+class DirectGLImageTransportFactory : public ImageTransportFactoryAndroid {
+ public:
+  DirectGLImageTransportFactory();
+  virtual ~DirectGLImageTransportFactory();
+
+  virtual gfx::GLSurfaceHandle CreateSharedSurfaceHandle() OVERRIDE {
+    return gfx::GLSurfaceHandle();
+  }
+  virtual void DestroySharedSurfaceHandle(
+      const gfx::GLSurfaceHandle& handle) OVERRIDE {}
+  virtual uint32_t InsertSyncPoint() OVERRIDE { return 0; }
+  virtual WebKit::WebGraphicsContext3D* GetContext3D() OVERRIDE {
+    return context_.get();
+  }
+  virtual GLHelper* GetGLHelper() OVERRIDE { return NULL; }
+
+ private:
+  scoped_ptr<webkit::gpu::WebGraphicsContext3DInProcessImpl> context_;
+
+  DISALLOW_COPY_AND_ASSIGN(DirectGLImageTransportFactory);
+};
+
+DirectGLImageTransportFactory::DirectGLImageTransportFactory() {
+  WebKit::WebGraphicsContext3D::Attributes attrs;
+  attrs.shareResources = false;
+  attrs.noAutomaticFlushes = true;
+  context_.reset(
+      webkit::gpu::WebGraphicsContext3DInProcessImpl::CreateForWindow(
+          attrs,
+          NULL,
+          NULL));
 }
 
-ImageTransportFactoryAndroid::ImageTransportFactoryAndroid() {
+DirectGLImageTransportFactory::~DirectGLImageTransportFactory() {
+}
+
+class CmdBufferImageTransportFactory : public ImageTransportFactoryAndroid {
+ public:
+  CmdBufferImageTransportFactory();
+  virtual ~CmdBufferImageTransportFactory();
+
+  virtual gfx::GLSurfaceHandle CreateSharedSurfaceHandle() OVERRIDE;
+  virtual void DestroySharedSurfaceHandle(
+      const gfx::GLSurfaceHandle& handle) OVERRIDE;
+  virtual uint32_t InsertSyncPoint() OVERRIDE;
+  virtual WebKit::WebGraphicsContext3D* GetContext3D() OVERRIDE {
+    return context_.get();
+  }
+  virtual GLHelper* GetGLHelper() OVERRIDE;
+
+ private:
+  scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context_;
+  scoped_ptr<GLHelper> gl_helper_;
+
+  DISALLOW_COPY_AND_ASSIGN(CmdBufferImageTransportFactory);
+};
+
+CmdBufferImageTransportFactory::CmdBufferImageTransportFactory() {
   WebKit::WebGraphicsContext3D::Attributes attrs;
   attrs.shareResources = true;
   GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance();
   GURL url("chrome://gpu/ImageTransportFactoryAndroid");
   base::WeakPtr<WebGraphicsContext3DSwapBuffersClient> swap_client;
-  context_.reset(
-      new WebGraphicsContext3DCommandBufferImpl(
-          0, // offscreen
-          url,
-          factory,
-          swap_client));
+  context_.reset(new WebGraphicsContext3DCommandBufferImpl(0, // offscreen
+                                                           url,
+                                                           factory,
+                                                           swap_client));
   context_->Initialize(
       attrs,
       false,
       CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE);
 }
 
-ImageTransportFactoryAndroid::~ImageTransportFactoryAndroid() {
+CmdBufferImageTransportFactory::~CmdBufferImageTransportFactory() {
 }
 
-gfx::GLSurfaceHandle ImageTransportFactoryAndroid::CreateSharedSurfaceHandle() {
+gfx::GLSurfaceHandle
+CmdBufferImageTransportFactory::CreateSharedSurfaceHandle() {
   if (!context_->makeContextCurrent()) {
     NOTREACHED() << "Failed to make shared graphics context current";
     return gfx::GLSurfaceHandle();
@@ -57,7 +114,7 @@
   return handle;
 }
 
-void ImageTransportFactoryAndroid::DestroySharedSurfaceHandle(
+void CmdBufferImageTransportFactory::DestroySharedSurfaceHandle(
     const gfx::GLSurfaceHandle& handle) {
   if (!context_->makeContextCurrent()) {
     NOTREACHED() << "Failed to make shared graphics context current";
@@ -69,19 +126,35 @@
   context_->finish();
 }
 
-uint32_t ImageTransportFactoryAndroid::InsertSyncPoint() {
+uint32_t CmdBufferImageTransportFactory::InsertSyncPoint() {
   return context_->insertSyncPoint();
 }
 
-WebKit::WebGraphicsContext3D* ImageTransportFactoryAndroid::GetContext3D() {
-  return context_.get();
-}
-
-GLHelper* ImageTransportFactoryAndroid::GetGLHelper() {
+GLHelper* CmdBufferImageTransportFactory::GetGLHelper() {
   if (!gl_helper_.get())
     gl_helper_.reset(new GLHelper(GetContext3D(), NULL));
 
   return gl_helper_.get();
 }
 
-}  // namespace content
+}  // anonymous namespace
+
+// static
+ImageTransportFactoryAndroid* ImageTransportFactoryAndroid::GetInstance() {
+  if (!g_factory) {
+    if (CompositorImpl::UsesDirectGL())
+      g_factory = new DirectGLImageTransportFactory();
+    else
+      g_factory = new CmdBufferImageTransportFactory();
+  }
+
+  return g_factory;
+}
+
+ImageTransportFactoryAndroid::ImageTransportFactoryAndroid() {
+}
+
+ImageTransportFactoryAndroid::~ImageTransportFactoryAndroid() {
+}
+
+} // namespace content
diff --git a/content/browser/renderer_host/image_transport_factory_android.h b/content/browser/renderer_host/image_transport_factory_android.h
index 34d9a584..669d516 100644
--- a/content/browser/renderer_host/image_transport_factory_android.h
+++ b/content/browser/renderer_host/image_transport_factory_android.h
@@ -8,32 +8,34 @@
 #include "base/memory/scoped_ptr.h"
 #include "ui/gfx/native_widget_types.h"
 
+namespace gfx {
+class GLShareGroup;
+}
+
 namespace WebKit {
-  class WebGraphicsContext3D;
+class WebGraphicsContext3D;
 }
 
 namespace content {
 class GLHelper;
-class WebGraphicsContext3DCommandBufferImpl;
 
 class ImageTransportFactoryAndroid {
  public:
-  ImageTransportFactoryAndroid();
-  ~ImageTransportFactoryAndroid();
+  virtual ~ImageTransportFactoryAndroid();
 
   static ImageTransportFactoryAndroid* GetInstance();
 
-  gfx::GLSurfaceHandle CreateSharedSurfaceHandle();
-  void DestroySharedSurfaceHandle(const gfx::GLSurfaceHandle& handle);
+  virtual gfx::GLSurfaceHandle CreateSharedSurfaceHandle() = 0;
+  virtual void DestroySharedSurfaceHandle(
+      const gfx::GLSurfaceHandle& handle) = 0;
 
-  uint32_t InsertSyncPoint();
+  virtual uint32_t InsertSyncPoint() = 0;
 
-  WebKit::WebGraphicsContext3D* GetContext3D();
-  GLHelper* GetGLHelper();
+  virtual WebKit::WebGraphicsContext3D* GetContext3D() = 0;
+  virtual GLHelper* GetGLHelper() = 0;
 
- private:
-  scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context_;
-  scoped_ptr<GLHelper> gl_helper_;
+protected:
+  ImageTransportFactoryAndroid();
 };
 
 }  // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index ae2fb837..8b4b59f 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -15,6 +15,7 @@
 #include "content/browser/renderer_host/compositor_impl_android.h"
 #include "content/browser/renderer_host/image_transport_factory_android.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/browser/renderer_host/surface_texture_transport_client_android.h"
 #include "content/common/android/device_info.h"
 #include "content/common/gpu/client/gl_helper.h"
 #include "content/common/gpu/gpu_messages.h"
@@ -22,6 +23,7 @@
 #include "third_party/khronos/GLES2/gl2.h"
 #include "third_party/khronos/GLES2/gl2ext.h"
 #include "third_party/WebKit/Source/Platform/chromium/public/Platform.h"
+#include "third_party/WebKit/Source/Platform/chromium/public/WebExternalTextureLayer.h"
 #include "third_party/WebKit/Source/Platform/chromium/public/WebSize.h"
 #include "ui/gfx/android/java_bitmap.h"
 #include "webkit/compositor_bindings/web_compositor_support_impl.h"
@@ -55,16 +57,25 @@
       content_view_core_(NULL),
       ime_adapter_android_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
       cached_background_color_(SK_ColorWHITE),
-      texture_layer_(WebKit::WebExternalTextureLayer::create()),
       texture_id_in_layer_(0) {
+  if (CompositorImpl::UsesDirectGL()) {
+    surface_texture_transport_.reset(new SurfaceTextureTransportClient());
+    layer_ = surface_texture_transport_->Initialize();
+  } else {
+    // TODO: Cannot use CompositorImpl::CompositorSupport() in unit tests.
+    texture_layer_.reset(WebKit::WebExternalTextureLayer::create());
+    layer_ = texture_layer_->layer();
+  }
+
   host_->SetView(this);
   SetContentViewCore(content_view_core);
   // RenderWidgetHost is initialized as visible. If is_hidden_ is true, tell
   // RenderWidgetHost to hide.
   if (is_hidden_)
     host_->WasHidden();
-  texture_layer_->layer()->setOpaque(true);
-  texture_layer_->layer()->setDrawsContent(!is_hidden_);
+
+  layer_->setOpaque(true);
+  layer_->setDrawsContent(!is_hidden_);
 }
 
 RenderWidgetHostViewAndroid::~RenderWidgetHostViewAndroid() {
@@ -116,6 +127,9 @@
 }
 
 void RenderWidgetHostViewAndroid::SetSize(const gfx::Size& size) {
+  if (surface_texture_transport_.get())
+    surface_texture_transport_->SetSize(size);
+
   host_->WasResized();
 }
 
@@ -229,13 +243,13 @@
   if (content_view_core_)
     is_hidden_ = false;
 
-  texture_layer_->layer()->setDrawsContent(true);
+  layer_->setDrawsContent(true);
 }
 
 void RenderWidgetHostViewAndroid::Hide() {
   is_hidden_ = true;
 
-  texture_layer_->layer()->setDrawsContent(false);
+  layer_->setDrawsContent(false);
 }
 
 bool RenderWidgetHostViewAndroid::IsShowing() {
@@ -293,7 +307,7 @@
 
 void RenderWidgetHostViewAndroid::Destroy() {
   if (content_view_core_) {
-    content_view_core_->RemoveWebLayer(texture_layer_->layer());
+    content_view_core_->RemoveWebLayer(layer_);
     content_view_core_ = NULL;
   }
 
@@ -378,7 +392,8 @@
     const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params,
     int gpu_host_id) {
   texture_layer_->setTextureId(params.surface_handle);
-  texture_layer_->layer()->setBounds(params.size);
+  DCHECK(texture_layer_->layer() == layer_);
+  layer_->setBounds(params.size);
   texture_id_in_layer_ = params.surface_handle;
   texture_size_in_layer_ = params.size;
 
@@ -416,11 +431,17 @@
 gfx::GLSurfaceHandle RenderWidgetHostViewAndroid::GetCompositingSurface() {
   if (CompositorImpl::IsInitialized()) {
     // The app uses the browser-side compositor.
-    if (shared_surface_.is_null())
-      shared_surface_ =
-          ImageTransportFactoryAndroid::GetInstance()->
-              CreateSharedSurfaceHandle();
-    return shared_surface_;
+    if (surface_texture_transport_.get()) {
+      return surface_texture_transport_->GetCompositingSurface(
+          host_->surface_id());
+    } else {
+      if (shared_surface_.is_null()) {
+        shared_surface_ =
+            ImageTransportFactoryAndroid::GetInstance()->
+            CreateSharedSurfaceHandle();
+      }
+      return shared_surface_;
+    }
   }
 
   // On Android, we cannot generate a window handle that can be passed to the
@@ -542,11 +563,11 @@
 void RenderWidgetHostViewAndroid::SetContentViewCore(
     ContentViewCoreImpl* content_view_core) {
   if (content_view_core_)
-    content_view_core_->RemoveWebLayer(texture_layer_->layer());
+    content_view_core_->RemoveWebLayer(layer_);
 
   content_view_core_ = content_view_core;
   if (content_view_core_)
-    content_view_core_->AttachWebLayer(texture_layer_->layer());
+    content_view_core_->AttachWebLayer(layer_);
 }
 
 void RenderWidgetHostViewAndroid::HasTouchEventHandlers(
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h
index 0f075cdc..44ed4078 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.h
+++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -12,7 +12,6 @@
 #include "content/browser/renderer_host/ime_adapter_android.h"
 #include "content/browser/renderer_host/render_widget_host_view_base.h"
 #include "third_party/skia/include/core/SkColor.h"
-#include "third_party/WebKit/Source/Platform/chromium/public/WebExternalTextureLayer.h"
 #include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3D.h"
 #include "ui/gfx/size.h"
 
@@ -22,6 +21,8 @@
 struct GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params;
 
 namespace WebKit {
+class WebExternalTextureLayer;
+class WebLayer;
 class WebTouchEvent;
 class WebMouseEvent;
 }
@@ -30,6 +31,7 @@
 class ContentViewCoreImpl;
 class RenderWidgetHost;
 class RenderWidgetHostImpl;
+class SurfaceTextureTransportClient;
 struct NativeWebKeyboardEvent;
 
 // -----------------------------------------------------------------------------
@@ -162,6 +164,11 @@
   // The texture layer for this view when using browser-side compositing.
   scoped_ptr<WebKit::WebExternalTextureLayer> texture_layer_;
 
+  // The layer used for rendering the contents of this view.
+  // It is either owned by texture_layer_ or surface_texture_transport_
+  // depending on the mode.
+  WebKit::WebLayer* layer_;
+
   // The most recent texture id that was pushed to the texture layer.
   unsigned int texture_id_in_layer_;
 
@@ -172,6 +179,9 @@
   // compositor) for this view.
   gfx::GLSurfaceHandle shared_surface_;
 
+  // Used for image transport when needing to share resources across threads.
+  scoped_ptr<SurfaceTextureTransportClient> surface_texture_transport_;
+
   DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAndroid);
 };
 
diff --git a/content/browser/renderer_host/surface_texture_transport_client_android.cc b/content/browser/renderer_host/surface_texture_transport_client_android.cc
new file mode 100644
index 0000000..685ee4e
--- /dev/null
+++ b/content/browser/renderer_host/surface_texture_transport_client_android.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/renderer_host/surface_texture_transport_client_android.h"
+
+#include <android/native_window_jni.h>
+
+#include "base/bind.h"
+#include "content/browser/gpu/gpu_surface_tracker.h"
+#include "content/browser/renderer_host/compositor_impl_android.h"
+#include "content/browser/renderer_host/image_transport_factory_android.h"
+#include "content/common/android/surface_texture_bridge.h"
+#include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3D.h"
+#include "third_party/WebKit/Source/Platform/chromium/public/WebVideoLayer.h"
+#include "webkit/compositor_bindings/web_compositor_support_impl.h"
+#include "webkit/media/webvideoframe_impl.h"
+
+namespace {
+
+static const uint32 kGLTextureExternalOES = 0x8D65;
+
+} // anonymous namespace
+
+namespace content {
+
+SurfaceTextureTransportClient::SurfaceTextureTransportClient()
+    : window_(NULL),
+      texture_id_(0) {
+}
+
+SurfaceTextureTransportClient::~SurfaceTextureTransportClient() {
+  if (window_)
+    ANativeWindow_release(window_);
+}
+
+WebKit::WebLayer* SurfaceTextureTransportClient::Initialize() {
+  // Use a SurfaceTexture to stream frames to the UI thread.
+  video_layer_.reset(
+      CompositorImpl::CompositorSupport()->createVideoLayer(this));
+  surface_texture_ = new SurfaceTextureBridge(0);
+  surface_texture_->SetFrameAvailableCallback(
+      base::Bind(
+          &SurfaceTextureTransportClient::OnSurfaceTextureFrameAvailable,
+          base::Unretained(this)));
+  surface_texture_->DetachFromGLContext();
+  return video_layer_->layer();
+}
+
+gfx::GLSurfaceHandle
+SurfaceTextureTransportClient::GetCompositingSurface(int surface_id) {
+  DCHECK(surface_id);
+  if (!window_)
+    window_ = surface_texture_->CreateSurface();
+
+  GpuSurfaceTracker::Get()->SetNativeWidget(surface_id, window_);
+  return gfx::GLSurfaceHandle(gfx::kDummyPluginWindow, false);
+}
+
+void SurfaceTextureTransportClient::SetSize(const gfx::Size& size) {
+  surface_texture_->SetDefaultBufferSize(size.width(), size.height());
+  video_layer_->layer()->setBounds(size);
+  video_frame_.reset();
+}
+
+WebKit::WebVideoFrame* SurfaceTextureTransportClient::getCurrentFrame() {
+  if (!texture_id_) {
+    WebKit::WebGraphicsContext3D* context =
+        ImageTransportFactoryAndroid::GetInstance()->GetContext3D();
+    context->makeContextCurrent();
+    texture_id_ = context->createTexture();
+  }
+  if (!video_frame_.get()) {
+    surface_texture_->AttachToGLContext(texture_id_);
+    const gfx::Size size = video_layer_->layer()->bounds();
+    video_frame_.reset(
+        new webkit_media::WebVideoFrameImpl(
+            media::VideoFrame::WrapNativeTexture(
+                texture_id_, kGLTextureExternalOES,
+                size,
+                gfx::Rect(gfx::Point(), size),
+                size,
+                base::TimeDelta(),
+                media::VideoFrame::ReadPixelsCB(),
+                base::Closure())));
+  }
+  surface_texture_->UpdateTexImage();
+
+  return video_frame_.get();
+}
+
+void SurfaceTextureTransportClient::putCurrentFrame(
+    WebKit::WebVideoFrame* frame) {
+}
+
+void SurfaceTextureTransportClient::OnSurfaceTextureFrameAvailable() {
+  video_layer_->layer()->invalidate();
+}
+
+} // namespace content
diff --git a/content/browser/renderer_host/surface_texture_transport_client_android.h b/content/browser/renderer_host/surface_texture_transport_client_android.h
new file mode 100644
index 0000000..26e87c5
--- /dev/null
+++ b/content/browser/renderer_host/surface_texture_transport_client_android.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_RENDERER_HOST_SURFACE_TEXTURE_TRANSPORT_CLIENT_ANDROID_H_
+#define CONTENT_BROWSER_RENDERER_HOST_SURFACE_TEXTURE_TRANSPORT_CLIENT_ANDROID_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "third_party/WebKit/Source/Platform/chromium/public/WebVideoFrameProvider.h"
+#include "ui/gfx/native_widget_types.h"
+
+struct ANativeWindow;
+
+namespace WebKit {
+class WebLayer;
+class WebVideoLayer;
+}
+
+namespace content {
+class SurfaceTextureBridge;
+
+class SurfaceTextureTransportClient : public WebKit::WebVideoFrameProvider {
+ public:
+  SurfaceTextureTransportClient();
+  virtual ~SurfaceTextureTransportClient();
+
+  WebKit::WebLayer* Initialize();
+  gfx::GLSurfaceHandle GetCompositingSurface(int surface_id);
+  void SetSize(const gfx::Size& size);
+
+  // WebKit::WebVideoFrameProvider implementation.
+  virtual void setVideoFrameProviderClient(Client*) OVERRIDE {}
+  virtual WebKit::WebVideoFrame* getCurrentFrame() OVERRIDE;
+  virtual void putCurrentFrame(WebKit::WebVideoFrame* frame) OVERRIDE;
+
+ private:
+  void OnSurfaceTextureFrameAvailable();
+
+  scoped_ptr<WebKit::WebVideoLayer> video_layer_;
+  scoped_refptr<SurfaceTextureBridge> surface_texture_;
+  ANativeWindow* window_;
+  scoped_ptr<WebKit::WebVideoFrame> video_frame_;
+  uint32 texture_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(SurfaceTextureTransportClient);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_RENDERER_HOST_SURFACE_TEXTURE_TRANSPORT_CLIENT_ANDROID_H_
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index f4d91512..02cad6f 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -723,6 +723,8 @@
     'browser/renderer_host/socket_stream_dispatcher_host.h',
     'browser/renderer_host/socket_stream_host.cc',
     'browser/renderer_host/socket_stream_host.h',
+    'browser/renderer_host/surface_texture_transport_client_android.cc',
+    'browser/renderer_host/surface_texture_transport_client_android.h',
     'browser/renderer_host/sync_resource_handler.cc',
     'browser/renderer_host/sync_resource_handler.h',
     'browser/renderer_host/tap_suppression_controller_aura.cc',
diff --git a/content/public/browser/android/compositor.h b/content/public/browser/android/compositor.h
index 11c1dbd..998c22d 100644
--- a/content/public/browser/android/compositor.h
+++ b/content/public/browser/android/compositor.h
@@ -38,9 +38,22 @@
   virtual ~Compositor() {}
 
   // Performs the global initialization needed before any compositor
-  // instance can be used.
+  // instance can be used. This should be called only once.
   static void Initialize();
 
+  enum CompositorFlags {
+    // Creates a direct GL context on the thread that draws
+    // (i.e. main or impl thread).
+    DIRECT_CONTEXT_ON_DRAW_THREAD = 1,
+
+    // Runs the compositor in threaded mode.
+    ENABLE_COMPOSITOR_THREAD = 1 << 1,
+  };
+
+  // Initialize with flags. This should only be called once instead
+  // of Initialize().
+  static void InitializeWithFlags(uint32 flags);
+
   // Creates and returns a compositor instance.
   static Compositor* Create(Client* client);
 
@@ -50,6 +63,11 @@
   // Set the output surface bounds.
   virtual void SetWindowBounds(const gfx::Size& size) = 0;
 
+  // Sets the window visibility. When becoming invisible, resources will get
+  // freed and other calls into the compositor are not allowed until after
+  // having been made visible again.
+  virtual void SetVisible(bool visible) = 0;
+
   // Set the output surface handle which the compositor renders into.
   virtual void SetWindowSurface(ANativeWindow* window) = 0;
 
diff --git a/ui/gl/gl_context_android.cc b/ui/gl/gl_context_android.cc
index 66ab2c6..270c312 100644
--- a/ui/gl/gl_context_android.cc
+++ b/ui/gl/gl_context_android.cc
@@ -10,6 +10,7 @@
 #include "ui/gl/gl_context_egl.h"
 #include "ui/gl/gl_context_stub.h"
 #include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_surface.h"
 
 namespace gfx {
 
@@ -21,7 +22,11 @@
   if (GetGLImplementation() == kGLImplementationMockGL)
     return scoped_refptr<GLContext>(new GLContextStub());
 
-  scoped_refptr<GLContextEGL> context(new GLContextEGL(share_group));
+  scoped_refptr<GLContext> context;
+  if (compatible_surface->GetHandle())
+    context = new GLContextEGL(share_group);
+  else
+    context = new GLContextStub();
   if (!context->Initialize(compatible_surface, gpu_preference))
     return NULL;
   return context;
diff --git a/ui/gl/gl_surface_android.cc b/ui/gl/gl_surface_android.cc
index 76002b7..e201ffd 100644
--- a/ui/gl/gl_surface_android.cc
+++ b/ui/gl/gl_surface_android.cc
@@ -13,6 +13,7 @@
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_context.h"
 #include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_surface_stub.h"
 
 using ui::GetLastEGLErrorString;
 
@@ -46,8 +47,11 @@
 
   switch (GetGLImplementation()) {
     case kGLImplementationEGLGLES2: {
-      scoped_refptr<GLSurface> surface = window ?
-          new NativeViewGLSurfaceEGL(false, window) : new AndroidViewSurface();
+      scoped_refptr<GLSurface> surface;
+      if (window)
+        surface = new NativeViewGLSurfaceEGL(false, window);
+      else
+        surface = new GLSurfaceStub();
       if (!surface->Initialize())
         return NULL;
       return surface;