diff options
34 files changed, 579 insertions, 334 deletions
diff --git a/content/common/gpu/gpu_channel.cc b/content/common/gpu/gpu_channel.cc index ba4a74b..e28e14d 100644 --- a/content/common/gpu/gpu_channel.cc +++ b/content/common/gpu/gpu_channel.cc @@ -238,13 +238,11 @@ bool GpuChannel::OnControlMessageReceived(const IPC::Message& msg) { OnCreateOffscreenSurface) IPC_MESSAGE_HANDLER(GpuChannelMsg_DestroySurface, OnDestroySurface) IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateVideoDecoder, - OnCreateVideoDecoder) + OnCreateVideoDecoder) IPC_MESSAGE_HANDLER(GpuChannelMsg_DestroyVideoDecoder, OnDestroyVideoDecoder) IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateTransportTexture, OnCreateTransportTexture) - IPC_MESSAGE_HANDLER(GpuChannelMsg_AssignTexturesToVideoDecoder, - OnAssignTexturesToVideoDecoder) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() DCHECK(handled) << msg.type(); @@ -353,15 +351,13 @@ void GpuChannel::OnCreateVideoDecoder(int32 decoder_host_id, int32 decoder_id = GenerateRouteID(); - // TODO(fischman): this is a BUG. We hand off stub->scheduler()->decoder() - // to be baked into the resulting GpuVideoDecodeAccelerator, but we don't own - // that GVDA, and we make no attempt to tear it down if/when - // stub->scheduler()->decoder() is destroyed. GpuVideoService should be - // subsumed into this class and GpuVideoDecodeAccelerator should be owned by - // the GpuCommandBufferStub that owns the commandbuffer GVDA is using. + // TODO(fischman): this is a BUG. We hand off stub to be baked into the + // resulting GpuVideoDecodeAccelerator, but we don't own that GVDA, and we + // make no attempt to tear it down if/when stub is destroyed. GpuVideoService + // should be subsumed into this class and GpuVideoDecodeAccelerator should be + // owned by GpuCommandBufferStub. bool ret = service->CreateVideoDecoder( - this, &router_, decoder_host_id, decoder_id, stub->scheduler()->decoder(), - configs); + this, &router_, decoder_host_id, decoder_id, stub, configs); DCHECK(ret) << "Failed to create a GpuVideoDecodeAccelerator"; } @@ -393,15 +389,6 @@ void GpuChannel::OnCreateTransportTexture(int32 context_route_id, #endif } -void GpuChannel::OnAssignTexturesToVideoDecoder( - int32 decoder_id, - const std::vector<int32>& buffer_ids, - const std::vector<uint32>& texture_ids, - const std::vector<gfx::Size>& sizes) { - GpuVideoService* service = GpuVideoService::GetInstance(); - service->AssignTexturesToDecoder(decoder_id, buffer_ids, texture_ids, sizes); -} - bool GpuChannel::Init(base::MessageLoopProxy* io_message_loop, base::WaitableEvent* shutdown_event) { // Check whether we're already initialized. diff --git a/content/common/gpu/gpu_channel.h b/content/common/gpu/gpu_channel.h index 6c57a29..8477b92 100644 --- a/content/common/gpu/gpu_channel.h +++ b/content/common/gpu/gpu_channel.h @@ -151,11 +151,6 @@ class GpuChannel : public IPC::Channel::Listener, void OnDestroyVideoDecoder(int32 decoder_id); void OnCreateTransportTexture(int32 context_route_id, int32 host_id); - void OnAssignTexturesToVideoDecoder(int32 decoder_id, - const std::vector<int32>& buffer_ids, - const std::vector<uint32>& texture_ids, - const std::vector<gfx::Size>& sizes); - // The lifetime of objects of this class is managed by a GpuChannelManager. // The GpuChannelManager destroy all the GpuChannels that they own when they // are destroyed. So a raw pointer is safe. diff --git a/content/common/gpu/gpu_command_buffer_stub.cc b/content/common/gpu/gpu_command_buffer_stub.cc index a6b378e..0060831 100644 --- a/content/common/gpu/gpu_command_buffer_stub.cc +++ b/content/common/gpu/gpu_command_buffer_stub.cc @@ -5,6 +5,7 @@ #if defined(ENABLE_GPU) #include "base/bind.h" +#include "base/callback.h" #include "base/debug/trace_event.h" #include "base/process_util.h" #include "base/shared_memory.h" @@ -152,6 +153,8 @@ void GpuCommandBufferStub::OnInitialize( &GpuChannel::OnLatchCallback, base::Unretained(channel_), route_id_)); scheduler_->SetScheduledCallback( NewCallback(this, &GpuCommandBufferStub::OnScheduled)); + scheduler_->SetTokenCallback(base::Bind( + &GpuCommandBufferStub::OnSetToken, base::Unretained(this))); if (watchdog_) scheduler_->SetCommandProcessedCallback( NewCallback(this, &GpuCommandBufferStub::OnCommandProcessed)); @@ -488,6 +491,16 @@ void GpuCommandBufferStub::CommandBufferWasDestroyed() { HandleDeferredMessages(); } +void GpuCommandBufferStub::AddSetTokenCallback( + const base::Callback<void(int32)>& callback) { + set_token_callbacks_.push_back(callback); +} + +void GpuCommandBufferStub::OnSetToken(int32 token) { + for (size_t i = 0; i < set_token_callbacks_.size(); ++i) + set_token_callbacks_[i].Run(token); +} + void GpuCommandBufferStub::ResizeCallback(gfx::Size size) { if (handle_ == gfx::kNullPluginWindow) { scheduler_->decoder()->ResizeOffscreenFrameBuffer(size); diff --git a/content/common/gpu/gpu_command_buffer_stub.h b/content/common/gpu/gpu_command_buffer_stub.h index fa8d7ee..5fdb0e9 100644 --- a/content/common/gpu/gpu_command_buffer_stub.h +++ b/content/common/gpu/gpu_command_buffer_stub.h @@ -63,6 +63,12 @@ class GpuCommandBufferStub // to the same renderer process. int32 route_id() const { return route_id_; } + // Return the current token in the underlying command buffer, or 0 if not yet + // initialized. + int32 token() const { + return command_buffer_.get() ? command_buffer_->GetState().token : 0; + } + #if defined(OS_WIN) // Called only by the compositor window's window proc void OnCompositorWindowPainted(); @@ -84,6 +90,11 @@ class GpuCommandBufferStub // unblock itself and handle pending messages. void CommandBufferWasDestroyed(); + // Register a callback to be Run() whenever the underlying scheduler receives + // a set_token() call. The callback will be Run() with the just-set token as + // its only parameter. Multiple callbacks may be registered. + void AddSetTokenCallback(const base::Callback<void(int32)>& callback); + private: // Message handlers: void OnInitialize(base::SharedMemoryHandle ring_buffer, @@ -126,6 +137,9 @@ class GpuCommandBufferStub void ResizeCallback(gfx::Size size); void ReportState(); + // Callback registered with GpuScheduler to receive set_token() notifications. + void OnSetToken(int32 token); + // The lifetime of objects of this class is managed by a GpuChannel. The // GpuChannels destroy all the GpuCommandBufferStubs that they own when they // are destroyed. So a raw pointer is safe. @@ -147,6 +161,7 @@ class GpuCommandBufferStub scoped_ptr<gpu::CommandBufferService> command_buffer_; scoped_ptr<gpu::GpuScheduler> scheduler_; std::queue<IPC::Message*> deferred_messages_; + std::vector<base::Callback<void(int32)> > set_token_callbacks_; // SetParent may be called before Initialize, in which case we need to keep // around the parent stub, so that Initialize can set the parent correctly. diff --git a/content/common/gpu/gpu_messages.h b/content/common/gpu/gpu_messages.h index f06f927..b17344b 100644 --- a/content/common/gpu/gpu_messages.h +++ b/content/common/gpu/gpu_messages.h @@ -2,10 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// Multiply-included message file, hence no include guard here, but see below +// for a much smaller-than-usual include guard section. + #include <vector> #include <string> - #include "base/shared_memory.h" #include "content/common/common_param_traits.h" #include "content/common/gpu/gpu_info.h" @@ -16,7 +18,6 @@ #include "ipc/ipc_message_macros.h" #include "ui/gfx/native_widget_types.h" #include "ui/gfx/size.h" -// Multiply-included message file, hence no include guard. #define IPC_MESSAGE_START GpuMsgStart @@ -98,6 +99,11 @@ IPC_STRUCT_TRAITS_BEGIN(GPUInfo) #endif IPC_STRUCT_TRAITS_END() +IPC_STRUCT_TRAITS_BEGIN(gpu::ReadWriteTokens) + IPC_STRUCT_TRAITS_MEMBER(last_token_read) + IPC_STRUCT_TRAITS_MEMBER(last_token_written) +IPC_STRUCT_TRAITS_END() + IPC_ENUM_TRAITS(content::CauseForGpuLaunch) //------------------------------------------------------------------------------ @@ -305,11 +311,12 @@ IPC_SYNC_MESSAGE_CONTROL1_1(GpuChannelMsg_CreateOffscreenSurface, IPC_MESSAGE_CONTROL1(GpuChannelMsg_DestroySurface, int /* route_id */) -// Create hardware video decoder && associate it with the output |decoder_id|; +// Create a hardware video decoder; the new route ID is returned through +// AcceleratedVideoDecoderHostMsg_CreateDone. // We need this to be control message because we had to map the GpuChannel and // |decoder_id|. IPC_MESSAGE_CONTROL3(GpuChannelMsg_CreateVideoDecoder, - int32, /* decoder_id */ + int32, /* decoder_host_id */ uint32, /* command buffer route id*/ std::vector<uint32>) /* configs */ @@ -324,13 +331,6 @@ IPC_MESSAGE_CONTROL2(GpuChannelMsg_CreateTransportTexture, int32, /* context_route_id */ int32 /* host_id */) -// Sent from Renderer process to the GPU process to give the texture IDs for -// the textures the decoder will use for output. -IPC_MESSAGE_CONTROL4(GpuChannelMsg_AssignTexturesToVideoDecoder, - int32, /* Decoder ID */ - std::vector<int32>, /* Picture buffer ID */ - std::vector<uint32>, /* Texture ID */ - std::vector<gfx::Size>) /* Size */ //------------------------------------------------------------------------------ // GPU Command Buffer Messages // These are messages between a renderer process to the GPU process relating to @@ -463,45 +463,68 @@ IPC_MESSAGE_ROUTED1(GpuTransportTextureHostMsg_TextureUpdated, //------------------------------------------------------------------------------ // Accelerated Video Decoder Messages // These messages are sent from Renderer process to GPU process. +// +// These messages defer execution until |tokens.last_token_written| is +// seen (using |tokens.last_token_read| as a wrap-around indicator). The +// implementation REQUIRES that |tokens| be the first parameter of these +// messages. + // Message to query configuration information from the GPU process. -IPC_SYNC_MESSAGE_CONTROL1_1(AcceleratedVideoDecoderMsg_GetConfigs, +IPC_SYNC_MESSAGE_CONTROL2_1(AcceleratedVideoDecoderMsg_GetConfigs, + gpu::ReadWriteTokens, /* tokens */ std::vector<uint32>, /* Proto config */ std::vector<uint32>) /* Matching configs */ // Message to initialize the accelerated video decoder. -IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderMsg_Initialize, +IPC_MESSAGE_ROUTED2(AcceleratedVideoDecoderMsg_Initialize, + gpu::ReadWriteTokens, /* tokens */ std::vector<uint32>) /* Config */ // Send input buffer for decoding. -IPC_MESSAGE_ROUTED3(AcceleratedVideoDecoderMsg_Decode, - int32, /* bitstream_buffer_id */ +IPC_MESSAGE_ROUTED4(AcceleratedVideoDecoderMsg_Decode, + gpu::ReadWriteTokens, /* tokens */ base::SharedMemoryHandle, /* input_buffer_handle */ + int32, /* bitstream_buffer_id */ int32) /* size */ +// Sent from Renderer process to the GPU process to give the texture IDs for +// the textures the decoder will use for output. Delays evaluation until +// |token.second| is seen. +IPC_MESSAGE_ROUTED4(AcceleratedVideoDecoderMsg_AssignTextures, + gpu::ReadWriteTokens, /* tokens */ + std::vector<int32>, /* Picture buffer ID */ + std::vector<uint32>, /* Texture ID */ + std::vector<gfx::Size>) /* Size */ + // Sent from Renderer process to the GPU process to give the system memory // buffers that the decoder will use for output. // // The length of the list of SharedMemoryHandles cannot exceed // FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE; see // ipc/file_descriptor_set_posix. -IPC_MESSAGE_ROUTED3(AcceleratedVideoDecoderMsg_AssignSysmemBuffers, +IPC_MESSAGE_ROUTED4(AcceleratedVideoDecoderMsg_AssignSysmemBuffers, + gpu::ReadWriteTokens, /* tokens */ std::vector<int32>, /* Picture buffer ID */ std::vector<base::SharedMemoryHandle>, /* Sysmem buffer */ std::vector<gfx::Size>) /* Size */ // Send from Renderer process to the GPU process to recycle the given picture // buffer for further decoding. -IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderMsg_ReusePictureBuffer, +IPC_MESSAGE_ROUTED2(AcceleratedVideoDecoderMsg_ReusePictureBuffer, + gpu::ReadWriteTokens, /* tokens */ int32) /* Picture buffer ID */ // Send flush request to the decoder. -IPC_MESSAGE_ROUTED0(AcceleratedVideoDecoderMsg_Flush) +IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderMsg_Flush, + gpu::ReadWriteTokens) /* tokens */ // Send abort request to the decoder. -IPC_MESSAGE_ROUTED0(AcceleratedVideoDecoderMsg_Abort) +IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderMsg_Abort, + gpu::ReadWriteTokens) /* tokens */ // Destroy and release decoder asynchronously. -IPC_SYNC_MESSAGE_CONTROL0_0(AcceleratedVideoDecoderMsg_Destroy) +IPC_SYNC_MESSAGE_CONTROL1_0(AcceleratedVideoDecoderMsg_Destroy, + gpu::ReadWriteTokens) /* tokens */ //------------------------------------------------------------------------------ // Accelerated Video Decoder Host Messages diff --git a/content/common/gpu/media/gpu_video_decode_accelerator.cc b/content/common/gpu/media/gpu_video_decode_accelerator.cc index ffe8096..3ca7235 100644 --- a/content/common/gpu/media/gpu_video_decode_accelerator.cc +++ b/content/common/gpu/media/gpu_video_decode_accelerator.cc @@ -8,28 +8,89 @@ #include "base/bind.h" #include "base/logging.h" +#include "base/stl_util-inl.h" +#include "gpu/command_buffer/common/command_buffer.h" #include "ipc/ipc_message_macros.h" #include "ipc/ipc_message_utils.h" #include "content/common/gpu/gpu_channel.h" +#include "content/common/gpu/gpu_command_buffer_stub.h" #include "content/common/gpu/gpu_messages.h" +#include "content/common/gpu/media/gpu_video_service.h" #include "ui/gfx/size.h" GpuVideoDecodeAccelerator::GpuVideoDecodeAccelerator( IPC::Message::Sender* sender, - int32 host_route_id) + int32 host_route_id, + int32 decoder_route_id, + GpuCommandBufferStub* stub) : sender_(sender), - route_id_(host_route_id), + host_route_id_(host_route_id), + decoder_route_id_(decoder_route_id), + stub_(stub), video_decode_accelerator_(NULL) { + stub_->AddSetTokenCallback(base::Bind( + &GpuVideoDecodeAccelerator::OnSetToken, this)); } -GpuVideoDecodeAccelerator::~GpuVideoDecodeAccelerator() {} +GpuVideoDecodeAccelerator::~GpuVideoDecodeAccelerator() { + STLDeleteElements(&deferred_messages_); +} + +void GpuVideoDecodeAccelerator::OnSetToken(int32 token) { + // Note: this always retries all deferred messages on every token arrival. + // There's an optimization to be done here by only trying messages which are + // waiting for tokens which are earlier than |token|. + std::vector<IPC::Message*> deferred_messages_copy; + std::swap(deferred_messages_copy, deferred_messages_); + for (size_t i = 0; i < deferred_messages_copy.size(); ++i) + OnMessageReceived(*deferred_messages_copy[i]); + STLDeleteElements(&deferred_messages_copy); +} + +bool GpuVideoDecodeAccelerator::DeferMessageIfNeeded( + const IPC::Message& msg, bool* deferred) { + // Only consider deferring for message types that need it. + switch (msg.type()) { + case AcceleratedVideoDecoderMsg_GetConfigs::ID: + case AcceleratedVideoDecoderMsg_Initialize::ID: + case AcceleratedVideoDecoderMsg_Decode::ID: + case AcceleratedVideoDecoderMsg_AssignTextures::ID: + case AcceleratedVideoDecoderMsg_AssignSysmemBuffers::ID: + case AcceleratedVideoDecoderMsg_ReusePictureBuffer::ID: + case AcceleratedVideoDecoderMsg_Flush::ID: + case AcceleratedVideoDecoderMsg_Abort::ID: + break; + default: + return false; + } + + gpu::ReadWriteTokens tokens; + void* iter = NULL; + if (!IPC::ParamTraits<gpu::ReadWriteTokens>::Read(&msg, &iter, &tokens)) + return false; + if (tokens.InRange(stub_->token())) { + deferred_messages_.push_back(new IPC::Message(msg)); + *deferred = true; + } else { + *deferred = false; + } + return true; +} bool GpuVideoDecodeAccelerator::OnMessageReceived(const IPC::Message& msg) { + bool deferred = false; + if (!DeferMessageIfNeeded(msg, &deferred)) + return false; + if (deferred) + return true; + bool handled = true; IPC_BEGIN_MESSAGE_MAP(GpuVideoDecodeAccelerator, msg) IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_GetConfigs, OnGetConfigs) IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_Initialize, OnInitialize) IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_Decode, OnDecode) + IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_AssignTextures, + OnAssignTextures) IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_AssignSysmemBuffers, OnAssignSysmemBuffers) IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_ReusePictureBuffer, @@ -54,7 +115,7 @@ void GpuVideoDecodeAccelerator::ProvidePictureBuffers( const gfx::Size& dimensions, media::VideoDecodeAccelerator::MemoryType type) { if (!Send(new AcceleratedVideoDecoderHostMsg_ProvidePictureBuffers( - route_id_, requested_num_of_buffers, dimensions, type))) { + host_route_id_, requested_num_of_buffers, dimensions, type))) { LOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_ProvidePictureBuffers) " << "failed"; } @@ -64,7 +125,7 @@ void GpuVideoDecodeAccelerator::DismissPictureBuffer( int32 picture_buffer_id) { // Notify client that picture buffer is now unused. if (!Send(new AcceleratedVideoDecoderHostMsg_DismissPictureBuffer( - route_id_, picture_buffer_id))) { + host_route_id_, picture_buffer_id))) { LOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_DismissPictureBuffer) " << "failed"; } @@ -73,7 +134,7 @@ void GpuVideoDecodeAccelerator::DismissPictureBuffer( void GpuVideoDecodeAccelerator::PictureReady( const media::Picture& picture) { if (!Send(new AcceleratedVideoDecoderHostMsg_PictureReady( - route_id_, + host_route_id_, picture.picture_buffer_id(), picture.bitstream_buffer_id(), picture.visible_size(), @@ -83,84 +144,96 @@ void GpuVideoDecodeAccelerator::PictureReady( } void GpuVideoDecodeAccelerator::NotifyEndOfStream() { - Send(new AcceleratedVideoDecoderHostMsg_EndOfStream(route_id_)); + Send(new AcceleratedVideoDecoderHostMsg_EndOfStream(host_route_id_)); } void GpuVideoDecodeAccelerator::NotifyError( media::VideoDecodeAccelerator::Error error) { if (!Send(new AcceleratedVideoDecoderHostMsg_ErrorNotification( - route_id_, error))) { + host_route_id_, error))) { LOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_ErrorNotification) " << "failed"; } } void GpuVideoDecodeAccelerator::OnGetConfigs( + const gpu::ReadWriteTokens& /* tokens */, const std::vector<uint32>& requested, std::vector<uint32>* matched) { + // TODO(fischman,vrk): this is borked; can't have a VDA before calling + // Initialize, but can't call Initialize until we have some configs! if (!video_decode_accelerator_.get()) return; video_decode_accelerator_->GetConfigs(requested, matched); } void GpuVideoDecodeAccelerator::OnInitialize( + const gpu::ReadWriteTokens& /* tokens */, const std::vector<uint32>& configs) { - if (!video_decode_accelerator_.get()) - return; - + DCHECK(!video_decode_accelerator_.get()); + GpuVideoService::GetInstance()->InitializeVideoDecoder(decoder_route_id_); + DCHECK(video_decode_accelerator_.get()); video_decode_accelerator_->Initialize(configs); } -void GpuVideoDecodeAccelerator::OnDecode(int32 id, - base::SharedMemoryHandle handle, - int32 size) { - if (!video_decode_accelerator_.get()) - return; +void GpuVideoDecodeAccelerator::OnDecode( + const gpu::ReadWriteTokens&, /* tokens */ + base::SharedMemoryHandle handle, int32 id, int32 size) { + DCHECK(video_decode_accelerator_.get()); video_decode_accelerator_->Decode(media::BitstreamBuffer(id, handle, size)); } void GpuVideoDecodeAccelerator::AssignGLESBuffers( const std::vector<media::GLESBuffer>& buffers) { - if (!video_decode_accelerator_.get()) - return; + // TODO(fischman,vrk): it's wonky that we handle the AssignTextures message by + // handing its contents to GpuVideoService which then turns around and calls + // this (public) method. Instead we should make GpuVideoService vend the + // translation method we need and use it directly. + DCHECK(video_decode_accelerator_.get()); video_decode_accelerator_->AssignGLESBuffers(buffers); } -void GpuVideoDecodeAccelerator::OnAssignSysmemBuffers( +void GpuVideoDecodeAccelerator::OnAssignTextures( + const gpu::ReadWriteTokens& /* tokens */, const std::vector<int32>& buffer_ids, - const std::vector<base::SharedMemoryHandle>& data, + const std::vector<uint32>& texture_ids, const std::vector<gfx::Size>& sizes) { + GpuVideoService* service = GpuVideoService::GetInstance(); + service->AssignTexturesToDecoder( + decoder_route_id_, buffer_ids, texture_ids, sizes); +} + +void GpuVideoDecodeAccelerator::OnAssignSysmemBuffers( + const gpu::ReadWriteTokens& /* tokens */, + const std::vector<int32> buffer_ids, + const std::vector<base::SharedMemoryHandle> data, + const std::vector<gfx::Size> sizes) { // TODO(vrk): Implement. NOTIMPLEMENTED(); } -void GpuVideoDecodeAccelerator::OnReusePictureBuffer(int32 picture_buffer_id) { - if (!video_decode_accelerator_.get()) - return; - +void GpuVideoDecodeAccelerator::OnReusePictureBuffer( + const gpu::ReadWriteTokens& /* tokens */, + int32 picture_buffer_id) { + DCHECK(video_decode_accelerator_.get()); video_decode_accelerator_->ReusePictureBuffer(picture_buffer_id); } -void GpuVideoDecodeAccelerator::OnFlush() { - if (!video_decode_accelerator_.get()) - return; - - if (!video_decode_accelerator_->Flush()) { - NotifyError( - media::VideoDecodeAccelerator::VIDEODECODERERROR_UNEXPECTED_FLUSH); - } +void GpuVideoDecodeAccelerator::OnFlush( + const gpu::ReadWriteTokens& /* tokens */) { + DCHECK(video_decode_accelerator_.get()); + video_decode_accelerator_->Flush(); } -void GpuVideoDecodeAccelerator::OnAbort() { - if (!video_decode_accelerator_.get()) - return; - +void GpuVideoDecodeAccelerator::OnAbort( + const gpu::ReadWriteTokens& /* tokens */) { + DCHECK(video_decode_accelerator_.get()); video_decode_accelerator_->Abort(); } void GpuVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer( int32 bitstream_buffer_id) { if (!Send(new AcceleratedVideoDecoderHostMsg_BitstreamBufferProcessed( - route_id_, bitstream_buffer_id))) { + host_route_id_, bitstream_buffer_id))) { DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_BitstreamBufferProcessed) " << "failed"; @@ -168,17 +241,17 @@ void GpuVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer( } void GpuVideoDecodeAccelerator::NotifyInitializeDone() { - if (!Send(new AcceleratedVideoDecoderHostMsg_InitializeDone(route_id_))) + if (!Send(new AcceleratedVideoDecoderHostMsg_InitializeDone(host_route_id_))) LOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_InitializeDone) failed"; } void GpuVideoDecodeAccelerator::NotifyFlushDone() { - if (!Send(new AcceleratedVideoDecoderHostMsg_FlushDone(route_id_))) + if (!Send(new AcceleratedVideoDecoderHostMsg_FlushDone(host_route_id_))) LOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_FlushDone) failed"; } void GpuVideoDecodeAccelerator::NotifyAbortDone() { - if (!Send(new AcceleratedVideoDecoderHostMsg_AbortDone(route_id_))) + if (!Send(new AcceleratedVideoDecoderHostMsg_AbortDone(host_route_id_))) LOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_AbortDone) failed"; } diff --git a/content/common/gpu/media/gpu_video_decode_accelerator.h b/content/common/gpu/media/gpu_video_decode_accelerator.h index a7e5de3..96954ff 100644 --- a/content/common/gpu/media/gpu_video_decode_accelerator.h +++ b/content/common/gpu/media/gpu_video_decode_accelerator.h @@ -13,13 +13,22 @@ #include "ipc/ipc_message.h" #include "media/video/video_decode_accelerator.h" +namespace gpu { +class ReadWriteTokens; +} + +class GpuCommandBufferStub; + class GpuVideoDecodeAccelerator : public base::RefCountedThreadSafe<GpuVideoDecodeAccelerator>, public IPC::Channel::Listener, public IPC::Message::Sender, public media::VideoDecodeAccelerator::Client { public: - GpuVideoDecodeAccelerator(IPC::Message::Sender* sender, int32 host_route_id); + GpuVideoDecodeAccelerator(IPC::Message::Sender* sender, + int32 host_route_id, + int32 decoder_route_id, + GpuCommandBufferStub* stub); virtual ~GpuVideoDecodeAccelerator(); // IPC::Channel::Listener implementation. @@ -52,24 +61,56 @@ class GpuVideoDecodeAccelerator void AssignGLESBuffers(const std::vector<media::GLESBuffer>& buffers); + // Callback to be fired when the underlying stub receives a new token. + void OnSetToken(int32 token); + private: + // Defers |msg| for later processing if it specifies a write token that hasn't + // come to pass yet, and set |*deferred| to true. Return false if the message + // failed to parse. + bool DeferMessageIfNeeded(const IPC::Message& msg, bool* deferred); + // Handlers for IPC messages. - void OnGetConfigs(const std::vector<uint32>& config, - std::vector<uint32>* configs); - void OnInitialize(const std::vector<uint32>& configs); - void OnDecode(int32 id, base::SharedMemoryHandle handle, int32 size); - void OnAssignSysmemBuffers(const std::vector<int32>& buffer_ids, - const std::vector<base::SharedMemoryHandle>& data, - const std::vector<gfx::Size>& sizes); - void OnReusePictureBuffer(int32 picture_buffer_id); - void OnFlush(); - void OnAbort(); + void OnGetConfigs( + const gpu::ReadWriteTokens& /* tokens */, + const std::vector<uint32>& config, + std::vector<uint32>* configs); + void OnInitialize( + const gpu::ReadWriteTokens& /* tokens */, + const std::vector<uint32>& configs); + void OnDecode( + const gpu::ReadWriteTokens& /* tokens */, + base::SharedMemoryHandle handle, int32 id, int32 size); + void OnAssignTextures( + const gpu::ReadWriteTokens& /* tokens */, + const std::vector<int32>& buffer_ids, + const std::vector<uint32>& texture_ids, + const std::vector<gfx::Size>& sizes); + void OnAssignSysmemBuffers( + const gpu::ReadWriteTokens& /* tokens */, + const std::vector<int32> buffer_ids, + const std::vector<base::SharedMemoryHandle> data, + const std::vector<gfx::Size> sizes); + void OnReusePictureBuffer( + const gpu::ReadWriteTokens& /* tokens */, + int32 picture_buffer_id); + void OnFlush(const gpu::ReadWriteTokens& /* tokens */); + void OnAbort(const gpu::ReadWriteTokens& /* tokens */); // Pointer to the IPC message sender. IPC::Message::Sender* sender_; // Route ID to communicate with the host. - int32 route_id_; + int32 host_route_id_; + + // Route ID of the decoder. + int32 decoder_route_id_; + + // Messages deferred for later processing when their tokens have come to pass. + std::vector<IPC::Message*> deferred_messages_; + + // Unowned pointer to the underlying GpuCommandBufferStub. + GpuCommandBufferStub* stub_; // Pointer to the underlying VideoDecodeAccelerator. scoped_ptr<media::VideoDecodeAccelerator> video_decode_accelerator_; diff --git a/content/common/gpu/media/gpu_video_service.cc b/content/common/gpu/media/gpu_video_service.cc index ebad95bf..2a9562e 100644 --- a/content/common/gpu/media/gpu_video_service.cc +++ b/content/common/gpu/media/gpu_video_service.cc @@ -7,7 +7,6 @@ #include "content/common/gpu/gpu_channel.h" #include "content/common/gpu/gpu_messages.h" #include "content/common/gpu/media/gpu_video_decode_accelerator.h" -#include "gpu/command_buffer/service/gles2_cmd_decoder.h" #if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) #include "content/common/gpu/media/omx_video_decode_accelerator.h" @@ -59,22 +58,14 @@ bool GpuVideoService::CreateVideoDecoder( MessageRouter* router, int32 decoder_host_id, int32 decoder_id, - gpu::gles2::GLES2Decoder* command_decoder, + GpuCommandBufferStub* stub, const std::vector<uint32>& configs) { // Create GpuVideoDecodeAccelerator and add to map. scoped_refptr<GpuVideoDecodeAccelerator> decoder = - new GpuVideoDecodeAccelerator(channel, decoder_host_id); - -#if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) - OmxVideoDecodeAccelerator* omx_decoder = - new OmxVideoDecodeAccelerator(decoder, MessageLoop::current()); - omx_decoder->SetEglState(gfx::GLSurfaceEGL::GetDisplay(), - command_decoder->GetGLContext()->GetHandle()); - decoder->set_video_decode_accelerator(omx_decoder); -#endif // defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) + new GpuVideoDecodeAccelerator(channel, decoder_host_id, decoder_id, stub); bool result = decoder_map_.insert(std::make_pair( - decoder_id, VideoDecoderInfo(decoder, command_decoder))).second; + decoder_id, VideoDecoderInfo(decoder, stub))).second; // Decoder ID is a unique ID determined by GpuVideoServiceHost. // We should always be adding entries here. @@ -90,6 +81,24 @@ bool GpuVideoService::CreateVideoDecoder( return true; } +void GpuVideoService::InitializeVideoDecoder(int32 decoder_id) { +#if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) + DecoderMap::iterator it = decoder_map_.find(decoder_id); + DCHECK(it != decoder_map_.end()); + GpuVideoDecodeAccelerator* decoder = it->second.video_decoder.get(); + GpuCommandBufferStub* stub = it->second.stub; + DCHECK(stub->scheduler()); + OmxVideoDecodeAccelerator* omx_decoder = + new OmxVideoDecodeAccelerator(decoder, MessageLoop::current()); + omx_decoder->SetEglState( + gfx::GLSurfaceEGL::GetDisplay(), + stub->scheduler()->decoder()->GetGLContext()->GetHandle()); + decoder->set_video_decode_accelerator(omx_decoder); +#else + NOTIMPLEMENTED() << "HW video decode acceleration not available."; +#endif // defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) +} + void GpuVideoService::DestroyVideoDecoder( MessageRouter* router, int32 decoder_id) { @@ -106,7 +115,9 @@ void GpuVideoService::AssignTexturesToDecoder( DCHECK(it != decoder_map_.end()); DCHECK_EQ(it->first, decoder_id); GpuVideoDecodeAccelerator* video_decoder = it->second.video_decoder; - gpu::gles2::GLES2Decoder* command_decoder = it->second.command_decoder; + DCHECK(it->second.stub->scheduler()); // Ensure already Initialize()'d. + gpu::gles2::GLES2Decoder* command_decoder = + it->second.stub->scheduler()->decoder(); std::vector<media::GLESBuffer> buffers; for (uint32 i = 0; i < buffer_ids.size(); ++i) { diff --git a/content/common/gpu/media/gpu_video_service.h b/content/common/gpu/media/gpu_video_service.h index e7e9950..2700de8 100644 --- a/content/common/gpu/media/gpu_video_service.h +++ b/content/common/gpu/media/gpu_video_service.h @@ -35,8 +35,9 @@ class GpuVideoService : public IPC::Channel::Listener { MessageRouter* router, int32 decoder_host_id, int32 decoder_id, - gpu::gles2::GLES2Decoder* command_decoder, + GpuCommandBufferStub* stub, const std::vector<uint32>& configs); + void InitializeVideoDecoder(int32 decoder_id); void DestroyVideoDecoder(MessageRouter* router, int32 decoder_id); @@ -49,12 +50,12 @@ class GpuVideoService : public IPC::Channel::Listener { private: struct VideoDecoderInfo { VideoDecoderInfo(scoped_refptr<GpuVideoDecodeAccelerator> g_v_d_a, - gpu::gles2::GLES2Decoder* g_d) + GpuCommandBufferStub* s) : video_decoder(g_v_d_a), - command_decoder(g_d) {} + stub(s) {} ~VideoDecoderInfo() {} scoped_refptr<GpuVideoDecodeAccelerator> video_decoder; - gpu::gles2::GLES2Decoder* command_decoder; + GpuCommandBufferStub* stub; }; // Map of video and command buffer decoders, indexed by video decoder id. typedef std::map<int32, VideoDecoderInfo> DecoderMap; diff --git a/content/common/gpu/media/omx_video_decode_accelerator.cc b/content/common/gpu/media/omx_video_decode_accelerator.cc index 2dfc1da7..36df321 100644 --- a/content/common/gpu/media/omx_video_decode_accelerator.cc +++ b/content/common/gpu/media/omx_video_decode_accelerator.cc @@ -335,12 +335,12 @@ bool OmxVideoDecodeAccelerator::CreateComponent() { return true; } -bool OmxVideoDecodeAccelerator::Decode( +void OmxVideoDecodeAccelerator::Decode( const media::BitstreamBuffer& bitstream_buffer) { DCHECK(!free_input_buffers_.empty()); if (!CanAcceptInput()) - return false; + return; OMX_BUFFERHEADERTYPE* omx_buffer = free_input_buffers_.front(); free_input_buffers_.pop(); @@ -350,7 +350,7 @@ bool OmxVideoDecodeAccelerator::Decode( new base::SharedMemory(bitstream_buffer.handle(), true)); if (!shm->Map(bitstream_buffer.size())) { LOG(ERROR) << "Failed to SharedMemory::Map()."; - return false; + return; } SharedMemoryAndId* input_buffer_details = new SharedMemoryAndId(); input_buffer_details->first.reset(shm.release()); @@ -373,10 +373,9 @@ bool OmxVideoDecodeAccelerator::Decode( if (result != OMX_ErrorNone) { LOG(ERROR) << "OMX_EmptyThisBuffer() failed with result " << result; StopOnError(); - return false; + return; } input_buffers_at_component_++; - return true; } void OmxVideoDecodeAccelerator::AssignGLESBuffers( @@ -440,14 +439,14 @@ void OmxVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { } } -bool OmxVideoDecodeAccelerator::Flush() { +void OmxVideoDecodeAccelerator::Flush() { OMX_STATETYPE il_state; OMX_GetState(component_handle_, &il_state); DCHECK_EQ(il_state, OMX_StateExecuting); // Decode the pending data first. Then flush I/O ports. if (il_state != OMX_StateExecuting) { client_->NotifyFlushDone(); - return false; + return; } on_buffer_flag_event_func_ = &OmxVideoDecodeAccelerator::FlushBegin; @@ -464,10 +463,9 @@ bool OmxVideoDecodeAccelerator::Flush() { if (result != OMX_ErrorNone) { LOG(ERROR) << "OMX_EmptyThisBuffer() failed with result " << result; StopOnError(); - return false; + return; } input_buffers_at_component_++; - return true; } void OmxVideoDecodeAccelerator::FlushBegin() { @@ -525,12 +523,12 @@ void OmxVideoDecodeAccelerator::OutputPortFlushDone(int port) { client_->NotifyFlushDone(); } -bool OmxVideoDecodeAccelerator::Abort() { +void OmxVideoDecodeAccelerator::Abort() { CHECK_EQ(message_loop_, MessageLoop::current()); // Abort() implies immediacy but Flush() actually decodes pending data first. // TODO(vhiremath@nvidia.com) Fix the Abort to handle this immediacy. ShutDownOMXFromExecuting(); - return true; + return; } // Event callback during initialization to handle DoneStateSet to idle diff --git a/content/common/gpu/media/omx_video_decode_accelerator.h b/content/common/gpu/media/omx_video_decode_accelerator.h index 36d9f78..c5d35f7 100644 --- a/content/common/gpu/media/omx_video_decode_accelerator.h +++ b/content/common/gpu/media/omx_video_decode_accelerator.h @@ -37,14 +37,14 @@ class OmxVideoDecodeAccelerator : public media::VideoDecodeAccelerator { bool GetConfigs(const std::vector<uint32>& requested_configs, std::vector<uint32>* matched_configs) OVERRIDE; bool Initialize(const std::vector<uint32>& config) OVERRIDE; - bool Decode(const media::BitstreamBuffer& bitstream_buffer) OVERRIDE; + void Decode(const media::BitstreamBuffer& bitstream_buffer) OVERRIDE; virtual void AssignGLESBuffers( const std::vector<media::GLESBuffer>& buffers) OVERRIDE; virtual void AssignSysmemBuffers( const std::vector<media::SysmemBuffer>& buffers) OVERRIDE; void ReusePictureBuffer(int32 picture_buffer_id) OVERRIDE; - bool Flush() OVERRIDE; - bool Abort() OVERRIDE; + void Flush() OVERRIDE; + void Abort() OVERRIDE; void SetEglState(EGLDisplay egl_display, EGLContext egl_context); diff --git a/content/common/gpu/media/omx_video_decode_accelerator_unittest.cc b/content/common/gpu/media/omx_video_decode_accelerator_unittest.cc index 9b55913..28d1d7c 100644 --- a/content/common/gpu/media/omx_video_decode_accelerator_unittest.cc +++ b/content/common/gpu/media/omx_video_decode_accelerator_unittest.cc @@ -610,7 +610,7 @@ void EglRenderingVDAClient::DecodeNextNALUs() { CHECK(shm.ShareToProcess(base::Process::Current().handle(), &dup_handle)); media::BitstreamBuffer bitstream_buffer( next_bitstream_buffer_id_++, dup_handle, end_pos - start_pos); - CHECK(decoder_->Decode(bitstream_buffer)); + decoder_->Decode(bitstream_buffer); encoded_data_next_pos_to_decode_ = end_pos; } diff --git a/content/renderer/gpu/gpu_channel_host.cc b/content/renderer/gpu/gpu_channel_host.cc index eeb7d62..7bbae72 100644 --- a/content/renderer/gpu/gpu_channel_host.cc +++ b/content/renderer/gpu/gpu_channel_host.cc @@ -60,14 +60,14 @@ bool GpuChannelHost::OnMessageReceived(const IPC::Message& message) { // This is expected, for example an asynchronous SwapBuffers notification // to a command buffer proxy that has since been destroyed. This function // fails silently in that case. + if (gpu_video_service_host_->OnMessageReceived(message)) + return true; return router_.RouteMessage(message); } void GpuChannelHost::OnChannelConnected(int32 peer_pid) { - // When the channel is connected we create a GpuVideoServiceHost and add it - // as a message filter. - channel_->AddFilter(gpu_video_service_host_.get()); channel_->AddFilter(transport_texture_service_.get()); + gpu_video_service_host_->set_channel(channel_.get()); } void GpuChannelHost::OnChannelError() { diff --git a/content/renderer/gpu/gpu_video_decode_accelerator_host.cc b/content/renderer/gpu/gpu_video_decode_accelerator_host.cc index 4f08dab..6aed720 100644 --- a/content/renderer/gpu/gpu_video_decode_accelerator_host.cc +++ b/content/renderer/gpu/gpu_video_decode_accelerator_host.cc @@ -4,14 +4,19 @@ #include "content/renderer/gpu/gpu_video_decode_accelerator_host.h" +#include "base/bind.h" #include "base/logging.h" +#include "base/message_loop.h" #include "base/shared_memory.h" #include "base/task.h" #include "content/common/gpu/gpu_messages.h" #include "content/common/view_messages.h" #include "content/renderer/render_thread.h" +#include "gpu/command_buffer/client/cmd_buffer_helper.h" +#include "gpu/command_buffer/common/command_buffer.h" #include "ipc/ipc_message_macros.h" #include "ipc/ipc_message_utils.h" +#include "ipc/ipc_platform_file.h" using media::VideoDecodeAccelerator; @@ -19,14 +24,18 @@ GpuVideoDecodeAcceleratorHost::GpuVideoDecodeAcceleratorHost( MessageRouter* router, IPC::Message::Sender* ipc_sender, int32 decoder_host_id, - uint32 command_buffer_route_id, + int32 command_buffer_route_id, + gpu::CommandBufferHelper* cmd_buffer_helper, VideoDecodeAccelerator::Client* client) : router_(router), ipc_sender_(ipc_sender), decoder_host_id_(decoder_host_id), - decoder_id_(0), + decoder_id_(-1), command_buffer_route_id_(command_buffer_route_id), + cmd_buffer_helper_(cmd_buffer_helper), client_(client) { + DCHECK(RenderThread::current()); + DCHECK_EQ(RenderThread::current()->message_loop(), MessageLoop::current()); } GpuVideoDecodeAcceleratorHost::~GpuVideoDecodeAcceleratorHost() {} @@ -39,6 +48,7 @@ void GpuVideoDecodeAcceleratorHost::OnChannelError() { } bool GpuVideoDecodeAcceleratorHost::OnMessageReceived(const IPC::Message& msg) { + DCHECK(CalledOnValidThread()); bool handled = true; IPC_BEGIN_MESSAGE_MAP(GpuVideoDecodeAcceleratorHost, msg) IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_BitstreamBufferProcessed, @@ -65,6 +75,16 @@ bool GpuVideoDecodeAcceleratorHost::OnMessageReceived(const IPC::Message& msg) { return handled; } +gpu::ReadWriteTokens GpuVideoDecodeAcceleratorHost::SyncTokens() { + DCHECK(CalledOnValidThread()); + // Note that the order below matters. InsertToken() must happen before + // Flush() and last_token_read() should be read before InsertToken(). + int32 read = cmd_buffer_helper_->last_token_read(); + int32 written = cmd_buffer_helper_->InsertToken(); + cmd_buffer_helper_->Flush(); + return gpu::ReadWriteTokens(read, written); +} + bool GpuVideoDecodeAcceleratorHost::GetConfigs( const std::vector<uint32>& requested_configs, std::vector<uint32>* matched_configs) { @@ -75,34 +95,35 @@ bool GpuVideoDecodeAcceleratorHost::GetConfigs( bool GpuVideoDecodeAcceleratorHost::Initialize( const std::vector<uint32>& configs) { + DCHECK(CalledOnValidThread()); router_->AddRoute(decoder_host_id_, this); // Temporarily save configs for after create is done and we're // ready to initialize. configs_ = configs; - if (!ipc_sender_->Send(new GpuChannelMsg_CreateVideoDecoder( - decoder_id_, command_buffer_route_id_, configs))) { + decoder_host_id_, command_buffer_route_id_, configs))) { LOG(ERROR) << "Send(GpuChannelMsg_CreateVideoDecoder) failed"; return false; } return true; } -bool GpuVideoDecodeAcceleratorHost::Decode( +void GpuVideoDecodeAcceleratorHost::Decode( const media::BitstreamBuffer& bitstream_buffer) { + DCHECK(CalledOnValidThread()); if (!ipc_sender_->Send(new AcceleratedVideoDecoderMsg_Decode( - decoder_id_, bitstream_buffer.id(), - bitstream_buffer.handle(), bitstream_buffer.size()))) { + decoder_id_, SyncTokens(), bitstream_buffer.handle(), + bitstream_buffer.id(), bitstream_buffer.size()))) { DLOG(ERROR) << "Send(AcceleratedVideoDecoderMsg_Decode) failed"; - return false; + // TODO(fischman/vrk): signal error to client. + return; } - - return true; } void GpuVideoDecodeAcceleratorHost::AssignGLESBuffers( const std::vector<media::GLESBuffer>& buffers) { + DCHECK(CalledOnValidThread()); // Rearrange data for IPC command. std::vector<int32> buffer_ids; std::vector<uint32> texture_ids; @@ -113,44 +134,51 @@ void GpuVideoDecodeAcceleratorHost::AssignGLESBuffers( buffer_ids.push_back(buffer.id()); sizes.push_back(buffer.size()); } - if (!ipc_sender_->Send(new GpuChannelMsg_AssignTexturesToVideoDecoder( - decoder_id_, buffer_ids, texture_ids, sizes))) { + if (!ipc_sender_->Send(new AcceleratedVideoDecoderMsg_AssignTextures( + decoder_id_, SyncTokens(), buffer_ids, texture_ids, sizes))) { LOG(ERROR) << "Send(AcceleratedVideoDecoderMsg_AssignGLESBuffers) failed"; } } void GpuVideoDecodeAcceleratorHost::AssignSysmemBuffers( const std::vector<media::SysmemBuffer>& buffers) { + DCHECK(CalledOnValidThread()); // TODO(vrk): Implement. NOTIMPLEMENTED(); } void GpuVideoDecodeAcceleratorHost::ReusePictureBuffer( int32 picture_buffer_id) { + DCHECK(CalledOnValidThread()); if (!ipc_sender_->Send(new AcceleratedVideoDecoderMsg_ReusePictureBuffer( - decoder_id_, picture_buffer_id))) { + decoder_id_, SyncTokens(), picture_buffer_id))) { LOG(ERROR) << "Send(AcceleratedVideoDecoderMsg_ReusePictureBuffer) failed"; } } -bool GpuVideoDecodeAcceleratorHost::Flush() { - if (!ipc_sender_->Send(new AcceleratedVideoDecoderMsg_Flush(decoder_id_))) { +void GpuVideoDecodeAcceleratorHost::Flush() { + DCHECK(CalledOnValidThread()); + if (!ipc_sender_->Send(new AcceleratedVideoDecoderMsg_Flush( + decoder_id_, SyncTokens()))) { LOG(ERROR) << "Send(AcceleratedVideoDecoderMsg_Flush) failed"; - return false; + // TODO(fischman/vrk): signal error to client. + return; } - return true; } -bool GpuVideoDecodeAcceleratorHost::Abort() { - if (!ipc_sender_->Send(new AcceleratedVideoDecoderMsg_Abort(decoder_id_))) { +void GpuVideoDecodeAcceleratorHost::Abort() { + DCHECK(CalledOnValidThread()); + if (!ipc_sender_->Send(new AcceleratedVideoDecoderMsg_Abort( + decoder_id_, SyncTokens()))) { LOG(ERROR) << "Send(AcceleratedVideoDecoderMsg_Abort) failed"; - return false; + // TODO(fischman/vrk): signal error to client. + return; } - return true; } void GpuVideoDecodeAcceleratorHost::OnBitstreamBufferProcessed( int32 bitstream_buffer_id) { + DCHECK(CalledOnValidThread()); client_->NotifyEndOfBitstreamBuffer(bitstream_buffer_id); } @@ -158,6 +186,7 @@ void GpuVideoDecodeAcceleratorHost::OnProvidePictureBuffer( uint32 num_requested_buffers, const gfx::Size& buffer_size, int32 mem_type) { + DCHECK(CalledOnValidThread()); media::VideoDecodeAccelerator::MemoryType converted_mem_type = static_cast<media::VideoDecodeAccelerator::MemoryType>(mem_type); client_->ProvidePictureBuffers( @@ -166,42 +195,50 @@ void GpuVideoDecodeAcceleratorHost::OnProvidePictureBuffer( void GpuVideoDecodeAcceleratorHost::OnDismissPictureBuffer( int32 picture_buffer_id) { + DCHECK(CalledOnValidThread()); client_->DismissPictureBuffer(picture_buffer_id); } void GpuVideoDecodeAcceleratorHost::OnCreateDone(int32 decoder_id) { + DCHECK(CalledOnValidThread()); decoder_id_ = decoder_id; if (!ipc_sender_->Send(new AcceleratedVideoDecoderMsg_Initialize( - decoder_id_, configs_))) { + decoder_id_, SyncTokens(), configs_))) { LOG(ERROR) << "Send(AcceleratedVideoDecoderMsg_Initialize) failed"; } } void GpuVideoDecodeAcceleratorHost::OnInitializeDone() { + DCHECK(CalledOnValidThread()); client_->NotifyInitializeDone(); } void GpuVideoDecodeAcceleratorHost::OnPictureReady( int32 picture_buffer_id, int32 bitstream_buffer_id, const gfx::Size& visible_size, const gfx::Size& decoded_size) { + DCHECK(CalledOnValidThread()); media::Picture picture( picture_buffer_id, bitstream_buffer_id, visible_size, decoded_size); client_->PictureReady(picture); } void GpuVideoDecodeAcceleratorHost::OnFlushDone() { + DCHECK(CalledOnValidThread()); client_->NotifyFlushDone(); } void GpuVideoDecodeAcceleratorHost::OnAbortDone() { + DCHECK(CalledOnValidThread()); client_->NotifyAbortDone(); } void GpuVideoDecodeAcceleratorHost::OnEndOfStream() { + DCHECK(CalledOnValidThread()); client_->NotifyEndOfStream(); } void GpuVideoDecodeAcceleratorHost::OnErrorNotification(uint32 error) { + DCHECK(CalledOnValidThread()); client_->NotifyError( static_cast<media::VideoDecodeAccelerator::Error>(error)); } diff --git a/content/renderer/gpu/gpu_video_decode_accelerator_host.h b/content/renderer/gpu/gpu_video_decode_accelerator_host.h index ea73da0..9012168 100644 --- a/content/renderer/gpu/gpu_video_decode_accelerator_host.h +++ b/content/renderer/gpu/gpu_video_decode_accelerator_host.h @@ -9,23 +9,31 @@ #include "base/memory/scoped_ptr.h" #include "base/shared_memory.h" +#include "base/threading/non_thread_safe.h" #include "ipc/ipc_channel.h" #include "media/video/video_decode_accelerator.h" class MessageLoop; class MessageRouter; +namespace gpu { +class CommandBufferHelper; +class ReadWriteTokens; +} // This class is used to talk to VideoDecodeAccelerator in the Gpu process // through IPC messages. -class GpuVideoDecodeAcceleratorHost : public IPC::Channel::Listener, - public media::VideoDecodeAccelerator { +class GpuVideoDecodeAcceleratorHost + : public IPC::Channel::Listener, + public media::VideoDecodeAccelerator, + public base::NonThreadSafe { public: // |router| is used to dispatch IPC messages to this object. // |ipc_sender| is used to send IPC messages to Gpu process. GpuVideoDecodeAcceleratorHost(MessageRouter* router, IPC::Message::Sender* ipc_sender, int32 decoder_host_id, - uint32 command_buffer_route_id, + int32 command_buffer_route_id, + gpu::CommandBufferHelper* cmd_buffer_helper, media::VideoDecodeAccelerator::Client* client); virtual ~GpuVideoDecodeAcceleratorHost(); @@ -39,16 +47,20 @@ class GpuVideoDecodeAcceleratorHost : public IPC::Channel::Listener, const std::vector<uint32>& requested_configs, std::vector<uint32>* matched_configs) OVERRIDE; virtual bool Initialize(const std::vector<uint32>& configs) OVERRIDE; - virtual bool Decode(const media::BitstreamBuffer& bitstream_buffer) OVERRIDE; + virtual void Decode(const media::BitstreamBuffer& bitstream_buffer) OVERRIDE; virtual void AssignGLESBuffers( const std::vector<media::GLESBuffer>& buffers) OVERRIDE; virtual void AssignSysmemBuffers( const std::vector<media::SysmemBuffer>& buffers) OVERRIDE; virtual void ReusePictureBuffer(int32 picture_buffer_id) OVERRIDE; - virtual bool Flush() OVERRIDE; - virtual bool Abort() OVERRIDE; + virtual void Flush() OVERRIDE; + virtual void Abort() OVERRIDE; private: + // Insert a token into the command buffer and return a token-pair suitable for + // sending over IPC for synchronization with the command buffer. + gpu::ReadWriteTokens SyncTokens(); + void OnBitstreamBufferProcessed(int32 bitstream_buffer_id); void OnProvidePictureBuffer( uint32 num_requested_buffers, const gfx::Size& buffer_size, int32 mem_type); @@ -78,7 +90,18 @@ class GpuVideoDecodeAcceleratorHost : public IPC::Channel::Listener, // Route ID for the command buffer associated with the context the GPU Video // Decoder uses. - uint32 command_buffer_route_id_; + // TODO(fischman): storing route_id's for GPU process entities in the renderer + // process is vulnerable to GPU process crashing & being respawned, and + // attempting to use an outdated or reused route id. + int32 command_buffer_route_id_; + + // Helper for the command buffer associated with the context the GPU Video + // Decoder uses. + // TODO(fischman): in the out-of-process case, this won't work + // (context3d->gles2_impl() will be NULL), and will have to be replaced with a + // dedicated message such as WaitForToken, which will serialize subsequent + // message processing behind it. + gpu::CommandBufferHelper* cmd_buffer_helper_; // Temporarily store configs here in between Create and Initialize phase. std::vector<uint32> configs_; diff --git a/content/renderer/gpu/gpu_video_service_host.cc b/content/renderer/gpu/gpu_video_service_host.cc index 9b3fe22..2a39476 100644 --- a/content/renderer/gpu/gpu_video_service_host.cc +++ b/content/renderer/gpu/gpu_video_service_host.cc @@ -12,32 +12,25 @@ GpuVideoServiceHost::GpuVideoServiceHost() : channel_(NULL), next_decoder_host_id_(0) { + DCHECK(RenderThread::current()); + DCHECK_EQ(RenderThread::current()->message_loop(), MessageLoop::current()); } GpuVideoServiceHost::~GpuVideoServiceHost() { } -void GpuVideoServiceHost::OnFilterAdded(IPC::Channel* channel) { - base::Closure on_initialized; - { - base::AutoLock auto_lock(lock_); - DCHECK(!channel_); - channel_ = channel; - on_initialized = on_initialized_; - } - if (!on_initialized.is_null()) - on_initialized.Run(); -} - -void GpuVideoServiceHost::OnFilterRemoved() { - // TODO(hclam): Implement. -} - -void GpuVideoServiceHost::OnChannelClosing() { - // TODO(hclam): Implement. +void GpuVideoServiceHost::set_channel(IPC::SyncChannel* channel) { + DCHECK(CalledOnValidThread()); + DCHECK(!channel_); + channel_ = channel; + if (!on_initialized_.is_null()) + on_initialized_.Run(); } bool GpuVideoServiceHost::OnMessageReceived(const IPC::Message& msg) { + DCHECK(CalledOnValidThread()); + if (!channel_) + return false; switch (msg.type()) { case AcceleratedVideoDecoderHostMsg_BitstreamBufferProcessed::ID: case AcceleratedVideoDecoderHostMsg_ProvidePictureBuffers::ID: @@ -57,25 +50,27 @@ bool GpuVideoServiceHost::OnMessageReceived(const IPC::Message& msg) { } } +void GpuVideoServiceHost::OnChannelError() { + DCHECK(CalledOnValidThread()); + channel_ = NULL; +} + void GpuVideoServiceHost::SetOnInitialized( const base::Closure& on_initialized) { - IPC::Channel* channel; - { - base::AutoLock auto_lock(lock_); - DCHECK(on_initialized_.is_null()); - on_initialized_ = on_initialized; - channel = channel_; - } - if (channel) + DCHECK(CalledOnValidThread()); + DCHECK(on_initialized_.is_null()); + on_initialized_ = on_initialized; + if (channel_) on_initialized.Run(); } GpuVideoDecodeAcceleratorHost* GpuVideoServiceHost::CreateVideoAccelerator( media::VideoDecodeAccelerator::Client* client, - int command_buffer_route_id) { - base::AutoLock auto_lock(lock_); + int32 command_buffer_route_id, + gpu::CommandBufferHelper* cmd_buffer_helper) { + DCHECK(CalledOnValidThread()); DCHECK(channel_); return new GpuVideoDecodeAcceleratorHost( &router_, channel_, next_decoder_host_id_++, - command_buffer_route_id, client); + command_buffer_route_id, cmd_buffer_helper, client); } diff --git a/content/renderer/gpu/gpu_video_service_host.h b/content/renderer/gpu/gpu_video_service_host.h index 83028c11..db519ef 100644 --- a/content/renderer/gpu/gpu_video_service_host.h +++ b/content/renderer/gpu/gpu_video_service_host.h @@ -6,6 +6,7 @@ #define CONTENT_RENDERER_GPU_GPU_VIDEO_SERVICE_HOST_H_ #include "base/memory/singleton.h" +#include "base/threading/non_thread_safe.h" #include "content/renderer/gpu/gpu_channel_host.h" #include "ipc/ipc_channel.h" #include "media/base/buffers.h" @@ -13,19 +14,26 @@ #include "media/video/video_decode_accelerator.h" class GpuVideoDecodeAcceleratorHost; +namespace gpu { +class CommandBufferHelper; +} -// GpuVideoServiceHost lives on IO thread and is used to dispatch IPC messages -// to GpuVideoDecoderHost objects. -class GpuVideoServiceHost : public IPC::ChannelProxy::MessageFilter { +// GpuVideoServiceHost lives on renderer thread and is used to dispatch IPC +// messages to GpuVideoDecodeAcceleratorHost objects. +class GpuVideoServiceHost + : public IPC::Channel::Listener, + public base::NonThreadSafe, + public base::RefCountedThreadSafe<GpuVideoServiceHost> { public: GpuVideoServiceHost(); virtual ~GpuVideoServiceHost(); - // IPC::ChannelProxy::MessageFilter implementations, called on IO thread. - virtual bool OnMessageReceived(const IPC::Message& message); - virtual void OnFilterAdded(IPC::Channel* channel); - virtual void OnFilterRemoved(); - virtual void OnChannelClosing(); + void set_channel(IPC::SyncChannel* channel); + + // IPC::Channel::Listener implementation; called on render thread because of + // GpuChannelHost's use of a ChannelProxy/SyncChannel. + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + virtual void OnChannelError() OVERRIDE; // Register a callback to be notified when |*this| can be used to // CreateVideo{Decoder,Accelerator} below. Called on RenderThread. @@ -38,14 +46,12 @@ class GpuVideoServiceHost : public IPC::ChannelProxy::MessageFilter { // in the GPU process. GpuVideoDecodeAcceleratorHost* CreateVideoAccelerator( media::VideoDecodeAccelerator::Client* client, - int command_buffer_route_id); + int32 command_buffer_route_id, + gpu::CommandBufferHelper* cmd_buffer_helper); private: - // Guards all members other than |router_|. - base::Lock lock_; - // Reference to the channel that the service listens to. - IPC::Channel* channel_; + IPC::SyncChannel* channel_; // Router to send messages to a GpuVideoDecoderHost. MessageRouter router_; diff --git a/content/renderer/pepper_platform_video_decoder_impl.cc b/content/renderer/pepper_platform_video_decoder_impl.cc index 1217bb9..8e186c8 100644 --- a/content/renderer/pepper_platform_video_decoder_impl.cc +++ b/content/renderer/pepper_platform_video_decoder_impl.cc @@ -17,11 +17,13 @@ using media::BitstreamBuffer; PlatformVideoDecoderImpl::PlatformVideoDecoderImpl( - VideoDecodeAccelerator::Client* client, uint32 command_buffer_route_id) + VideoDecodeAccelerator::Client* client, + int32 command_buffer_route_id, + gpu::CommandBufferHelper* cmd_buffer_helper) : client_(client), command_buffer_route_id_(command_buffer_route_id), - decoder_(NULL), - message_loop_(NULL) { + cmd_buffer_helper_(cmd_buffer_helper), + decoder_(NULL) { DCHECK(client); } @@ -42,8 +44,6 @@ bool PlatformVideoDecoderImpl::Initialize(const std::vector<uint32>& config) { RenderThread* render_thread = RenderThread::current(); DCHECK(render_thread); - message_loop_ = MessageLoop::current(); - DCHECK(message_loop_); channel_ = render_thread->EstablishGpuChannelSync( content::CAUSE_FOR_GPU_LAUNCH_VIDEODECODEACCELERATOR_INITIALIZE); @@ -67,26 +67,18 @@ bool PlatformVideoDecoderImpl::Initialize(const std::vector<uint32>& config) { void PlatformVideoDecoderImpl::InitializeDecoder( const std::vector<uint32>& configs) { - // Only create GpuVideoDecodeAcceleratorHost on IO thread. - if (ChildProcess::current()->io_message_loop() != MessageLoop::current() ) { - ChildProcess::current()->io_message_loop()-> - PostTask(FROM_HERE, base::Bind( - &PlatformVideoDecoderImpl::InitializeDecoder, - base::Unretained(this), - configs)); - return; - } + DCHECK_EQ(RenderThread::current()->message_loop(), MessageLoop::current()); GpuVideoServiceHost* video_service = channel_->gpu_video_service_host(); decoder_.reset(video_service->CreateVideoAccelerator( - this, command_buffer_route_id_)); + this, command_buffer_route_id_, cmd_buffer_helper_)); // Send IPC message to initialize decoder in GPU process. decoder_->Initialize(configs); } -bool PlatformVideoDecoderImpl::Decode(const BitstreamBuffer& bitstream_buffer) { +void PlatformVideoDecoderImpl::Decode(const BitstreamBuffer& bitstream_buffer) { DCHECK(decoder_.get()); - return decoder_->Decode(bitstream_buffer); + decoder_->Decode(bitstream_buffer); } void PlatformVideoDecoderImpl::AssignGLESBuffers( @@ -107,96 +99,62 @@ void PlatformVideoDecoderImpl::ReusePictureBuffer( decoder_->ReusePictureBuffer(picture_buffer_id); } -bool PlatformVideoDecoderImpl::Flush() { +void PlatformVideoDecoderImpl::Flush() { DCHECK(decoder_.get()); - return decoder_->Flush(); + decoder_->Flush(); } -bool PlatformVideoDecoderImpl::Abort() { +void PlatformVideoDecoderImpl::Abort() { DCHECK(decoder_.get()); - return decoder_->Abort(); + decoder_->Abort(); } void PlatformVideoDecoderImpl::NotifyEndOfStream() { - DCHECK(message_loop_); - message_loop_-> - PostTask(FROM_HERE, base::Bind( - &VideoDecodeAccelerator::Client::NotifyEndOfStream, - base::Unretained(client_))); + DCHECK_EQ(RenderThread::current()->message_loop(), MessageLoop::current()); + client_->NotifyEndOfStream(); } void PlatformVideoDecoderImpl::NotifyError( VideoDecodeAccelerator::Error error) { - DCHECK(message_loop_); - message_loop_-> - PostTask(FROM_HERE, base::Bind( - &VideoDecodeAccelerator::Client::NotifyError, - base::Unretained(client_), - error)); + DCHECK_EQ(RenderThread::current()->message_loop(), MessageLoop::current()); + client_->NotifyError(error); } void PlatformVideoDecoderImpl::ProvidePictureBuffers( uint32 requested_num_of_buffers, const gfx::Size& dimensions, media::VideoDecodeAccelerator::MemoryType type) { - DCHECK(message_loop_); - message_loop_-> - PostTask(FROM_HERE, base::Bind( - &VideoDecodeAccelerator::Client::ProvidePictureBuffers, - base::Unretained(client_), - requested_num_of_buffers, - dimensions, - type)); + DCHECK_EQ(RenderThread::current()->message_loop(), MessageLoop::current()); + client_->ProvidePictureBuffers(requested_num_of_buffers, dimensions, type); } void PlatformVideoDecoderImpl::DismissPictureBuffer(int32 picture_buffer_id) { - DCHECK(message_loop_); - message_loop_-> - PostTask(FROM_HERE, base::Bind( - &VideoDecodeAccelerator::Client::DismissPictureBuffer, - base::Unretained(client_), - picture_buffer_id)); + DCHECK_EQ(RenderThread::current()->message_loop(), MessageLoop::current()); + client_->DismissPictureBuffer(picture_buffer_id); } void PlatformVideoDecoderImpl::PictureReady(const media::Picture& picture) { - DCHECK(message_loop_); - message_loop_-> - PostTask(FROM_HERE, base::Bind( - &VideoDecodeAccelerator::Client::PictureReady, - base::Unretained(client_), - picture)); + DCHECK_EQ(RenderThread::current()->message_loop(), MessageLoop::current()); + client_->PictureReady(picture); } void PlatformVideoDecoderImpl::NotifyInitializeDone() { - DCHECK(message_loop_); - message_loop_-> - PostTask(FROM_HERE, base::Bind( - &VideoDecodeAccelerator::Client::NotifyInitializeDone, - base::Unretained(client_))); + DCHECK_EQ(RenderThread::current()->message_loop(), MessageLoop::current()); + client_->NotifyInitializeDone(); } void PlatformVideoDecoderImpl::NotifyEndOfBitstreamBuffer( int32 bitstream_buffer_id) { - DCHECK(message_loop_); - message_loop_-> - PostTask(FROM_HERE, base::Bind( - &VideoDecodeAccelerator::Client::NotifyEndOfBitstreamBuffer, - base::Unretained(client_), - bitstream_buffer_id)); + DCHECK_EQ(RenderThread::current()->message_loop(), MessageLoop::current()); + client_->NotifyEndOfBitstreamBuffer(bitstream_buffer_id); } void PlatformVideoDecoderImpl::NotifyFlushDone() { - DCHECK(message_loop_); - message_loop_-> - PostTask(FROM_HERE, base::Bind( - &VideoDecodeAccelerator::Client::NotifyFlushDone, - base::Unretained(client_))); + DCHECK_EQ(RenderThread::current()->message_loop(), MessageLoop::current()); + client_->NotifyFlushDone(); } void PlatformVideoDecoderImpl::NotifyAbortDone() { - DCHECK(message_loop_); - message_loop_-> - PostTask(FROM_HERE, base::Bind( - &VideoDecodeAccelerator::Client::NotifyAbortDone, - base::Unretained(client_))); + DCHECK_EQ(RenderThread::current()->message_loop(), MessageLoop::current()); + client_->NotifyAbortDone(); } diff --git a/content/renderer/pepper_platform_video_decoder_impl.h b/content/renderer/pepper_platform_video_decoder_impl.h index 4f10db6..703bc91 100644 --- a/content/renderer/pepper_platform_video_decoder_impl.h +++ b/content/renderer/pepper_platform_video_decoder_impl.h @@ -14,15 +14,19 @@ #include "webkit/plugins/ppapi/plugin_delegate.h" class GpuChannelHost; +namespace gpu { +class CommandBufferHelper; +} class PlatformVideoDecoderImpl : public webkit::ppapi::PluginDelegate::PlatformVideoDecoder, public media::VideoDecodeAccelerator::Client, public base::RefCountedThreadSafe<PlatformVideoDecoderImpl> { public: - explicit PlatformVideoDecoderImpl( + PlatformVideoDecoderImpl( media::VideoDecodeAccelerator::Client* client, - uint32 command_buffer_route_id); + int32 command_buffer_route_id, + gpu::CommandBufferHelper* cmd_buffer_helper); virtual ~PlatformVideoDecoderImpl(); // PlatformVideoDecoder implementation. @@ -30,15 +34,15 @@ class PlatformVideoDecoderImpl const std::vector<uint32>& requested_configs, std::vector<uint32>* matched_configs) OVERRIDE; virtual bool Initialize(const std::vector<uint32>& config) OVERRIDE; - virtual bool Decode( + virtual void Decode( const media::BitstreamBuffer& bitstream_buffer) OVERRIDE; virtual void AssignGLESBuffers( const std::vector<media::GLESBuffer>& buffers) OVERRIDE; virtual void AssignSysmemBuffers( const std::vector<media::SysmemBuffer>& buffers) OVERRIDE; virtual void ReusePictureBuffer(int32 picture_buffer_id); - virtual bool Flush() OVERRIDE; - virtual bool Abort() OVERRIDE; + virtual void Flush() OVERRIDE; + virtual void Abort() OVERRIDE; // VideoDecodeAccelerator::Client implementation. virtual void ProvidePictureBuffers( @@ -65,7 +69,10 @@ class PlatformVideoDecoderImpl media::VideoDecodeAccelerator::Client* client_; // Route ID for the command buffer associated with video decoder's context. - uint32 command_buffer_route_id_; + int32 command_buffer_route_id_; + + // Helper for the command buffer associated with video decoder's context. + gpu::CommandBufferHelper* cmd_buffer_helper_; // Host for GpuVideoDecodeAccelerator. scoped_ptr<media::VideoDecodeAccelerator> decoder_; @@ -73,9 +80,6 @@ class PlatformVideoDecoderImpl // Host for Gpu Channel. scoped_refptr<GpuChannelHost> channel_; - // Message loop on which plugin is initialized. - MessageLoop* message_loop_; - DISALLOW_COPY_AND_ASSIGN(PlatformVideoDecoderImpl); }; diff --git a/content/renderer/pepper_plugin_delegate_impl.cc b/content/renderer/pepper_plugin_delegate_impl.cc index 4adc7b0..087e292 100644 --- a/content/renderer/pepper_plugin_delegate_impl.cc +++ b/content/renderer/pepper_plugin_delegate_impl.cc @@ -829,8 +829,10 @@ webkit::ppapi::PluginDelegate::PlatformContext3D* webkit::ppapi::PluginDelegate::PlatformVideoDecoder* PepperPluginDelegateImpl::CreateVideoDecoder( media::VideoDecodeAccelerator::Client* client, - int command_buffer_route_id) { - return new PlatformVideoDecoderImpl(client, command_buffer_route_id); + int32 command_buffer_route_id, + gpu::CommandBufferHelper* cmd_buffer_helper) { + return new PlatformVideoDecoderImpl( + client, command_buffer_route_id, cmd_buffer_helper); } void PepperPluginDelegateImpl::NumberOfFindResultsChanged(int identifier, diff --git a/content/renderer/pepper_plugin_delegate_impl.h b/content/renderer/pepper_plugin_delegate_impl.h index 2c7bf47..e920c46 100644 --- a/content/renderer/pepper_plugin_delegate_impl.h +++ b/content/renderer/pepper_plugin_delegate_impl.h @@ -29,6 +29,10 @@ class Point; class Rect; } +namespace gpu { +class CommandBufferHelper; +} + namespace IPC { struct ChannelHandle; } @@ -180,7 +184,8 @@ class PepperPluginDelegateImpl virtual PlatformContext3D* CreateContext3D(); virtual PlatformVideoDecoder* CreateVideoDecoder( media::VideoDecodeAccelerator::Client* client, - int command_buffer_route_id); + int32 command_buffer_route_id, + gpu::CommandBufferHelper* cmd_buffer_helper); virtual PpapiBroker* ConnectToPpapiBroker( webkit::ppapi::PPB_Broker_Impl* client); virtual void NumberOfFindResultsChanged(int identifier, diff --git a/gpu/command_buffer/common/command_buffer.cc b/gpu/command_buffer/common/command_buffer.cc new file mode 100644 index 0000000..5a12ed1 --- /dev/null +++ b/gpu/command_buffer/common/command_buffer.cc @@ -0,0 +1,31 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "../common/command_buffer.h" +#include "../common/logging.h" + +namespace gpu { + +ReadWriteTokens::ReadWriteTokens() + : last_token_read(-1), last_token_written(-1) { +} + +ReadWriteTokens::ReadWriteTokens(int32 read, int32 written) + : last_token_read(read), last_token_written(written) { +} + +bool ReadWriteTokens::InRange(int32 token) const { + int32 min = last_token_read; + int32 max = last_token_written; + GPU_DCHECK_GE(min, 0); + GPU_DCHECK_GE(max, 0); + if (min <= max) { + // token should be in [min .. max) + return (token >= min) && (token < max); + } + // token should be in [0 .. max) or [min .. wrap token) + return (token >= min) || (token < max); +} + +} // namespace gpu diff --git a/gpu/command_buffer/common/command_buffer.h b/gpu/command_buffer/common/command_buffer.h index d438f72..d5fb24d 100644 --- a/gpu/command_buffer/common/command_buffer.h +++ b/gpu/command_buffer/common/command_buffer.h @@ -123,6 +123,27 @@ class CommandBuffer { DISALLOW_COPY_AND_ASSIGN(CommandBuffer); }; +// Synchronizing other mechanisms (such as IPC) with the CommandBuffer requires +// inserting (writing) a token into the buffer and knowing what the last token +// read at that point was. ReadWriteTokens is a convenience struct for passing +// these pairs around. Expected usage is to compare a current token to +// [last_token_read,last_token_written). +class ReadWriteTokens { + public: + ReadWriteTokens(int32 read, int32 written); + // Required to support pickling. Use by anything else will DCHECK in InRange. + ReadWriteTokens(); + + // Return true iff |value| is in the range described by |tokens|, accounting + // for (up to) one wrap-around. + bool InRange(int32 token) const; + + // These want to be private (and const) but can't in order to support + // pickling. + int32 last_token_read; + int32 last_token_written; +}; + } // namespace gpu #endif // GPU_COMMAND_BUFFER_COMMON_COMMAND_BUFFER_H_ diff --git a/gpu/command_buffer/service/gpu_scheduler.cc b/gpu/command_buffer/service/gpu_scheduler.cc index a67fd3a..1ff60d4 100644 --- a/gpu/command_buffer/service/gpu_scheduler.cc +++ b/gpu/command_buffer/service/gpu_scheduler.cc @@ -273,6 +273,8 @@ Buffer GpuScheduler::GetSharedMemoryBuffer(int32 shm_id) { void GpuScheduler::set_token(int32 token) { command_buffer_->SetToken(token); + if (!set_token_callback_.is_null()) + set_token_callback_.Run(token); } bool GpuScheduler::SetGetOffset(int32 offset) { @@ -311,6 +313,12 @@ void GpuScheduler::SetCommandProcessedCallback( command_processed_callback_.reset(callback); } +void GpuScheduler::SetTokenCallback( + const base::Callback<void(int32)>& callback) { + DCHECK(set_token_callback_.is_null()); + set_token_callback_ = callback; +} + void GpuScheduler::ScheduleProcessCommands() { MessageLoop::current()->PostTask( FROM_HERE, diff --git a/gpu/command_buffer/service/gpu_scheduler.h b/gpu/command_buffer/service/gpu_scheduler.h index a5d10ae..eedae30 100644 --- a/gpu/command_buffer/service/gpu_scheduler.h +++ b/gpu/command_buffer/service/gpu_scheduler.h @@ -158,6 +158,11 @@ class GpuScheduler : public CommandBufferEngine { decoder_->SetLatchCallback(callback); } + // Sets a callback which is called when set_token() is called, and passes the + // just-set token to the callback. DCHECKs that no callback has previously + // been registered for this notification. + void SetTokenCallback(const base::Callback<void(int32)>& callback); + // Get the GLES2Decoder associated with this scheduler. gles2::GLES2Decoder* decoder() const { return decoder_.get(); } @@ -218,6 +223,7 @@ class GpuScheduler : public CommandBufferEngine { scoped_ptr<Callback1<gfx::Size>::Type> wrapped_resize_callback_; scoped_ptr<Callback0::Type> wrapped_swap_buffers_callback_; scoped_ptr<Callback0::Type> command_processed_callback_; + base::Callback<void(int32)> set_token_callback_; }; } // namespace gpu diff --git a/gpu/gpu.gyp b/gpu/gpu.gyp index 6e4a2c3a0..d9f0efa 100644 --- a/gpu/gpu.gyp +++ b/gpu/gpu.gyp @@ -46,6 +46,7 @@ 'command_buffer/common/buffer.h', 'command_buffer/common/cmd_buffer_common.h', 'command_buffer/common/cmd_buffer_common.cc', + 'command_buffer/common/command_buffer.cc', 'command_buffer/common/command_buffer.h', 'command_buffer/common/constants.h', 'command_buffer/common/gles2_cmd_ids_autogen.h', diff --git a/media/video/video_decode_accelerator.h b/media/video/video_decode_accelerator.h index c50da97..ab0d471 100644 --- a/media/video/video_decode_accelerator.h +++ b/media/video/video_decode_accelerator.h @@ -255,9 +255,7 @@ class VideoDecodeAccelerator { // bitstream buffer id. // Parameters: // |bitstream_buffer| is the input bitstream that is sent for decoding. - // - // Returns true when command successfully accepted. Otherwise false. - virtual bool Decode(const BitstreamBuffer& bitstream_buffer) = 0; + virtual void Decode(const BitstreamBuffer& bitstream_buffer) = 0; // Assigns a set of picture buffers to the video decoder. // AssignGLESBuffers assigns texture-backed buffers. @@ -285,17 +283,13 @@ class VideoDecodeAccelerator { // pictures and buffers held inside the decoder and returning of bitstream // buffers using the callbacks implemented by the plug-in. Once done with // flushing, the decode will call NotifyFlushDone(). - // - // Returns true when command successfully accepted. Otherwise false. - virtual bool Flush() = 0; + virtual void Flush() = 0; // Aborts the decoder. Decode will abort the decoding as soon as possible and // will not output anything. NotifyAbortDone() is called as soon as abort has // been finished. After abort all buffers can be considered dismissed, even // when there has not been callbacks to dismiss them. - // - // Returns true when command successfully accepted. Otherwise false. - virtual bool Abort() = 0; + virtual void Abort() = 0; }; } // namespace media diff --git a/ppapi/examples/gles2/gles2.cc b/ppapi/examples/gles2/gles2.cc index 0499958..657159b 100644 --- a/ppapi/examples/gles2/gles2.cc +++ b/ppapi/examples/gles2/gles2.cc @@ -73,14 +73,6 @@ class GLES2DemoInstance : public pp::Instance, public pp::Graphics3DClient_Dev, GLuint vertex_buffers[2]; }; - // Serialize PPB_Video_Decoder_Dev operations w.r.t. GPU command buffer. - // TODO(fischman): figure out how much of this is actually necessary. - // Probably any necessary serialization ought to be happening in the - // PPAPI implementation, not in the plugin! - void FinishGL() { - gles2_if_->Finish(context_->pp_resource()); - } - // Initialize Video Decoder. void InitializeDecoder(); @@ -272,7 +264,6 @@ void GLES2DemoInstance::ProvidePictureBuffers( buffers.push_back(buffer); assert(buffers_by_id_.insert(std::make_pair(id, buffer)).second); } - FinishGL(); video_decoder_->AssignGLESBuffers(buffers); } @@ -282,8 +273,6 @@ void GLES2DemoInstance::DismissPictureBuffer( assert(it != buffers_by_id_.end()); DeleteTexture(it->second.texture_id); buffers_by_id_.erase(it); - - FinishGL(); } void GLES2DemoInstance::PictureReady( @@ -340,18 +329,14 @@ void GLES2DemoInstance::InitGL() { assertNoGLError(); CreateGLObjects(); - - FinishGL(); } void GLES2DemoInstance::Render(const PP_GLESBuffer_Dev& buffer) { if (is_painting_) { // We are dropping frames if we don't render fast enough - // that is why sometimes the last frame rendered is < 249. - if (video_decoder_) { - FinishGL(); + if (video_decoder_) video_decoder_->ReusePictureBuffer(buffer.info.id); - } return; } is_painting_ = true; @@ -369,7 +354,6 @@ void GLES2DemoInstance::Render(const PP_GLESBuffer_Dev& buffer) { void GLES2DemoInstance::PaintFinished(int32_t result, int picture_buffer_id) { is_painting_ = false; - FinishGL(); if (video_decoder_) video_decoder_->ReusePictureBuffer(picture_buffer_id); } diff --git a/webkit/plugins/ppapi/mock_plugin_delegate.cc b/webkit/plugins/ppapi/mock_plugin_delegate.cc index 476d4c9..1270504 100644 --- a/webkit/plugins/ppapi/mock_plugin_delegate.cc +++ b/webkit/plugins/ppapi/mock_plugin_delegate.cc @@ -46,7 +46,8 @@ MockPluginDelegate::PlatformContext3D* MockPluginDelegate::CreateContext3D() { MockPluginDelegate::PlatformVideoDecoder* MockPluginDelegate::CreateVideoDecoder( media::VideoDecodeAccelerator::Client* client, - int command_buffer_route_id) { + int32 command_buffer_route_id, + gpu::CommandBufferHelper* cmd_buffer_helper) { return NULL; } diff --git a/webkit/plugins/ppapi/mock_plugin_delegate.h b/webkit/plugins/ppapi/mock_plugin_delegate.h index 0b91348..c58d4fd 100644 --- a/webkit/plugins/ppapi/mock_plugin_delegate.h +++ b/webkit/plugins/ppapi/mock_plugin_delegate.h @@ -7,6 +7,10 @@ #include "webkit/plugins/ppapi/plugin_delegate.h" +namespace gpu { +class CommandBufferHelper; +} + namespace webkit { namespace ppapi { @@ -24,7 +28,8 @@ class MockPluginDelegate : public PluginDelegate { virtual PlatformContext3D* CreateContext3D(); virtual PlatformVideoDecoder* CreateVideoDecoder( media::VideoDecodeAccelerator::Client* client, - int command_buffer_route_id); + int32 command_buffer_route_id, + gpu::CommandBufferHelper* cmd_buffer_helper); virtual PlatformAudio* CreateAudio(uint32_t sample_rate, uint32_t sample_count, PlatformAudio::Client* client); diff --git a/webkit/plugins/ppapi/plugin_delegate.h b/webkit/plugins/ppapi/plugin_delegate.h index c72eaaa..dae68a8 100644 --- a/webkit/plugins/ppapi/plugin_delegate.h +++ b/webkit/plugins/ppapi/plugin_delegate.h @@ -46,6 +46,7 @@ class Rect; namespace gpu { class CommandBuffer; +class CommandBufferHelper; } namespace ppapi { @@ -263,7 +264,8 @@ class PluginDelegate { // The caller will own the pointer returned from this. virtual PlatformVideoDecoder* CreateVideoDecoder( media::VideoDecodeAccelerator::Client* client, - int command_buffer_route_id) = 0; + int32 command_buffer_route_id, + gpu::CommandBufferHelper* cmd_buffer_helper) = 0; // The caller is responsible for calling Shutdown() on the returned pointer // to clean up the corresponding resources allocated during this call. diff --git a/webkit/plugins/ppapi/ppb_video_decoder_impl.cc b/webkit/plugins/ppapi/ppb_video_decoder_impl.cc index d1e41d4..f5f6126 100644 --- a/webkit/plugins/ppapi/ppb_video_decoder_impl.cc +++ b/webkit/plugins/ppapi/ppb_video_decoder_impl.cc @@ -8,6 +8,7 @@ #include "base/logging.h" #include "base/message_loop.h" +#include "gpu/command_buffer/client/gles2_implementation.h" #include "media/video/picture.h" #include "ppapi/c/dev/pp_video_dev.h" #include "ppapi/c/dev/ppb_video_decoder_dev.h" @@ -65,6 +66,7 @@ void CopyToConfigList( PPB_VideoDecoder_Impl::PPB_VideoDecoder_Impl(PluginInstance* instance) : Resource(instance), callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), + context3d_id_(0), abort_callback_(PP_BlockUntilComplete()), flush_callback_(PP_BlockUntilComplete()) { ppp_videodecoder_ = @@ -73,6 +75,8 @@ PPB_VideoDecoder_Impl::PPB_VideoDecoder_Impl(PluginInstance* instance) } PPB_VideoDecoder_Impl::~PPB_VideoDecoder_Impl() { + if (context3d_id_) + ResourceTracker::Get()->UnrefResource(context3d_id_); } PPB_VideoDecoder_API* PPB_VideoDecoder_Impl::AsPPB_VideoDecoder_API() { @@ -120,6 +124,8 @@ int32_t PPB_VideoDecoder_Impl::Initialize( PPB_Context3D_Impl* context3d = static_cast<PPB_Context3D_Impl*>(enter.object()); + context3d_id_ = context_id; + ResourceTracker::Get()->AddRefResource(context3d_id_); int command_buffer_route_id = context3d->platform_context()->GetCommandBufferRouteId(); if (command_buffer_route_id == 0) @@ -127,7 +133,7 @@ int32_t PPB_VideoDecoder_Impl::Initialize( platform_video_decoder_.reset( instance()->delegate()->CreateVideoDecoder( - this, command_buffer_route_id)); + this, command_buffer_route_id, context3d->gles2_impl()->helper())); if (!platform_video_decoder_.get()) return PP_ERROR_FAILED; @@ -160,10 +166,8 @@ int32_t PPB_VideoDecoder_Impl::Decode( CHECK(bitstream_buffer_callbacks_.insert(std::make_pair( bitstream_buffer->id, callback)).second); - if (platform_video_decoder_->Decode(decode_buffer)) - return PP_OK_COMPLETIONPENDING; - else - return PP_ERROR_FAILED; + platform_video_decoder_->Decode(decode_buffer); + return PP_OK_COMPLETIONPENDING; } void PPB_VideoDecoder_Impl::AssignGLESBuffers( @@ -223,10 +227,8 @@ int32_t PPB_VideoDecoder_Impl::Flush(PP_CompletionCallback callback) { // TODO(vmr): Check for current flush/abort operations. flush_callback_ = callback; - if (platform_video_decoder_->Flush()) - return PP_OK_COMPLETIONPENDING; - else - return PP_ERROR_FAILED; + platform_video_decoder_->Flush(); + return PP_OK_COMPLETIONPENDING; } int32_t PPB_VideoDecoder_Impl::Abort(PP_CompletionCallback callback) { @@ -237,10 +239,8 @@ int32_t PPB_VideoDecoder_Impl::Abort(PP_CompletionCallback callback) { // TODO(vmr): Check for current flush/abort operations. abort_callback_ = callback; - if (platform_video_decoder_->Abort()) - return PP_OK_COMPLETIONPENDING; - else - return PP_ERROR_FAILED; + platform_video_decoder_->Abort(); + return PP_OK_COMPLETIONPENDING; } void PPB_VideoDecoder_Impl::ProvidePictureBuffers( diff --git a/webkit/plugins/ppapi/ppb_video_decoder_impl.h b/webkit/plugins/ppapi/ppb_video_decoder_impl.h index 5b4a326..75db896 100644 --- a/webkit/plugins/ppapi/ppb_video_decoder_impl.h +++ b/webkit/plugins/ppapi/ppb_video_decoder_impl.h @@ -84,6 +84,10 @@ class PPB_VideoDecoder_Impl : public Resource, // Factory to produce our callbacks. base::ScopedCallbackFactory<PPB_VideoDecoder_Impl> callback_factory_; + // The resource ID of the underlying Context3d object being used. Used only + // for reference counting to keep it alive for the lifetime of |*this|. + PP_Resource context3d_id_; + PP_CompletionCallback initialization_callback_; PP_CompletionCallback abort_callback_; PP_CompletionCallback flush_callback_; diff --git a/webkit/plugins/ppapi/resource_tracker.h b/webkit/plugins/ppapi/resource_tracker.h index b728895..84669e1 100644 --- a/webkit/plugins/ppapi/resource_tracker.h +++ b/webkit/plugins/ppapi/resource_tracker.h @@ -175,10 +175,11 @@ class ResourceTracker : public ::ppapi::TrackerBase { // For each PP_Resource, keep the Resource* (as refptr) and plugin use count. // This use count is different then Resource's RefCount, and is manipulated - // using this RefResource/UnrefResource. When it drops to zero, we just remove - // the resource from this resource tracker, but the resource object will be - // alive so long as some scoped_refptr still holds it's reference. This - // prevents plugins from forcing destruction of Resource objects. + // using this AddRefResource/UnrefResource. When it drops to zero, we just + // remove the resource from this resource tracker, but the resource object + // will be alive so long as some scoped_refptr still holds it's + // reference. This prevents plugins from forcing destruction of Resource + // objects. typedef std::pair<scoped_refptr<Resource>, size_t> ResourceAndRefCount; typedef base::hash_map<PP_Resource, ResourceAndRefCount> ResourceMap; ResourceMap live_resources_; |