blob: c82fd30b99fcc4d526c507ffdbf122fe95645097 [file] [log] [blame]
// 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