[go: nahoru, domu]

Android StreamTexture SharedImage path

This path refactors Android's StreamTexture* based video path to use
SharedImages. This consists of two main parts:

1. Remove all GL code from StreamTextureFactory/StreamTextureWrapper,
   allowing the client code to be independent of graphics API. As part
   of this the logic around StreamTextures was moved to GpuChannelHost,
   and no longer requires a GLES2 command buffer.
2. Allocate a new SharedImage each time the video size changes,
   allowing the SharedImages to have an immutable size. Also refactors
   the SharedImage creation code to have better synchronization logic.

Bug: 938149
Change-Id: Ib9ccc102f348b0c8ea9303875f67caaf0702e421
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1616526
Commit-Queue: Eric Karl <ericrk@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: vikas soni <vikassoni@chromium.org>
Reviewed-by: Frank Liberato <liberato@chromium.org>
Reviewed-by: Antoine Labour <piman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#672738}
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
index 38e45c1..d0f0cef 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -455,6 +455,10 @@
     return sync_token;
   }
 
+  void Flush() override {
+    // No need to flush in this implementation.
+  }
+
   // DirectContextProviderDelegate implementation.
   gpu::SharedImageManager* GetSharedImageManager() override {
     return shared_image_manager_;
diff --git a/components/viz/test/test_context_provider.cc b/components/viz/test/test_context_provider.cc
index ec2393c..7dd29e0 100644
--- a/components/viz/test/test_context_provider.cc
+++ b/components/viz/test/test_context_provider.cc
@@ -203,6 +203,10 @@
   return most_recent_generated_token_;
 }
 
