| // Copyright 2019 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 "media/gpu/android/maybe_render_early_manager.h" |
| |
| #include <algorithm> |
| |
| #include "base/containers/cxx20_erase.h" |
| #include "base/macros.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/threading/sequence_bound.h" |
| #include "media/gpu/android/codec_image_group.h" |
| #include "media/gpu/android/codec_surface_bundle.h" |
| |
| namespace media { |
| |
| // GPU-thread side of the default MaybeRenderEarlyManager. This handles doing |
| // the actual rendering. |
| class GpuMaybeRenderEarlyImpl { |
| public: |
| GpuMaybeRenderEarlyImpl() {} |
| |
| GpuMaybeRenderEarlyImpl(const GpuMaybeRenderEarlyImpl&) = delete; |
| GpuMaybeRenderEarlyImpl& operator=(const GpuMaybeRenderEarlyImpl&) = delete; |
| |
| ~GpuMaybeRenderEarlyImpl() = default; |
| |
| void SetCodecImageGroup(scoped_refptr<CodecImageGroup> image_group) { |
| image_group_ = std::move(image_group); |
| } |
| |
| void AddCodecImage(scoped_refptr<CodecImageHolder> codec_image_holder) { |
| // Register to find out when this CodecImage is unused, so that we can try |
| // to render a new image early. |
| codec_image_holder->codec_image_raw()->AddUnusedCB(base::BindOnce( |
| &GpuMaybeRenderEarlyImpl::OnImageUnused, weak_factory_.GetWeakPtr())); |
| |
| DCHECK(std::find(images_.begin(), images_.end(), |
| codec_image_holder->codec_image_raw()) == images_.end()); |
| images_.push_back(codec_image_holder->codec_image_raw()); |
| |
| // Add |image| to our current image group. This makes sure that any overlay |
| // lasts as long as the images. For TextureOwner, it doesn't do much. |
| image_group_->AddCodecImage(codec_image_holder->codec_image_raw()); |
| } |
| |
| void MaybeRenderEarly(scoped_refptr<gpu::RefCountedLock> drdc_lock) { |
| base::AutoLockMaybe auto_lock(drdc_lock ? drdc_lock->GetDrDcLockPtr() |
| : nullptr); |
| internal::MaybeRenderEarly(&images_); |
| } |
| |
| private: |
| void OnImageUnused(CodecImage* image) { |
| // |image| is no longer used, so try to render a new image speculatively. |
| DCHECK(std::find(images_.begin(), images_.end(), image) != images_.end()); |
| // Remember that |image_group_| might not be the same one that |image| |
| // belongs to. |
| base::Erase(images_, image); |
| internal::MaybeRenderEarly(&images_); |
| } |
| |
| // Outstanding images that should be considered for early rendering. |
| std::vector<CodecImage*> images_; |
| |
| // Current image group to which new images (frames) will be added. We'll |
| // replace this when SetImageGroup() is called. |
| scoped_refptr<CodecImageGroup> image_group_; |
| |
| base::WeakPtrFactory<GpuMaybeRenderEarlyImpl> weak_factory_{this}; |
| }; |
| |
| // Default implementation of MaybeRenderEarlyManager. Lives on whatever thread |
| // you like, but will hop to the gpu thread to do real work. |
| class MaybeRenderEarlyManagerImpl : public MaybeRenderEarlyManager, |
| public gpu::RefCountedLockHelperDrDc { |
| public: |
| MaybeRenderEarlyManagerImpl( |
| scoped_refptr<base::SequencedTaskRunner> gpu_task_runner, |
| scoped_refptr<gpu::RefCountedLock> drdc_lock) |
| : gpu::RefCountedLockHelperDrDc(std::move(drdc_lock)), |
| gpu_task_runner_(gpu_task_runner), |
| gpu_impl_(std::move(gpu_task_runner)) {} |
| |
| MaybeRenderEarlyManagerImpl(const MaybeRenderEarlyManagerImpl&) = delete; |
| MaybeRenderEarlyManagerImpl& operator=(const MaybeRenderEarlyManagerImpl&) = |
| delete; |
| |
| ~MaybeRenderEarlyManagerImpl() override = default; |
| |
| void SetSurfaceBundle( |
| scoped_refptr<CodecSurfaceBundle> surface_bundle) override { |
| // Start a new image group. Note that there's no reason that we can't have |
| // more than one group per surface bundle; it's okay if we're called |
| // multiple times with the same surface bundle. It just helps to combine |
| // the callbacks if we don't, especially since AndroidOverlay doesn't know |
| // how to remove destruction callbacks. That's one reason why we don't just |
| // make the CodecImage register itself. The other is that the threading is |
| // easier if we do it this way, since the image group is constructed on the |
| // proper thread to talk to the overlay. |
| auto image_group = base::MakeRefCounted<CodecImageGroup>( |
| gpu_task_runner_, std::move(surface_bundle), GetDrDcLock()); |
| |
| // Give the image group to |gpu_impl_|. Note that we don't drop our ref to |
| // |image_group| on this thread. It can only be constructed here. |
| gpu_impl_.AsyncCall(&GpuMaybeRenderEarlyImpl::SetCodecImageGroup) |
| .WithArgs(std::move(image_group)); |
| } |
| |
| void AddCodecImage( |
| scoped_refptr<CodecImageHolder> codec_image_holder) override { |
| gpu_impl_.AsyncCall(&GpuMaybeRenderEarlyImpl::AddCodecImage) |
| .WithArgs(std::move(codec_image_holder)); |
| } |
| |
| void MaybeRenderEarly() override { |
| gpu_impl_.AsyncCall(&GpuMaybeRenderEarlyImpl::MaybeRenderEarly) |
| .WithArgs(GetDrDcLock()); |
| } |
| |
| private: |
| scoped_refptr<base::SequencedTaskRunner> gpu_task_runner_; |
| |
| // Gpu-side. |
| base::SequenceBound<GpuMaybeRenderEarlyImpl> gpu_impl_; |
| }; |
| |
| // static |
| std::unique_ptr<MaybeRenderEarlyManager> MaybeRenderEarlyManager::Create( |
| scoped_refptr<base::SequencedTaskRunner> task_runner, |
| scoped_refptr<gpu::RefCountedLock> lock) { |
| return std::make_unique<MaybeRenderEarlyManagerImpl>(std::move(task_runner), |
| std::move(lock)); |
| } |
| |
| } // namespace media |