Commit 6f6776f4 authored by Miguel Casas's avatar Miguel Casas Committed by Commit Bot

media/gpu/linux: convert MailboxVideoFrameConverter to SharedImages

This CL migrates MailboxVideoFrameConverter from using Textures to
using SharedImages.  No external functionality changes are expected.

Couple of things need to be added:

- ScopedSharedImage: an internal class to scope a SharedImage lifetime.
 SharedImages are kept in |shared_images_|, indexed by a unique id.

- Added GetGpuChannelCB that can be derived from the GetStubCB and that
 is needed for SharedImage creation and destruction. They are generated
 on Create(), so this interface doesn't change.

- This CL uses a WeakPtr to the GpuChannel, accessing its SharedImageStub
 and the gpu::Scheduler that way.

Most of the work goes in:
 - InitializeOnGpuTaskRunner() and then
 - the sequence ConvertFrameOnGPUThread() (calls either
  GenerateSharedImageOnGPUThread() or UpdateSharedImageOnGPUThread()) then
  jumps back to WrapMailboxAndVideoFrameAndOutput().

Test: crosvideo.appspot.com resolution-changing videos  (vp9, h264, vp8)
of course with the new VD decoder, on kohaku and scarlet/dru.

Bug: 998279
Change-Id: Ic9b5b2270d1b488562bc2725bba89dc2a0350012
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1772642
Commit-Queue: Miguel Casas <mcasas@chromium.org>
Reviewed-by: default avatarAlexandre Courbot <acourbot@chromium.org>
Reviewed-by: default avatarEric Karl <ericrk@chromium.org>
Reviewed-by: default avatarChih-Yu Huang <akahuang@chromium.org>
Reviewed-by: default avatarDan Sanders <sandersd@chromium.org>
Reviewed-by: default avatarAndres Calderon Jaramillo <andrescj@chromium.org>
Cr-Commit-Position: refs/heads/master@{#698666}
parent fca05b6c
...@@ -430,6 +430,10 @@ bool Scheduler::ShouldYield(SequenceId sequence_id) { ...@@ -430,6 +430,10 @@ bool Scheduler::ShouldYield(SequenceId sequence_id) {
return running_sequence->ShouldYieldTo(next_sequence); return running_sequence->ShouldYieldTo(next_sequence);
} }
base::WeakPtr<Scheduler> Scheduler::AsWeakPtr() {
return weak_factory_.GetWeakPtr();
}
void Scheduler::SyncTokenFenceReleased(const SyncToken& sync_token, void Scheduler::SyncTokenFenceReleased(const SyncToken& sync_token,
uint32_t order_num, uint32_t order_num,
SequenceId release_sequence_id, SequenceId release_sequence_id,
......
...@@ -92,6 +92,8 @@ class GPU_EXPORT Scheduler { ...@@ -92,6 +92,8 @@ class GPU_EXPORT Scheduler {
// If the sequence should yield so that a higher priority sequence may run. // If the sequence should yield so that a higher priority sequence may run.
bool ShouldYield(SequenceId sequence_id); bool ShouldYield(SequenceId sequence_id);
base::WeakPtr<Scheduler> AsWeakPtr();
private: private:
struct SchedulingState { struct SchedulingState {
......
...@@ -13,91 +13,104 @@ ...@@ -13,91 +13,104 @@
#include "base/memory/scoped_refptr.h" #include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h" #include "base/single_thread_task_runner.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "media/base/video_decoder.h" #include "media/base/video_decoder.h"
#include "media/base/video_frame.h" #include "media/base/video_frame.h"
#include "media/gpu/command_buffer_helper.h"
#include "media/gpu/media_gpu_export.h" #include "media/gpu/media_gpu_export.h"
#include "media/gpu/video_frame_converter.h" #include "media/gpu/video_frame_converter.h"
namespace gpu {
class GpuChannel;
class CommandBufferStub;
} // namespace gpu
namespace media { namespace media {
// The linux VideoDecoder implementations request DMA-buf VideoFrame from the // This class is used for converting DMA-buf backed VideoFrames to mailbox-based
// DmabufVideoFramePool, and store the decoded data into DMA-buf. However the // VideoFrames. See ConvertFrame() for more details.
// client of the VideoDecoder may only accept mailbox VideoFrame.
// This class is used for converting DMA-buf VideoFrame to mailbox VideoFrame.
// After conversion, the mailbox VideoFrame will retain a reference of the // After conversion, the mailbox VideoFrame will retain a reference of the
// VideoFrame passed to ConvertFrame(). // VideoFrame passed to ConvertFrame().
class MEDIA_GPU_EXPORT MailboxVideoFrameConverter : public VideoFrameConverter { class MEDIA_GPU_EXPORT MailboxVideoFrameConverter : public VideoFrameConverter {
public: public:
using UnwrapFrameCB = using UnwrapFrameCB =
base::RepeatingCallback<VideoFrame*(const VideoFrame& wrapped_frame)>; base::RepeatingCallback<VideoFrame*(const VideoFrame& wrapped_frame)>;
using GetCommandBufferStubCB = base::OnceCallback<gpu::CommandBufferStub*()>; using GetCommandBufferStubCB =
base::RepeatingCallback<gpu::CommandBufferStub*()>;
// Create a MailboxVideoFrameConverter instance. Return nullptr if any using GetGpuChannelCB =
// argument is invalid. base::RepeatingCallback<base::WeakPtr<gpu::GpuChannel>()>;
// Creates a MailboxVideoFrameConverter instance. The callers will send
// wrapped VideoFrames to ConvertFrame(), |unwrap_frame_cb| is the callback
// used to get the original, unwrapped, VideoFrame. |gpu_task_runner| is the
// task runner of the GPU main thread. Returns nullptr if any argument is
// invalid.
static std::unique_ptr<VideoFrameConverter> Create( static std::unique_ptr<VideoFrameConverter> Create(
UnwrapFrameCB unwrap_frame_cb, UnwrapFrameCB unwrap_frame_cb,
scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner, scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
GetCommandBufferStubCB get_stub_cb); GetCommandBufferStubCB get_stub_cb);
// Convert DMA-buf VideoFrame to mailbox VideoFrame. // Enqueues |frame| to be converted to a gpu::Mailbox backed VideoFrame.
// For each frame, we bind DMA-buf to GL texture and create mailbox on the GPU // |frame| must wrap a DMA-buf backed VideoFrame that is retrieved via
// main thread. // |unwrap_frame_cb_|. The generated gpu::Mailbox-based VideoFrame is kept
// The mailbox of each frame will be stored at |mailbox_table_|. When // alive until the original (i.e. the unwrapped) DMA-Buf based VideoFrame one
// converting a frame second time, we just lookup the table instead of // goes out of scope.
// creating texture and mailbox.
void ConvertFrame(scoped_refptr<VideoFrame> frame) override; void ConvertFrame(scoped_refptr<VideoFrame> frame) override;
void AbortPendingFrames() override; void AbortPendingFrames() override;
bool HasPendingFrames() const override; bool HasPendingFrames() const override;
private: private:
// In order to recycle VideoFrame, the DmabufVideoFramePool implementation may // A self-cleaning SharedImage, with move-only semantics.
// wrap the frame. We want to create texture only once for the same buffer, so class ScopedSharedImage;
// we need to get the original frame at ConvertFrame(). |unwrap_frame_cb| is
// the callback used to get the original frame.
// |gpu_task_runner| is the task runner of the GPU main thread. We generate
// mailbox on it.
// |get_stub_cb| is the callback used to get the CommandBufferStub, which is
// used to create CommandBufferHelper.
MailboxVideoFrameConverter( MailboxVideoFrameConverter(
UnwrapFrameCB unwrap_frame_cb, UnwrapFrameCB unwrap_frame_cb,
scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner, scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
GetCommandBufferStubCB get_stub_cb); GetGpuChannelCB get_gpu_channel_cb);
// Destructor runs on the GPU main thread. // Destructor runs on the GPU main thread.
~MailboxVideoFrameConverter() override; ~MailboxVideoFrameConverter() override;
void Destroy() override; void Destroy() override;
void DestroyOnGPUThread(); void DestroyOnGPUThread();
bool CreateCommandBufferHelper(); // TODO(crbug.com/998279): replace s/OnGPUThread/OnGPUTaskRunner/.
bool InitializeOnGPUThread();
// Try to convert frames in |input_frame_queue_| and output the converted
// frames to client. // Wraps |mailbox| and |frame| into a new VideoFrame and sends it via
void TryOutputFrames(); // |output_cb_|.
void WrapMailboxAndVideoFrameAndOutput(VideoFrame* origin_frame,
// Generate mailbox for the DMA-buf VideoFrame. This method runs on the GPU scoped_refptr<VideoFrame> frame,
// main thread. const gpu::Mailbox& mailbox);
// |origin_frame| is unwrapped from |frame| passed from ConvertFrame().
// |frame| is passed only for keeping |origin_frame| alive. // ConvertFrame() delegates to this method to GenerateSharedImageOnGPUThread()
void GenerateMailbox(VideoFrame* origin_frame, // or just UpdateSharedImageOnGPUThread(), then to jump back to
scoped_refptr<VideoFrame> frame); // WrapMailboxAndVideoFrameAndOutput().
void ConvertFrameOnGPUThread(VideoFrame* origin_frame,
// Register the mapping between DMA-buf VideoFrame and the mailbox. scoped_refptr<VideoFrame> frame,
// |frame| is passed only for keeping |origin_frame| alive. gpu::Mailbox mailbox);
void RegisterMailbox(VideoFrame* origin_frame,
const gpu::Mailbox& mailbox, // Generates a ScopedSharedImage from a DMA-buf backed |video_frame|, and
scoped_refptr<VideoFrame> frame); // returns it or nullptr if that could not be done. |video_frame| must be kept
// alive for the duration of this method. This method runs on
// Thunk for calling UnregisterMailbox() on |task_runner|. // |gpu_task_runner_|.
// Because this thunk may be called in any thread, We cannot dereference std::unique_ptr<ScopedSharedImage> GenerateSharedImageOnGPUThread(
// WeakPtr. Therefore we wrap the WeakPtr by base::Optional to avoid task VideoFrame* video_frame);
// runner defererence the WeakPtr.
static void UnregisterMailboxThunk( // Registers the mapping between a DMA-buf VideoFrame and the SharedImage.
scoped_refptr<base::SequencedTaskRunner> task_runner, // |origin_frame| must be kept alive for the duration of this method.
base::Optional<base::WeakPtr<MailboxVideoFrameConverter>> converter, void RegisterSharedImage(
const int origin_frame_id); VideoFrame* origin_frame,
// Remove the mapping between the frame whose unique id is |origin_frame_id| std::unique_ptr<ScopedSharedImage> scoped_shared_image);
// and the mailbox. // Unregisters the |origin_frame_id| and associated SharedImage.
void UnregisterMailbox(const int origin_frame_id); void UnregisterSharedImage(int origin_frame_id);
// Updates the SharedImage associated to |mailbox|. Returns true if the update
// could be carried out, false otherwise.
bool UpdateSharedImageOnGPUThread(const gpu::Mailbox& mailbox);
// Waits on |sync_token|, keeping |frame| alive until it is signalled. It
// trampolines threads to |gpu_task_runner| if necessary.
void WaitOnSyncTokenAndReleaseFrameOnGPUThread(
scoped_refptr<VideoFrame> frame,
const gpu::SyncToken& sync_token);
// Invoked when any error occurs. |msg| is the error message. // Invoked when any error occurs. |msg| is the error message.
void OnError(const std::string& msg); void OnError(const std::string& msg);
...@@ -112,24 +125,29 @@ class MEDIA_GPU_EXPORT MailboxVideoFrameConverter : public VideoFrameConverter { ...@@ -112,24 +125,29 @@ class MEDIA_GPU_EXPORT MailboxVideoFrameConverter : public VideoFrameConverter {
UnwrapFrameCB unwrap_frame_cb_; UnwrapFrameCB unwrap_frame_cb_;
const scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner_; const scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner_;
GetCommandBufferStubCB get_stub_cb_; const GetGpuChannelCB get_gpu_channel_cb_;
// The interface to communicate with command buffer. We use this to create and
// destroy texture, wait for SyncToken, and generate mailbox. // |gpu_channel_| will outlive CommandBufferStub, keep the former as a WeakPtr
scoped_refptr<CommandBufferHelper> command_buffer_helper_; // to guarantee proper resource cleanup. To be dereferenced on
// |gpu_task_runner_| only.
base::WeakPtr<gpu::GpuChannel> gpu_channel_;
// Mapping from the unique id of the frame to its corresponding mailbox. // Mapping from the unique id of the frame to its corresponding SharedImage.
// Accessed only on |parent_task_runner_|. // Accessed only on |parent_task_runner_|.
std::map<int, gpu::Mailbox> mailbox_table_; // TODO(crbug.com/998279): use base::small_map.
// TODO(crbug.com/998279): use VideoFrame::unique_id() return type.
std::map<int, std::unique_ptr<ScopedSharedImage>> shared_images_;
// The queue of input frames and the unique_id of their origin frame. // The queue of input frames and the unique_id of their origin frame.
// Accessed only on |parent_task_runner_|. // Accessed only on |parent_task_runner_|.
// TODO(crbug.com/998279): remove this member entirely.
base::queue<std::pair<scoped_refptr<VideoFrame>, int>> input_frame_queue_; base::queue<std::pair<scoped_refptr<VideoFrame>, int>> input_frame_queue_;
// The weak pointer of this, bound to |parent_task_runner_|. // The weak pointer of this, bound to |parent_task_runner_|.
// Used at the VideoFrame destruction callback. // Used at the VideoFrame destruction callback.
base::WeakPtr<MailboxVideoFrameConverter> parent_weak_this_; base::WeakPtr<MailboxVideoFrameConverter> parent_weak_this_;
// The weak pointer of this, bound to |gpu_task_runner_|. // The weak pointer of this, bound to |gpu_task_runner_|.
// Used to generate mailbox on the GPU main thread. // Used to generate SharedImages on the GPU main thread.
base::WeakPtr<MailboxVideoFrameConverter> gpu_weak_this_; base::WeakPtr<MailboxVideoFrameConverter> gpu_weak_this_;
base::WeakPtrFactory<MailboxVideoFrameConverter> parent_weak_this_factory_{ base::WeakPtrFactory<MailboxVideoFrameConverter> parent_weak_this_factory_{
this}; this};
......
...@@ -235,10 +235,10 @@ std::unique_ptr<VideoDecoder> GpuMojoMediaClient::CreateVideoDecoder( ...@@ -235,10 +235,10 @@ std::unique_ptr<VideoDecoder> GpuMojoMediaClient::CreateVideoDecoder(
base::BindRepeating(&DmabufVideoFramePool::UnwrapFrame, base::BindRepeating(&DmabufVideoFramePool::UnwrapFrame,
base::Unretained(frame_pool.get())), base::Unretained(frame_pool.get())),
gpu_task_runner_, gpu_task_runner_,
base::BindOnce(&GetCommandBufferStub, gpu_task_runner_, base::BindRepeating(&GetCommandBufferStub, gpu_task_runner_,
media_gpu_channel_manager_, media_gpu_channel_manager_,
command_buffer_id->channel_token, command_buffer_id->channel_token,
command_buffer_id->route_id)); command_buffer_id->route_id));
video_decoder = ChromeosVideoDecoderFactory::Create( video_decoder = ChromeosVideoDecoderFactory::Create(
task_runner, std::move(frame_pool), std::move(frame_converter)); task_runner, std::move(frame_pool), std::move(frame_converter));
#endif // BUILDFLAG(USE_V4L2_CODEC) || BUILDFLAG(USE_VAAPI) #endif // BUILDFLAG(USE_V4L2_CODEC) || BUILDFLAG(USE_VAAPI)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment