Skip to content

Commit

Permalink
Setup GPU memory buffer manager for Video capture in Linux
Browse files Browse the repository at this point in the history
Create the GPU memory buffer manager from the viz::Gpu and set it to
the V4L2 video capture GPU memory buffer manager.

Bug: 1425770
Change-Id: Ic47afc63bbfb0ae841ad3204a34b868a8c6cfcdc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4392949
Reviewed-by: Henrik Boström <hbos@chromium.org>
Commit-Queue: Ilya Nikolaevskiy <ilnik@chromium.org>
Reviewed-by: Ilya Nikolaevskiy <ilnik@chromium.org>
Reviewed-by: Markus Handell <handellm@google.com>
Cr-Commit-Position: refs/heads/main@{#1150230}
  • Loading branch information
yzhou51 authored and Chromium LUCI CQ committed May 29, 2023
1 parent 3ccbcab commit 811adef
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 6 deletions.
8 changes: 8 additions & 0 deletions media/capture/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,14 @@ component("capture_lib") {
"video/linux/video_capture_device_linux.cc",
"video/linux/video_capture_device_linux.h",
]
deps += [ "//gpu/command_buffer/client" ]
}

if (is_linux) {
sources += [
"video/linux/video_capture_gpu_memory_buffer_manager.cc",
"video/linux/video_capture_gpu_memory_buffer_manager.h",
]
}

if (is_chromeos_ash) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/capture/video/linux/video_capture_gpu_memory_buffer_manager.h"

namespace media {

VideoCaptureGpuMemoryBufferManager::VideoCaptureGpuMemoryBufferManager()
: gpu_buffer_manager_(nullptr) {}

VideoCaptureGpuMemoryBufferManager::~VideoCaptureGpuMemoryBufferManager() =
default;

// static
VideoCaptureGpuMemoryBufferManager&
VideoCaptureGpuMemoryBufferManager::GetInstance() {
static base::NoDestructor<VideoCaptureGpuMemoryBufferManager> instance;
return *instance;
}

void VideoCaptureGpuMemoryBufferManager::SetGpuMemoryBufferManager(
gpu::GpuMemoryBufferManager* gbm) {
base::AutoLock lock(lock_);
gpu_buffer_manager_ = gbm;
}

gpu::GpuMemoryBufferManager*
VideoCaptureGpuMemoryBufferManager::GetGpuMemoryBufferManager() {
base::AutoLock lock(lock_);
return gpu_buffer_manager_;
}

void VideoCaptureGpuMemoryBufferManager::OnContextLost() {
base::AutoLock lock(lock_);
for (auto& observer : observers_) {
observer.OnContextLost();
}
}

void VideoCaptureGpuMemoryBufferManager::AddObserver(
VideoCaptureGpuContextLostObserver* observer) {
base::AutoLock lock(lock_);
if (observers_.HasObserver(observer)) {
return;
}

observers_.AddObserver(observer);
}

void VideoCaptureGpuMemoryBufferManager::RemoveObserver(
VideoCaptureGpuContextLostObserver* to_remove) {
base::AutoLock lock(lock_);
observers_.RemoveObserver(to_remove);
}

} // namespace media
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_CAPTURE_VIDEO_LINUX_VIDEO_CAPTURE_GPU_MEMORY_BUFFER_MANAGER_H_
#define MEDIA_CAPTURE_VIDEO_LINUX_VIDEO_CAPTURE_GPU_MEMORY_BUFFER_MANAGER_H_

#include "base/no_destructor.h"
#include "base/observer_list.h"
#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
#include "media/capture/capture_export.h"

