summaryrefslogtreecommitdiff
path: root/chromium/media/gpu/android/maybe_render_early_manager.cc
blob: 3ba450a3f06888acdb69b7e9a21d6c4e8143de9f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// 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() {}
  ~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() { 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};

  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_.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);
  }

 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