+void TestSharedImageInterface::Flush() {
+  // No need to flush in this implementation.
+}
+
 bool TestSharedImageInterface::CheckSharedImageExists(
     const gpu::Mailbox& mailbox) const {
   return shared_images_.contains(mailbox);
diff --git a/components/viz/test/test_context_provider.h b/components/viz/test/test_context_provider.h
index d2fb0392..cc2d5e26 100644
--- a/components/viz/test/test_context_provider.h
+++ b/components/viz/test/test_context_provider.h
@@ -78,6 +78,8 @@
   gpu::SyncToken GenVerifiedSyncToken() override;
   gpu::SyncToken GenUnverifiedSyncToken() override;
 
+  void Flush() override;
+
   size_t shared_image_count() const { return shared_images_.size(); }
   const gfx::Size& MostRecentSize() const { return most_recent_size_; }
   const gpu::SyncToken& MostRecentGeneratedToken() const {
diff --git a/content/renderer/media/android/stream_texture_factory.cc b/content/renderer/media/android/stream_texture_factory.cc
index a2ee9ff..6fcea5f 100644
--- a/content/renderer/media/android/stream_texture_factory.cc
+++ b/content/renderer/media/android/stream_texture_factory.cc
@@ -6,11 +6,8 @@
 
 #include "base/bind.h"
 #include "base/macros.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
-#include "gpu/ipc/client/command_buffer_proxy_impl.h"
 #include "gpu/ipc/client/gpu_channel_host.h"
 #include "gpu/ipc/common/gpu_messages.h"
-#include "services/viz/public/cpp/gpu/context_provider_command_buffer.h"
 #include "ui/gfx/geometry/size.h"
 
 namespace content {
@@ -71,63 +68,60 @@
     received_frame_cb_.Run();
 }
 
-void StreamTextureProxy::SetStreamTextureSize(const gfx::Size& size) {
-  host_->SetStreamTextureSize(size);
-}
-
 void StreamTextureProxy::ForwardStreamTextureForSurfaceRequest(
     const base::UnguessableToken& request_token) {
   host_->ForwardStreamTextureForSurfaceRequest(request_token);
 }
 
+void StreamTextureProxy::CreateSharedImage(
+    const gfx::Size& size,
+    gpu::Mailbox* mailbox,
+    gpu::SyncToken* unverified_sync_token) {
+  *mailbox = host_->CreateSharedImage(size);
+  if (!mailbox)
+    return;
+  *unverified_sync_token = host_->GenUnverifiedSyncToken();
+}
+
 // static
 scoped_refptr<StreamTextureFactory> StreamTextureFactory::Create(
-    scoped_refptr<viz::ContextProviderCommandBuffer> context_provider) {
-  return new StreamTextureFactory(std::move(context_provider));
+    scoped_refptr<gpu::GpuChannelHost> channel) {
+  return new StreamTextureFactory(std::move(channel));
 }
 
 StreamTextureFactory::StreamTextureFactory(
-    scoped_refptr<viz::ContextProviderCommandBuffer> context_provider)
-    : context_provider_(std::move(context_provider)),
-      channel_(context_provider_->GetCommandBufferProxy()->channel()) {
+    scoped_refptr<gpu::GpuChannelHost> channel)
+    : channel_(std::move(channel)) {
   DCHECK(channel_);
 }
 
-StreamTextureFactory::~StreamTextureFactory() {}
+StreamTextureFactory::~StreamTextureFactory() = default;
 
-ScopedStreamTextureProxy StreamTextureFactory::CreateProxy(
-    unsigned* texture_id,
-    gpu::Mailbox* texture_mailbox) {
-  int32_t route_id = CreateStreamTexture(texture_id, texture_mailbox);
+ScopedStreamTextureProxy StreamTextureFactory::CreateProxy() {
+  int32_t route_id = CreateStreamTexture();
   if (!route_id)
     return ScopedStreamTextureProxy();
   return ScopedStreamTextureProxy(new StreamTextureProxy(
       std::make_unique<StreamTextureHost>(channel_, route_id)));
 }
 
-unsigned StreamTextureFactory::CreateStreamTexture(
-    unsigned* texture_id,
-    gpu::Mailbox* texture_mailbox) {
-  GLuint route_id = 0;
-  gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
-  gl->GenTextures(1, texture_id);
-  gl->ShallowFlushCHROMIUM();
-  route_id = context_provider_->GetCommandBufferProxy()->CreateStreamTexture(
-      *texture_id);
-  if (!route_id) {
-    gl->DeleteTextures(1, texture_id);
-    // Flush to ensure that the stream texture gets deleted in a timely fashion.
-    gl->ShallowFlushCHROMIUM();
-    *texture_id = 0;
-    *texture_mailbox = gpu::Mailbox();
-  } else {
-    gl->ProduceTextureDirectCHROMIUM(*texture_id, texture_mailbox->name);
-  }
-  return route_id;
+bool StreamTextureFactory::IsLost() const {
+  return channel_->IsLost();
 }
 
-gpu::gles2::GLES2Interface* StreamTextureFactory::ContextGL() {
-  return context_provider_->ContextGL();
+unsigned StreamTextureFactory::CreateStreamTexture() {
+  int32_t stream_id = channel_->GenerateRouteID();
+  bool succeeded = false;
+  channel_->Send(new GpuChannelMsg_CreateStreamTexture(stream_id, &succeeded));
+  if (!succeeded) {
+    DLOG(ERROR) << "GpuChannelMsg_CreateStreamTexture returned failure";
+    return 0;
+  }
+  return stream_id;
+}
+
+gpu::SharedImageInterface* StreamTextureFactory::SharedImageInterface() {
+  return channel_->shared_image_interface();
 }
 
 }  // namespace content
diff --git a/content/renderer/media/android/stream_texture_factory.h b/content/renderer/media/android/stream_texture_factory.h
index 38ce94d..e65bf4e11 100644
--- a/content/renderer/media/android/stream_texture_factory.h
+++ b/content/renderer/media/android/stream_texture_factory.h
@@ -20,16 +20,11 @@
 #include "ui/gfx/geometry/size.h"
 
 namespace gpu {
-namespace gles2 {
-class GLES2Interface;
-}  // namespace gles2
 class GpuChannelHost;
+class SharedImageInterface;
+struct SyncToken;
 }  // namespace gpu
 
-namespace viz {
-class ContextProviderCommandBuffer;
-}
-
 namespace content {
 
 class StreamTextureFactory;
@@ -50,15 +45,21 @@
   // StreamTextureHost::Listener implementation:
   void OnFrameAvailable() override;
 
-  // Set the streamTexture size.
-  void SetStreamTextureSize(const gfx::Size& size);
-
   // Sends an IPC to the GPU process.
   // Asks the StreamTexture to forward its SurfaceTexture to the
   // ScopedSurfaceRequestManager, using the gpu::ScopedSurfaceRequestConduit.
   void ForwardStreamTextureForSurfaceRequest(
       const base::UnguessableToken& request_token);
 
+  // Creates a SharedImage for the provided texture size. Returns the
+  // |mailbox| for the SharedImage, as well as an |unverified_sync_token|
+  // representing SharedImage creation.
+  // If creation fails, returns an empty |mailbox| and does not modify
+  // |unverified_sync_token|.
+  void CreateSharedImage(const gfx::Size& size,
+                         gpu::Mailbox* mailbox,
+                         gpu::SyncToken* unverified_sync_token);
+
   // Clears |received_frame_cb_| in a thread safe way.
   void ClearReceivedFrameCB();
 
@@ -90,33 +91,26 @@
     : public base::RefCounted<StreamTextureFactory> {
  public:
   static scoped_refptr<StreamTextureFactory> Create(
-      scoped_refptr<viz::ContextProviderCommandBuffer> context_provider);
+      scoped_refptr<gpu::GpuChannelHost> channel);
 
-  // Create the StreamTextureProxy object. This internally calls
-  // CreateSteamTexture with the recieved arguments. CreateSteamTexture
-  // generates a texture and stores it in  *texture_id, the texture is produced
-  // into a mailbox so it can be shipped in a VideoFrame, it creates a
-  // gpu::StreamTexture and returns its route_id. If this route_id is  invalid
-  // nullptr is returned and *texture_id will be set to 0. If the route_id is
-  // valid it returns StreamTextureProxy object. The caller needs to take care
-  // of cleaning up the texture_id.
-  ScopedStreamTextureProxy CreateProxy(unsigned* texture_id,
-                                       gpu::Mailbox* texture_mailbox);
+  // Create the StreamTextureProxy object. This internally creates a
+  // gpu::StreamTexture and returns its route_id. If this route_id is invalid
+  // nullptr is returned. If the route_id is valid it returns
+  // StreamTextureProxy object.
+  ScopedStreamTextureProxy CreateProxy();
 
-  gpu::gles2::GLES2Interface* ContextGL();
+  // Returns true if the StreamTextureFactory's channel is lost.
+  bool IsLost() const;
+
+  gpu::SharedImageInterface* SharedImageInterface();
 
  private:
   friend class base::RefCounted<StreamTextureFactory>;
-  StreamTextureFactory(
-      scoped_refptr<viz::ContextProviderCommandBuffer> context_provider);
+  StreamTextureFactory(scoped_refptr<gpu::GpuChannelHost> channel);
   ~StreamTextureFactory();
-  // Creates a gpu::StreamTexture and returns its id.  Sets |*texture_id| to the
-  // client-side id of the gpu::StreamTexture. The texture is produced into
-  // a mailbox so it can be shipped in a VideoFrame.
-  unsigned CreateStreamTexture(unsigned* texture_id,
-                               gpu::Mailbox* texture_mailbox);
+  // Creates a gpu::StreamTexture and returns its id.
+  unsigned CreateStreamTexture();
 
-  scoped_refptr<viz::ContextProviderCommandBuffer> context_provider_;
   scoped_refptr<gpu::GpuChannelHost> channel_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(StreamTextureFactory);
diff --git a/content/renderer/media/android/stream_texture_wrapper_impl.cc b/content/renderer/media/android/stream_texture_wrapper_impl.cc
index 8a0eceb9..256ea79 100644
--- a/content/renderer/media/android/stream_texture_wrapper_impl.cc
+++ b/content/renderer/media/android/stream_texture_wrapper_impl.cc
@@ -8,21 +8,17 @@
 #include "base/callback.h"
 #include "cc/layers/video_frame_provider.h"
 #include "gpu/GLES2/gl2extchromium.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
+#include "gpu/command_buffer/client/shared_image_interface.h"
 #include "media/base/bind_to_current_loop.h"
 
-using gpu::gles2::GLES2Interface;
-
 namespace {
 // Non-member function to allow it to run even after this class is deleted.
-void OnReleaseTexture(scoped_refptr<content::StreamTextureFactory> factories,
-                      uint32_t texture_id,
-                      const gpu::SyncToken& sync_token) {
-  GLES2Interface* gl = factories->ContextGL();
-  gl->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
-  gl->DeleteTextures(1, &texture_id);
-  // Flush to ensure that the stream texture gets deleted in a timely fashion.
-  gl->ShallowFlushCHROMIUM();
+void OnReleaseVideoFrame(scoped_refptr<content::StreamTextureFactory> factories,
+                         gpu::Mailbox mailbox,
+                         const gpu::SyncToken& sync_token) {
+  gpu::SharedImageInterface* sii = factories->SharedImageInterface();
+  sii->DestroySharedImage(sync_token, mailbox);
+  sii->Flush();
 }
 }
 
@@ -33,21 +29,12 @@
     scoped_refptr<StreamTextureFactory> factory,
     scoped_refptr<base::SingleThreadTaskRunner> main_task_runner)
     : enable_texture_copy_(enable_texture_copy),
-      texture_id_(0),
       factory_(factory),
       main_task_runner_(main_task_runner),
       weak_factory_(this) {}
 
 StreamTextureWrapperImpl::~StreamTextureWrapperImpl() {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
-
-  if (texture_id_) {
-    GLES2Interface* gl = factory_->ContextGL();
-    gl->DeleteTextures(1, &texture_id_);
-    // Flush to ensure that the stream texture gets deleted in a timely fashion.
-    gl->ShallowFlushCHROMIUM();
-  }
-
   SetCurrentFrameInternal(nullptr);
 }
 
@@ -64,37 +51,24 @@
   return current_frame_;
 }
 
-void StreamTextureWrapperImpl::ReallocateVideoFrame(
-    const gfx::Size& natural_size) {
+void StreamTextureWrapperImpl::ReallocateVideoFrame() {
   DVLOG(2) << __func__;
   DCHECK(main_task_runner_->BelongsToCurrentThread());
 
-  GLES2Interface* gl = factory_->ContextGL();
-  GLuint texture_target = GL_TEXTURE_EXTERNAL_OES;
-  GLuint texture_id_ref =
-      gl->CreateAndConsumeTextureCHROMIUM(texture_mailbox_.name);
-  gl->Flush();
-
+  gpu::Mailbox mailbox;
   gpu::SyncToken texture_mailbox_sync_token;
-  if (texture_mailbox_sync_token.namespace_id() ==
-      gpu::CommandBufferNamespace::IN_PROCESS) {
-    // TODO(boliu): Remove this once Android WebView switches to IPC-based
-    // command buffer for video.
-    gl->GenSyncTokenCHROMIUM(texture_mailbox_sync_token.GetData());
-  } else {
-    gl->GenUnverifiedSyncTokenCHROMIUM(texture_mailbox_sync_token.GetData());
-  }
-
+  stream_texture_proxy_->CreateSharedImage(natural_size_, &mailbox,
+                                           &texture_mailbox_sync_token);
   gpu::MailboxHolder holders[media::VideoFrame::kMaxPlanes] = {
-      gpu::MailboxHolder(texture_mailbox_, texture_mailbox_sync_token,
-                         texture_target)};
+      gpu::MailboxHolder(mailbox, texture_mailbox_sync_token,
+                         GL_TEXTURE_EXTERNAL_OES)};
 
   scoped_refptr<media::VideoFrame> new_frame =
       media::VideoFrame::WrapNativeTextures(
           media::PIXEL_FORMAT_ARGB, holders,
           media::BindToCurrentLoop(
-              base::BindOnce(&OnReleaseTexture, factory_, texture_id_ref)),
-          natural_size, gfx::Rect(natural_size), natural_size,
+              base::BindOnce(&OnReleaseVideoFrame, factory_, mailbox)),
+          natural_size_, gfx::Rect(natural_size_), natural_size_,
           base::TimeDelta());
 
   if (enable_texture_copy_) {
@@ -140,9 +114,7 @@
     return;
 
   natural_size_ = new_size;
-
-  ReallocateVideoFrame(new_size);
-  stream_texture_proxy_->SetStreamTextureSize(new_size);
+  ReallocateVideoFrame();
 }
 
 void StreamTextureWrapperImpl::Initialize(
@@ -175,14 +147,13 @@
     return;
   }
 
-  stream_texture_proxy_ =
-      factory_->CreateProxy(&texture_id_, &texture_mailbox_);
+  stream_texture_proxy_ = factory_->CreateProxy();
   if (!stream_texture_proxy_) {
     init_cb.Run(false);
     return;
   }
 
-  ReallocateVideoFrame(natural_size_);
+  ReallocateVideoFrame();
 
   stream_texture_proxy_->BindToTaskRunner(received_frame_cb,
                                           compositor_task_runner_);
diff --git a/content/renderer/media/android/stream_texture_wrapper_impl.h b/content/renderer/media/android/stream_texture_wrapper_impl.h
index bb14d61..153eb9f5 100644
--- a/content/renderer/media/android/stream_texture_wrapper_impl.h
+++ b/content/renderer/media/android/stream_texture_wrapper_impl.h
@@ -20,26 +20,27 @@
 // any thread, but additional threading considerations are listed in the
 // comments of individual methods.
 //
-// The StreamTexture is an abstraction allowing Chrome to wrap a SurfaceTexture
+// The StreamTexture is an abstraction allowing Chrome to wrap a SurfaceOwner
 // living in the GPU process. It allows VideoFrames to be created from the
-// SurfaceTexture's texture, in the Renderer process.
+// SurfaceOwner's texture, in the Renderer process.
 //
 // The general idea behind our use of StreamTexture is as follows:
-// - We create a client GL texture in the Renderer process.
-// - We request the creation of a StreamTexture via the StreamTextureFactory,
-// passing the client texture ID. The call is sent to the GPU process via the
-// CommandBuffer. The "platform" GL texture reference associated with the client
-// texture ID is looked up in the TextureManager. A StreamTexture is then
-// created, wrapping a SurfaceTexture created from the texture reference. The
-// SurfaceTexture's OnFrameAvailable() callback is tied to StreamTexture's
-// OnFrameAvailable(), which fires an IPC accross the GPU channel.
+// - We request the creation of a StreamTexture via the StreamTextureFactory.
+// The call is sent to the GPU process via the CommandBuffer. A StreamTexture is
+// then created, wrapping a SurfaceOwner. The SurfaceOwner's
+// OnFrameAvailable() callback is tied to StreamTexture's OnFrameAvailable(),
+// which fires an IPC across the GPU channel.
 // - We create a StreamTextureProxy in the Renderer process which listens for
 // the IPC fired by the StreamTexture's OnFrameAvailable() callback.
 // - We bind the StreamTextureProxy's lifetime to the |compositor_task_runner_|.
-// - We wrap the client texture into a VideoFrame.
-// - When the SurfaceTexture's OnFrameAvailable() callback is fired (and routed
+// - We create a SharedImage mailbox representing the StreamTexture at a given
+// size.
+// - We create a VideoFrame which takes ownership of this SharedImage mailbox.
+// - When the SurfaceOwner's OnFrameAvailable() callback is fired (and routed
 // to the StreamTextureProxy living on the compositor thread), we notify
 // |client_| that a new frame is available, via the DidReceiveFrame() callback.
+// - When the StreamTextureProxy is destroyed, it delivers a notification over
+// the channel, cleaning up the StreamTexture ref in the GPU process.
 class CONTENT_EXPORT StreamTextureWrapperImpl
     : public media::StreamTextureWrapper {
  public:
@@ -100,18 +101,12 @@
   void InitializeOnMainThread(const base::RepeatingClosure& received_frame_cb,
                               const StreamTextureWrapperInitCB& init_cb);
 
-  void ReallocateVideoFrame(const gfx::Size& natural_size);
+  void ReallocateVideoFrame();
 
   void SetCurrentFrameInternal(scoped_refptr<media::VideoFrame> video_frame);
 
   bool enable_texture_copy_;
 
-  // Client GL texture ID allocated to the StreamTexture.
-  unsigned texture_id_;
-
-  // GL texture mailbox for |texture_id_|.
-  gpu::Mailbox texture_mailbox_;
-
   // Object for calling back the compositor thread to repaint the video when a
   // frame is available. It should be bound to |compositor_task_runner_|.
   ScopedStreamTextureProxy stream_texture_proxy_;
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 4b5092c..a2a6d6a 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -1412,19 +1412,13 @@
 
 scoped_refptr<StreamTextureFactory> RenderThreadImpl::GetStreamTexureFactory() {
   DCHECK(IsMainThread());
-  if (!stream_texture_factory_.get() ||
-      stream_texture_factory_->ContextGL()->GetGraphicsResetStatusKHR() !=
-          GL_NO_ERROR) {
-    scoped_refptr<viz::ContextProviderCommandBuffer> shared_context_provider =
-        SharedMainThreadContextProvider();
-    if (!shared_context_provider) {
+  if (!stream_texture_factory_ || stream_texture_factory_->IsLost()) {
+    scoped_refptr<gpu::GpuChannelHost> channel = EstablishGpuChannelSync();
+    if (!channel) {
       stream_texture_factory_ = nullptr;
       return nullptr;
     }
-    DCHECK(shared_context_provider->GetCommandBufferProxy());
-    DCHECK(shared_context_provider->GetCommandBufferProxy()->channel());
-    stream_texture_factory_ =
-        StreamTextureFactory::Create(std::move(shared_context_provider));
+    stream_texture_factory_ = StreamTextureFactory::Create(std::move(channel));
   }
   return stream_texture_factory_;
 }
diff --git a/content/renderer/stream_texture_host_android.cc b/content/renderer/stream_texture_host_android.cc
index ca8003cf..b4f28bc 100644
--- a/content/renderer/stream_texture_host_android.cc
+++ b/content/renderer/stream_texture_host_android.cc
@@ -7,6 +7,7 @@
 #include "base/unguessable_token.h"
 #include "content/renderer/render_thread_impl.h"
 #include "gpu/ipc/client/gpu_channel_host.h"
+#include "gpu/ipc/common/command_buffer_id.h"
 #include "gpu/ipc/common/gpu_messages.h"
 #include "ipc/ipc_message_macros.h"
 
@@ -23,8 +24,15 @@
 }
 
 StreamTextureHost::~StreamTextureHost() {
-  if (channel_)
+  if (channel_) {
+    // We destroy the StreamTexture as a deferred message followed by a flush
+    // to ensure this is ordered correctly with regards to previous deferred
+    // messages, such as CreateSharedImage.
+    uint32_t flush_id = channel_->EnqueueDeferredMessage(
+        GpuStreamTextureMsg_Destroy(route_id_));
+    channel_->EnsureFlush(flush_id);
     channel_->RemoveRoute(route_id_);
+  }
 }
 
 bool StreamTextureHost::BindToCurrentThread(Listener* listener) {
@@ -58,11 +66,6 @@
     listener_->OnFrameAvailable();
 }
 
-void StreamTextureHost::SetStreamTextureSize(const gfx::Size& size) {
-  if (channel_)
-    channel_->Send(new GpuStreamTextureMsg_SetSize(route_id_, size));
-}
-
 void StreamTextureHost::ForwardStreamTextureForSurfaceRequest(
     const base::UnguessableToken& request_token) {
   if (channel_) {
@@ -71,4 +74,21 @@
   }
 }
 
+gpu::Mailbox StreamTextureHost::CreateSharedImage(const gfx::Size& size) {
+  if (!channel_)
+    return gpu::Mailbox();
+
+  auto mailbox = gpu::Mailbox::GenerateForSharedImage();
+  channel_->EnqueueDeferredMessage(GpuStreamTextureMsg_CreateSharedImage(
+      route_id_, mailbox, size, ++release_id_));
+  return mailbox;
+}
+
+gpu::SyncToken StreamTextureHost::GenUnverifiedSyncToken() {
+  return gpu::SyncToken(gpu::CommandBufferNamespace::GPU_IO,
+                        gpu::CommandBufferIdFromChannelAndRoute(
+                            channel_->channel_id(), route_id_),
+                        release_id_);
+}
+
 }  // namespace content
diff --git a/content/renderer/stream_texture_host_android.h b/content/renderer/stream_texture_host_android.h
index 0959300..62f8f7b0 100644
--- a/content/renderer/stream_texture_host_android.h
+++ b/content/renderer/stream_texture_host_android.h
@@ -22,6 +22,8 @@
 
 namespace gpu {
 class GpuChannelHost;
+struct Mailbox;
+struct SyncToken;
 }
 
 namespace content {
@@ -48,9 +50,10 @@
   bool OnMessageReceived(const IPC::Message& message) override;
   void OnChannelError() override;
 
-  void SetStreamTextureSize(const gfx::Size& size);
   void ForwardStreamTextureForSurfaceRequest(
       const base::UnguessableToken& request_token);
+  gpu::Mailbox CreateSharedImage(const gfx::Size& size);
+  gpu::SyncToken GenUnverifiedSyncToken();
 
  private:
   // Message handlers:
@@ -59,6 +62,8 @@
   int32_t route_id_;
   Listener* listener_;
   scoped_refptr<gpu::GpuChannelHost> channel_;
+  uint32_t release_id_ = 0;
+
   base::WeakPtrFactory<StreamTextureHost> weak_ptr_factory_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(StreamTextureHost);
diff --git a/gpu/command_buffer/client/shared_image_interface.h b/gpu/command_buffer/client/shared_image_interface.h
index 24b3623..962506a 100644
--- a/gpu/command_buffer/client/shared_image_interface.h
+++ b/gpu/command_buffer/client/shared_image_interface.h
@@ -134,6 +134,9 @@
   // Generates a verified SyncToken that is released after all previous
   // commands on this interface have executed on the service side.
   virtual SyncToken GenVerifiedSyncToken() = 0;
+
+  // Flush the SharedImageInterface, issuing any deferred IPCs.
+  virtual void Flush() = 0;
 };
 
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/abstract_texture_impl_shared_context_state.cc b/gpu/command_buffer/service/abstract_texture_impl_shared_context_state.cc
index 0e4c62c..9b6f131 100644
--- a/gpu/command_buffer/service/abstract_texture_impl_shared_context_state.cc
+++ b/gpu/command_buffer/service/abstract_texture_impl_shared_context_state.cc
@@ -87,7 +87,11 @@
 void AbstractTextureImplOnSharedContext::BindStreamTextureImage(
     GLStreamTextureImage* image,
     GLuint service_id) {
-  NOTIMPLEMENTED();
+  const GLint level = 0;
+  const GLuint target = texture_->target();
+  texture_->SetLevelStreamTextureImage(
+      target, level, image, Texture::ImageState::UNBOUND, service_id);
+  texture_->SetLevelCleared(target, level, true);
 }
 
 void AbstractTextureImplOnSharedContext::BindImage(gl::GLImage* image,
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc
index 619b9bbb..7c4753a 100644
--- a/gpu/command_buffer/service/texture_manager.cc
+++ b/gpu/command_buffer/service/texture_manager.cc
@@ -1874,6 +1874,10 @@
   Texture::LevelInfo& info = face_infos_[face_index].level_infos[level];
   DCHECK_EQ(info.target, target);
   DCHECK_EQ(info.level, level);
+  // Workaround for StreamTexture which must be re-copied on each access.
+  // TODO(ericrk): Remove this once SharedImage transition is complete.
+  if (info.image && !info.image->HasMutableState())
+    return;
   info.image_state = state;
 }
 
diff --git a/gpu/ipc/client/command_buffer_proxy_impl.cc b/gpu/ipc/client/command_buffer_proxy_impl.cc
index b753d1b..5a34972 100644
--- a/gpu/ipc/client/command_buffer_proxy_impl.cc
+++ b/gpu/ipc/client/command_buffer_proxy_impl.cc
@@ -475,23 +475,6 @@
   Send(new GpuCommandBufferMsg_DestroyImage(route_id_, id));
 }
 
-uint32_t CommandBufferProxyImpl::CreateStreamTexture(uint32_t texture_id) {
-  CheckLock();
-  base::AutoLock lock(last_state_lock_);
-  if (last_state_.error != gpu::error::kNoError)
-    return 0;
-
-  int32_t stream_id = channel_->GenerateRouteID();
-  bool succeeded = false;
-  Send(new GpuCommandBufferMsg_CreateStreamTexture(route_id_, texture_id,
-                                                   stream_id, &succeeded));
-  if (!succeeded) {
-    DLOG(ERROR) << "GpuCommandBufferMsg_CreateStreamTexture returned failure";
-    return 0;
-  }
-  return stream_id;
-}
-
 void CommandBufferProxyImpl::SetLock(base::Lock* lock) {
   lock_ = lock;
 }
diff --git a/gpu/ipc/client/command_buffer_proxy_impl.h b/gpu/ipc/client/command_buffer_proxy_impl.h
index 48b4586..11e07b36 100644
--- a/gpu/ipc/client/command_buffer_proxy_impl.h
+++ b/gpu/ipc/client/command_buffer_proxy_impl.h
@@ -151,7 +151,6 @@
   const base::UnsafeSharedMemoryRegion& GetSharedStateRegion() const {
     return shared_state_shm_;
   }
-  uint32_t CreateStreamTexture(uint32_t texture_id);
 
  private:
   typedef std::map<int32_t, scoped_refptr<gpu::Buffer>> TransferBufferMap;
diff --git a/gpu/ipc/client/shared_image_interface_proxy.cc b/gpu/ipc/client/shared_image_interface_proxy.cc
index fa1e2c7..682b231 100644
--- a/gpu/ipc/client/shared_image_interface_proxy.cc
+++ b/gpu/ipc/client/shared_image_interface_proxy.cc
@@ -246,6 +246,11 @@
       next_release_id_);
 }
 
+void SharedImageInterfaceProxy::Flush() {
+  base::AutoLock lock(lock_);
+  host_->EnsureFlush(last_flush_id_);
+}
+
 bool SharedImageInterfaceProxy::GetSHMForPixelData(
     base::span<const uint8_t> pixel_data,
     size_t* shm_offset,
diff --git a/gpu/ipc/client/shared_image_interface_proxy.h b/gpu/ipc/client/shared_image_interface_proxy.h
index 8db9c29..2a40103 100644
--- a/gpu/ipc/client/shared_image_interface_proxy.h
+++ b/gpu/ipc/client/shared_image_interface_proxy.h
@@ -44,6 +44,7 @@
                           const Mailbox& mailbox) override;
   SyncToken GenVerifiedSyncToken() override;
   SyncToken GenUnverifiedSyncToken() override;
+  void Flush() override;
 
 #if defined(OS_WIN)
   SwapChainMailboxes CreateSwapChain(viz::ResourceFormat format,
diff --git a/gpu/ipc/common/gpu_messages.h b/gpu/ipc/common/gpu_messages.h
index 332977b5..332c102 100644
--- a/gpu/ipc/common/gpu_messages.h
+++ b/gpu/ipc/common/gpu_messages.h
@@ -205,6 +205,11 @@
 // messages have been received.
 IPC_SYNC_MESSAGE_CONTROL0_0(GpuChannelMsg_Nop)
 
+// Creates a StreamTexture attached to the provided |stream_id|.
+IPC_SYNC_MESSAGE_CONTROL1_1(GpuChannelMsg_CreateStreamTexture,
+                            int32_t, /* stream_id */
+                            bool /* succeeded */)
+
 #if defined(OS_ANDROID)
 //------------------------------------------------------------------------------
 // Tells the StreamTexture to send its SurfaceTexture to the browser process,
@@ -212,16 +217,22 @@
 IPC_MESSAGE_ROUTED1(GpuStreamTextureMsg_ForwardForSurfaceRequest,
                     base::UnguessableToken)
 
-// Tells the GPU process to set the size of StreamTexture from the given
-// stream Id.
-IPC_MESSAGE_ROUTED1(GpuStreamTextureMsg_SetSize, gfx::Size /* size */)
-
 // Tells the service-side instance to start sending frame available
 // notifications.
 IPC_MESSAGE_ROUTED0(GpuStreamTextureMsg_StartListening)
 
 // Inform the renderer that a new frame is available.
 IPC_MESSAGE_ROUTED0(GpuStreamTextureMsg_FrameAvailable)
+
+// Create a SharedImage for the current StreamTexture at the provided |size|.
+IPC_MESSAGE_ROUTED3(GpuStreamTextureMsg_CreateSharedImage,
+                    gpu::Mailbox /* mailbox */,
+                    gfx::Size /* size */,
+                    uint32_t /* release_id */)
+
+// Destroys the StreamTexture attached to the provided |stream_id|.
+IPC_MESSAGE_ROUTED0(GpuStreamTextureMsg_Destroy)
+
 #endif
 
 //------------------------------------------------------------------------------
@@ -321,12 +332,6 @@
 // Destroy a previously created image.
 IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_DestroyImage, int32_t /* id */)
 
-// Attaches an external image stream to the client texture.
-IPC_SYNC_MESSAGE_ROUTED2_1(GpuCommandBufferMsg_CreateStreamTexture,
-                           uint32_t, /* client_texture_id */
-                           int32_t,  /* stream_id */
-                           bool /* succeeded */)
-
 // Send a GPU fence handle and store it for the specified gpu fence ID.
 IPC_MESSAGE_ROUTED2(GpuCommandBufferMsg_CreateGpuFenceFromHandle,
                     uint32_t /* gpu_fence_id */,
diff --git a/gpu/ipc/in_process_command_buffer.cc b/gpu/ipc/in_process_command_buffer.cc
index 616b8d7..0487d74 100644
--- a/gpu/ipc/in_process_command_buffer.cc
+++ b/gpu/ipc/in_process_command_buffer.cc
@@ -283,6 +283,10 @@
     return sync_token;
   }
 
+  void Flush() override {
+    // No need to flush in this implementation.
+  }
+
   CommandBufferId command_buffer_id() const { return command_buffer_id_; }
 
  private:
diff --git a/gpu/ipc/service/DEPS b/gpu/ipc/service/DEPS
index c6f81396..b333190 100644
--- a/gpu/ipc/service/DEPS
+++ b/gpu/ipc/service/DEPS
@@ -5,6 +5,7 @@
   "+components/viz/common/gpu/gpu_vsync_callback.h",
   "+components/viz/common/gpu/vulkan_context_provider.h",
   "+components/viz/common/resources/resource_format.h",
+  "+components/viz/common/resources/resource_sizes.h",
   "+third_party/skia",
   "+ui/accelerated_widget_mac",
   "+ui/base",
diff --git a/gpu/ipc/service/command_buffer_stub.cc b/gpu/ipc/service/command_buffer_stub.cc
index 125fe87..9dcb6e3 100644
--- a/gpu/ipc/service/command_buffer_stub.cc
+++ b/gpu/ipc/service/command_buffer_stub.cc
@@ -49,10 +49,6 @@
 #include "base/win/win_util.h"
 #endif
 
-#if defined(OS_ANDROID)
-#include "gpu/ipc/service/stream_texture_android.h"
-#endif
-
 namespace gpu {
 struct WaitForCommandState {
   WaitForCommandState(int32_t start, int32_t end, IPC::Message* reply)
diff --git a/gpu/ipc/service/gles2_command_buffer_stub.cc b/gpu/ipc/service/gles2_command_buffer_stub.cc
index 28cc844..cf8b983 100644
--- a/gpu/ipc/service/gles2_command_buffer_stub.cc
+++ b/gpu/ipc/service/gles2_command_buffer_stub.cc
@@ -56,10 +56,6 @@
 #include "base/win/win_util.h"
 #endif
 
-#if defined(OS_ANDROID)
-#include "gpu/ipc/service/stream_texture_android.h"
-#endif
-
 namespace gpu {
 
 GLES2CommandBufferStub::GLES2CommandBufferStub(
@@ -440,8 +436,6 @@
                         OnReturnFrontBuffer);
     IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_CreateImage, OnCreateImage);
     IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_DestroyImage, OnDestroyImage);
-    IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_CreateStreamTexture,
-                        OnCreateStreamTexture)
     IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_CreateGpuFenceFromHandle,
                         OnCreateGpuFenceFromHandle)
     IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_GetGpuFenceHandle,
@@ -556,16 +550,6 @@
   image_manager->RemoveImage(id);
 }
 