namespace media {

class VideoCaptureGpuContextLostObserver {
public:
virtual void OnContextLost() = 0;

protected:
virtual ~VideoCaptureGpuContextLostObserver() = default;
};

// GPU memory buffer manager for Linux Video Capture.
// This class provides the access to `gpu::GpuMemoryBufferManager` for the
// `V4L2GpuMemoryBufferTracker`. It listens the GPU context lost event and
// broadcast it to trackers.
class CAPTURE_EXPORT VideoCaptureGpuMemoryBufferManager final
: public VideoCaptureGpuContextLostObserver {
public:
static VideoCaptureGpuMemoryBufferManager& GetInstance();

VideoCaptureGpuMemoryBufferManager(
const VideoCaptureGpuMemoryBufferManager&) = delete;
VideoCaptureGpuMemoryBufferManager& operator=(
const VideoCaptureGpuMemoryBufferManager&) = delete;

// Set gpu::GpuMemoryBufferManager by
// `VideoCaptureServiceImpl::VizGpuContextProvider` from the main thead of
// utility process. It will be set with
// `viz::Gpu::GetGpuMemoryBufferManager()` when calling
// `VideoCaptureServiceImpl::VizGpuContextProvider::StartContextProviderIfNeeded()`
// success or set to nullptr if failed.
void SetGpuMemoryBufferManager(gpu::GpuMemoryBufferManager*);

// This method is called by `V4L2GpuMemoryBufferTracker::Init()` from the
// single thread task runner created in the
// `VideoCaptureDeviceLinux::VideoCaptureDeviceLinux()`. It will be called
// when VideoCaptureBufferPoolImpl want to create new tracker for the v4l2
// camera capture data. It will return nullptr when
// `VideoCaptureServiceImpl::VizGpuContextProvider::StartContextProviderIfNeeded()`
// failed.
gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager();

// VideoCaptureGpuContextLostObserver implementation.
void OnContextLost() override;

void AddObserver(VideoCaptureGpuContextLostObserver*);
void RemoveObserver(VideoCaptureGpuContextLostObserver*);

private:
friend class base::NoDestructor<VideoCaptureGpuMemoryBufferManager>;

VideoCaptureGpuMemoryBufferManager();
~VideoCaptureGpuMemoryBufferManager() override;

mutable base::Lock lock_;
// The |gpu_buffer_manager_| is nullptr before set by the
// `VideoCaptureServiceImpl::VizGpuContextProvider::StartContextProviderIfNeeded()`
// which is called with the memory buffer manager that viz::Gpu owns.
raw_ptr<gpu::GpuMemoryBufferManager> gpu_buffer_manager_ GUARDED_BY(lock_);

// Protects observer list. The observer list will be operated from the
// |v4l2_task_runner| of V4L2CaptureDelegate and the |main_task_runner_| of
// VideoCaptureServiceImpl::VizGpuContextProvider.
base::ObserverList<VideoCaptureGpuContextLostObserver>::Unchecked observers_
GUARDED_BY(lock_);
};

} // namespace media

#endif // MEDIA_CAPTURE_VIDEO_LINUX_VIDEO_CAPTURE_GPU_MEMORY_BUFFER_MANAGER_H_
25 changes: 19 additions & 6 deletions services/video_capture/video_capture_service_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@

#if BUILDFLAG(IS_LINUX)
#include "media/capture/capture_switches.h"
#include "media/capture/video/linux/video_capture_gpu_memory_buffer_manager.h"
#include "services/viz/public/cpp/gpu/context_provider_command_buffer.h"
#endif // BUILDFLAG(IS_LINUX)

Expand Down Expand Up @@ -126,7 +127,10 @@ class VideoCaptureServiceImpl::VizGpuContextProvider
VizGpuContextProvider(std::unique_ptr<viz::Gpu> viz_gpu)
: main_task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()),
viz_gpu_(std::move(viz_gpu)) {
StartContextProviderIfNeeded();
if (StartContextProviderIfNeeded()) {
media::VideoCaptureGpuMemoryBufferManager::GetInstance()
.SetGpuMemoryBufferManager(viz_gpu_->GetGpuMemoryBufferManager());
}
}
~VizGpuContextProvider() override {
// Ensure destroy context provider and not receive callbacks before clear up
Expand All @@ -141,16 +145,24 @@ class VideoCaptureServiceImpl::VizGpuContextProvider
context_provider_->RemoveObserver(this);
context_provider_.reset();

StartContextProviderIfNeeded();
bool success = StartContextProviderIfNeeded();
// Clear the GPU memory buffer manager if failed.
if (!success) {
media::VideoCaptureGpuMemoryBufferManager::GetInstance()
.SetGpuMemoryBufferManager(nullptr);
}

// Notify context lost after new context ready.
media::VideoCaptureGpuMemoryBufferManager::GetInstance().OnContextLost();
}

private:
void StartContextProviderIfNeeded() {
bool StartContextProviderIfNeeded() {
DCHECK_EQ(context_provider_, nullptr);
DCHECK(main_task_runner_->BelongsToCurrentThread());

if (!viz_gpu_) {
return;
return false;
}

scoped_refptr<gpu::GpuChannelHost> gpu_channel_host =
Expand All @@ -160,7 +172,7 @@ class VideoCaptureServiceImpl::VizGpuContextProvider
}

if (!gpu_channel_host) {
return;
return false;
}

scoped_refptr<viz::ContextProvider> context_provider =
Expand All @@ -179,11 +191,12 @@ class VideoCaptureServiceImpl::VizGpuContextProvider
context_provider->BindToCurrentSequence();
if (context_result != gpu::ContextResult::kSuccess) {
LOG(ERROR) << "Bind context provider failed.";
return;
return false;
}

context_provider->AddObserver(this);
context_provider_ = std::move(context_provider);
return true;
}

// Task runner for operating |viz_gpu_| and
Expand Down

0 comments on commit 811adef

Please sign in to comment.