pooled_shared_image_video_provider.cc 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "media/gpu/android/pooled_shared_image_video_provider.h"
  5. #include "base/memory/ptr_util.h"
  6. #include "gpu/command_buffer/common/sync_token.h"
  7. #include "media/base/bind_to_current_loop.h"
  8. #include "mojo/public/cpp/bindings/callback_helpers.h"
  9. namespace media {
  10. // static
  11. std::unique_ptr<PooledSharedImageVideoProvider>
  12. PooledSharedImageVideoProvider::Create(
  13. scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
  14. GetStubCB get_stub_cb,
  15. std::unique_ptr<SharedImageVideoProvider> provider,
  16. scoped_refptr<gpu::RefCountedLock> drdc_lock) {
  17. return base::WrapUnique(new PooledSharedImageVideoProvider(
  18. base::SequenceBound<GpuHelperImpl>(std::move(gpu_task_runner),
  19. std::move(get_stub_cb)),
  20. std::move(provider), std::move(drdc_lock)));
  21. }
  22. PooledSharedImageVideoProvider::PooledImage::PooledImage(const ImageSpec& spec,
  23. ImageRecord record)
  24. : spec(spec), record(std::move(record)) {}
  25. PooledSharedImageVideoProvider::PooledImage::~PooledImage() = default;
  26. PooledSharedImageVideoProvider::PendingRequest::PendingRequest(
  27. const ImageSpec& spec,
  28. ImageReadyCB cb)
  29. : spec(spec), cb(std::move(cb)) {}
  30. PooledSharedImageVideoProvider::PendingRequest::~PendingRequest() = default;
  31. PooledSharedImageVideoProvider::PooledSharedImageVideoProvider(
  32. base::SequenceBound<GpuHelper> gpu_helper,
  33. std::unique_ptr<SharedImageVideoProvider> provider,
  34. scoped_refptr<gpu::RefCountedLock> drdc_lock)
  35. : gpu::RefCountedLockHelperDrDc(std::move(drdc_lock)),
  36. provider_(std::move(provider)),
  37. gpu_helper_(std::move(gpu_helper)),
  38. weak_factory_(this) {}
  39. // Note that this will drop everything in |pool_|, which will call all the
  40. // release callbacks for the underlying byffer.
  41. PooledSharedImageVideoProvider::~PooledSharedImageVideoProvider() = default;
  42. // SharedImageVideoProvider
  43. void PooledSharedImageVideoProvider::Initialize(GpuInitCB gpu_init_cb) {
  44. provider_->Initialize(std::move(gpu_init_cb));
  45. }
  46. void PooledSharedImageVideoProvider::RequestImage(ImageReadyCB cb,
  47. const ImageSpec& spec) {
  48. // See if the pool matches the requested spec.
  49. if (pool_spec_ != spec) {
  50. // Nope -- mark any outstanding images for destruction and start a new pool.
  51. // Note that this calls all the release callbacks.
  52. pool_.clear();
  53. // Any images added to the pool should match |spec|.
  54. pool_spec_ = spec;
  55. }
  56. // Push this onto the pending requests.
  57. // IMPORTANT BUT SUBTLE NOTE: |spec| doesn't mention the TextureOwner, but it
  58. // is sent to the provider so it must also match the one that was used with
  59. // |spec|. We assume that the generation id will be updated by our caller
  60. // whenever the TextureOwner changes. While this is fragile, it's also just
  61. // a temporary thing. Keeping a strong ref to |texture_owner| would probably
  62. // work, but it's not good to keep refs to those around longer than needed.
  63. // It might be okay to do that directly, since the request (if any) that's
  64. // pending for it would have the strong ref, so maybe we could just add it
  65. // here too.
  66. pending_requests_.emplace_back(spec, std::move(cb));
  67. // Are there any free images in the pool? If so, then pop one and use it to
  68. // process the request we just pushed, assuming that it's the most recent. We
  69. // could optimize this call out if |pending_requensts_| wasn't empty before,
  70. // since we know it doesn't match the pool spec if the pool's not empty. As
  71. // it is, it will just pop and re-push the pooled buffer in the (rare) case
  72. // that the pool doesn't match.
  73. if (!pool_.empty()) {
  74. auto front = std::move(pool_.front());
  75. pool_.pop_front();
  76. ProcessFreePooledImage(front);
  77. // TODO(liberato): See if skipping the return if |pool_| is now empty is
  78. // helpful, especially during start-up. Alternatively, just request some
  79. // constant number of images (~5) when the pool spec changes, then add them
  80. // one at a time if needed.
  81. return;
  82. }
  83. // Request a new image, since we don't have enough. There might be some
  84. // outstanding that will be returned, but we'd like to have enough not to wait
  85. // on them. This has the nice property that everything in |pending_requests_|
  86. // will have an image delivered in order for it. Note that we might not
  87. // exactly match up returned (new) images to the requests; there might be
  88. // intervening returns of existing images from the client that happen to match
  89. // if we switch from spec A => spec B => spec A, but that's okay. We can be
  90. // sure that there are at least as many that will arrive as we need.
  91. auto ready_cb =
  92. base::BindOnce(&PooledSharedImageVideoProvider::OnImageCreated,
  93. weak_factory_.GetWeakPtr(), spec);
  94. provider_->RequestImage(std::move(ready_cb), spec);
  95. }
  96. void PooledSharedImageVideoProvider::OnImageCreated(ImageSpec spec,
  97. ImageRecord record) {
  98. // Wrap |record| up for the pool, and process it.
  99. scoped_refptr<PooledImage> pooled_image =
  100. base::MakeRefCounted<PooledImage>(std::move(spec), std::move(record));
  101. ProcessFreePooledImage(pooled_image);
  102. }
  103. void PooledSharedImageVideoProvider::OnImageReturned(
  104. scoped_refptr<PooledImage> pooled_image,
  105. const gpu::SyncToken& sync_token) {
  106. // An image has been returned to us. Wait for |sync_token| and then send it
  107. // to ProcessFreePooledImage to re-use / pool / delete.
  108. gpu_helper_.AsyncCall(&GpuHelper::OnImageReturned)
  109. .WithArgs(sync_token, pooled_image->record.codec_image_holder,
  110. BindToCurrentLoop(base::BindOnce(
  111. &PooledSharedImageVideoProvider::ProcessFreePooledImage,
  112. weak_factory_.GetWeakPtr(), pooled_image)),
  113. GetDrDcLock());
  114. }
  115. void PooledSharedImageVideoProvider::ProcessFreePooledImage(
  116. scoped_refptr<PooledImage> pooled_image) {
  117. // Are there any requests pending?
  118. if (pending_requests_.size()) {
  119. // See if |record| matches the top request. If so, fulfill it, else drop
  120. // |record| since we don't need it. Note that it's possible to have pending
  121. // requests that don't match the pool spec; the pool spec is the most recent
  122. // request. There might be other ones that were made before that which we
  123. // didn't fulfill yet.
  124. auto& front = pending_requests_.front();
  125. if (pooled_image->spec == front.spec) {
  126. // Construct a record that notifies us when the image is released.
  127. // TODO(liberato): Don't copy fields this way.
  128. ImageRecord record;
  129. record.mailbox = pooled_image->record.mailbox;
  130. record.is_vulkan = pooled_image->record.is_vulkan;
  131. record.codec_image_holder = pooled_image->record.codec_image_holder;
  132. // The release CB notifies us instead of |provider_|.
  133. record.release_cb = mojo::WrapCallbackWithDefaultInvokeIfNotRun(
  134. base::BindOnce(&PooledSharedImageVideoProvider::OnImageReturned,
  135. weak_factory_.GetWeakPtr(), std::move(pooled_image)),
  136. gpu::SyncToken());
  137. // Save the callback and remove the request, in case |cb| calls us back.
  138. auto cb = std::move(front.cb);
  139. pending_requests_.pop_front();
  140. std::move(cb).Run(std::move(record));
  141. return;
  142. }
  143. // Can't fulfill the topmost request. Discard |pooled_image|, even if it
  144. // matches the pool. The reason is that any pending requests will have
  145. // images created for them, which we'll use when they arrive. It would be
  146. // okay to store |pooled_image| in the pool if it matches, but then we'd
  147. // have more pooled images than we expect.
  148. return;
  149. }
  150. // There are no outstanding image requests, or the top one doesn't match
  151. // |pooled_image|. If this image is compatible with the pool, then pool it.
  152. // Otherwise, discard it.
  153. // See if |record| matches |pool_spec_|. If not, then drop it. Otherwise,
  154. // pool it for later. Note that we don't explicitly call the release cb,
  155. // since dropping the image is sufficient to notify |provider_|. Note that
  156. // we've already waited for any sync token at this point, so it's okay if we
  157. // don't provide one to the underlying release cb.
  158. if (pool_spec_ != pooled_image->spec)
  159. return;
  160. // Add it to the pool.
  161. pool_.push_front(std::move(pooled_image));
  162. }
  163. PooledSharedImageVideoProvider::GpuHelperImpl::GpuHelperImpl(
  164. GetStubCB get_stub_cb)
  165. : weak_factory_(this) {
  166. gpu::CommandBufferStub* stub = get_stub_cb.Run();
  167. if (stub) {
  168. command_buffer_helper_ = CommandBufferHelper::Create(stub);
  169. }
  170. }
  171. PooledSharedImageVideoProvider::GpuHelperImpl::~GpuHelperImpl() = default;
  172. void PooledSharedImageVideoProvider::GpuHelperImpl::OnImageReturned(
  173. const gpu::SyncToken& sync_token,
  174. scoped_refptr<CodecImageHolder> codec_image_holder,
  175. base::OnceClosure cb,
  176. scoped_refptr<gpu::RefCountedLock> drdc_lock) {
  177. auto on_sync_token_cleared_cb = base::BindOnce(
  178. &GpuHelperImpl::OnSyncTokenCleared, weak_factory_.GetWeakPtr(),
  179. std::move(codec_image_holder), std::move(cb), std::move(drdc_lock));
  180. command_buffer_helper_->WaitForSyncToken(sync_token,
  181. std::move(on_sync_token_cleared_cb));
  182. }
  183. void PooledSharedImageVideoProvider::GpuHelperImpl::OnSyncTokenCleared(
  184. scoped_refptr<CodecImageHolder> codec_image_holder,
  185. base::OnceClosure cb,
  186. scoped_refptr<gpu::RefCountedLock> drdc_lock) {
  187. {
  188. base::AutoLockMaybe auto_lock(drdc_lock ? drdc_lock->GetDrDcLockPtr()
  189. : nullptr);
  190. codec_image_holder->codec_image_raw()->NotifyUnused();
  191. }
  192. // Do this last, since |cb| might post to some other thread.
  193. std::move(cb).Run();
  194. }
  195. } // namespace media