-void GLES2CommandBufferStub::OnCreateStreamTexture(uint32_t texture_id,
-                                                   int32_t stream_id,
-                                                   bool* succeeded) {
-#if defined(OS_ANDROID)
-  *succeeded = StreamTexture::Create(this, texture_id, stream_id);
-#else
-  *succeeded = false;
-#endif
-}
-
 void GLES2CommandBufferStub::OnSwapBuffers(uint64_t swap_id, uint32_t flags) {
   pending_swap_completed_params_.push_back({swap_id, flags});
   pending_presented_params_.push_back({swap_id, flags});
diff --git a/gpu/ipc/service/gles2_command_buffer_stub.h b/gpu/ipc/service/gles2_command_buffer_stub.h
index 166ef98..5346b52d 100644
--- a/gpu/ipc/service/gles2_command_buffer_stub.h
+++ b/gpu/ipc/service/gles2_command_buffer_stub.h
@@ -60,9 +60,6 @@
   void OnGetGpuFenceHandle(uint32_t gpu_fence_id);
   void OnCreateImage(GpuCommandBufferMsg_CreateImage_Params params);
   void OnDestroyImage(int32_t id);
-  void OnCreateStreamTexture(uint32_t texture_id,
-                             int32_t stream_id,
-                             bool* succeeded);
 
   void OnSwapBuffers(uint64_t swap_id, uint32_t flags) override;
 
diff --git a/gpu/ipc/service/gpu_channel.cc b/gpu/ipc/service/gpu_channel.cc
index 71446ad..3e3dc5a 100644
--- a/gpu/ipc/service/gpu_channel.cc
+++ b/gpu/ipc/service/gpu_channel.cc
@@ -33,6 +33,7 @@
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
 #include "gpu/command_buffer/common/mailbox.h"
+#include "gpu/command_buffer/service/abstract_texture_impl_shared_context_state.h"
 #include "gpu/command_buffer/service/image_factory.h"
 #include "gpu/command_buffer/service/image_manager.h"
 #include "gpu/command_buffer/service/mailbox_manager.h"
@@ -55,6 +56,10 @@
 #include "ui/gl/gl_surface.h"
 #include "ui/gl/gl_utils.h"
 
+#if defined(OS_ANDROID)
+#include "gpu/ipc/service/stream_texture_android.h"
+#endif  // defined(OS_ANDROID)
+
 namespace gpu {
 
 struct GpuChannelMessage {
@@ -400,6 +405,14 @@
   // Clear stubs first because of dependencies.
   stubs_.clear();
 
+#if defined(OS_ANDROID)
+  // Release any references to this channel held by StreamTexture.
+  for (auto& stream_texture : stream_textures_) {
+    stream_texture.second->ReleaseChannel();
+  }
+  stream_textures_.clear();
+#endif  // OS_ANDROID
+
   // Destroy filter first to stop posting tasks to scheduler.
   filter_->Destroy();
 
@@ -548,6 +561,8 @@
                         OnCreateCommandBuffer)
     IPC_MESSAGE_HANDLER(GpuChannelMsg_DestroyCommandBuffer,
                         OnDestroyCommandBuffer)
+    IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateStreamTexture,
+                        OnCreateStreamTexture)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -631,6 +646,16 @@
   }
   return nullptr;
 }
