[Dr-Dc] Thread safe MCVD path.
1. Added a global lock to be used by SharedImageVideo, FrameInfoHelper, MaybeRenderEarlyManager etc to perform thread safe access to CodecImage, CodecBufferWaitCoordinator and CodecOutputBufferRenderer. 2. SharedImageVideo, FrameInfoHelper, MaybeRenderEarlyManager and some other media classes will hold the lock and CodecImage, CodecBufferWaitCoordinator, CodecOutputBufferRenderer will expect lock to be held. Bug: 1186282 Change-Id: I2d3490a88a2597ab632721f6d5832f882af9e970 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3039341 Reviewed-by: Vasiliy Telezhnikov <vasilyt@chromium.org> Reviewed-by: Frank Liberato <liberato@chromium.org> Commit-Queue: vikas soni <vikassoni@chromium.org> Cr-Commit-Position: refs/heads/master@{#905344}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
8e3b827f16
commit
03bd0d43c7
gpu
command_buffer
service
ipc
service
media
gpu
android
codec_buffer_wait_coordinator.cccodec_buffer_wait_coordinator.hcodec_image.cccodec_image.hcodec_image_group.cccodec_image_group.hcodec_image_group_unittest.cccodec_image_unittest.cccodec_output_buffer_renderer.cccodec_output_buffer_renderer.hcodec_surface_bundle.cccodec_surface_bundle.hdirect_shared_image_video_provider.ccdirect_shared_image_video_provider.hframe_info_helper.ccframe_info_helper.hframe_info_helper_unittest.ccmaybe_render_early_manager.ccmaybe_render_early_manager.hmedia_codec_video_decoder.ccmedia_codec_video_decoder.hmedia_codec_video_decoder_unittest.ccmock_codec_buffer_wait_coordinator.ccmock_codec_image.ccpooled_shared_image_video_provider.ccpooled_shared_image_video_provider.hpooled_shared_image_video_provider_unittest.ccvideo_frame_factory_impl.ccvideo_frame_factory_impl.hvideo_frame_factory_impl_unittest.cc
mojo
services
@ -451,6 +451,8 @@ target(link_target_type, "gles2_sources") {
|
||||
"ahardwarebuffer_utils.h",
|
||||
"image_reader_gl_owner.cc",
|
||||
"image_reader_gl_owner.h",
|
||||
"ref_counted_lock.cc",
|
||||
"ref_counted_lock.h",
|
||||
"shared_image_backing_android.cc",
|
||||
"shared_image_backing_android.h",
|
||||
"shared_image_backing_egl_image.cc",
|
||||
|
@ -267,7 +267,6 @@ gl::ScopedJavaSurface ImageReaderGLOwner::CreateJavaSurface() const {
|
||||
}
|
||||
|
||||
void ImageReaderGLOwner::UpdateTexImage() {
|
||||
DCHECK_CALLED_ON_VALID_THREAD(gpu_main_thread_checker_);
|
||||
base::AutoLock auto_lock(lock_);
|
||||
|
||||
// If we've lost the texture, then do nothing.
|
||||
@ -503,9 +502,8 @@ void ImageReaderGLOwner::RunWhenBufferIsAvailable(base::OnceClosure callback) {
|
||||
// and acquire updated image and hence will use FrameInfo of the previous
|
||||
// image which will result in wrong coded size for all future frames. To
|
||||
// avoid, this no other threads should try to UpdateTexImage() when this
|
||||
// callback is run.
|
||||
// TODO(vikassoni) : Fix this issue when MCVD path is made thread safe using
|
||||
// global locks. For MediaPlayer path we never call this method.
|
||||
// callback is run. lock held by the caller (GetFrameInfo()) of this
|
||||
// method ensures that this never happens.
|
||||
std::move(callback).Run();
|
||||
} else {
|
||||
base::AutoLock auto_lock(lock_);
|
||||
|
22
gpu/command_buffer/service/ref_counted_lock.cc
Normal file
22
gpu/command_buffer/service/ref_counted_lock.cc
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2021 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 "gpu/command_buffer/service/ref_counted_lock.h"
|
||||
|
||||
#include "gpu/config/gpu_finch_features.h"
|
||||
|
||||
namespace gpu {
|
||||
|
||||
RefCountedLockHelperDrDc::RefCountedLockHelperDrDc(
|
||||
scoped_refptr<RefCountedLock> lock)
|
||||
: lock_(std::move(lock)) {
|
||||
// |lock_| should be present if DrDc feature is enabled and it should not
|
||||
// be present if feature is disabled.
|
||||
DCHECK((features::IsDrDcEnabled() && lock_) ||
|
||||
(!features::IsDrDcEnabled() && !lock_));
|
||||
}
|
||||
|
||||
RefCountedLockHelperDrDc::~RefCountedLockHelperDrDc() = default;
|
||||
|
||||
} // namespace gpu
|
61
gpu/command_buffer/service/ref_counted_lock.h
Normal file
61
gpu/command_buffer/service/ref_counted_lock.h
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright 2021 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.
|
||||
|
||||
#ifndef GPU_COMMAND_BUFFER_SERVICE_REF_COUNTED_LOCK_H_
|
||||
#define GPU_COMMAND_BUFFER_SERVICE_REF_COUNTED_LOCK_H_
|
||||
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
#include "gpu/gpu_gles2_export.h"
|
||||
|
||||
namespace gpu {
|
||||
|
||||
// Ref counted wrapper for base::Lock.
|
||||
class GPU_GLES2_EXPORT RefCountedLock
|
||||
: public base::RefCountedThreadSafe<RefCountedLock> {
|
||||
public:
|
||||
RefCountedLock() = default;
|
||||
|
||||
// Disallow copy and assign.
|
||||
RefCountedLock(const RefCountedLock&) = delete;
|
||||
RefCountedLock& operator=(const RefCountedLock&) = delete;
|
||||
|
||||
base::Lock* GetDrDcLockPtr() { return &lock_; }
|
||||
void AssertAcquired() { lock_.AssertAcquired(); }
|
||||
|
||||
private:
|
||||
friend class base::RefCountedThreadSafe<RefCountedLock>;
|
||||
~RefCountedLock() = default;
|
||||
|
||||
base::Lock lock_;
|
||||
};
|
||||
|
||||
// Helper class for handling RefCountedLock for drdc usage.
|
||||
class GPU_GLES2_EXPORT RefCountedLockHelperDrDc {
|
||||
public:
|
||||
explicit RefCountedLockHelperDrDc(scoped_refptr<RefCountedLock> lock);
|
||||
~RefCountedLockHelperDrDc();
|
||||
|
||||
base::Lock* GetDrDcLockPtr() const {
|
||||
return lock_ ? lock_->GetDrDcLockPtr() : nullptr;
|
||||
}
|
||||
|
||||
const scoped_refptr<RefCountedLock>& GetDrDcLock() { return lock_; }
|
||||
|
||||
void AssertAcquiredDrDcLock() const {
|
||||
if (lock_)
|
||||
lock_->AssertAcquired();
|
||||
}
|
||||
|
||||
std::unique_ptr<base::AutoLockMaybe> GetScopedDrDcLock() const {
|
||||
return std::make_unique<base::AutoLockMaybe>(GetDrDcLockPtr());
|
||||
}
|
||||
|
||||
private:
|
||||
mutable scoped_refptr<RefCountedLock> lock_;
|
||||
};
|
||||
|
||||
} // namespace gpu
|
||||
|
||||
#endif // GPU_COMMAND_BUFFER_SERVICE_REF_COUNTED_LOCK_H_
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "base/android/scoped_hardware_buffer_fence_sync.h"
|
||||
#include "base/android/scoped_hardware_buffer_handle.h"
|
||||
#include "base/threading/thread_task_runner_handle.h"
|
||||
#include "components/viz/common/gpu/vulkan_context_provider.h"
|
||||
#include "components/viz/common/resources/resource_format_utils.h"
|
||||
#include "components/viz/common/resources/resource_sizes.h"
|
||||
@ -44,7 +45,8 @@ SharedImageVideo::SharedImageVideo(
|
||||
SkAlphaType alpha_type,
|
||||
scoped_refptr<StreamTextureSharedImageInterface> stream_texture_sii,
|
||||
scoped_refptr<SharedContextState> context_state,
|
||||
bool is_thread_safe)
|
||||
bool is_thread_safe,
|
||||
scoped_refptr<RefCountedLock> drdc_lock)
|
||||
: SharedImageBackingAndroid(
|
||||
mailbox,
|
||||
viz::RGBA_8888,
|
||||
@ -57,20 +59,51 @@ SharedImageVideo::SharedImageVideo(
|
||||
viz::RGBA_8888),
|
||||
is_thread_safe,
|
||||
base::ScopedFD()),
|
||||
RefCountedLockHelperDrDc(std::move(drdc_lock)),
|
||||
stream_texture_sii_(std::move(stream_texture_sii)),
|
||||
context_state_(std::move(context_state)) {
|
||||
context_state_(std::move(context_state)),
|
||||
task_runner_(base::ThreadTaskRunnerHandle::Get()) {
|
||||
DCHECK(stream_texture_sii_);
|
||||
DCHECK(context_state_);
|
||||
|
||||
// Currently this backing is not thread safe.
|
||||
DCHECK(!is_thread_safe);
|
||||
context_state_->AddContextLostObserver(this);
|
||||
}
|
||||
|
||||
SharedImageVideo::~SharedImageVideo() {
|
||||
stream_texture_sii_->ReleaseResources();
|
||||
if (context_state_)
|
||||
context_state_->RemoveContextLostObserver(this);
|
||||
if (task_runner_->RunsTasksInCurrentSequence()) {
|
||||
CleanupOnCorrectThread(std::move(stream_texture_sii_),
|
||||
std::move(context_state_), this, /*event=*/nullptr,
|
||||
GetDrDcLock());
|
||||
} else {
|
||||
base::WaitableEvent event;
|
||||
task_runner_->PostTask(
|
||||
FROM_HERE,
|
||||
base::BindOnce(&SharedImageVideo::CleanupOnCorrectThread,
|
||||
std::move(stream_texture_sii_),
|
||||
std::move(context_state_), base::Unretained(this),
|
||||
&event, GetDrDcLock()));
|
||||
event.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
void SharedImageVideo::CleanupOnCorrectThread(
|
||||
scoped_refptr<StreamTextureSharedImageInterface> stream_texture_sii,
|
||||
scoped_refptr<SharedContextState> context_state,
|
||||
SharedImageVideo* backing,
|
||||
base::WaitableEvent* event,
|
||||
scoped_refptr<RefCountedLock> drdc_lock) {
|
||||
if (context_state)
|
||||
context_state->RemoveContextLostObserver(backing);
|
||||
context_state.reset();
|
||||
|
||||
{
|
||||
base::AutoLockMaybe auto_lock(drdc_lock ? drdc_lock->GetDrDcLockPtr()
|
||||
: nullptr);
|
||||
stream_texture_sii->ReleaseResources();
|
||||
stream_texture_sii.reset();
|
||||
}
|
||||
if (event)
|
||||
event->Signal();
|
||||
}
|
||||
|
||||
gfx::Rect SharedImageVideo::ClearedRect() const {
|
||||
@ -88,22 +121,26 @@ void SharedImageVideo::Update(std::unique_ptr<gfx::GpuFence> in_fence) {
|
||||
|
||||
bool SharedImageVideo::ProduceLegacyMailbox(MailboxManager* mailbox_manager) {
|
||||
// Android does not use legacy mailbox anymore. Hence marking this as
|
||||
// NOTREACHED() now. Once all platform stops using legacy mailbox, this method
|
||||
// can be removed.
|
||||
// NOTREACHED() now. Once all platform stops using legacy mailbox, this
|
||||
// method can be removed.
|
||||
NOTREACHED();
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t SharedImageVideo::EstimatedSizeForMemTracking() const {
|
||||
// This backing contributes to gpu memory only if its bound to the texture and
|
||||
// not when the backing is created.
|
||||
base::AutoLockMaybe auto_lock(GetDrDcLockPtr());
|
||||
|
||||
// This backing contributes to gpu memory only if its bound to the texture
|
||||
// and not when the backing is created.
|
||||
return stream_texture_sii_->IsUsingGpuMemory() ? estimated_size() : 0;
|
||||
}
|
||||
|
||||
void SharedImageVideo::OnContextLost() {
|
||||
// We release codec buffers when shared image context is lost. This is because
|
||||
// texture owner's texture was created on shared context. Once shared context
|
||||
// is lost, no one should try to use that texture.
|
||||
base::AutoLockMaybe auto_lock(GetDrDcLockPtr());
|
||||
|
||||
// We release codec buffers when shared image context is lost. This is
|
||||
// because texture owner's texture was created on shared context. Once
|
||||
// shared context is lost, no one should try to use that texture.
|
||||
stream_texture_sii_->ReleaseResources();
|
||||
context_state_->RemoveContextLostObserver(this);
|
||||
context_state_ = nullptr;
|
||||
@ -116,8 +153,7 @@ absl::optional<VulkanYCbCrInfo> SharedImageVideo::GetYcbcrInfo(
|
||||
if (!context_state->GrContextIsVulkan())
|
||||
return absl::nullopt;
|
||||
|
||||
// GetAHardwareBuffer() renders the latest image and gets AHardwareBuffer
|
||||
// from it.
|
||||
// Get AHardwareBuffer from the latest frame.
|
||||
auto scoped_hardware_buffer = texture_owner->GetAHardwareBuffer();
|
||||
if (!scoped_hardware_buffer) {
|
||||
return absl::nullopt;
|
||||
@ -140,20 +176,25 @@ absl::optional<VulkanYCbCrInfo> SharedImageVideo::GetYcbcrInfo(
|
||||
|
||||
std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
|
||||
SharedImageVideo::GetAHardwareBuffer() {
|
||||
base::AutoLockMaybe auto_lock(GetDrDcLockPtr());
|
||||
|
||||
DCHECK(stream_texture_sii_);
|
||||
return stream_texture_sii_->GetAHardwareBuffer();
|
||||
}
|
||||
|
||||
// Representation of SharedImageVideo as a GL Texture.
|
||||
class SharedImageRepresentationGLTextureVideo
|
||||
: public SharedImageRepresentationGLTexture {
|
||||
: public SharedImageRepresentationGLTexture,
|
||||
public RefCountedLockHelperDrDc {
|
||||
public:
|
||||
SharedImageRepresentationGLTextureVideo(
|
||||
SharedImageManager* manager,
|
||||
SharedImageVideo* backing,
|
||||
MemoryTypeTracker* tracker,
|
||||
std::unique_ptr<gles2::AbstractTexture> texture)
|
||||
std::unique_ptr<gles2::AbstractTexture> texture,
|
||||
scoped_refptr<RefCountedLock> drdc_lock)
|
||||
: SharedImageRepresentationGLTexture(manager, backing, tracker),
|
||||
RefCountedLockHelperDrDc(std::move(drdc_lock)),
|
||||
texture_(std::move(texture)) {}
|
||||
|
||||
gles2::Texture* GetTexture() override {
|
||||
@ -164,6 +205,8 @@ class SharedImageRepresentationGLTextureVideo
|
||||
}
|
||||
|
||||
bool BeginAccess(GLenum mode) override {
|
||||
scoped_lock_ = GetScopedDrDcLock();
|
||||
|
||||
// This representation should only be called for read or overlay.
|
||||
DCHECK(mode == GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM ||
|
||||
mode == GL_SHARED_IMAGE_ACCESS_MODE_OVERLAY_CHROMIUM);
|
||||
@ -173,26 +216,30 @@ class SharedImageRepresentationGLTextureVideo
|
||||
return true;
|
||||
}
|
||||
|
||||
void EndAccess() override {}
|
||||
void EndAccess() override { scoped_lock_.reset(); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<gles2::AbstractTexture> texture_;
|
||||
std::unique_ptr<base::AutoLockMaybe> scoped_lock_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SharedImageRepresentationGLTextureVideo);
|
||||
};
|
||||
|
||||
// Representation of SharedImageVideo as a GL Texture.
|
||||
class SharedImageRepresentationGLTexturePassthroughVideo
|
||||
: public SharedImageRepresentationGLTexturePassthrough {
|
||||
: public SharedImageRepresentationGLTexturePassthrough,
|
||||
public RefCountedLockHelperDrDc {
|
||||
public:
|
||||
SharedImageRepresentationGLTexturePassthroughVideo(
|
||||
SharedImageManager* manager,
|
||||
SharedImageVideo* backing,
|
||||
MemoryTypeTracker* tracker,
|
||||
std::unique_ptr<gles2::AbstractTexture> abstract_texture)
|
||||
std::unique_ptr<gles2::AbstractTexture> abstract_texture,
|
||||
scoped_refptr<RefCountedLock> drdc_lock)
|
||||
: SharedImageRepresentationGLTexturePassthrough(manager,
|
||||
backing,
|
||||
tracker),
|
||||
RefCountedLockHelperDrDc(std::move(drdc_lock)),
|
||||
abstract_texture_(std::move(abstract_texture)),
|
||||
passthrough_texture_(gles2::TexturePassthrough::CheckedCast(
|
||||
abstract_texture_->GetTextureBase())) {
|
||||
@ -206,6 +253,8 @@ class SharedImageRepresentationGLTexturePassthroughVideo
|
||||
}
|
||||
|
||||
bool BeginAccess(GLenum mode) override {
|
||||
scoped_lock_ = GetScopedDrDcLock();
|
||||
|
||||
// This representation should only be called for read or overlay.
|
||||
DCHECK(mode == GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM ||
|
||||
mode == GL_SHARED_IMAGE_ACCESS_MODE_OVERLAY_CHROMIUM);
|
||||
@ -215,27 +264,31 @@ class SharedImageRepresentationGLTexturePassthroughVideo
|
||||
return true;
|
||||
}
|
||||
|
||||
void EndAccess() override {}
|
||||
void EndAccess() override { scoped_lock_.reset(); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<gles2::AbstractTexture> abstract_texture_;
|
||||
scoped_refptr<gles2::TexturePassthrough> passthrough_texture_;
|
||||
std::unique_ptr<base::AutoLockMaybe> scoped_lock_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SharedImageRepresentationGLTexturePassthroughVideo);
|
||||
};
|
||||
|
||||
class SharedImageRepresentationVideoSkiaVk
|
||||
: public SharedImageRepresentationSkiaVkAndroid {
|
||||
: public SharedImageRepresentationSkiaVkAndroid,
|
||||
public RefCountedLockHelperDrDc {
|
||||
public:
|
||||
SharedImageRepresentationVideoSkiaVk(
|
||||
SharedImageManager* manager,
|
||||
SharedImageBackingAndroid* backing,
|
||||
scoped_refptr<SharedContextState> context_state,
|
||||
MemoryTypeTracker* tracker)
|
||||
MemoryTypeTracker* tracker,
|
||||
scoped_refptr<RefCountedLock> drdc_lock)
|
||||
: SharedImageRepresentationSkiaVkAndroid(manager,
|
||||
backing,
|
||||
std::move(context_state),
|
||||
tracker) {}
|
||||
tracker),
|
||||
RefCountedLockHelperDrDc(std::move(drdc_lock)) {}
|
||||
|
||||
sk_sp<SkSurface> BeginWriteAccess(
|
||||
int final_msaa_count,
|
||||
@ -254,6 +307,8 @@ class SharedImageRepresentationVideoSkiaVk
|
||||
std::vector<GrBackendSemaphore>* begin_semaphores,
|
||||
std::vector<GrBackendSemaphore>* end_semaphores,
|
||||
std::unique_ptr<GrBackendSurfaceMutableState>* end_state) override {
|
||||
scoped_lock_ = GetScopedDrDcLock();
|
||||
|
||||
DCHECK(!scoped_hardware_buffer_);
|
||||
auto* video_backing = static_cast<SharedImageVideo*>(backing());
|
||||
DCHECK(video_backing);
|
||||
@ -283,11 +338,11 @@ class SharedImageRepresentationVideoSkiaVk
|
||||
return nullptr;
|
||||
|
||||
// We always use VK_IMAGE_TILING_OPTIMAL while creating the vk image in
|
||||
// VulkanImplementationAndroid::CreateVkImageAndImportAHB. Hence pass the
|
||||
// tiling parameter as VK_IMAGE_TILING_OPTIMAL to below call rather than
|
||||
// passing |vk_image_info.tiling|. This is also to ensure that the promise
|
||||
// image created here at [1] as well the fullfil image created via the
|
||||
// current function call are consistent and both are using
|
||||
// VulkanImplementationAndroid::CreateVkImageAndImportAHB. Hence pass
|
||||
// the tiling parameter as VK_IMAGE_TILING_OPTIMAL to below call rather
|
||||
// than passing |vk_image_info.tiling|. This is also to ensure that the
|
||||
// promise image created here at [1] as well the fulfill image created
|
||||
// via the current function call are consistent and both are using
|
||||
// VK_IMAGE_TILING_OPTIMAL. [1] -
|
||||
// https://cs.chromium.org/chromium/src/components/viz/service/display_embedder/skia_output_surface_impl.cc?rcl=db5ffd448ba5d66d9d3c5c099754e5067c752465&l=789.
|
||||
DCHECK_EQ(static_cast<int32_t>(vulkan_image_->image_tiling()),
|
||||
@ -310,17 +365,19 @@ class SharedImageRepresentationVideoSkiaVk
|
||||
|
||||
SharedImageRepresentationSkiaVkAndroid::EndReadAccess();
|
||||
|
||||
// Pass the end read access sync fd to the scoped hardware buffer. This will
|
||||
// make sure that the AImage associated with the hardware buffer will be
|
||||
// deleted only when the read access is ending.
|
||||
// Pass the end read access sync fd to the scoped hardware buffer. This
|
||||
// will make sure that the AImage associated with the hardware buffer will
|
||||
// be deleted only when the read access is ending.
|
||||
scoped_hardware_buffer_->SetReadFence(android_backing()->TakeReadFence(),
|
||||
true);
|
||||
scoped_hardware_buffer_ = nullptr;
|
||||
scoped_lock_.reset();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
|
||||
scoped_hardware_buffer_;
|
||||
std::unique_ptr<base::AutoLockMaybe> scoped_lock_;
|
||||
};
|
||||
|
||||
// TODO(vikassoni): Currently GLRenderer doesn't support overlays with shared
|
||||
@ -329,6 +386,8 @@ class SharedImageRepresentationVideoSkiaVk
|
||||
std::unique_ptr<SharedImageRepresentationGLTexture>
|
||||
SharedImageVideo::ProduceGLTexture(SharedImageManager* manager,
|
||||
MemoryTypeTracker* tracker) {
|
||||
base::AutoLockMaybe auto_lock(GetDrDcLockPtr());
|
||||
|
||||
// For (old) overlays, we don't have a texture owner, but overlay promotion
|
||||
// might not happen for some reasons. In that case, it will try to draw
|
||||
// which should result in no image.
|
||||
@ -341,7 +400,7 @@ SharedImageVideo::ProduceGLTexture(SharedImageManager* manager,
|
||||
return nullptr;
|
||||
|
||||
return std::make_unique<SharedImageRepresentationGLTextureVideo>(
|
||||
manager, this, tracker, std::move(texture));
|
||||
manager, this, tracker, std::move(texture), GetDrDcLock());
|
||||
}
|
||||
|
||||
// TODO(vikassoni): Currently GLRenderer doesn't support overlays with shared
|
||||
@ -350,6 +409,8 @@ SharedImageVideo::ProduceGLTexture(SharedImageManager* manager,
|
||||
std::unique_ptr<SharedImageRepresentationGLTexturePassthrough>
|
||||
SharedImageVideo::ProduceGLTexturePassthrough(SharedImageManager* manager,
|
||||
MemoryTypeTracker* tracker) {
|
||||
base::AutoLockMaybe auto_lock(GetDrDcLockPtr());
|
||||
|
||||
// For (old) overlays, we don't have a texture owner, but overlay promotion
|
||||
// might not happen for some reasons. In that case, it will try to draw
|
||||
// which should result in no image.
|
||||
@ -362,7 +423,7 @@ SharedImageVideo::ProduceGLTexturePassthrough(SharedImageManager* manager,
|
||||
return nullptr;
|
||||
|
||||
return std::make_unique<SharedImageRepresentationGLTexturePassthroughVideo>(
|
||||
manager, this, tracker, std::move(texture));
|
||||
manager, this, tracker, std::move(texture), GetDrDcLock());
|
||||
}
|
||||
|
||||
// Currently SkiaRenderer doesn't support overlays.
|
||||
@ -370,6 +431,8 @@ std::unique_ptr<SharedImageRepresentationSkia> SharedImageVideo::ProduceSkia(
|
||||
SharedImageManager* manager,
|
||||
MemoryTypeTracker* tracker,
|
||||
scoped_refptr<SharedContextState> context_state) {
|
||||
base::AutoLockMaybe auto_lock(GetDrDcLockPtr());
|
||||
|
||||
DCHECK(context_state);
|
||||
|
||||
// For (old) overlays, we don't have a texture owner, but overlay promotion
|
||||
@ -380,11 +443,15 @@ std::unique_ptr<SharedImageRepresentationSkia> SharedImageVideo::ProduceSkia(
|
||||
|
||||
if (context_state->GrContextIsVulkan()) {
|
||||
return std::make_unique<SharedImageRepresentationVideoSkiaVk>(
|
||||
manager, this, std::move(context_state), tracker);
|
||||
manager, this, std::move(context_state), tracker, GetDrDcLock());
|
||||
}
|
||||
|
||||
DCHECK(context_state->GrContextIsGL());
|
||||
const bool passthrough = Passthrough();
|
||||
auto* texture_base = stream_texture_sii_->GetTextureBase();
|
||||
DCHECK(texture_base);
|
||||
const bool passthrough =
|
||||
(texture_base->GetType() == gpu::TextureBase::Type::kPassthrough);
|
||||
|
||||
auto texture = GenAbstractTexture(context_state, passthrough);
|
||||
if (!texture)
|
||||
return nullptr;
|
||||
@ -394,27 +461,22 @@ std::unique_ptr<SharedImageRepresentationSkia> SharedImageVideo::ProduceSkia(
|
||||
if (passthrough) {
|
||||
gl_representation =
|
||||
std::make_unique<SharedImageRepresentationGLTexturePassthroughVideo>(
|
||||
manager, this, tracker, std::move(texture));
|
||||
manager, this, tracker, std::move(texture), GetDrDcLock());
|
||||
} else {
|
||||
gl_representation =
|
||||
std::make_unique<SharedImageRepresentationGLTextureVideo>(
|
||||
manager, this, tracker, std::move(texture));
|
||||
manager, this, tracker, std::move(texture), GetDrDcLock());
|
||||
}
|
||||
return SharedImageRepresentationSkiaGL::Create(std::move(gl_representation),
|
||||
std::move(context_state),
|
||||
manager, this, tracker);
|
||||
}
|
||||
|
||||
bool SharedImageVideo::Passthrough() {
|
||||
auto* texture_base = stream_texture_sii_->GetTextureBase();
|
||||
DCHECK(texture_base);
|
||||
|
||||
return (texture_base->GetType() == gpu::TextureBase::Type::kPassthrough);
|
||||
}
|
||||
|
||||
std::unique_ptr<gles2::AbstractTexture> SharedImageVideo::GenAbstractTexture(
|
||||
scoped_refptr<SharedContextState> context_state,
|
||||
const bool passthrough) {
|
||||
AssertAcquiredDrDcLock();
|
||||
|
||||
std::unique_ptr<gles2::AbstractTexture> texture;
|
||||
if (passthrough) {
|
||||
texture = std::make_unique<gles2::AbstractTextureImplPassthrough>(
|
||||
@ -426,8 +488,8 @@ std::unique_ptr<gles2::AbstractTexture> SharedImageVideo::GenAbstractTexture(
|
||||
GL_RGBA, GL_UNSIGNED_BYTE);
|
||||
}
|
||||
|
||||
// If TextureOwner binds texture implicitly on update, that means it will use
|
||||
// TextureOwner texture_id to update and bind. Hence use TextureOwner
|
||||
// If TextureOwner binds texture implicitly on update, that means it will
|
||||
// use TextureOwner texture_id to update and bind. Hence use TextureOwner
|
||||
// texture_id in abstract texture via BindStreamTextureImage().
|
||||
if (stream_texture_sii_->TextureOwnerBindsTextureOnUpdate()) {
|
||||
texture->BindStreamTextureImage(
|
||||
@ -438,48 +500,63 @@ std::unique_ptr<gles2::AbstractTexture> SharedImageVideo::GenAbstractTexture(
|
||||
}
|
||||
|
||||
void SharedImageVideo::BeginGLReadAccess(const GLuint service_id) {
|
||||
AssertAcquiredDrDcLock();
|
||||
stream_texture_sii_->UpdateAndBindTexImage(service_id);
|
||||
}
|
||||
|
||||
// Representation of SharedImageVideo as an overlay plane.
|
||||
class SharedImageRepresentationOverlayVideo
|
||||
: public gpu::SharedImageRepresentationOverlay {
|
||||
: public gpu::SharedImageRepresentationOverlay,
|
||||
public RefCountedLockHelperDrDc {
|
||||
public:
|
||||
SharedImageRepresentationOverlayVideo(gpu::SharedImageManager* manager,
|
||||
SharedImageVideo* backing,
|
||||
gpu::MemoryTypeTracker* tracker)
|
||||
gpu::MemoryTypeTracker* tracker,
|
||||
scoped_refptr<RefCountedLock> drdc_lock)
|
||||
: gpu::SharedImageRepresentationOverlay(manager, backing, tracker),
|
||||
stream_image_(backing->stream_texture_sii_) {}
|
||||
RefCountedLockHelperDrDc(std::move(drdc_lock)) {}
|
||||
|
||||
protected:
|
||||
bool BeginReadAccess(std::vector<gfx::GpuFence>* acquire_fences) override {
|
||||
scoped_lock_ = GetScopedDrDcLock();
|
||||
|
||||
// A |CodecImage| is already in a SurfaceView, render content to the
|
||||
// overlay.
|
||||
if (!stream_image_->HasTextureOwner()) {
|
||||
if (!stream_image()->HasTextureOwner()) {
|
||||
TRACE_EVENT0("media",
|
||||
"SharedImageRepresentationOverlayVideo::BeginReadAccess");
|
||||
stream_image_->RenderToOverlay();
|
||||
stream_image()->RenderToOverlay();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void EndReadAccess(gfx::GpuFenceHandle release_fence) override {
|
||||
DCHECK(release_fence.is_null());
|
||||
scoped_lock_.reset();
|
||||
}
|
||||
|
||||
gl::GLImage* GetGLImage() override {
|
||||
DCHECK(stream_image_->HasTextureOwner())
|
||||
AssertAcquiredDrDcLock();
|
||||
|
||||
DCHECK(stream_image()->HasTextureOwner())
|
||||
<< "The backing is already in a SurfaceView!";
|
||||
return stream_image_.get();
|
||||
return stream_image();
|
||||
}
|
||||
|
||||
void NotifyOverlayPromotion(bool promotion,
|
||||
const gfx::Rect& bounds) override {
|
||||
stream_image_->NotifyOverlayPromotion(promotion, bounds);
|
||||
base::AutoLockMaybe auto_lock(GetDrDcLockPtr());
|
||||
stream_image()->NotifyOverlayPromotion(promotion, bounds);
|
||||
}
|
||||
|
||||
private:
|
||||
scoped_refptr<StreamTextureSharedImageInterface> stream_image_;
|
||||
std::unique_ptr<base::AutoLockMaybe> scoped_lock_;
|
||||
|
||||
StreamTextureSharedImageInterface* stream_image() {
|
||||
auto* video_backing = static_cast<SharedImageVideo*>(backing());
|
||||
DCHECK(video_backing);
|
||||
return video_backing->stream_texture_sii_.get();
|
||||
}
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SharedImageRepresentationOverlayVideo);
|
||||
};
|
||||
@ -487,8 +564,8 @@ class SharedImageRepresentationOverlayVideo
|
||||
std::unique_ptr<gpu::SharedImageRepresentationOverlay>
|
||||
SharedImageVideo::ProduceOverlay(gpu::SharedImageManager* manager,
|
||||
gpu::MemoryTypeTracker* tracker) {
|
||||
return std::make_unique<SharedImageRepresentationOverlayVideo>(manager, this,
|
||||
tracker);
|
||||
return std::make_unique<SharedImageRepresentationOverlayVideo>(
|
||||
manager, this, tracker, GetDrDcLock());
|
||||
}
|
||||
|
||||
} // namespace gpu
|
||||
|
@ -8,6 +8,9 @@
|
||||
#include <memory>
|
||||
|
||||
#include "base/memory/scoped_refptr.h"
|
||||
#include "base/single_thread_task_runner.h"
|
||||
#include "base/synchronization/waitable_event.h"
|
||||
#include "gpu/command_buffer/service/ref_counted_lock.h"
|
||||
#include "gpu/command_buffer/service/shared_context_state.h"
|
||||
#include "gpu/command_buffer/service/shared_image_backing_android.h"
|
||||
#include "gpu/command_buffer/service/stream_texture_shared_image_interface.h"
|
||||
@ -28,7 +31,8 @@ class AbstractTexture;
|
||||
// TextureOwner or overlay as needed in order to draw them.
|
||||
class GPU_GLES2_EXPORT SharedImageVideo
|
||||
: public SharedImageBackingAndroid,
|
||||
public SharedContextState::ContextLostObserver {
|
||||
public SharedContextState::ContextLostObserver,
|
||||
public RefCountedLockHelperDrDc {
|
||||
public:
|
||||
SharedImageVideo(
|
||||
const Mailbox& mailbox,
|
||||
@ -38,7 +42,8 @@ class GPU_GLES2_EXPORT SharedImageVideo
|
||||
SkAlphaType alpha_type,
|
||||
scoped_refptr<StreamTextureSharedImageInterface> stream_texture_sii,
|
||||
scoped_refptr<SharedContextState> shared_context_state,
|
||||
bool is_thread_safe);
|
||||
bool is_thread_safe,
|
||||
scoped_refptr<RefCountedLock> drdc_lock);
|
||||
|
||||
~SharedImageVideo() override;
|
||||
|
||||
@ -88,10 +93,6 @@ class GPU_GLES2_EXPORT SharedImageVideo
|
||||
friend class SharedImageRepresentationVideoSkiaVk;
|
||||
friend class SharedImageRepresentationOverlayVideo;
|
||||
|
||||
// Whether we're using the passthrough command decoder and should generate
|
||||
// passthrough textures.
|
||||
bool Passthrough();
|
||||
|
||||
// Helper method to generate an abstract texture.
|
||||
std::unique_ptr<gles2::AbstractTexture> GenAbstractTexture(
|
||||
scoped_refptr<SharedContextState> context_state,
|
||||
@ -99,8 +100,22 @@ class GPU_GLES2_EXPORT SharedImageVideo
|
||||
|
||||
void BeginGLReadAccess(const GLuint service_id);
|
||||
|
||||
// Creating representations on SharedImageVideo is already thread safe
|
||||
// but SharedImageVideo backing can be destroyed on any thread when a
|
||||
// backing is used by multiple threads like dr-dc. Hence backing is not
|
||||
// guaranteed to be destroyed on the same thread on which it was created.
|
||||
// This method ensures that all the member variables of this class are
|
||||
// destroyed on the thread in which it was created.
|
||||
static void CleanupOnCorrectThread(
|
||||
scoped_refptr<StreamTextureSharedImageInterface> stream_texture_sii,
|
||||
scoped_refptr<SharedContextState> context_state,
|
||||
SharedImageVideo* backing,
|
||||
base::WaitableEvent* event,
|
||||
scoped_refptr<RefCountedLock> lock);
|
||||
|
||||
scoped_refptr<StreamTextureSharedImageInterface> stream_texture_sii_;
|
||||
scoped_refptr<SharedContextState> context_state_;
|
||||
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SharedImageVideo);
|
||||
};
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "base/synchronization/waitable_event.h"
|
||||
#include "base/threading/thread_task_runner_handle.h"
|
||||
#include "gpu/command_buffer/service/abstract_texture.h"
|
||||
#include "gpu/config/gpu_finch_features.h"
|
||||
#include "ui/gl/scoped_binders.h"
|
||||
#include "ui/gl/scoped_make_current.h"
|
||||
|
||||
@ -33,6 +34,7 @@ SurfaceTextureGLOwner::SurfaceTextureGLOwner(
|
||||
surface_(gl::GLSurface::GetCurrent()) {
|
||||
DCHECK(context_);
|
||||
DCHECK(surface_);
|
||||
DCHECK(!features::IsDrDcEnabled());
|
||||
}
|
||||
|
||||
SurfaceTextureGLOwner::~SurfaceTextureGLOwner() {
|
||||
|
@ -327,7 +327,7 @@ gpu::Mailbox StreamTexture::CreateSharedImage(const gfx::Size& coded_size) {
|
||||
auto shared_image = std::make_unique<SharedImageVideo>(
|
||||
mailbox, coded_size, gfx::ColorSpace::CreateSRGB(),
|
||||
kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, this, context_state_,
|
||||
false);
|
||||
/*is_thread_safe=*/true, /*lock=*/nullptr);
|
||||
channel_->shared_image_stub()->factory()->RegisterBacking(
|
||||
std::move(shared_image), /*allow_legacy_mailbox=*/false);
|
||||
|
||||
|
@ -27,8 +27,10 @@ struct FrameAvailableEvent
|
||||
};
|
||||
|
||||
CodecBufferWaitCoordinator::CodecBufferWaitCoordinator(
|
||||
scoped_refptr<gpu::TextureOwner> texture_owner)
|
||||
: texture_owner_(std::move(texture_owner)),
|
||||
scoped_refptr<gpu::TextureOwner> texture_owner,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock)
|
||||
: RefCountedLockHelperDrDc(std::move(drdc_lock)),
|
||||
texture_owner_(std::move(texture_owner)),
|
||||
frame_available_event_(new FrameAvailableEvent()),
|
||||
task_runner_(base::ThreadTaskRunnerHandle::Get()) {
|
||||
DCHECK(texture_owner_);
|
||||
@ -41,14 +43,17 @@ CodecBufferWaitCoordinator::~CodecBufferWaitCoordinator() {
|
||||
}
|
||||
|
||||
void CodecBufferWaitCoordinator::SetReleaseTimeToNow() {
|
||||
AssertAcquiredDrDcLock();
|
||||
release_time_ = base::TimeTicks::Now();
|
||||
}
|
||||
|
||||
bool CodecBufferWaitCoordinator::IsExpectingFrameAvailable() {
|
||||
AssertAcquiredDrDcLock();
|
||||
return !release_time_.is_null();
|
||||
}
|
||||
|
||||
void CodecBufferWaitCoordinator::WaitForFrameAvailable() {
|
||||
AssertAcquiredDrDcLock();
|
||||
DCHECK(!release_time_.is_null());
|
||||
|
||||
const base::TimeTicks call_time = base::TimeTicks::Now();
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "base/synchronization/waitable_event.h"
|
||||
#include "base/threading/thread_checker.h"
|
||||
#include "base/time/time.h"
|
||||
#include "gpu/command_buffer/service/ref_counted_lock.h"
|
||||
#include "gpu/command_buffer/service/texture_owner.h"
|
||||
#include "media/base/tuneable.h"
|
||||
#include "media/gpu/media_gpu_export.h"
|
||||
@ -19,12 +20,17 @@ struct FrameAvailableEvent;
|
||||
|
||||
// This class supports waiting for codec buffers to be released/rendered before
|
||||
// using them. This class is RefCountedThreadSafe to make sure it's safe to
|
||||
// keep and drop refptrs to it on any thread.
|
||||
// keep and drop refptrs to it on any thread. Note that when DrDc is
|
||||
// enabled(kEnableDrDc), a per codec dr-dc lock is expected to be held while
|
||||
// calling methods of this class. This is ensured by adding
|
||||
// AssertAcquiredDrDcLock() to those methods.
|
||||
class MEDIA_GPU_EXPORT CodecBufferWaitCoordinator
|
||||
: public base::RefCountedThreadSafe<CodecBufferWaitCoordinator> {
|
||||
: public base::RefCountedThreadSafe<CodecBufferWaitCoordinator>,
|
||||
public gpu::RefCountedLockHelperDrDc {
|
||||
public:
|
||||
explicit CodecBufferWaitCoordinator(
|
||||
scoped_refptr<gpu::TextureOwner> texture_owner);
|
||||
scoped_refptr<gpu::TextureOwner> texture_owner,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock);
|
||||
|
||||
scoped_refptr<gpu::TextureOwner> texture_owner() const {
|
||||
DCHECK(texture_owner_);
|
||||
@ -55,6 +61,7 @@ class MEDIA_GPU_EXPORT CodecBufferWaitCoordinator
|
||||
friend class base::RefCountedThreadSafe<CodecBufferWaitCoordinator>;
|
||||
|
||||
scoped_refptr<gpu::TextureOwner> texture_owner_;
|
||||
|
||||
base::TimeTicks release_time_;
|
||||
scoped_refptr<FrameAvailableEvent> frame_available_event_;
|
||||
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
|
||||
|
@ -12,14 +12,19 @@
|
||||
#include "base/callback_helpers.h"
|
||||
#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
|
||||
#include "gpu/command_buffer/service/texture_manager.h"
|
||||
#include "gpu/config/gpu_finch_features.h"
|
||||
#include "ui/gl/gl_context.h"
|
||||
#include "ui/gl/scoped_make_current.h"
|
||||
|
||||
namespace media {
|
||||
|
||||
CodecImage::CodecImage(const gfx::Size& coded_size) : coded_size_(coded_size) {}
|
||||
CodecImage::CodecImage(const gfx::Size& coded_size,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock)
|
||||
: RefCountedLockHelperDrDc(std::move(drdc_lock)), coded_size_(coded_size) {}
|
||||
|
||||
CodecImage::~CodecImage() {
|
||||
DCHECK_CALLED_ON_VALID_THREAD(gpu_main_thread_checker_);
|
||||
AssertAcquiredDrDcLock();
|
||||
NotifyUnused();
|
||||
}
|
||||
|
||||
@ -34,10 +39,14 @@ void CodecImage::Initialize(
|
||||
}
|
||||
|
||||
void CodecImage::AddUnusedCB(UnusedCB unused_cb) {
|
||||
DCHECK_CALLED_ON_VALID_THREAD(gpu_main_thread_checker_);
|
||||
unused_cbs_.push_back(std::move(unused_cb));
|
||||
}
|
||||
|
||||
void CodecImage::NotifyUnused() {
|
||||
DCHECK_CALLED_ON_VALID_THREAD(gpu_main_thread_checker_);
|
||||
AssertAcquiredDrDcLock();
|
||||
|
||||
// If we haven't done so yet, release the codec output buffer. Also drop
|
||||
// our reference to the TextureOwner (if any). In other words, undo anything
|
||||
// that we did in Initialize.
|
||||
@ -50,24 +59,30 @@ void CodecImage::NotifyUnused() {
|
||||
}
|
||||
|
||||
gfx::Size CodecImage::GetSize() {
|
||||
DCHECK_CALLED_ON_VALID_THREAD(gpu_main_thread_checker_);
|
||||
return coded_size_;
|
||||
}
|
||||
|
||||
unsigned CodecImage::GetInternalFormat() {
|
||||
DCHECK_CALLED_ON_VALID_THREAD(gpu_main_thread_checker_);
|
||||
return GL_RGBA;
|
||||
}
|
||||
|
||||
unsigned CodecImage::GetDataType() {
|
||||
DCHECK_CALLED_ON_VALID_THREAD(gpu_main_thread_checker_);
|
||||
return GL_UNSIGNED_BYTE;
|
||||
}
|
||||
|
||||
CodecImage::BindOrCopy CodecImage::ShouldBindOrCopy() {
|
||||
DCHECK_CALLED_ON_VALID_THREAD(gpu_main_thread_checker_);
|
||||
|
||||
// If we're using an overlay, then pretend it's bound. That way, we'll get
|
||||
// calls to ScheduleOverlayPlane. Otherwise, CopyTexImage needs to be called.
|
||||
return is_texture_owner_backed_ ? COPY : BIND;
|
||||
}
|
||||
|
||||
bool CodecImage::BindTexImage(unsigned target) {
|
||||
DCHECK_CALLED_ON_VALID_THREAD(gpu_main_thread_checker_);
|
||||
DCHECK_EQ(BIND, ShouldBindOrCopy());
|
||||
return true;
|
||||
}
|
||||
@ -75,6 +90,12 @@ bool CodecImage::BindTexImage(unsigned target) {
|
||||
void CodecImage::ReleaseTexImage(unsigned target) {}
|
||||
|
||||
bool CodecImage::CopyTexImage(unsigned target) {
|
||||
DCHECK_CALLED_ON_VALID_THREAD(gpu_main_thread_checker_);
|
||||
|
||||
// This method is only called for SurfaceTexture implementation for which DrDc
|
||||
// is disabled.
|
||||
DCHECK(!features::IsDrDcEnabled());
|
||||
|
||||
TRACE_EVENT0("media", "CodecImage::CopyTexImage");
|
||||
DCHECK_EQ(COPY, ShouldBindOrCopy());
|
||||
|
||||
@ -133,6 +154,7 @@ bool CodecImage::ScheduleOverlayPlane(
|
||||
|
||||
void CodecImage::NotifyOverlayPromotion(bool promotion,
|
||||
const gfx::Rect& bounds) {
|
||||
AssertAcquiredDrDcLock();
|
||||
// Use-after-release. It happens if the renderer crashes before getting
|
||||
// returns from viz.
|
||||
if (!promotion_hint_cb_)
|
||||
@ -165,17 +187,22 @@ void CodecImage::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
|
||||
const std::string& dump_name) {}
|
||||
|
||||
void CodecImage::ReleaseResources() {
|
||||
DCHECK_CALLED_ON_VALID_THREAD(gpu_main_thread_checker_);
|
||||
ReleaseCodecBuffer();
|
||||
}
|
||||
|
||||
bool CodecImage::IsUsingGpuMemory() const {
|
||||
DCHECK_CALLED_ON_VALID_THREAD(gpu_main_thread_checker_);
|
||||
AssertAcquiredDrDcLock();
|
||||
if (!output_buffer_renderer_)
|
||||
return false;
|
||||
|
||||
// Only the images which are bound to texture accounts for gpu memory.
|
||||
return output_buffer_renderer_->was_tex_image_bound();
|
||||
}
|
||||
|
||||
void CodecImage::UpdateAndBindTexImage(GLuint service_id) {
|
||||
AssertAcquiredDrDcLock();
|
||||
RenderToTextureOwnerFrontBuffer(BindingsMode::kEnsureTexImageBound,
|
||||
service_id);
|
||||
}
|
||||
@ -189,12 +216,16 @@ gpu::TextureBase* CodecImage::GetTextureBase() const {
|
||||
}
|
||||
|
||||
bool CodecImage::RenderToFrontBuffer() {
|
||||
DCHECK_CALLED_ON_VALID_THREAD(gpu_main_thread_checker_);
|
||||
AssertAcquiredDrDcLock();
|
||||
if (!output_buffer_renderer_)
|
||||
return false;
|
||||
return output_buffer_renderer_->RenderToFrontBuffer();
|
||||
}
|
||||
|
||||
bool CodecImage::RenderToTextureOwnerBackBuffer() {
|
||||
DCHECK_CALLED_ON_VALID_THREAD(gpu_main_thread_checker_);
|
||||
AssertAcquiredDrDcLock();
|
||||
if (!output_buffer_renderer_)
|
||||
return false;
|
||||
|
||||
@ -203,6 +234,7 @@ bool CodecImage::RenderToTextureOwnerBackBuffer() {
|
||||
|
||||
bool CodecImage::RenderToTextureOwnerFrontBuffer(BindingsMode bindings_mode,
|
||||
GLuint service_id) {
|
||||
AssertAcquiredDrDcLock();
|
||||
if (!output_buffer_renderer_)
|
||||
return false;
|
||||
return output_buffer_renderer_->RenderToTextureOwnerFrontBuffer(bindings_mode,
|
||||
@ -210,23 +242,29 @@ bool CodecImage::RenderToTextureOwnerFrontBuffer(BindingsMode bindings_mode,
|
||||
}
|
||||
|
||||
bool CodecImage::RenderToOverlay() {
|
||||
AssertAcquiredDrDcLock();
|
||||
if (!output_buffer_renderer_)
|
||||
return false;
|
||||
return output_buffer_renderer_->RenderToOverlay();
|
||||
}
|
||||
|
||||
bool CodecImage::TextureOwnerBindsTextureOnUpdate() {
|
||||
AssertAcquiredDrDcLock();
|
||||
if (!output_buffer_renderer_)
|
||||
return false;
|
||||
return output_buffer_renderer_->texture_owner()->binds_texture_on_update();
|
||||
}
|
||||
|
||||
void CodecImage::ReleaseCodecBuffer() {
|
||||
DCHECK_CALLED_ON_VALID_THREAD(gpu_main_thread_checker_);
|
||||
AssertAcquiredDrDcLock();
|
||||
output_buffer_renderer_.reset();
|
||||
}
|
||||
|
||||
std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
|
||||
CodecImage::GetAHardwareBuffer() {
|
||||
AssertAcquiredDrDcLock();
|
||||
|
||||
// It would be nice if this didn't happen, but we can be incorrectly marked
|
||||
// as free when viz is still using us for drawing. This can happen if the
|
||||
// renderer crashes before receiving returns. It's hard to catch elsewhere,
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "base/callback.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/memory/ref_counted_delete_on_sequence.h"
|
||||
#include "gpu/command_buffer/service/ref_counted_lock.h"
|
||||
#include "gpu/command_buffer/service/stream_texture_shared_image_interface.h"
|
||||
#include "media/gpu/android/codec_output_buffer_renderer.h"
|
||||
#include "media/gpu/android/promotion_hint_aggregator.h"
|
||||
@ -27,9 +28,14 @@ class ScopedHardwareBufferFenceSync;
|
||||
namespace media {
|
||||
|
||||
// A GLImage that renders MediaCodec buffers to a TextureOwner or overlay
|
||||
// as needed in order to draw them.
|
||||
// as needed in order to draw them. Note that when DrDc is enabled(kEnableDrDc),
|
||||
// a per codec dr-dc lock is expected to be held while calling methods of this
|
||||
// class. This is ensured by adding AssertAcquiredDrDcLock() to those methods.
|
||||
// We are not adding a Locked suffix on those methods since many of those
|
||||
// methods are either overrides or virtual.
|
||||
class MEDIA_GPU_EXPORT CodecImage
|
||||
: public gpu::StreamTextureSharedImageInterface {
|
||||
: public gpu::StreamTextureSharedImageInterface,
|
||||
gpu::RefCountedLockHelperDrDc {
|
||||
public:
|
||||
// Callback to notify that a codec image is now unused in the sense of not
|
||||
// being out for display. This lets us signal interested folks once a video
|
||||
@ -42,7 +48,8 @@ class MEDIA_GPU_EXPORT CodecImage
|
||||
// destroying it.
|
||||
using UnusedCB = base::OnceCallback<void(CodecImage*)>;
|
||||
|
||||
CodecImage(const gfx::Size& coded_size);
|
||||
CodecImage(const gfx::Size& coded_size,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock);
|
||||
|
||||
// (Re-)Initialize this CodecImage to use |output_buffer| et. al.
|
||||
//
|
||||
@ -178,6 +185,10 @@ class MEDIA_GPU_EXPORT CodecImage
|
||||
|
||||
std::vector<UnusedCB> unused_cbs_;
|
||||
|
||||
// Bound to the gpu main thread on which this CodecImage is created. Some
|
||||
// methods can only be called on this thread.
|
||||
THREAD_CHECKER(gpu_main_thread_checker_);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CodecImage);
|
||||
};
|
||||
|
||||
|
@ -12,8 +12,10 @@ namespace media {
|
||||
|
||||
CodecImageGroup::CodecImageGroup(
|
||||
scoped_refptr<base::SequencedTaskRunner> task_runner,
|
||||
scoped_refptr<CodecSurfaceBundle> surface_bundle)
|
||||
: surface_bundle_(std::move(surface_bundle)),
|
||||
scoped_refptr<CodecSurfaceBundle> surface_bundle,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock)
|
||||
: gpu::RefCountedLockHelperDrDc(std::move(drdc_lock)),
|
||||
surface_bundle_(std::move(surface_bundle)),
|
||||
task_runner_(std::move(task_runner)) {
|
||||
// If the surface bundle has an overlay, then register for destruction
|
||||
// callbacks. We thread-hop to the right thread, which means that we might
|
||||
@ -50,6 +52,7 @@ void CodecImageGroup::AddCodecImage(CodecImage* image) {
|
||||
// If somebody adds an image after the surface has been destroyed, fail the
|
||||
// image immediately. This can happen due to thread hopping.
|
||||
if (!surface_bundle_) {
|
||||
base::AutoLockMaybe auto_lock(GetDrDcLockPtr());
|
||||
image->ReleaseCodecBuffer();
|
||||
return;
|
||||
}
|
||||
@ -75,8 +78,10 @@ void CodecImageGroup::OnSurfaceDestroyed(AndroidOverlay* overlay) {
|
||||
CHECK(task_runner_->RunsTasksInCurrentSequence());
|
||||
// Release any codec buffer, so that the image doesn't try to render to the
|
||||
// overlay. If it already did, that's fine.
|
||||
for (CodecImage* image : images_)
|
||||
for (CodecImage* image : images_) {
|
||||
base::AutoLockMaybe auto_lock(GetDrDcLockPtr());
|
||||
image->ReleaseCodecBuffer();
|
||||
}
|
||||
|
||||
// While this might cause |surface_bundle_| to be deleted, it's okay because
|
||||
// it's a RefCountedDeleteOnSequence.
|
||||
|
@ -36,13 +36,15 @@ class CodecSurfaceBundle;
|
||||
// bundle (and overlay) may be accessed. All other methods will run on the
|
||||
// provided task runner.
|
||||
class MEDIA_GPU_EXPORT CodecImageGroup
|
||||
: public base::RefCountedThreadSafe<CodecImageGroup> {
|
||||
: public base::RefCountedThreadSafe<CodecImageGroup>,
|
||||
public gpu::RefCountedLockHelperDrDc {
|
||||
public:
|
||||
// NOTE: Construction happens on the correct thread to access |bundle| and
|
||||
// any overlay it contains. All other access to this class will happen on
|
||||
// |task_runner|, including destruction.
|
||||
CodecImageGroup(scoped_refptr<base::SequencedTaskRunner> task_runner,
|
||||
scoped_refptr<CodecSurfaceBundle> bundle);
|
||||
scoped_refptr<CodecSurfaceBundle> bundle,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock);
|
||||
|
||||
// Notify us that |image| uses |surface_bundle_|. We will remove |image| from
|
||||
// the group automatically when it's no longer using |surface_bundle_|.
|
||||
|
@ -29,7 +29,9 @@ class CodecImageGroupWithDestructionHook : public CodecImageGroup {
|
||||
CodecImageGroupWithDestructionHook(
|
||||
scoped_refptr<base::SequencedTaskRunner> task_runner,
|
||||
scoped_refptr<CodecSurfaceBundle> surface_bundle)
|
||||
: CodecImageGroup(std::move(task_runner), std::move(surface_bundle)) {}
|
||||
: CodecImageGroup(std::move(task_runner),
|
||||
std::move(surface_bundle),
|
||||
/*lock=*/nullptr) {}
|
||||
|
||||
void SetDestructionCallback(base::OnceClosure cb) {
|
||||
destruction_cb_ = std::move(cb);
|
||||
@ -111,7 +113,8 @@ TEST_F(CodecImageGroupTest, SurfaceBundleWithoutOverlayDoesntCrash) {
|
||||
scoped_refptr<CodecSurfaceBundle> surface_bundle =
|
||||
base::MakeRefCounted<CodecSurfaceBundle>();
|
||||
scoped_refptr<CodecImageGroup> image_group =
|
||||
base::MakeRefCounted<CodecImageGroup>(gpu_task_runner_, surface_bundle);
|
||||
base::MakeRefCounted<CodecImageGroup>(gpu_task_runner_, surface_bundle,
|
||||
/*lock=*/nullptr);
|
||||
// TODO(liberato): we should also make sure that adding an image doesn't call
|
||||
// ReleaseCodecBuffer when it's added.
|
||||
}
|
||||
|
@ -90,9 +90,10 @@ class CodecImageTest : public testing::Test {
|
||||
auto codec_buffer_wait_coordinator =
|
||||
kind == kTextureOwner ? codec_buffer_wait_coordinator_ : nullptr;
|
||||
auto buffer_renderer = std::make_unique<CodecOutputBufferRenderer>(
|
||||
std::move(buffer), codec_buffer_wait_coordinator);
|
||||
std::move(buffer), codec_buffer_wait_coordinator, /*lock=*/nullptr);
|
||||
|
||||
scoped_refptr<CodecImage> image = new CodecImage(buffer_renderer->size());
|
||||
scoped_refptr<CodecImage> image =
|
||||
new CodecImage(buffer_renderer->size(), /*lock=*/nullptr);
|
||||
image->Initialize(
|
||||
std::move(buffer_renderer), kind == kTextureOwner,
|
||||
base::BindRepeating(&PromotionHintReceiver::OnPromotionHint,
|
||||
@ -374,10 +375,11 @@ TEST_F(CodecImageTest, CodedSizeVsVisibleSize) {
|
||||
const gfx::Size coded_size(128, 128);
|
||||
const gfx::Size visible_size(100, 100);
|
||||
auto buffer = CodecOutputBuffer::CreateForTesting(0, visible_size);
|
||||
auto buffer_renderer =
|
||||
std::make_unique<CodecOutputBufferRenderer>(std::move(buffer), nullptr);
|
||||
auto buffer_renderer = std::make_unique<CodecOutputBufferRenderer>(
|
||||
std::move(buffer), nullptr, /*lock=*/nullptr);
|
||||
|
||||
scoped_refptr<CodecImage> image = new CodecImage(coded_size);
|
||||
scoped_refptr<CodecImage> image =
|
||||
new CodecImage(coded_size, /*lock=*/nullptr);
|
||||
image->Initialize(std::move(buffer_renderer), false,
|
||||
PromotionHintAggregator::NotifyPromotionHintCB());
|
||||
|
||||
|
@ -43,15 +43,17 @@ std::unique_ptr<ui::ScopedMakeCurrent> MakeCurrentIfNeeded(
|
||||
|
||||
CodecOutputBufferRenderer::CodecOutputBufferRenderer(
|
||||
std::unique_ptr<CodecOutputBuffer> output_buffer,
|
||||
scoped_refptr<CodecBufferWaitCoordinator> codec_buffer_wait_coordinator)
|
||||
: output_buffer_(std::move(output_buffer)),
|
||||
scoped_refptr<CodecBufferWaitCoordinator> codec_buffer_wait_coordinator,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock)
|
||||
: RefCountedLockHelperDrDc(std::move(drdc_lock)),
|
||||
output_buffer_(std::move(output_buffer)),
|
||||
codec_buffer_wait_coordinator_(std::move(codec_buffer_wait_coordinator)) {
|
||||
|
||||
}
|
||||
|
||||
CodecOutputBufferRenderer::~CodecOutputBufferRenderer() = default;
|
||||
|
||||
bool CodecOutputBufferRenderer::RenderToTextureOwnerBackBuffer() {
|
||||
AssertAcquiredDrDcLock();
|
||||
DCHECK_NE(phase_, Phase::kInFrontBuffer);
|
||||
if (phase_ == Phase::kInBackBuffer)
|
||||
return true;
|
||||
@ -83,6 +85,7 @@ bool CodecOutputBufferRenderer::RenderToTextureOwnerBackBuffer() {
|
||||
bool CodecOutputBufferRenderer::RenderToTextureOwnerFrontBuffer(
|
||||
BindingsMode bindings_mode,
|
||||
GLuint service_id) {
|
||||
AssertAcquiredDrDcLock();
|
||||
// Normally, we should have a wait coordinator if we're called. However, if
|
||||
// the renderer is torn down (either VideoFrameSubmitter or the whole process)
|
||||
// before we get returns back from viz, then we can be notified that we're
|
||||
@ -152,6 +155,7 @@ bool CodecOutputBufferRenderer::RenderToTextureOwnerFrontBuffer(
|
||||
|
||||
void CodecOutputBufferRenderer::EnsureBoundIfNeeded(BindingsMode mode,
|
||||
GLuint service_id) {
|
||||
AssertAcquiredDrDcLock();
|
||||
DCHECK(codec_buffer_wait_coordinator_);
|
||||
|
||||
if (codec_buffer_wait_coordinator_->texture_owner()
|
||||
@ -174,6 +178,7 @@ void CodecOutputBufferRenderer::EnsureBoundIfNeeded(BindingsMode mode,
|
||||
}
|
||||
|
||||
bool CodecOutputBufferRenderer::RenderToOverlay() {
|
||||
AssertAcquiredDrDcLock();
|
||||
if (phase_ == Phase::kInFrontBuffer)
|
||||
return true;
|
||||
if (phase_ == Phase::kInvalidated)
|
||||
@ -188,6 +193,8 @@ bool CodecOutputBufferRenderer::RenderToOverlay() {
|
||||
}
|
||||
|
||||
bool CodecOutputBufferRenderer::RenderToFrontBuffer() {
|
||||
AssertAcquiredDrDcLock();
|
||||
|
||||
// This code is used to trigger early rendering of the image before it is used
|
||||
// for compositing, there is no need to bind the image. Hence pass texture
|
||||
// service_id as 0.
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "gpu/command_buffer/service/ref_counted_lock.h"
|
||||
#include "gpu/command_buffer/service/stream_texture_shared_image_interface.h"
|
||||
#include "media/gpu/android/codec_buffer_wait_coordinator.h"
|
||||
#include "media/gpu/android/codec_wrapper.h"
|
||||
@ -18,14 +19,18 @@ namespace media {
|
||||
|
||||
// A class that holds CodecOutputBuffer and renders it to TextureOwner or
|
||||
// overlay as necessary. Unit tests for this class are part of CodecImage unit
|
||||
// tests.
|
||||
class MEDIA_GPU_EXPORT CodecOutputBufferRenderer {
|
||||
// tests. Note that when DrDc is enabled(kEnableDrDc),
|
||||
// a per codec dr-dc lock is expected to be held while calling methods of this
|
||||
// class. This is ensured by adding AssertAcquiredDrDcLock() to those methods.
|
||||
class MEDIA_GPU_EXPORT CodecOutputBufferRenderer
|
||||
: public gpu::RefCountedLockHelperDrDc {
|
||||
public:
|
||||
using BindingsMode = gpu::StreamTextureSharedImageInterface::BindingsMode;
|
||||
|
||||
CodecOutputBufferRenderer(
|
||||
std::unique_ptr<CodecOutputBuffer> output_buffer,
|
||||
scoped_refptr<CodecBufferWaitCoordinator> codec_buffer_wait_coordinator);
|
||||
scoped_refptr<CodecBufferWaitCoordinator> codec_buffer_wait_coordinator,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock);
|
||||
~CodecOutputBufferRenderer();
|
||||
|
||||
CodecOutputBufferRenderer(const CodecOutputBufferRenderer&) = delete;
|
||||
@ -60,6 +65,7 @@ class MEDIA_GPU_EXPORT CodecOutputBufferRenderer {
|
||||
|
||||
// Whether the codec buffer has been rendered to the front buffer.
|
||||
bool was_rendered_to_front_buffer() const {
|
||||
AssertAcquiredDrDcLock();
|
||||
return phase_ == Phase::kInFrontBuffer;
|
||||
}
|
||||
|
||||
|
@ -20,12 +20,14 @@ CodecSurfaceBundle::CodecSurfaceBundle(std::unique_ptr<AndroidOverlay> overlay)
|
||||
overlay_(std::move(overlay)) {}
|
||||
|
||||
CodecSurfaceBundle::CodecSurfaceBundle(
|
||||
scoped_refptr<gpu::TextureOwner> texture_owner)
|
||||
scoped_refptr<gpu::TextureOwner> texture_owner,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock)
|
||||
: RefCountedDeleteOnSequence<CodecSurfaceBundle>(
|
||||
base::SequencedTaskRunnerHandle::Get()),
|
||||
codec_buffer_wait_coordinator_(
|
||||
base::MakeRefCounted<CodecBufferWaitCoordinator>(
|
||||
std::move(texture_owner))),
|
||||
std::move(texture_owner),
|
||||
std::move(drdc_lock))),
|
||||
texture_owner_surface_(codec_buffer_wait_coordinator_->texture_owner()
|
||||
->CreateJavaSurface()) {}
|
||||
|
||||
|
@ -12,6 +12,10 @@
|
||||
#include "media/gpu/media_gpu_export.h"
|
||||
#include "ui/gl/android/scoped_java_surface.h"
|
||||
|
||||
namespace gpu {
|
||||
class RefCountedLock;
|
||||
} // namespace gpu
|
||||
|
||||
namespace media {
|
||||
|
||||
// CodecSurfaceBundle is a Java surface, and the TextureOwner or Overlay that
|
||||
@ -28,7 +32,8 @@ class MEDIA_GPU_EXPORT CodecSurfaceBundle
|
||||
// Create an empty bundle to be manually populated.
|
||||
CodecSurfaceBundle();
|
||||
explicit CodecSurfaceBundle(std::unique_ptr<AndroidOverlay> overlay);
|
||||
explicit CodecSurfaceBundle(scoped_refptr<gpu::TextureOwner> texture_owner);
|
||||
explicit CodecSurfaceBundle(scoped_refptr<gpu::TextureOwner> texture_owner,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock);
|
||||
|
||||
const base::android::JavaRef<jobject>& GetJavaSurface() const;
|
||||
|
||||
|
@ -54,8 +54,10 @@ using gpu::gles2::AbstractTexture;
|
||||
|
||||
DirectSharedImageVideoProvider::DirectSharedImageVideoProvider(
|
||||
scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
|
||||
GetStubCB get_stub_cb)
|
||||
: gpu_factory_(gpu_task_runner, std::move(get_stub_cb)),
|
||||
GetStubCB get_stub_cb,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock)
|
||||
: gpu::RefCountedLockHelperDrDc(std::move(drdc_lock)),
|
||||
gpu_factory_(gpu_task_runner, std::move(get_stub_cb)),
|
||||
gpu_task_runner_(std::move(gpu_task_runner)) {}
|
||||
|
||||
DirectSharedImageVideoProvider::~DirectSharedImageVideoProvider() = default;
|
||||
@ -84,7 +86,7 @@ void DirectSharedImageVideoProvider::RequestImage(ImageReadyCB cb,
|
||||
// Note: `cb` is only run on successful creation, so this does not use
|
||||
// `AsyncCall()` + `Then()` to chain the callbacks.
|
||||
gpu_factory_.AsyncCall(&GpuSharedImageVideoFactory::CreateImage)
|
||||
.WithArgs(BindToCurrentLoop(std::move(cb)), spec);
|
||||
.WithArgs(BindToCurrentLoop(std::move(cb)), spec, GetDrDcLock());
|
||||
}
|
||||
|
||||
GpuSharedImageVideoFactory::GpuSharedImageVideoFactory(
|
||||
@ -139,16 +141,18 @@ void GpuSharedImageVideoFactory::Initialize(
|
||||
|
||||
void GpuSharedImageVideoFactory::CreateImage(
|
||||
FactoryImageReadyCB image_ready_cb,
|
||||
const SharedImageVideoProvider::ImageSpec& spec) {
|
||||
const SharedImageVideoProvider::ImageSpec& spec,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock) {
|
||||
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
|
||||
|
||||
// Generate a shared image mailbox.
|
||||
auto mailbox = gpu::Mailbox::GenerateForSharedImage();
|
||||
auto codec_image = base::MakeRefCounted<CodecImage>(spec.coded_size);
|
||||
auto codec_image =
|
||||
base::MakeRefCounted<CodecImage>(spec.coded_size, drdc_lock);
|
||||
|
||||
TRACE_EVENT0("media", "GpuSharedImageVideoFactory::CreateVideoFrame");
|
||||
|
||||
if (!CreateImageInternal(spec, mailbox, codec_image)) {
|
||||
if (!CreateImageInternal(spec, mailbox, codec_image, std::move(drdc_lock))) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -185,7 +189,8 @@ void GpuSharedImageVideoFactory::CreateImage(
|
||||
bool GpuSharedImageVideoFactory::CreateImageInternal(
|
||||
const SharedImageVideoProvider::ImageSpec& spec,
|
||||
gpu::Mailbox mailbox,
|
||||
scoped_refptr<CodecImage> image) {
|
||||
scoped_refptr<CodecImage> image,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock) {
|
||||
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
|
||||
if (!MakeContextCurrent(stub_))
|
||||
return false;
|
||||
@ -213,7 +218,7 @@ bool GpuSharedImageVideoFactory::CreateImageInternal(
|
||||
auto shared_image = std::make_unique<gpu::SharedImageVideo>(
|
||||
mailbox, coded_size, gfx::ColorSpace::CreateSRGB(),
|
||||
kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, std::move(image),
|
||||
std::move(shared_context), false /* is_thread_safe */);
|
||||
std::move(shared_context), /*is_thread_safe=*/true, std::move(drdc_lock));
|
||||
|
||||
// Register it with shared image mailbox as well as legacy mailbox. This
|
||||
// keeps |shared_image| around until its destruction cb is called.
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "base/single_thread_task_runner.h"
|
||||
#include "base/threading/sequence_bound.h"
|
||||
#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
|
||||
#include "gpu/command_buffer/service/ref_counted_lock.h"
|
||||
#include "gpu/command_buffer/service/shared_image_representation.h"
|
||||
#include "gpu/command_buffer/service/texture_manager.h"
|
||||
#include "gpu/command_buffer/service/texture_owner.h"
|
||||
@ -29,11 +30,13 @@ class GpuSharedImageVideoFactory;
|
||||
// SharedImageVideoProvider implementation that lives on the thread that it's
|
||||
// created on, but hops to the GPU thread to create new shared images on demand.
|
||||
class MEDIA_GPU_EXPORT DirectSharedImageVideoProvider
|
||||
: public SharedImageVideoProvider {
|
||||
: public SharedImageVideoProvider,
|
||||
public gpu::RefCountedLockHelperDrDc {
|
||||
public:
|
||||
DirectSharedImageVideoProvider(
|
||||
scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
|
||||
GetStubCB get_stub_cb);
|
||||
GetStubCB get_stub_cb,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock);
|
||||
~DirectSharedImageVideoProvider() override;
|
||||
|
||||
// SharedImageVideoProvider
|
||||
@ -74,13 +77,15 @@ class GpuSharedImageVideoFactory
|
||||
// create the per-frame texture. All of that is only needed for legacy
|
||||
// mailbox support, where we have to have one texture per CodecImage.
|
||||
void CreateImage(FactoryImageReadyCB cb,
|
||||
const SharedImageVideoProvider::ImageSpec& spec);
|
||||
const SharedImageVideoProvider::ImageSpec& spec,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock);
|
||||
|
||||
private:
|
||||
// Creates a SharedImage for |mailbox|, and returns success or failure.
|
||||
bool CreateImageInternal(const SharedImageVideoProvider::ImageSpec& spec,
|
||||
gpu::Mailbox mailbox,
|
||||
scoped_refptr<CodecImage> image);
|
||||
scoped_refptr<CodecImage> image,
|
||||
scoped_refptr<gpu::RefCountedLock>);
|
||||
|
||||
void OnWillDestroyStub(bool have_context) override;
|
||||
|
||||
|
@ -24,10 +24,13 @@ FrameInfoHelper::FrameInfo& FrameInfoHelper::FrameInfo::operator=(
|
||||
|
||||
// Concrete implementation of FrameInfoHelper that renders output buffers and
|
||||
// gets the FrameInfo they need.
|
||||
class FrameInfoHelperImpl : public FrameInfoHelper {
|
||||
class FrameInfoHelperImpl : public FrameInfoHelper,
|
||||
public gpu::RefCountedLockHelperDrDc {
|
||||
public:
|
||||
FrameInfoHelperImpl(scoped_refptr<base::SequencedTaskRunner> gpu_task_runner,
|
||||
SharedImageVideoProvider::GetStubCB get_stub_cb) {
|
||||
SharedImageVideoProvider::GetStubCB get_stub_cb,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock)
|
||||
: gpu::RefCountedLockHelperDrDc(std::move(drdc_lock)) {
|
||||
on_gpu_ = base::SequenceBound<OnGpu>(std::move(gpu_task_runner),
|
||||
std::move(get_stub_cb));
|
||||
}
|
||||
@ -71,7 +74,8 @@ class FrameInfoHelperImpl : public FrameInfoHelper {
|
||||
void GetFrameInfoImpl(
|
||||
std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer,
|
||||
base::OnceCallback<void(std::unique_ptr<CodecOutputBufferRenderer>,
|
||||
absl::optional<FrameInfo>)> cb) {
|
||||
absl::optional<FrameInfo>)> cb,
|
||||
std::unique_ptr<base::AutoLockMaybe> scoped_drdc_lock) {
|
||||
DCHECK(buffer_renderer);
|
||||
|
||||
auto texture_owner = buffer_renderer->texture_owner();
|
||||
@ -92,14 +96,22 @@ class FrameInfoHelperImpl : public FrameInfoHelper {
|
||||
info->ycbcr_info = GetYCbCrInfo(texture_owner.get());
|
||||
}
|
||||
}
|
||||
|
||||
// Release the lock here since we already got the frame info.
|
||||
scoped_drdc_lock.reset();
|
||||
std::move(cb).Run(std::move(buffer_renderer), info);
|
||||
}
|
||||
|
||||
void GetFrameInfo(
|
||||
std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer,
|
||||
base::OnceCallback<void(std::unique_ptr<CodecOutputBufferRenderer>,
|
||||
absl::optional<FrameInfo>)> cb) {
|
||||
absl::optional<FrameInfo>)> cb,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock) {
|
||||
// Note that we need to ensure that no other thread renders another buffer
|
||||
// in between while we are getting frame info here. Otherwise we will get
|
||||
// wrong frame info. This is ensured by holding |lock| here until
|
||||
// GetFrameInfoImpl() ends.
|
||||
auto scoped_drdc_lock = std::make_unique<base::AutoLockMaybe>(
|
||||
drdc_lock ? drdc_lock->GetDrDcLockPtr() : nullptr);
|
||||
DCHECK(buffer_renderer);
|
||||
|
||||
auto texture_owner = buffer_renderer->texture_owner();
|
||||
@ -107,7 +119,8 @@ class FrameInfoHelperImpl : public FrameInfoHelper {
|
||||
|
||||
auto buffer_available_cb =
|
||||
base::BindOnce(&OnGpu::GetFrameInfoImpl, weak_factory_.GetWeakPtr(),
|
||||
std::move(buffer_renderer), std::move(cb));
|
||||
std::move(buffer_renderer), std::move(cb),
|
||||
std::move(scoped_drdc_lock));
|
||||
texture_owner->RunWhenBufferIsAvailable(std::move(buffer_available_cb));
|
||||
}
|
||||
|
||||
@ -171,7 +184,6 @@ class FrameInfoHelperImpl : public FrameInfoHelper {
|
||||
void ProcessRequestsQueue() {
|
||||
while (!requests_.empty()) {
|
||||
auto& request = requests_.front();
|
||||
|
||||
if (!request.buffer_renderer) {
|
||||
// If we don't have buffer_renderer we can Run callback immediately.
|
||||
std::move(request.callback).Run(nullptr, FrameInfo());
|
||||
@ -198,7 +210,8 @@ class FrameInfoHelperImpl : public FrameInfoHelper {
|
||||
weak_factory_.GetWeakPtr()));
|
||||
|
||||
on_gpu_.AsyncCall(&OnGpu::GetFrameInfo)
|
||||
.WithArgs(std::move(request.buffer_renderer), std::move(cb));
|
||||
.WithArgs(std::move(request.buffer_renderer), std::move(cb),
|
||||
GetDrDcLock());
|
||||
// We didn't complete this request quite yet, so we can't process queue
|
||||
// any further.
|
||||
break;
|
||||
@ -220,9 +233,10 @@ class FrameInfoHelperImpl : public FrameInfoHelper {
|
||||
// static
|
||||
std::unique_ptr<FrameInfoHelper> FrameInfoHelper::Create(
|
||||
scoped_refptr<base::SequencedTaskRunner> gpu_task_runner,
|
||||
SharedImageVideoProvider::GetStubCB get_stub_cb) {
|
||||
return std::make_unique<FrameInfoHelperImpl>(std::move(gpu_task_runner),
|
||||
std::move(get_stub_cb));
|
||||
SharedImageVideoProvider::GetStubCB get_stub_cb,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock) {
|
||||
return std::make_unique<FrameInfoHelperImpl>(
|
||||
std::move(gpu_task_runner), std::move(get_stub_cb), std::move(drdc_lock));
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
|
@ -34,7 +34,8 @@ class MEDIA_GPU_EXPORT FrameInfoHelper {
|
||||
|
||||
static std::unique_ptr<FrameInfoHelper> Create(
|
||||
scoped_refptr<base::SequencedTaskRunner> gpu_task_runner,
|
||||
SharedImageVideoProvider::GetStubCB get_stub_cb);
|
||||
SharedImageVideoProvider::GetStubCB get_stub_cb,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock);
|
||||
|
||||
virtual ~FrameInfoHelper() = default;
|
||||
|
||||
|
@ -27,8 +27,8 @@ std::unique_ptr<FrameInfoHelper> CreateHelper() {
|
||||
auto task_runner = base::ThreadTaskRunnerHandle::Get();
|
||||
auto get_stub_cb =
|
||||
base::BindRepeating([]() -> gpu::CommandBufferStub* { return nullptr; });
|
||||
return FrameInfoHelper::Create(std::move(task_runner),
|
||||
std::move(get_stub_cb));
|
||||
return FrameInfoHelper::Create(std::move(task_runner), std::move(get_stub_cb),
|
||||
/*lock=*/nullptr);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@ -57,12 +57,12 @@ class FrameInfoHelperTest : public testing::Test {
|
||||
gfx::Size size,
|
||||
scoped_refptr<gpu::TextureOwner> texture_owner) {
|
||||
auto codec_buffer_wait_coordinator =
|
||||
texture_owner
|
||||
? base::MakeRefCounted<CodecBufferWaitCoordinator>(texture_owner)
|
||||
: nullptr;
|
||||
texture_owner ? base::MakeRefCounted<CodecBufferWaitCoordinator>(
|
||||
texture_owner, /*lock=*/nullptr)
|
||||
: nullptr;
|
||||
auto buffer = CodecOutputBuffer::CreateForTesting(0, size);
|
||||
auto buffer_renderer = std::make_unique<CodecOutputBufferRenderer>(
|
||||
std::move(buffer), codec_buffer_wait_coordinator);
|
||||
std::move(buffer), codec_buffer_wait_coordinator, /*lock=*/nullptr);
|
||||
|
||||
// We don't have codec, so releasing test buffer is not possible. Mark it as
|
||||
// rendered for test purpose.
|
||||
|
@ -41,7 +41,11 @@ class GpuMaybeRenderEarlyImpl {
|
||||
image_group_->AddCodecImage(codec_image_holder->codec_image_raw());
|
||||
}
|
||||
|
||||
void MaybeRenderEarly() { internal::MaybeRenderEarly(&images_); }
|
||||
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) {
|
||||
@ -67,11 +71,14 @@ class 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 {
|
||||
class MaybeRenderEarlyManagerImpl : public MaybeRenderEarlyManager,
|
||||
public gpu::RefCountedLockHelperDrDc {
|
||||
public:
|
||||
MaybeRenderEarlyManagerImpl(
|
||||
scoped_refptr<base::SequencedTaskRunner> gpu_task_runner)
|
||||
: gpu_task_runner_(gpu_task_runner),
|
||||
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() override = default;
|
||||
|
||||
@ -86,7 +93,7 @@ class MaybeRenderEarlyManagerImpl : public MaybeRenderEarlyManager {
|
||||
// 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));
|
||||
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.
|
||||
@ -101,7 +108,8 @@ class MaybeRenderEarlyManagerImpl : public MaybeRenderEarlyManager {
|
||||
}
|
||||
|
||||
void MaybeRenderEarly() override {
|
||||
gpu_impl_.AsyncCall(&GpuMaybeRenderEarlyImpl::MaybeRenderEarly);
|
||||
gpu_impl_.AsyncCall(&GpuMaybeRenderEarlyImpl::MaybeRenderEarly)
|
||||
.WithArgs(GetDrDcLock());
|
||||
}
|
||||
|
||||
private:
|
||||
@ -115,8 +123,10 @@ class MaybeRenderEarlyManagerImpl : public MaybeRenderEarlyManager {
|
||||
|
||||
// static
|
||||
std::unique_ptr<MaybeRenderEarlyManager> MaybeRenderEarlyManager::Create(
|
||||
scoped_refptr<base::SequencedTaskRunner> task_runner) {
|
||||
return std::make_unique<MaybeRenderEarlyManagerImpl>(std::move(task_runner));
|
||||
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
|
||||
|
@ -43,7 +43,8 @@ class MEDIA_GPU_EXPORT MaybeRenderEarlyManager {
|
||||
// Note that the returned object should be accessed from the thread that
|
||||
// created it.
|
||||
static std::unique_ptr<MaybeRenderEarlyManager> Create(
|
||||
scoped_refptr<base::SequencedTaskRunner> gpu_task_runner);
|
||||
scoped_refptr<base::SequencedTaskRunner> gpu_task_runner,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MaybeRenderEarlyManager);
|
||||
};
|
||||
|
@ -224,8 +224,10 @@ MediaCodecVideoDecoder::MediaCodecVideoDecoder(
|
||||
std::unique_ptr<AndroidVideoSurfaceChooser> surface_chooser,
|
||||
AndroidOverlayMojoFactoryCB overlay_factory_cb,
|
||||
RequestOverlayInfoCB request_overlay_info_cb,
|
||||
std::unique_ptr<VideoFrameFactory> video_frame_factory)
|
||||
: media_log_(std::move(media_log)),
|
||||
std::unique_ptr<VideoFrameFactory> video_frame_factory,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock)
|
||||
: gpu::RefCountedLockHelperDrDc(std::move(drdc_lock)),
|
||||
media_log_(std::move(media_log)),
|
||||
codec_allocator_(codec_allocator),
|
||||
request_overlay_info_cb_(std::move(request_overlay_info_cb)),
|
||||
is_surface_control_enabled_(IsSurfaceControlEnabled(gpu_feature_info)),
|
||||
@ -259,12 +261,13 @@ std::unique_ptr<VideoDecoder> MediaCodecVideoDecoder::Create(
|
||||
std::unique_ptr<AndroidVideoSurfaceChooser> surface_chooser,
|
||||
AndroidOverlayMojoFactoryCB overlay_factory_cb,
|
||||
RequestOverlayInfoCB request_overlay_info_cb,
|
||||
std::unique_ptr<VideoFrameFactory> video_frame_factory) {
|
||||
std::unique_ptr<VideoFrameFactory> video_frame_factory,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock) {
|
||||
auto* decoder = new MediaCodecVideoDecoder(
|
||||
gpu_preferences, gpu_feature_info, std::move(media_log), device_info,
|
||||
codec_allocator, std::move(surface_chooser),
|
||||
std::move(overlay_factory_cb), std::move(request_overlay_info_cb),
|
||||
std::move(video_frame_factory));
|
||||
std::move(video_frame_factory), std::move(drdc_lock));
|
||||
return std::make_unique<AsyncDestroyVideoDecoder<MediaCodecVideoDecoder>>(
|
||||
base::WrapUnique(decoder));
|
||||
}
|
||||
@ -526,7 +529,8 @@ void MediaCodecVideoDecoder::OnVideoFrameFactoryInitialized(
|
||||
EnterTerminalState(State::kError, "Could not allocated TextureOwner");
|
||||
return;
|
||||
}
|
||||
texture_owner_bundle_ = new CodecSurfaceBundle(std::move(texture_owner));
|
||||
texture_owner_bundle_ =
|
||||
new CodecSurfaceBundle(std::move(texture_owner), GetDrDcLock());
|
||||
|
||||
// This is for A/B power testing only. Turn off Dialog-based overlays in
|
||||
// power testing mode, unless we need them for L1 content.
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "base/threading/thread_checker.h"
|
||||
#include "base/timer/elapsed_timer.h"
|
||||
#include "base/timer/timer.h"
|
||||
#include "gpu/command_buffer/service/ref_counted_lock.h"
|
||||
#include "gpu/config/gpu_feature_info.h"
|
||||
#include "gpu/config/gpu_preferences.h"
|
||||
#include "media/base/android/media_crypto_context.h"
|
||||
@ -60,7 +61,9 @@ struct PendingDecode {
|
||||
// playbacks that need them.
|
||||
// TODO: Lazy initialization should be handled at a higher layer of the media
|
||||
// stack for both simplicity and cross platform support.
|
||||
class MEDIA_GPU_EXPORT MediaCodecVideoDecoder final : public VideoDecoder {
|
||||
class MEDIA_GPU_EXPORT MediaCodecVideoDecoder final
|
||||
: public VideoDecoder,
|
||||
public gpu::RefCountedLockHelperDrDc {
|
||||
public:
|
||||
static std::vector<SupportedVideoDecoderConfig> GetSupportedConfigs();
|
||||
|
||||
@ -76,7 +79,8 @@ class MEDIA_GPU_EXPORT MediaCodecVideoDecoder final : public VideoDecoder {
|
||||
std::unique_ptr<AndroidVideoSurfaceChooser> surface_chooser,
|
||||
AndroidOverlayMojoFactoryCB overlay_factory_cb,
|
||||
RequestOverlayInfoCB request_overlay_info_cb,
|
||||
std::unique_ptr<VideoFrameFactory> video_frame_factory);
|
||||
std::unique_ptr<VideoFrameFactory> video_frame_factory,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock);
|
||||
|
||||
// VideoDecoder implementation:
|
||||
VideoDecoderType GetDecoderType() const override;
|
||||
@ -105,7 +109,8 @@ class MEDIA_GPU_EXPORT MediaCodecVideoDecoder final : public VideoDecoder {
|
||||
std::unique_ptr<AndroidVideoSurfaceChooser> surface_chooser,
|
||||
AndroidOverlayMojoFactoryCB overlay_factory_cb,
|
||||
RequestOverlayInfoCB request_overlay_info_cb,
|
||||
std::unique_ptr<VideoFrameFactory> video_frame_factory);
|
||||
std::unique_ptr<VideoFrameFactory> video_frame_factory,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock);
|
||||
|
||||
// Set up |cdm_context| as part of initialization. Guarantees that |init_cb|
|
||||
// will be called depending on the outcome, though not necessarily before this
|
||||
|
@ -151,7 +151,7 @@ class MediaCodecVideoDecoderTest : public testing::TestWithParam<VideoCodec> {
|
||||
base::BindRepeating(&CreateAndroidOverlayCb),
|
||||
base::BindRepeating(&MediaCodecVideoDecoderTest::RequestOverlayInfoCb,
|
||||
base::Unretained(this)),
|
||||
std::move(video_frame_factory));
|
||||
std::move(video_frame_factory), /*lock=*/nullptr);
|
||||
mcvd_ = std::make_unique<AsyncDestroyVideoDecoder<MediaCodecVideoDecoder>>(
|
||||
base::WrapUnique(mcvd));
|
||||
mcvd_raw_ = mcvd;
|
||||
|
@ -11,7 +11,7 @@ using testing::Return;
|
||||
|
||||
MockCodecBufferWaitCoordinator::MockCodecBufferWaitCoordinator(
|
||||
scoped_refptr<NiceMock<gpu::MockTextureOwner>> texture_owner)
|
||||
: CodecBufferWaitCoordinator(texture_owner),
|
||||
: CodecBufferWaitCoordinator(texture_owner, /*lock=*/nullptr),
|
||||
mock_texture_owner(std::move(texture_owner)),
|
||||
expecting_frame_available(false) {
|
||||
ON_CALL(*this, texture_owner()).WillByDefault(Return(mock_texture_owner));
|
||||
|
@ -7,7 +7,7 @@
|
||||
namespace media {
|
||||
|
||||
MockCodecImage::MockCodecImage(const gfx::Size& coded_size)
|
||||
: CodecImage(coded_size) {}
|
||||
: CodecImage(coded_size, /*lock=*/nullptr) {}
|
||||
|
||||
MockCodecImage::~MockCodecImage() = default;
|
||||
|
||||
|
@ -16,11 +16,12 @@ std::unique_ptr<PooledSharedImageVideoProvider>
|
||||
PooledSharedImageVideoProvider::Create(
|
||||
scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
|
||||
GetStubCB get_stub_cb,
|
||||
std::unique_ptr<SharedImageVideoProvider> provider) {
|
||||
std::unique_ptr<SharedImageVideoProvider> provider,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock) {
|
||||
return base::WrapUnique(new PooledSharedImageVideoProvider(
|
||||
base::SequenceBound<GpuHelperImpl>(std::move(gpu_task_runner),
|
||||
std::move(get_stub_cb)),
|
||||
std::move(provider)));
|
||||
std::move(provider), std::move(drdc_lock)));
|
||||
}
|
||||
|
||||
PooledSharedImageVideoProvider::PooledImage::PooledImage(const ImageSpec& spec,
|
||||
@ -38,8 +39,10 @@ PooledSharedImageVideoProvider::PendingRequest::~PendingRequest() = default;
|
||||
|
||||
PooledSharedImageVideoProvider::PooledSharedImageVideoProvider(
|
||||
base::SequenceBound<GpuHelper> gpu_helper,
|
||||
std::unique_ptr<SharedImageVideoProvider> provider)
|
||||
: provider_(std::move(provider)),
|
||||
std::unique_ptr<SharedImageVideoProvider> provider,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock)
|
||||
: gpu::RefCountedLockHelperDrDc(std::move(drdc_lock)),
|
||||
provider_(std::move(provider)),
|
||||
gpu_helper_(std::move(gpu_helper)),
|
||||
weak_factory_(this) {}
|
||||
|
||||
@ -124,7 +127,8 @@ void PooledSharedImageVideoProvider::OnImageReturned(
|
||||
.WithArgs(sync_token, pooled_image->record.codec_image_holder,
|
||||
BindToCurrentLoop(base::BindOnce(
|
||||
&PooledSharedImageVideoProvider::ProcessFreePooledImage,
|
||||
weak_factory_.GetWeakPtr(), pooled_image)));
|
||||
weak_factory_.GetWeakPtr(), pooled_image)),
|
||||
GetDrDcLock());
|
||||
}
|
||||
|
||||
void PooledSharedImageVideoProvider::ProcessFreePooledImage(
|
||||
@ -196,18 +200,25 @@ PooledSharedImageVideoProvider::GpuHelperImpl::~GpuHelperImpl() = default;
|
||||
void PooledSharedImageVideoProvider::GpuHelperImpl::OnImageReturned(
|
||||
const gpu::SyncToken& sync_token,
|
||||
scoped_refptr<CodecImageHolder> codec_image_holder,
|
||||
base::OnceClosure cb) {
|
||||
base::OnceClosure cb,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock) {
|
||||
auto on_sync_token_cleared_cb = base::BindOnce(
|
||||
&GpuHelperImpl::OnSyncTokenCleared, weak_factory_.GetWeakPtr(),
|
||||
std::move(codec_image_holder), std::move(cb));
|
||||
std::move(codec_image_holder), std::move(cb), std::move(drdc_lock));
|
||||
command_buffer_helper_->WaitForSyncToken(sync_token,
|
||||
std::move(on_sync_token_cleared_cb));
|
||||
}
|
||||
|
||||
void PooledSharedImageVideoProvider::GpuHelperImpl::OnSyncTokenCleared(
|
||||
scoped_refptr<CodecImageHolder> codec_image_holder,
|
||||
base::OnceClosure cb) {
|
||||
codec_image_holder->codec_image_raw()->NotifyUnused();
|
||||
base::OnceClosure cb,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock) {
|
||||
{
|
||||
base::AutoLockMaybe auto_lock(drdc_lock ? drdc_lock->GetDrDcLockPtr()
|
||||
: nullptr);
|
||||
codec_image_holder->codec_image_raw()->NotifyUnused();
|
||||
}
|
||||
|
||||
// Do this last, since |cb| might post to some other thread.
|
||||
std::move(cb).Run();
|
||||
}
|
||||
|
@ -17,7 +17,8 @@ class PooledSharedImageVideoProviderTest;
|
||||
|
||||
// Provider class for shared images.
|
||||
class MEDIA_GPU_EXPORT PooledSharedImageVideoProvider
|
||||
: public SharedImageVideoProvider {
|
||||
: public SharedImageVideoProvider,
|
||||
public gpu::RefCountedLockHelperDrDc {
|
||||
public:
|
||||
// Helper class that processes image returns on the gpu thread.
|
||||
class GpuHelper {
|
||||
@ -29,7 +30,8 @@ class MEDIA_GPU_EXPORT PooledSharedImageVideoProvider
|
||||
virtual void OnImageReturned(
|
||||
const gpu::SyncToken& sync_token,
|
||||
scoped_refptr<CodecImageHolder> codec_image_holder,
|
||||
base::OnceClosure cb) = 0;
|
||||
base::OnceClosure cb,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock) = 0;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(GpuHelper);
|
||||
@ -40,7 +42,8 @@ class MEDIA_GPU_EXPORT PooledSharedImageVideoProvider
|
||||
static std::unique_ptr<PooledSharedImageVideoProvider> Create(
|
||||
scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
|
||||
GetStubCB get_stub_cb,
|
||||
std::unique_ptr<SharedImageVideoProvider> provider);
|
||||
std::unique_ptr<SharedImageVideoProvider> provider,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock);
|
||||
|
||||
~PooledSharedImageVideoProvider() override;
|
||||
|
||||
@ -53,7 +56,8 @@ class MEDIA_GPU_EXPORT PooledSharedImageVideoProvider
|
||||
|
||||
PooledSharedImageVideoProvider(
|
||||
base::SequenceBound<GpuHelper> gpu_helper,
|
||||
std::unique_ptr<SharedImageVideoProvider> provider);
|
||||
std::unique_ptr<SharedImageVideoProvider> provider,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock);
|
||||
|
||||
class GpuHelperImpl : public GpuHelper {
|
||||
public:
|
||||
@ -63,11 +67,13 @@ class MEDIA_GPU_EXPORT PooledSharedImageVideoProvider
|
||||
// GpuHelper
|
||||
void OnImageReturned(const gpu::SyncToken& sync_token,
|
||||
scoped_refptr<CodecImageHolder> codec_image_holder,
|
||||
base::OnceClosure cb) override;
|
||||
base::OnceClosure cb,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock) override;
|
||||
|
||||
private:
|
||||
void OnSyncTokenCleared(scoped_refptr<CodecImageHolder> codec_image_holder,
|
||||
base::OnceClosure cb);
|
||||
base::OnceClosure cb,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock);
|
||||
|
||||
scoped_refptr<CommandBufferHelper> command_buffer_helper_;
|
||||
base::WeakPtrFactory<GpuHelperImpl> weak_factory_;
|
||||
|
@ -29,7 +29,8 @@ class PooledSharedImageVideoProviderTest : public testing::Test {
|
||||
// PooledSharedImageVideoProvider::GpuHelper
|
||||
void OnImageReturned(const gpu::SyncToken& sync_token,
|
||||
scoped_refptr<CodecImageHolder> codec_image_holder,
|
||||
base::OnceClosure cb) override {
|
||||
base::OnceClosure cb,
|
||||
scoped_refptr<gpu::RefCountedLock> lock) override {
|
||||
*sync_token_out_ = sync_token;
|
||||
|
||||
// Run the output cb.
|
||||
@ -52,7 +53,8 @@ class PooledSharedImageVideoProviderTest : public testing::Test {
|
||||
mock_provider_raw_ = mock_provider.get();
|
||||
|
||||
provider_ = base::WrapUnique(new PooledSharedImageVideoProvider(
|
||||
std::move(mock_gpu_helper), std::move(mock_provider)));
|
||||
std::move(mock_gpu_helper), std::move(mock_provider),
|
||||
/*lock=*/nullptr));
|
||||
}
|
||||
|
||||
// Return an ImageReadyCB that saves the ImageRecord in |image_records_|.
|
||||
|
@ -99,8 +99,10 @@ VideoFrameFactoryImpl::VideoFrameFactoryImpl(
|
||||
const gpu::GpuPreferences& gpu_preferences,
|
||||
std::unique_ptr<SharedImageVideoProvider> image_provider,
|
||||
std::unique_ptr<MaybeRenderEarlyManager> mre_manager,
|
||||
std::unique_ptr<FrameInfoHelper> frame_info_helper)
|
||||
: image_provider_(std::move(image_provider)),
|
||||
std::unique_ptr<FrameInfoHelper> frame_info_helper,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock)
|
||||
: gpu::RefCountedLockHelperDrDc(std::move(drdc_lock)),
|
||||
image_provider_(std::move(image_provider)),
|
||||
gpu_task_runner_(std::move(gpu_task_runner)),
|
||||
copy_mode_(GetVideoFrameCopyMode(
|
||||
gpu_preferences.enable_threaded_texture_mailboxes)),
|
||||
@ -167,7 +169,7 @@ void VideoFrameFactoryImpl::CreateVideoFrame(
|
||||
gfx::Rect visible_rect(coded_size);
|
||||
|
||||
auto output_buffer_renderer = std::make_unique<CodecOutputBufferRenderer>(
|
||||
std::move(output_buffer), codec_buffer_wait_coordinator_);
|
||||
std::move(output_buffer), codec_buffer_wait_coordinator_, GetDrDcLock());
|
||||
|
||||
// The pixel format doesn't matter here as long as it's valid for texture
|
||||
// frames. But SkiaRenderer wants to ensure that the format of the resource
|
||||
|
@ -31,7 +31,9 @@ class MaybeRenderEarlyManager;
|
||||
// decoder as soon as possible. It's not thread safe; it should be created, used
|
||||
// and destructed on a single sequence. It's implemented by proxying calls
|
||||
// to a helper class hosted on the gpu thread.
|
||||
class MEDIA_GPU_EXPORT VideoFrameFactoryImpl : public VideoFrameFactory {
|
||||
class MEDIA_GPU_EXPORT VideoFrameFactoryImpl
|
||||
: public VideoFrameFactory,
|
||||
public gpu::RefCountedLockHelperDrDc {
|
||||
public:
|
||||
// Callback used to return a mailbox and release callback for an image. The
|
||||
// release callback may be dropped without being run, and the image will be
|
||||
@ -51,7 +53,8 @@ class MEDIA_GPU_EXPORT VideoFrameFactoryImpl : public VideoFrameFactory {
|
||||
const gpu::GpuPreferences& gpu_preferences,
|
||||
std::unique_ptr<SharedImageVideoProvider> image_provider,
|
||||
std::unique_ptr<MaybeRenderEarlyManager> mre_manager,
|
||||
std::unique_ptr<FrameInfoHelper> frame_info_helper);
|
||||
std::unique_ptr<FrameInfoHelper> frame_info_helper,
|
||||
scoped_refptr<gpu::RefCountedLock> drdc_lock);
|
||||
~VideoFrameFactoryImpl() override;
|
||||
|
||||
void Initialize(OverlayMode overlay_mode, InitCB init_cb) override;
|
||||
|
@ -68,12 +68,12 @@ class VideoFrameFactoryImplTest : public testing::Test {
|
||||
|
||||
impl_ = std::make_unique<VideoFrameFactoryImpl>(
|
||||
task_runner_, gpu_preferences_, std::move(image_provider),
|
||||
std::move(mre_manager), std::move(info_helper));
|
||||
std::move(mre_manager), std::move(info_helper), /*lock=*/nullptr);
|
||||
auto texture_owner = base::MakeRefCounted<NiceMock<gpu::MockTextureOwner>>(
|
||||
0, nullptr, nullptr, true);
|
||||
auto codec_buffer_wait_coordinator =
|
||||
base::MakeRefCounted<CodecBufferWaitCoordinator>(
|
||||
std::move(texture_owner));
|
||||
std::move(texture_owner), /*lock=*/nullptr);
|
||||
|
||||
// Provide a non-null |codec_buffer_wait_coordinator| to |impl_|.
|
||||
impl_->SetCodecBufferWaitCorrdinatorForTesting(
|
||||
@ -170,7 +170,8 @@ TEST_F(VideoFrameFactoryImplTest,
|
||||
scoped_refptr<CodecSurfaceBundle> surface_bundle =
|
||||
base::MakeRefCounted<CodecSurfaceBundle>(
|
||||
base::MakeRefCounted<NiceMock<gpu::MockTextureOwner>>(0, nullptr,
|
||||
nullptr, true));
|
||||
nullptr, true),
|
||||
/*lock=*/nullptr);
|
||||
EXPECT_CALL(*mre_manager_raw_, SetSurfaceBundle(surface_bundle));
|
||||
impl_->SetSurfaceBundle(surface_bundle);
|
||||
base::RunLoop().RunUntilIdle();
|
||||
|
@ -5,6 +5,8 @@
|
||||
#include "media/mojo/services/gpu_mojo_media_client.h"
|
||||
|
||||
#include "base/memory/ptr_util.h"
|
||||
#include "gpu/command_buffer/service/ref_counted_lock.h"
|
||||
#include "gpu/config/gpu_finch_features.h"
|
||||
#include "media/base/android/android_cdm_factory.h"
|
||||
#include "media/base/media_log.h"
|
||||
#include "media/base/media_switches.h"
|
||||
@ -29,22 +31,37 @@ namespace media {
|
||||
|
||||
std::unique_ptr<VideoDecoder> CreatePlatformVideoDecoder(
|
||||
const VideoDecoderTraits& traits) {
|
||||
scoped_refptr<gpu::RefCountedLock> ref_counted_lock;
|
||||
|
||||
// When this feature is enabled, CodecImage, CodecBufferWaitCorrdinator and
|
||||
// other media classes used in MCVD path will be accessed by multiple gpu
|
||||
// threads. To implement thread safetyness, we are using a global ref
|
||||
// counted lock here. CodecImage, CodecOutputBufferRenderer,
|
||||
// CodecBufferWaitCoordinator expects this ref counted lock to be held by the
|
||||
// classes which are accessing them (SharedImageVideo, MRE, FrameInfoHelper
|
||||
// etc.)
|
||||
if (features::IsDrDcEnabled()) {
|
||||
ref_counted_lock = base::MakeRefCounted<gpu::RefCountedLock>();
|
||||
}
|
||||
|
||||
std::unique_ptr<SharedImageVideoProvider> image_provider =
|
||||
std::make_unique<DirectSharedImageVideoProvider>(
|
||||
traits.gpu_task_runner, traits.get_command_buffer_stub_cb);
|
||||
traits.gpu_task_runner, traits.get_command_buffer_stub_cb,
|
||||
ref_counted_lock);
|
||||
|
||||
if (base::FeatureList::IsEnabled(kUsePooledSharedImageVideoProvider)) {
|
||||
// Wrap |image_provider| in a pool.
|
||||
image_provider = PooledSharedImageVideoProvider::Create(
|
||||
traits.gpu_task_runner, traits.get_command_buffer_stub_cb,
|
||||
std::move(image_provider));
|
||||
std::move(image_provider), ref_counted_lock);
|
||||
}
|
||||
// TODO(liberato): Create this only if we're using Vulkan, else it's
|
||||
// ignored. If we can tell that here, then VideoFrameFactory can use it
|
||||
// as a signal about whether it's supposed to get YCbCrInfo rather than
|
||||
// requiring the provider to set |is_vulkan| in the ImageRecord.
|
||||
auto frame_info_helper = FrameInfoHelper::Create(
|
||||
traits.gpu_task_runner, traits.get_command_buffer_stub_cb);
|
||||
traits.gpu_task_runner, traits.get_command_buffer_stub_cb,
|
||||
ref_counted_lock);
|
||||
|
||||
return MediaCodecVideoDecoder::Create(
|
||||
traits.gpu_preferences, traits.gpu_feature_info,
|
||||
@ -57,8 +74,10 @@ std::unique_ptr<VideoDecoder> CreatePlatformVideoDecoder(
|
||||
std::make_unique<VideoFrameFactoryImpl>(
|
||||
traits.gpu_task_runner, traits.gpu_preferences,
|
||||
std::move(image_provider),
|
||||
MaybeRenderEarlyManager::Create(traits.gpu_task_runner),
|
||||
std::move(frame_info_helper)));
|
||||
MaybeRenderEarlyManager::Create(traits.gpu_task_runner,
|
||||
ref_counted_lock),
|
||||
std::move(frame_info_helper), ref_counted_lock),
|
||||
ref_counted_lock);
|
||||
}
|
||||
|
||||
SupportedVideoDecoderConfigs GetPlatformSupportedVideoDecoderConfigs(
|
||||
@ -86,4 +105,4 @@ VideoDecoderType GetPlatformDecoderImplementationType(
|
||||
return VideoDecoderType::kMediaCodec;
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
} // namespace media
|
||||
|
Reference in New Issue
Block a user