Skip to content

Commit

Permalink
gpu: Migrate Media GPU VDA IPCs to Mojo
Browse files Browse the repository at this point in the history
GpuVideoDecodeAccelerator/Host runs IPCs between renderer and GPU
processes, sharing a route with a specific CommandBufferStub/ProxyImpl.
This is a bit tricky to do with Mojo because Media IPCs are a layer
above GPU, and we therefore need CommandBuffer-associated interfaces
that CommandBuffer doesn't know about.

To facilitate this we introduce a generic BindMediaReceiver API on
CommandBuffer which takes a mojo::GenericPendingAssociatedReceiver, i.e.
an associated interface endpoint that can be of any type. We then
introduce a GPU-side hook that the Media stack can use to handle such
requests.

The primordial associated interface introduced here is
GpuAcceleratedVideoDecoderProvider, which in turn has a single IPC for
binding a GpuAcceleratedVideoDecoder/Client pair, also associated with
the CommandBuffer.

This migration removes the last remaining legacy IPC messages used by
the GPU process, so once this is landed we can altogether remove IPC
Channel from GPU code.

Bug: 1196476, 993189
Change-Id: Ife986434b3c10b5796ce995d837a37c29514af49
Test: manually tested with custom extension doing a hardware VP9 decode via pp::VideoDecoder
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2956897
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Avi Drissman <avi@chromium.org>
Reviewed-by: Sean Topping <seantopping@chromium.org>
Reviewed-by: Robert Sesek <rsesek@chromium.org>
Reviewed-by: Sunny Sachanandani <sunnyps@chromium.org>
Reviewed-by: Dan Sanders <sandersd@chromium.org>
Commit-Queue: Ken Rockot <rockot@google.com>
Cr-Commit-Position: refs/heads/master@{#893111}
  • Loading branch information
krockot authored and Chromium LUCI CQ committed Jun 16, 2021
1 parent b9d7179 commit a55ea67
Show file tree
Hide file tree
Showing 35 changed files with 567 additions and 685 deletions.
1 change: 0 additions & 1 deletion chromecast/media/gpu/cast_gpu_factory_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
#include "media/base/media_util.h"
#include "media/gpu/gpu_video_accelerator_util.h"
#include "media/gpu/ipc/client/gpu_video_decode_accelerator_host.h"
#include "media/gpu/ipc/common/media_messages.h"
#include "media/mojo/clients/mojo_video_decoder.h"
#include "media/mojo/clients/mojo_video_encode_accelerator.h"
#include "services/viz/public/cpp/gpu/context_provider_command_buffer.h"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
#include "gpu/ipc/client/command_buffer_proxy_impl.h"
#include "gpu/ipc/client/gpu_channel_host.h"
#include "media/gpu/gpu_video_accelerator_util.h"
#include "media/gpu/ipc/common/media_messages.h"
#include "services/viz/public/cpp/gpu/context_provider_command_buffer.h"

namespace content {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
#include "gpu/ipc/common/gpu_memory_buffer_support.h"
#include "media/base/bind_to_current_loop.h"
#include "media/gpu/gpu_video_accelerator_util.h"
#include "media/gpu/ipc/common/media_messages.h"
#include "media/mojo/buildflags.h"
#include "media/mojo/clients/mojo_video_decoder.h"
#include "media/mojo/clients/mojo_video_encode_accelerator.h"
Expand Down
5 changes: 5 additions & 0 deletions gpu/ipc/client/command_buffer_proxy_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,11 @@ void CommandBufferProxyImpl::OnDisconnect() {
OnGpuAsyncMessageError(context_lost_reason, gpu::error::kLostContext);
}

void CommandBufferProxyImpl::BindMediaReceiver(
mojo::GenericPendingAssociatedReceiver receiver) {
command_buffer_->BindMediaReceiver(std::move(receiver));
}

void CommandBufferProxyImpl::OnDestroyed(gpu::error::ContextLostReason reason,
gpu::error::Error error) {
base::AutoLockMaybe lock(lock_);
Expand Down
5 changes: 5 additions & 0 deletions gpu/ipc/client/command_buffer_proxy_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ class GPU_EXPORT CommandBufferProxyImpl : public gpu::CommandBuffer,

void OnDisconnect();

// Asks the GPU side to bind an associated interface which will share message
// ordering with this command buffer. Used by media clients for interfaces not
// defined at the GPU layer.
void BindMediaReceiver(mojo::GenericPendingAssociatedReceiver receiver);

// CommandBuffer implementation:
State GetLastState() override;
void Flush(int32_t put_offset) override;
Expand Down
8 changes: 8 additions & 0 deletions gpu/ipc/common/gpu_channel.mojom
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import "gpu/ipc/common/sync_token.mojom";
import "gpu/ipc/common/vulkan_ycbcr_info.mojom";
import "mojo/public/mojom/base/shared_memory.mojom";
import "mojo/public/mojom/base/unguessable_token.mojom";
import "mojo/public/mojom/base/generic_pending_associated_receiver.mojom";
import "services/viz/public/mojom/compositing/resource_format.mojom";
import "skia/public/mojom/image_info.mojom";
import "skia/public/mojom/surface_origin.mojom";
Expand Down Expand Up @@ -268,6 +269,13 @@ interface CommandBuffer {
// then sends a corresponding SignalAck on the CommandBufferClient interface,
// using `signal_id` to identify this request.
SignalQuery(uint32 query, uint32 signal_id);

// Binds an associated interface which shares its message ordering with this
// CommandBuffer. This allows the Media stack above the core GPU layer to
// establish such interfaces without introducing a layering violation. See
// GpuChannel::set_command_buffer_media_binder().
[Sync] BindMediaReceiver(
mojo_base.mojom.GenericPendingAssociatedReceiver receiver) => ();
};

// Corresponds to gpu::SwapBuffersCompleteParams.
Expand Down
10 changes: 10 additions & 0 deletions gpu/ipc/service/command_buffer_stub.cc
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,16 @@ void CommandBufferStub::SignalQuery(uint32_t query_id, uint32_t id) {
OnSignalAck(id);
}
}

void CommandBufferStub::BindMediaReceiver(
mojo::GenericPendingAssociatedReceiver receiver,
BindMediaReceiverCallback callback) {
const auto& binder = channel_->command_buffer_media_binder();
if (binder)
binder.Run(this, std::move(receiver));
std::move(callback).Run();
}

void CommandBufferStub::OnFenceSyncRelease(uint64_t release) {
SyncToken sync_token(CommandBufferNamespace::GPU_IO, command_buffer_id_,
release);
Expand Down
11 changes: 10 additions & 1 deletion gpu/ipc/service/command_buffer_stub.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "gpu/command_buffer/service/context_group.h"
#include "gpu/command_buffer/service/decoder_client.h"
#include "gpu/command_buffer/service/program_cache.h"
#include "gpu/command_buffer/service/scheduler_task_runner.h"
#include "gpu/command_buffer/service/sequence_id.h"
#include "gpu/ipc/common/gpu_channel.mojom.h"
#include "gpu/ipc/common/surface_handle.h"
Expand All @@ -50,7 +51,6 @@ class MemoryTracker;
struct SyncToken;
struct WaitForCommandState;
class GpuChannel;
class SchedulerTaskRunner;
class SyncPointClientState;

// CommandBufferStub is a base class for different CommandBuffer backends
Expand Down Expand Up @@ -89,6 +89,13 @@ class GPU_IPC_SERVICE_EXPORT CommandBufferStub

~CommandBufferStub() override;

// Exposes a SequencedTaskRunner which can be used to schedule tasks in
// sequence with this CommandBufferStub -- that is, on the same gpu::Scheduler
// sequence. Does not support nested loops or delayed tasks.
scoped_refptr<base::SequencedTaskRunner> task_runner() const {
return scheduler_task_runner_;
}

// This must leave the GL context associated with the newly-created
// CommandBufferStub current, so the GpuChannel can initialize
// the gpu::Capabilities.
Expand Down Expand Up @@ -221,6 +228,8 @@ class GPU_IPC_SERVICE_EXPORT CommandBufferStub
void DestroyImage(int32_t id) override;
void SignalSyncToken(const SyncToken& sync_token, uint32_t id) override;
void SignalQuery(uint32_t query, uint32_t id) override;
void BindMediaReceiver(mojo::GenericPendingAssociatedReceiver receiver,
BindMediaReceiverCallback callback) override;

virtual void OnTakeFrontBuffer(const Mailbox& mailbox) {}
virtual void OnReturnFrontBuffer(const Mailbox& mailbox, bool is_lost) {}
Expand Down
62 changes: 1 addition & 61 deletions gpu/ipc/service/gpu_channel.cc
Original file line number Diff line number Diff line change
Expand Up @@ -347,33 +347,7 @@ void GpuChannelMessageFilter::RemoveChannelFilter(
bool GpuChannelMessageFilter::OnMessageReceived(const IPC::Message& message) {
DCHECK(io_thread_checker_.CalledOnValidThread());
DCHECK(ipc_channel_);

if (message.should_unblock() || message.is_reply())
return MessageErrorHandler(message, "Unexpected message type");

for (scoped_refptr<IPC::MessageFilter>& filter : channel_filters_) {
if (filter->OnMessageReceived(message))
return true;
}

base::AutoLock auto_lock(gpu_channel_lock_);
if (!gpu_channel_)
return MessageErrorHandler(message, "Channel destroyed");

if (message.routing_id() == MSG_ROUTING_CONTROL)
return MessageErrorHandler(message, "Invalid control message");

// Messages which do not have sync token dependencies.
SequenceId sequence_id = GetSequenceId(message.routing_id());
if (sequence_id.is_null())
return MessageErrorHandler(message, "Invalid route id");

scheduler_->ScheduleTask(
Scheduler::Task(sequence_id,
base::BindOnce(&gpu::GpuChannel::HandleMessage,
gpu_channel_->AsWeakPtr(), message),
std::vector<SyncToken>()));
return true;
return false;
}

SequenceId GpuChannelMessageFilter::GetSequenceId(int32_t route_id) const {
Expand Down Expand Up @@ -650,18 +624,6 @@ void GpuChannel::Init(IPC::ChannelHandle channel_handle,
channel_ = sync_channel_.get();
}

void GpuChannel::InitForTesting(IPC::Channel* channel) {
channel_ = channel;
// |channel| is an IPC::TestSink in tests, so don't add the filter to it
// because it will forward sent messages back to the filter.
// Call OnFilterAdded() to prevent DCHECK failures.
filter_->OnFilterAdded(channel);
}

void GpuChannel::SetUnhandledMessageListener(IPC::Listener* listener) {
unhandled_message_listener_ = listener;
}

base::WeakPtr<GpuChannel> GpuChannel::AsWeakPtr() {
return weak_factory_.GetWeakPtr();
}
Expand Down Expand Up @@ -820,11 +782,6 @@ void GpuChannel::WaitForGetOffsetInRange(
std::move(callback));
}

void GpuChannel::HandleMessageForTesting(const IPC::Message& msg) {
// Message filter gets message first on IO thread.
filter_->OnMessageReceived(msg);
}

mojom::GpuChannel& GpuChannel::GetGpuChannelForTesting() {
return *filter_;
}
Expand All @@ -847,23 +804,6 @@ bool GpuChannel::CreateSharedImageStub() {
return true;
}

void GpuChannel::HandleMessage(const IPC::Message& msg) {
int32_t routing_id = msg.routing_id();
CommandBufferStub* stub = LookupCommandBuffer(routing_id);

DCHECK(!stub || stub->IsScheduled());

DVLOG(1) << "received message @" << &msg << " on channel @" << this
<< " with type " << msg.type();

bool handled = false;
if (routing_id != MSG_ROUTING_CONTROL)
handled = router_.RouteMessage(msg);

if (!handled && unhandled_message_listener_)
handled = unhandled_message_listener_->OnMessageReceived(msg);
}

#if defined(OS_ANDROID)
const CommandBufferStub* GpuChannel::GetOneStub() const {
for (const auto& kv : stubs_) {
Expand Down
21 changes: 15 additions & 6 deletions gpu/ipc/service/gpu_channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "ipc/ipc_sender.h"
#include "ipc/ipc_sync_channel.h"
#include "ipc/message_router.h"
#include "mojo/public/cpp/bindings/generic_pending_associated_receiver.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gl/gl_share_group.h"
Expand Down Expand Up @@ -84,7 +85,16 @@ class GPU_IPC_SERVICE_EXPORT GpuChannel : public IPC::Listener,

base::WeakPtr<GpuChannel> AsWeakPtr();

void SetUnhandledMessageListener(IPC::Listener* listener);
using CommandBufferMediaBinder =
base::RepeatingCallback<void(CommandBufferStub*,
mojo::GenericPendingAssociatedReceiver)>;
void set_command_buffer_media_binder(CommandBufferMediaBinder binder) {
command_buffer_media_binder_ = std::move(binder);
}

const CommandBufferMediaBinder& command_buffer_media_binder() const {
return command_buffer_media_binder_;
}

// Get the GpuChannelManager that owns this channel.
GpuChannelManager* gpu_channel_manager() const {
Expand Down Expand Up @@ -155,8 +165,6 @@ class GPU_IPC_SERVICE_EXPORT GpuChannel : public IPC::Listener,
gfx::BufferPlane plane,
SurfaceHandle surface_handle);

void HandleMessage(const IPC::Message& msg);

// Executes a DeferredRequest that was previously received and has now been
// scheduled by the scheduler.
void ExecuteDeferredRequest(mojom::DeferredRequestParamsPtr params);
Expand All @@ -173,7 +181,6 @@ class GPU_IPC_SERVICE_EXPORT GpuChannel : public IPC::Listener,
int32_t end,
mojom::GpuChannel::WaitForGetOffsetInRangeCallback callback);

void HandleMessageForTesting(const IPC::Message& msg);
mojom::GpuChannel& GetGpuChannelForTesting();

ImageDecodeAcceleratorStub* GetImageDecodeAcceleratorStub() const;
Expand Down Expand Up @@ -239,6 +246,10 @@ class GPU_IPC_SERVICE_EXPORT GpuChannel : public IPC::Listener,
// The message filter on the io thread.
scoped_refptr<GpuChannelMessageFilter> filter_;

// An optional binder to handle associated interface requests from the Media
// stack, targeting a specific CommandBuffer.
CommandBufferMediaBinder command_buffer_media_binder_;

// Map of routing id to command buffer stub.
base::flat_map<int32_t, std::unique_ptr<CommandBufferStub>> stubs_;

Expand All @@ -256,8 +267,6 @@ class GPU_IPC_SERVICE_EXPORT GpuChannel : public IPC::Listener,
// message loop.
SyncPointManager* const sync_point_manager_;

IPC::Listener* unhandled_message_listener_ = nullptr;

// Used to implement message routing functionality to CommandBuffer objects
IPC::MessageRouter router_;

Expand Down
38 changes: 0 additions & 38 deletions gpu/ipc/service/gpu_channel_test_common.cc
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ GpuChannel* GpuChannelTestCommon::CreateChannel(int32_t client_id,
GpuChannel* channel = channel_manager()->EstablishChannel(
base::UnguessableToken::Create(), client_id, kClientTracingId,
is_gpu_host, true);
channel->InitForTesting(&sink_);
base::ProcessId kProcessId = 1;
channel->OnChannelConnected(kProcessId);
return channel;
Expand Down Expand Up @@ -146,43 +145,6 @@ void GpuChannelTestCommon::CreateCommandBuffer(
loop.Run();
}

void GpuChannelTestCommon::HandleMessage(GpuChannel* channel,
IPC::Message* msg) {
// Some IPCs (such as GpuCommandBufferMsg_Initialize) will generate more
// delayed responses, drop those if they exist.
sink_.ClearMessages();

// Needed to appease DCHECKs.
msg->set_unblock(false);

// Message filter gets message first on IO thread.
channel->HandleMessageForTesting(*msg);

// Run the HandleMessage task posted to the main thread.
task_environment_.RunUntilIdle();

// Replies are sent to the sink.
if (msg->is_sync()) {
const IPC::Message* reply_msg = sink_.GetMessageAt(0);
ASSERT_TRUE(reply_msg);
EXPECT_TRUE(!reply_msg->is_reply_error());

EXPECT_TRUE(IPC::SyncMessage::IsMessageReplyTo(
*reply_msg, IPC::SyncMessage::GetMessageId(*msg)));

IPC::MessageReplyDeserializer* deserializer =
static_cast<IPC::SyncMessage*>(msg)->GetReplyDeserializer();
ASSERT_TRUE(deserializer);
deserializer->SerializeOutputParameters(*reply_msg);

delete deserializer;
}

sink_.ClearMessages();

delete msg;
}

base::UnsafeSharedMemoryRegion GpuChannelTestCommon::GetSharedMemoryRegion() {
return base::UnsafeSharedMemoryRegion::Create(
sizeof(CommandBufferSharedState));
Expand Down
8 changes: 0 additions & 8 deletions gpu/ipc/service/gpu_channel_test_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
#include "gpu/command_buffer/common/capabilities.h"
#include "gpu/command_buffer/common/context_result.h"
#include "gpu/ipc/common/gpu_channel.mojom.h"
#include "ipc/ipc_test_sink.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace base {
Expand All @@ -24,10 +23,6 @@ class MemoryDumpManager;
} // namespace trace_event
} // namespace base

namespace IPC {
class Message;
} // namespace IPC

namespace gpu {
class GpuChannel;
class GpuChannelManager;
Expand Down Expand Up @@ -58,14 +53,11 @@ class GpuChannelTestCommon : public testing::Test {
ContextResult* out_result,
Capabilities* out_capabilities);

void HandleMessage(GpuChannel* channel, IPC::Message* msg);

base::UnsafeSharedMemoryRegion GetSharedMemoryRegion();

private:
base::test::TaskEnvironment task_environment_;
std::unique_ptr<base::trace_event::MemoryDumpManager> memory_dump_manager_;
IPC::TestSink sink_;
std::unique_ptr<SyncPointManager> sync_point_manager_;
std::unique_ptr<SharedImageManager> shared_image_manager_;
std::unique_ptr<Scheduler> scheduler_;
Expand Down
14 changes: 3 additions & 11 deletions ipc/ipc_mojo_bootstrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -529,15 +529,7 @@ class ChannelAssociatedGroupController
task_runner_ = std::move(runner);
client_ = client;

const bool binding_to_calling_sequence =
task_runner_->RunsTasksInCurrentSequence();
const bool binding_to_channel_sequence =
binding_to_calling_sequence &&
(controller_->proxy_task_runner_->RunsTasksInCurrentSequence() ||
controller_->task_runner_->RunsTasksInCurrentSequence());
const bool tried_to_bind_off_sequence =
!binding_to_calling_sequence || !binding_to_channel_sequence;
if (tried_to_bind_off_sequence && CanBindOffSequence())
if (CanBindOffSequence())
was_bound_off_sequence_ = true;
}

Expand Down Expand Up @@ -994,7 +986,6 @@ class ChannelAssociatedGroupController
}

void AcceptSyncMessage(mojo::InterfaceId interface_id, uint32_t message_id) {
DCHECK(proxy_task_runner_->BelongsToCurrentThread());
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("mojom"),
"ChannelAssociatedGroupController::AcceptSyncMessage");

Expand All @@ -1012,7 +1003,8 @@ class ChannelAssociatedGroupController
// Using client->interface_name() is safe here because this is a static
// string defined for each mojo interface.
TRACE_EVENT0("mojom", client->interface_name());
DCHECK(endpoint->task_runner()->RunsTasksInCurrentSequence());
DCHECK(endpoint->task_runner()->RunsTasksInCurrentSequence() ||
proxy_task_runner_->RunsTasksInCurrentSequence());
MessageWrapper message_wrapper = endpoint->PopSyncMessage(message_id);

// The message must have already been dequeued by the endpoint waking up
Expand Down
Loading

0 comments on commit a55ea67

Please sign in to comment.