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() {}