blob: 878a7b90a3786f30366e32da90256fbbf7df2b4c [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/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() : weak_factory_(this) {}
~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()->SetNowUnusedCB(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() { internal::MaybeRenderEarly(&images_); }
private:
void OnImageUnused(CodecImage* image) {
// |image| no longer needs a reference to the surface, so remove it from the
// current image group.
//
// It would be nice if this were sufficient to allow CodecImageGroup to skip
// adding a DestructionCB to CodecImage. However, since we use a weak ptr
// for the callback, it isn't safe. CodecImageGroup uses a strong ref.
DCHECK(std::find(images_.begin(), images_.end(), image) != images_.end());
image_group_->RemoveCodecImage(image);
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_;
DISALLOW_COPY_AND_ASSIGN(GpuMaybeRenderEarlyImpl);
};
// 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:
MaybeRenderEarlyManagerImpl(
scoped_refptr<base::SequencedTaskRunner> gpu_task_runner)
: gpu_task_runner_(gpu_task_runner),
gpu_impl_(std::move(gpu_task_runner)) {}
~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));
// 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_.Post(FROM_HERE, &GpuMaybeRenderEarlyImpl::SetCodecImageGroup,
std::move(image_group));
}
void AddCodecImage(
scoped_refptr<CodecImageHolder> codec_image_holder) override {
gpu_impl_.Post(FROM_HERE, &GpuMaybeRenderEarlyImpl::AddCodecImage,
std::move(codec_image_holder));
}
void MaybeRenderEarly() override {
gpu_impl_.Post(FROM_HERE, &GpuMaybeRenderEarlyImpl::MaybeRenderEarly);
}
private:
scoped_refptr<base::SequencedTaskRunner> gpu_task_runner_;
// Gpu-side.
base::SequenceBound<GpuMaybeRenderEarlyImpl> gpu_impl_;
DISALLOW_COPY_AND_ASSIGN(MaybeRenderEarlyManagerImpl);
};
// static
std::unique_ptr<MaybeRenderEarlyManager> MaybeRenderEarlyManager::Create(
scoped_refptr<base::SequencedTaskRunner> task_runner) {
return std::make_unique<MaybeRenderEarlyManagerImpl>(std::move(task_runner));
}
} // namespace media