+
+void GpuChannel::DestroyStreamTexture(int32_t stream_id) {
+  auto found = stream_textures_.find(stream_id);
+  if (found == stream_textures_.end()) {
+    LOG(ERROR) << "Trying to destroy a non-existent stream texture.";
+    return;
+  }
+  found->second->ReleaseChannel();
+  stream_textures_.erase(stream_id);
+}
 #endif
 
 void GpuChannel::OnCreateCommandBuffer(
@@ -757,6 +782,28 @@
   RemoveRoute(route_id);
 }
 
+void GpuChannel::OnCreateStreamTexture(int32_t stream_id, bool* succeeded) {
+#if defined(OS_ANDROID)
+  auto found = stream_textures_.find(stream_id);
+  if (found != stream_textures_.end()) {
+    LOG(ERROR)
+        << "Trying to create a StreamTexture with an existing stream_id.";
+    *succeeded = false;
+    return;
+  }
+  scoped_refptr<StreamTexture> stream_texture =
+      StreamTexture::Create(this, stream_id);
+  if (!stream_texture) {
+    *succeeded = false;
+    return;
+  }
+  stream_textures_.emplace(stream_id, std::move(stream_texture));
+  *succeeded = true;
+#else
+  *succeeded = false;
+#endif
+}
+
 void GpuChannel::CacheShader(const std::string& key,
                              const std::string& shader) {
   gpu_channel_manager_->delegate()->StoreShaderToDisk(client_id_, key, shader);
diff --git a/gpu/ipc/service/gpu_channel.h b/gpu/ipc/service/gpu_channel.h
index 8c10927..c784ac6 100644
--- a/gpu/ipc/service/gpu_channel.h
+++ b/gpu/ipc/service/gpu_channel.h
@@ -41,13 +41,13 @@
 }
 
 namespace gpu {
-
 class GpuChannelManager;
 class GpuChannelMessageFilter;
 class ImageDecodeAcceleratorStub;
 class ImageDecodeAcceleratorWorker;
 class Scheduler;
 class SharedImageStub;
+class StreamTexture;
 class SyncPointManager;
 
 // Encapsulates an IPC channel between the GPU process and one renderer
@@ -159,6 +159,10 @@
 
 #if defined(OS_ANDROID)
   const CommandBufferStub* GetOneStub() const;
+
+  // Called by StreamTexture to remove the GpuChannel's reference to the
+  // StreamTexture.
+  void DestroyStreamTexture(int32_t stream_id);
 #endif
 
   SharedImageStub* shared_image_stub() const {
@@ -189,6 +193,7 @@
                              gpu::ContextResult* result,
                              gpu::Capabilities* capabilities);
   void OnDestroyCommandBuffer(int32_t route_id);
+  void OnCreateStreamTexture(int32_t stream_id, bool* succeeded);
   bool CreateSharedImageStub();
 
   std::unique_ptr<IPC::SyncChannel> sync_channel_;  // nullptr in tests.
@@ -240,6 +245,11 @@
 
   const bool is_gpu_host_;
 
+#if defined(OS_ANDROID)
+  // Set of active StreamTextures.
+  base::flat_map<int32_t, scoped_refptr<StreamTexture>> stream_textures_;
+#endif
+
   // Member variables should appear before the WeakPtrFactory, to ensure that
   // any WeakPtrs to Controller are invalidated before its members variable's
   // destructors are executed, rendering them invalid.
diff --git a/gpu/ipc/service/stream_texture_android.cc b/gpu/ipc/service/stream_texture_android.cc
index 8d6d9f6..921c3c71 100644
--- a/gpu/ipc/service/stream_texture_android.cc
+++ b/gpu/ipc/service/stream_texture_android.cc
@@ -7,77 +7,146 @@
 #include <string.h>
 
 #include "base/bind.h"
-#include "gpu/command_buffer/service/context_group.h"
+#include "components/viz/common/resources/resource_sizes.h"
+#include "gpu/command_buffer/common/shared_image_usage.h"
+#include "gpu/command_buffer/service/abstract_texture_impl_shared_context_state.h"
 #include "gpu/command_buffer/service/context_state.h"
-#include "gpu/command_buffer/service/decoder_context.h"
-#include "gpu/command_buffer/service/texture_manager.h"
+#include "gpu/command_buffer/service/mailbox_manager.h"
+#include "gpu/command_buffer/service/scheduler.h"
+#include "gpu/command_buffer/service/shared_context_state.h"
+#include "gpu/command_buffer/service/shared_image_backing.h"
+#include "gpu/command_buffer/service/shared_image_factory.h"
 #include "gpu/ipc/common/android/scoped_surface_request_conduit.h"
+#include "gpu/ipc/common/command_buffer_id.h"
 #include "gpu/ipc/common/gpu_messages.h"
 #include "gpu/ipc/service/gpu_channel.h"
+#include "gpu/ipc/service/gpu_channel_manager.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gl/gl_context.h"
+#include "ui/gl/scoped_binders.h"
 #include "ui/gl/scoped_make_current.h"
 
 namespace gpu {
-
-using gles2::ContextGroup;
-using gles2::TextureManager;
-using gles2::TextureRef;
-
-// static
-bool StreamTexture::Create(CommandBufferStub* owner_stub,
-                           uint32_t client_texture_id,
-                           int stream_id) {
-  gles2::ContextGroup* context_group =
-      owner_stub->decoder_context()->GetContextGroup();
-  DCHECK(context_group);
-  TextureManager* texture_manager = context_group->texture_manager();
-  TextureRef* texture = texture_manager->GetTexture(client_texture_id);
-
-  if (texture && (!texture->texture()->target() ||
-                  texture->texture()->target() == GL_TEXTURE_EXTERNAL_OES)) {
-
-    // TODO: Ideally a valid image id was returned to the client so that
-    // it could then call glBindTexImage2D() for doing the following.
-    scoped_refptr<gpu::gles2::GLStreamTextureImage> gl_image(
-        new StreamTexture(owner_stub, stream_id, texture->service_id()));
-    gfx::Size size = gl_image->GetSize();
-    texture_manager->SetTarget(texture, GL_TEXTURE_EXTERNAL_OES);
-    texture_manager->SetLevelInfo(texture, GL_TEXTURE_EXTERNAL_OES, 0, GL_RGBA,
-                                  size.width(), size.height(), 1, 0, GL_RGBA,
-                                  GL_UNSIGNED_BYTE, gfx::Rect(size));
-    texture_manager->SetLevelStreamTextureImage(
-        texture, GL_TEXTURE_EXTERNAL_OES, 0, gl_image.get(),
-        gles2::Texture::UNBOUND, 0);
-    return true;
+namespace {
+std::unique_ptr<ui::ScopedMakeCurrent> MakeCurrent(
+    SharedContextState* context_state) {
+  std::unique_ptr<ui::ScopedMakeCurrent> scoped_make_current;
+  bool needs_make_current = !context_state->IsCurrent(nullptr);
+  if (needs_make_current) {
+    scoped_make_current = std::make_unique<ui::ScopedMakeCurrent>(
+        context_state->context(), context_state->surface());
   }
-
-  return false;
+  return scoped_make_current;
 }
 
-StreamTexture::StreamTexture(CommandBufferStub* owner_stub,
-                             int32_t route_id,
-                             uint32_t texture_id)
-    : surface_owner_(SurfaceOwner::Create(texture_id)),
+class SharedImageBackingStreamTexture : public gpu::SharedImageBacking {
+ public:
+  SharedImageBackingStreamTexture(
+      const gpu::Mailbox& mailbox,
+      const gfx::Size& size,
+      std::unique_ptr<gpu::gles2::AbstractTexture> abstract_texture)
+      : SharedImageBacking(
+            mailbox,
+            viz::RGBA_8888,
+            size,
+            gfx::ColorSpace(),
+            gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_GLES2,
+            viz::ResourceSizes::UncheckedSizeInBytes<size_t>(size,
+                                                             viz::RGBA_8888),
+            false /* is_thread_safe */),
+        abstract_texture_(std::move(abstract_texture)) {}
+
+  ~SharedImageBackingStreamTexture() override {}
+
+  // SharedImageBacking implementation.
+  bool IsCleared() const override { return true; }
+  void SetCleared() override {}
+  void Update(std::unique_ptr<gfx::GpuFence> in_fence) override {
+    NOTREACHED();
+  }
+  bool ProduceLegacyMailbox(gpu::MailboxManager* mailbox_manager) override {
+    mailbox_manager->ProduceTexture(mailbox(),
+                                    abstract_texture_->GetTextureBase());
+    return true;
+  }
+  void Destroy() override {}
+
+ private:
+  // |abstract_texture_| is only used for legacy mailbox.
+  std::unique_ptr<gpu::gles2::AbstractTexture> abstract_texture_;
+
+  DISALLOW_COPY_AND_ASSIGN(SharedImageBackingStreamTexture);
+};
+
+}  // namespace
+
+// static
+scoped_refptr<StreamTexture> StreamTexture::Create(GpuChannel* channel,
+                                                   int stream_id) {
+  ContextResult result;
+  auto context_state =
+      channel->gpu_channel_manager()->GetSharedContextState(&result);
+  if (result != ContextResult::kSuccess)
+    return nullptr;
+  auto scoped_make_current = MakeCurrent(context_state.get());
+  auto texture = std::make_unique<gles2::AbstractTextureImplOnSharedContext>(
+      GL_TEXTURE_EXTERNAL_OES, GL_RGBA, 0, 0, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+      context_state.get());
+  return new StreamTexture(channel, stream_id, std::move(texture),
+                           std::move(context_state));
+}
+
+StreamTexture::StreamTexture(
+    GpuChannel* channel,
+    int32_t route_id,
+    std::unique_ptr<gles2::AbstractTexture> surface_owner_texture,
+    scoped_refptr<SharedContextState> context_state)
+    : surface_owner_texture_(std::move(surface_owner_texture)),
+      surface_owner_texture_id_(
+          surface_owner_texture_->GetTextureBase()->service_id()),
+      surface_owner_(SurfaceOwner::Create(surface_owner_texture_id_)),
       size_(0, 0),
       has_pending_frame_(false),
-      owner_stub_(owner_stub),
+      channel_(channel),
       route_id_(route_id),
       has_listener_(false),
-      texture_id_(texture_id),
+      context_state_(std::move(context_state)),
+      sequence_(
+          channel_->scheduler()->CreateSequence(SchedulingPriority::kLow)),
+      sync_point_client_state_(
+          channel_->sync_point_manager()->CreateSyncPointClientState(
+              CommandBufferNamespace::GPU_IO,
+              CommandBufferIdFromChannelAndRoute(channel_->client_id(),
+                                                 route_id),
+              sequence_)),
       weak_factory_(this) {
-  owner_stub->AddDestructionObserver(this);
+  context_state_->AddContextLostObserver(this);
   memset(current_matrix_, 0, sizeof(current_matrix_));
-  owner_stub->channel()->AddRoute(route_id, owner_stub->sequence_id(), this);
+  channel->AddRoute(route_id, sequence_, this);
   surface_owner_->SetFrameAvailableCallback(base::BindRepeating(
       &StreamTexture::OnFrameAvailable, weak_factory_.GetWeakPtr()));
 }
 
 StreamTexture::~StreamTexture() {
-  if (owner_stub_) {
-    owner_stub_->RemoveDestructionObserver(this);
-    owner_stub_->channel()->RemoveRoute(route_id_);
-  }
+  // |channel_| is always released before GpuChannel releases its reference to
+  // this class.
+  DCHECK(!channel_);
+  context_state_->RemoveContextLostObserver(this);
+}
+
+void StreamTexture::ReleaseChannel() {
+  DCHECK(channel_);
+  channel_->RemoveRoute(route_id_);
+  channel_->scheduler()->DestroySequence(sequence_);
+  sequence_ = SequenceId();
+  sync_point_client_state_->Destroy();
+  sync_point_client_state_ = nullptr;
+  channel_ = nullptr;
+
+  // If the channel goes away, there is no need to keep the SurfaceTexture
+  // around. The GL texture will keep working regardless with the currently
+  // bound frame.
+  surface_owner_ = nullptr;
 }
 
 // gpu::gles2::GLStreamTextureMatrix implementation
@@ -90,62 +159,27 @@
   YInvertMatrix(xform);
 }
 
-void StreamTexture::OnWillDestroyStub(bool have_context) {
-  owner_stub_->RemoveDestructionObserver(this);
-  owner_stub_->channel()->RemoveRoute(route_id_);
-
-  owner_stub_ = nullptr;
-
-  // If the owner goes away, there is no need to keep the SurfaceTexture around.
-  // The GL texture will keep working regardless with the currently bound frame.
+void StreamTexture::OnContextLost() {
   surface_owner_ = nullptr;
 }
 
-std::unique_ptr<ui::ScopedMakeCurrent> StreamTexture::MakeStubCurrent() {
-  std::unique_ptr<ui::ScopedMakeCurrent> scoped_make_current;
-  bool needs_make_current =
-      !owner_stub_->decoder_context()->GetGLContext()->IsCurrent(nullptr);
-  if (needs_make_current) {
-    scoped_make_current.reset(new ui::ScopedMakeCurrent(
-        owner_stub_->decoder_context()->GetGLContext(),
-        owner_stub_->surface()));
-  }
-  return scoped_make_current;
-}
-
 void StreamTexture::UpdateTexImage() {
   DCHECK(surface_owner_.get());
-  DCHECK(owner_stub_);
 
   if (!has_pending_frame_) return;
 
-  std::unique_ptr<ui::ScopedMakeCurrent> scoped_make_current(MakeStubCurrent());
-
+  auto scoped_make_current = MakeCurrent(context_state_.get());
+  gl::ScopedTextureBinder scoped_bind_texture(GL_TEXTURE_EXTERNAL_OES,
+                                              surface_owner_texture_id_);
   surface_owner_->UpdateTexImage();
-
   has_pending_frame_ = false;
-
-  if (scoped_make_current.get()) {
-    // UpdateTexImage() implies glBindTexture().
-    // The cmd decoder takes care of restoring the binding for this GLImage as
-    // far as the current context is concerned, but if we temporarily change
-    // it, we have to keep the state intact in *that* context also.
-    const gles2::ContextState* state =
-        owner_stub_->decoder_context()->GetContextState();
-    const gles2::TextureUnit& active_unit =
-        state->texture_units[state->active_texture_unit];
-    glBindTexture(GL_TEXTURE_EXTERNAL_OES,
-                  active_unit.bound_texture_external_oes.get()
-                      ? active_unit.bound_texture_external_oes->service_id()
-                      : 0);
-  }
 }
 
 bool StreamTexture::CopyTexImage(unsigned target) {
   if (target != GL_TEXTURE_EXTERNAL_OES)
     return false;
 
-  if (!owner_stub_ || !surface_owner_.get())
+  if (!surface_owner_.get())
     return false;
 
   GLint texture_id;
@@ -156,33 +190,19 @@
   // On some devices GL_TEXTURE_BINDING_EXTERNAL_OES is not supported as
   // glGetIntegerv() parameter. In this case the value of |texture_id| will be
   // zero and we assume that it is properly bound to |texture_id_|.
-  if (texture_id > 0 && static_cast<unsigned>(texture_id) != texture_id_)
+  if (texture_id > 0 &&
+      static_cast<unsigned>(texture_id) != surface_owner_texture_id_)
     return false;
 
   UpdateTexImage();
 
-  gles2::ContextGroup* context_group =
-      owner_stub_->decoder_context()->GetContextGroup();
-  DCHECK(context_group);
-  TextureManager* texture_manager = context_group->texture_manager();
-  gles2::Texture* texture =
-      texture_manager->GetTextureForServiceId(texture_id_);
-  if (texture) {
-    // By setting image state to UNBOUND instead of COPIED we ensure that
-    // CopyTexImage() is called each time the surface texture is used for
-    // drawing.
-    texture->SetLevelStreamTextureImage(GL_TEXTURE_EXTERNAL_OES, 0, this,
-                                        gles2::Texture::UNBOUND, 0);
-  }
-
   return true;
 }
 
 void StreamTexture::OnFrameAvailable() {
   has_pending_frame_ = true;
-  if (has_listener_ && owner_stub_) {
-    owner_stub_->channel()->Send(
-        new GpuStreamTextureMsg_FrameAvailable(route_id_));
+  if (has_listener_ && channel_) {
+    channel_->Send(new GpuStreamTextureMsg_FrameAvailable(route_id_));
   }
 }
 
@@ -200,7 +220,9 @@
     IPC_MESSAGE_HANDLER(GpuStreamTextureMsg_StartListening, OnStartListening)
     IPC_MESSAGE_HANDLER(GpuStreamTextureMsg_ForwardForSurfaceRequest,
                         OnForwardForSurfaceRequest)
-    IPC_MESSAGE_HANDLER(GpuStreamTextureMsg_SetSize, OnSetSize)
+    IPC_MESSAGE_HANDLER(GpuStreamTextureMsg_CreateSharedImage,
+                        OnCreateSharedImage)
+    IPC_MESSAGE_HANDLER(GpuStreamTextureMsg_Destroy, OnDestroy)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
 
@@ -215,7 +237,7 @@
 
 void StreamTexture::OnForwardForSurfaceRequest(
     const base::UnguessableToken& request_token) {
-  if (!owner_stub_)
+  if (!channel_)
     return;
 
   ScopedSurfaceRequestConduit::GetInstance()
@@ -223,28 +245,49 @@
                                              surface_owner_.get());
 }
 
-void StreamTexture::OnSetSize(const gfx::Size& size) {
+void StreamTexture::OnCreateSharedImage(const gpu::Mailbox& mailbox,
+                                        const gfx::Size& size,
+                                        uint32_t release_id) {
+  DCHECK(channel_);
   size_ = size;
-  if (!owner_stub_ || !surface_owner_.get())
+
+  if (!surface_owner_)
     return;
 
-  gles2::ContextGroup* context_group =
-      owner_stub_->decoder_context()->GetContextGroup();
-  DCHECK(context_group);
-  TextureManager* texture_manager = context_group->texture_manager();
-  gles2::Texture* texture =
-      texture_manager->GetTextureForServiceId(texture_id_);
-  if (texture) {
-    // SetLevelInfo will reset the image / stream texture image, which may be
-    // the last reference to |this|, so keep a reference around, and make sure
-    // to reset the stream texture image.
-    scoped_refptr<StreamTexture> self(this);
-    texture->SetLevelInfo(GL_TEXTURE_EXTERNAL_OES, 0, GL_RGBA, size.width(),
-                          size.height(), 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
-                          gfx::Rect(size));
-    texture->SetLevelStreamTextureImage(GL_TEXTURE_EXTERNAL_OES, 0, this,
-                                        gles2::Texture::UNBOUND, 0);
-  }
+  // We do not update |surface_owner_texture_|'s internal gles2::Texture's
+  // size. This is because the gles2::Texture is never used directly, the
+  // associated |surface_owner_texture_id_| being the only part of that object
+  // we interact with.
+  // If we ever use |surface_owner_texture_|, we need to ensure that it gets
+  // updated here.
+
+  auto scoped_make_current = MakeCurrent(context_state_.get());
+  auto legacy_mailbox_texture =
+      std::make_unique<gles2::AbstractTextureImplOnSharedContext>(
+          GL_TEXTURE_EXTERNAL_OES, GL_RGBA, size.width(), size.height(), 1, 0,
+          GL_RGBA, GL_UNSIGNED_BYTE, context_state_.get());
+  legacy_mailbox_texture->BindStreamTextureImage(this,
+                                                 surface_owner_texture_id_);
+
+  auto shared_image = std::make_unique<SharedImageBackingStreamTexture>(
+      mailbox, size_, std::move(legacy_mailbox_texture));
+  channel_->shared_image_stub()->factory()->RegisterBacking(
+      std::move(shared_image), true /* allow_legacy_mailbox */);
+
+  SyncToken sync_token(sync_point_client_state_->namespace_id(),
+                       sync_point_client_state_->command_buffer_id(),
+                       release_id);
+  auto* mailbox_manager = channel_->gpu_channel_manager()->mailbox_manager();
+  mailbox_manager->PushTextureUpdates(sync_token);
+  sync_point_client_state_->ReleaseFenceSync(release_id);
+}
+
+void StreamTexture::OnDestroy() {
+  DCHECK(channel_);
+
+  // The following call may delete the StreamTexture, so we must ensure that no
+  // access to |this| occurs after the call.
+  channel_->DestroyStreamTexture(route_id_);
 }
 
 StreamTexture::BindOrCopy StreamTexture::ShouldBindOrCopy() {
@@ -283,4 +326,8 @@
   // TODO(ericrk): Add OnMemoryDump for GLImages. crbug.com/514914
 }
 
+bool StreamTexture::HasMutableState() const {
+  return false;
+}
+
 }  // namespace gpu
diff --git a/gpu/ipc/service/stream_texture_android.h b/gpu/ipc/service/stream_texture_android.h
index aabd38f9..918e936 100644
--- a/gpu/ipc/service/stream_texture_android.h
+++ b/gpu/ipc/service/stream_texture_android.h
@@ -10,37 +10,41 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/unguessable_token.h"
 #include "gpu/command_buffer/service/gl_stream_texture_image.h"
+#include "gpu/command_buffer/service/shared_context_state.h"
 #include "gpu/ipc/common/android/surface_owner_android.h"
 #include "gpu/ipc/service/command_buffer_stub.h"
 #include "ipc/ipc_listener.h"
 #include "ui/gl/android/surface_texture.h"
 #include "ui/gl/gl_image.h"
 
-namespace ui {
-class ScopedMakeCurrent;
-}
-
 namespace gfx {
 class Size;
 }
 
 namespace gpu {
+class GpuChannel;
+struct Mailbox;
 
 class StreamTexture : public gpu::gles2::GLStreamTextureImage,
                       public IPC::Listener,
-                      public CommandBufferStub::DestructionObserver {
+                      public SharedContextState::ContextLostObserver {
  public:
-  static bool Create(CommandBufferStub* owner_stub,
-                     uint32_t client_texture_id,
-                     int stream_id);
+  static scoped_refptr<StreamTexture> Create(GpuChannel* channel,
+                                             int stream_id);
+
+  // Cleans up related data and nulls |channel_|. Called when the channel
+  // releases its ref on this class.
+  void ReleaseChannel();
 
  private:
-  StreamTexture(CommandBufferStub* owner_stub,
+  StreamTexture(GpuChannel* channel,
                 int32_t route_id,
-                uint32_t texture_id);
+                std::unique_ptr<gles2::AbstractTexture> surface_owner_texture,
+                scoped_refptr<SharedContextState> context_state);
   ~StreamTexture() override;
 
   // gl::GLImage implementation:
@@ -65,6 +69,7 @@
   void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
                     uint64_t process_tracing_id,
                     const std::string& dump_name) override;
+  bool HasMutableState() const override;
 
   // gpu::gles2::GLStreamTextureMatrix implementation
   void GetTextureMatrix(float xform[16]) override;
@@ -74,10 +79,8 @@
                            int display_width,
                            int display_height) override {}
 
-  // CommandBufferStub::DestructionObserver implementation.
-  void OnWillDestroyStub(bool have_context) override;
-
-  std::unique_ptr<ui::ScopedMakeCurrent> MakeStubCurrent();
+  // SharedContextState::ContextLostObserver implementation.
+  void OnContextLost() override;
 
   void UpdateTexImage();
 
@@ -90,8 +93,17 @@
   // IPC message handlers:
   void OnStartListening();
   void OnForwardForSurfaceRequest(const base::UnguessableToken& request_token);
-  void OnSetSize(const gfx::Size& size);
+  void OnCreateSharedImage(const gpu::Mailbox& mailbox,
+                           const gfx::Size& size,
+                           uint32_t release_id);
+  void OnDestroy();
 
+  // An AbstractTexture which owns |surface_owner_texture_id_|, which is used
+  // by |surface_owner_|.
+  std::unique_ptr<gles2::AbstractTexture> surface_owner_texture_;
+  uint32_t surface_owner_texture_id_;
+
+  // The SurfaceOwner which receives frames.
   std::unique_ptr<SurfaceOwner> surface_owner_;
 
   // Current transform matrix of the surface owner.
@@ -103,10 +115,12 @@
   // Whether a new frame is available that we should update to.
   bool has_pending_frame_;
 
-  CommandBufferStub* owner_stub_;
+  GpuChannel* channel_;
   int32_t route_id_;
   bool has_listener_;
-  uint32_t texture_id_;
+  scoped_refptr<SharedContextState> context_state_;
+  SequenceId sequence_;
+  scoped_refptr<gpu::SyncPointClientState> sync_point_client_state_;
 
   base::WeakPtrFactory<StreamTexture> weak_factory_;
   DISALLOW_COPY_AND_ASSIGN(StreamTexture);
diff --git a/ui/gl/gl_image.cc b/ui/gl/gl_image.cc
index 0ab4af7..c54f118 100644
--- a/ui/gl/gl_image.cc
+++ b/ui/gl/gl_image.cc
@@ -34,4 +34,8 @@
 }
 #endif
 
+bool GLImage::HasMutableState() const {
+  return true;
+}
+
 }  // namespace gl
diff --git a/ui/gl/gl_image.h b/ui/gl/gl_image.h
index a6b1e47..3949a09 100644
--- a/ui/gl/gl_image.h
+++ b/ui/gl/gl_image.h
@@ -138,6 +138,10 @@
   enum class Type { NONE, MEMORY, IOSURFACE, DXGI_IMAGE, DXGI_SWAP_CHAIN };
   virtual Type GetType() const;
 
+  // Workaround for StreamTexture which must be re-copied on each access.
+  // TODO(ericrk): Remove this once SharedImage transition is complete.
+  virtual bool HasMutableState() const;
+
  protected:
   virtual ~GLImage() {}