Commit f3947c5a authored by Paulo Warren's avatar Paulo Warren Committed by Commit Bot

gpu: Add a new vaapi shared image representation

This CL creates a new shared image representation as a VASurface. This
representation will be used in an Ozone context to represent a video
frame that was produced by the video acceleration api.

This representation will allow us to pass a NativePixmap to the VA-API
for the purposes of hardware accelerated video decoding.

We currently follow a VideoFrame centered design where the decoded
buffer is written onto from the hardware decoder as a VASurfaceID. The
decoded graphics buffer is wrapped in a VideoFrame, and passed to the
graphics pipeline as a Mailbox. This change eliminates the need to
convert buffers into the various required forms, and instead centralize
the lifetime as a single entity.

BUG=1058103
TEST=None

Change-Id: I482f3aa6d29a7093e8016ab4e74762e61c600865
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2083662Reviewed-by: default avatarMiguel Casas <mcasas@chromium.org>
Reviewed-by: default avatarAndres Calderon Jaramillo <andrescj@chromium.org>
Reviewed-by: default avatarKhushal <khushalsagar@chromium.org>
Commit-Queue: Paulo Warren <pwarren@chromium.org>
Cr-Commit-Position: refs/heads/master@{#754533}
parent bbb9bf14
......@@ -5,6 +5,7 @@
import("//build/config/jumbo.gni")
import("//build/config/ui.gni")
import("//gpu/vulkan/features.gni")
import("//media/gpu/args.gni")
import("//skia/features.gni")
import("//third_party/protobuf/proto_library.gni")
import("//ui/gl/features.gni")
......@@ -304,6 +305,7 @@ target(link_target_type, "gles2_sources") {
"//gpu/config",
"//gpu/ipc/common",
"//gpu/vulkan:buildflags",
"//media/gpu:buildflags",
"//skia:buildflags",
"//third_party/angle:angle_image_util",
"//third_party/angle:commit_id",
......@@ -350,6 +352,9 @@ target(link_target_type, "gles2_sources") {
"shared_image_representation_gl_ozone.cc",
"shared_image_representation_gl_ozone.h",
]
if (use_vaapi) {
deps += [ "//media/gpu/vaapi:common" ]
}
}
if (is_linux && use_dawn) {
......
......@@ -12,7 +12,17 @@ include_rules = [
]
specific_include_rules = {
"image_reader_gl_owner_unittest.cc": [
"image_reader_gl_owner_unittest\.cc": [
"+media/base/media_switches.h",
],
"shared_image_backing_ozone\.cc": [
"+media/gpu/vaapi/vaapi_wrapper.h",
"+media/gpu/vaapi/va_surface.h",
],
"shared_image_representation\.cc": [
"+media/gpu/vaapi/va_surface.h",
],
"shared_image_.*\.h": [
"+media/gpu/buildflags.h",
],
}
......@@ -78,6 +78,14 @@ SharedImageBacking::ProduceOverlay(SharedImageManager* manager,
return nullptr;
}
#if BUILDFLAG(USE_VAAPI)
std::unique_ptr<SharedImageRepresentationVaapi>
SharedImageBacking::ProduceVASurface(SharedImageManager* manager,
MemoryTypeTracker* tracker) {
return nullptr;
}
#endif
void SharedImageBacking::AddRef(SharedImageRepresentation* representation) {
AutoLock auto_lock(this);
......
......@@ -17,6 +17,7 @@
#include "components/viz/common/resources/resource_format.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "gpu/gpu_gles2_export.h"
#include "media/gpu/buildflags.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
......@@ -43,6 +44,7 @@ class SharedImageRepresentationGLTexturePassthrough;
class SharedImageRepresentationSkia;
class SharedImageRepresentationDawn;
class SharedImageRepresentationOverlay;
class SharedImageRepresentationVaapi;
class MemoryTypeTracker;
// Represents the actual storage (GL texture, VkImage, GMB) for a SharedImage.
......@@ -139,6 +141,11 @@ class GPU_GLES2_EXPORT SharedImageBacking {
virtual std::unique_ptr<SharedImageRepresentationOverlay> ProduceOverlay(
SharedImageManager* manager,
MemoryTypeTracker* tracker);
#if BUILDFLAG(USE_VAAPI)
virtual std::unique_ptr<SharedImageRepresentationVaapi> ProduceVASurface(
SharedImageManager* manager,
MemoryTypeTracker* tracker);
#endif
// Used by subclasses during destruction.
bool have_context() const EXCLUSIVE_LOCKS_REQUIRED(lock_);
......
......@@ -8,6 +8,7 @@
#include <vulkan/vulkan.h>
#include <memory>
#include <utility>
#include "base/logging.h"
#include "base/memory/ptr_util.h"
......@@ -42,6 +43,10 @@
#include "gpu/command_buffer/service/shared_image_representation_dawn_ozone.h"
#endif // BUILDFLAG(USE_DAWN)
#if BUILDFLAG(USE_VAAPI)
#include "media/gpu/vaapi/vaapi_wrapper.h"
#endif // BUILDFLAG(USE_VAAPI)
namespace gpu {
namespace {
......@@ -95,7 +100,11 @@ std::unique_ptr<SharedImageBackingOzone> SharedImageBackingOzone::Create(
std::move(pixmap), std::move(dawn_procs)));
}
SharedImageBackingOzone::~SharedImageBackingOzone() = default;
SharedImageBackingOzone::~SharedImageBackingOzone() {
#if BUILDFLAG(USE_VAAPI)
DCHECK(surface_->HasOneRef());
#endif
}
void SharedImageBackingOzone::Update(std::unique_ptr<gfx::GpuFence> in_fence) {
NOTIMPLEMENTED_LOG_ONCE();
......@@ -173,6 +182,34 @@ SharedImageBackingOzone::ProduceOverlay(SharedImageManager* manager,
return nullptr;
}
#if BUILDFLAG(USE_VAAPI)
std::unique_ptr<SharedImageRepresentationVaapi>
SharedImageBackingOzone::ProduceVASurface(SharedImageManager* manager,
MemoryTypeTracker* tracker) {
DCHECK(pixmap_);
// We will only use |vaapi_wrapper_| to import surfaces and do
// synchronization, so the mode and profile is irrelevant.
// TODO(pwarren): Add a UMA callback to report VA-API errors.
if (!vaapi_wrapper_) {
DCHECK(!surface_);
vaapi_wrapper_ = media::VaapiWrapper::Create(
media::VaapiWrapper::CodecMode::kDecode, VAProfile::VAProfileNone,
/*report_error_to_uma_cb=*/base::DoNothing());
// We reuse the surface in subsequent calls to ProduceVASurface.
// |surface_| is self-cleaning. When all references are gone,
// VaapiWrapper::DestroySurface() is called for us.
surface_ = vaapi_wrapper_->CreateVASurfaceForPixmap(pixmap_);
}
DCHECK(surface_);
return std::make_unique<SharedImageRepresentationVaapi>(manager, this,
tracker, surface_);
}
#endif
SharedImageBackingOzone::SharedImageBackingOzone(
const Mailbox& mailbox,
viz::ResourceFormat format,
......
......@@ -21,11 +21,19 @@
#include "gpu/command_buffer/service/shared_image_manager.h"
#include "gpu/command_buffer/service/shared_image_representation.h"
#include "gpu/ipc/common/surface_handle.h"
#include "media/gpu/buildflags.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/gpu_fence.h"
#include "ui/gfx/native_pixmap.h"
#if BUILDFLAG(USE_VAAPI)
namespace media {
class VaapiWrapper;
class VASurface;
} // namespace media
#endif
namespace gpu {
// Implementation of SharedImageBacking that uses a NativePixmap created via
......@@ -66,6 +74,11 @@ class SharedImageBackingOzone final : public ClearTrackingSharedImageBacking {
std::unique_ptr<SharedImageRepresentationOverlay> ProduceOverlay(
SharedImageManager* manager,
MemoryTypeTracker* tracker) override;
#if BUILDFLAG(USE_VAAPI)
std::unique_ptr<SharedImageRepresentationVaapi> ProduceVASurface(
SharedImageManager* manager,
MemoryTypeTracker* tracker) override;
#endif
private:
SharedImageBackingOzone(
......@@ -81,6 +94,15 @@ class SharedImageBackingOzone final : public ClearTrackingSharedImageBacking {
scoped_refptr<gfx::NativePixmap> pixmap_;
scoped_refptr<base::RefCountedData<DawnProcTable>> dawn_procs_;
#if BUILDFLAG(USE_VAAPI)
// Cached VA-API wrapper used to call the VA-API.
scoped_refptr<media::VaapiWrapper> vaapi_wrapper_;
// Cached VASurface that should be created once, and passed to all
// representations produced by this backing.
scoped_refptr<media::VASurface> surface_;
#endif
DISALLOW_COPY_AND_ASSIGN(SharedImageBackingOzone);
};
......
......@@ -271,6 +271,31 @@ SharedImageManager::ProduceOverlay(const gpu::Mailbox& mailbox,
return representation;
}
#if BUILDFLAG(USE_VAAPI)
std::unique_ptr<SharedImageRepresentationVaapi>
SharedImageManager::ProduceVASurface(const Mailbox& mailbox,
MemoryTypeTracker* tracker) {
CALLED_ON_VALID_THREAD();
AutoLock autolock(this);
auto found = images_.find(mailbox);
if (found == images_.end()) {
LOG(ERROR) << "SharedImageManager::ProduceVASurface: Trying to produce a "
"VA-API representation from a non-existent mailbox.";
return nullptr;
}
auto representation = (*found)->ProduceVASurface(this, tracker);
if (!representation) {
LOG(ERROR) << "SharedImageManager::ProduceVASurface: Trying to produce a "
"VA-API representation from an incompatible mailbox.";
return nullptr;
}
return representation;
}
#endif
void SharedImageManager::OnRepresentationDestroyed(
const Mailbox& mailbox,
SharedImageRepresentation* representation) {
......
......@@ -14,6 +14,7 @@
#include "gpu/command_buffer/common/mailbox.h"
#include "gpu/command_buffer/service/shared_image_backing.h"
#include "gpu/gpu_gles2_export.h"
#include "media/gpu/buildflags.h"
namespace gpu {
class SharedImageRepresentationFactoryRef;
......@@ -63,6 +64,11 @@ class GPU_GLES2_EXPORT SharedImageManager {
std::unique_ptr<SharedImageRepresentationOverlay> ProduceOverlay(
const Mailbox& mailbox,
MemoryTypeTracker* ref);
#if BUILDFLAG(USE_VAAPI)
std::unique_ptr<SharedImageRepresentationVaapi> ProduceVASurface(
const Mailbox& mailbox,
MemoryTypeTracker* ref);
#endif
// Called by SharedImageRepresentation in the destructor.
void OnRepresentationDestroyed(const Mailbox& mailbox,
......
......@@ -7,6 +7,10 @@
#include "gpu/command_buffer/service/texture_manager.h"
#include "third_party/skia/include/core/SkPromiseImageTexture.h"
#if BUILDFLAG(USE_VAAPI)
#include "media/gpu/vaapi/va_surface.h"
#endif
namespace gpu {
SharedImageRepresentation::SharedImageRepresentation(
......@@ -213,4 +217,36 @@ SharedImageRepresentationFactoryRef::~SharedImageRepresentationFactoryRef() {
backing()->MarkForDestruction();
}
#if BUILDFLAG(USE_VAAPI)
SharedImageRepresentationVaapi::SharedImageRepresentationVaapi(
SharedImageManager* manager,
SharedImageBacking* backing,
MemoryTypeTracker* tracker,
scoped_refptr<media::VASurface> va_surface)
: SharedImageRepresentation(manager, backing, tracker),
va_surface_(std::move(va_surface)) {}
SharedImageRepresentationVaapi::~SharedImageRepresentationVaapi() = default;
SharedImageRepresentationVaapi::ScopedWriteAccess::ScopedWriteAccess(
util::PassKey<SharedImageRepresentationVaapi> /* pass_key */,
SharedImageRepresentationVaapi* representation)
: ScopedAccessBase(representation) {}
SharedImageRepresentationVaapi::ScopedWriteAccess::~ScopedWriteAccess() {
representation()->EndAccess();
}
const media::VASurface*
SharedImageRepresentationVaapi::ScopedWriteAccess::va_surface() const {
return representation()->va_surface_.get();
}
std::unique_ptr<SharedImageRepresentationVaapi::ScopedWriteAccess>
SharedImageRepresentationVaapi::BeginScopedWriteAccess() {
return std::make_unique<ScopedWriteAccess>(
util::PassKey<SharedImageRepresentationVaapi>(), this);
}
#endif
} // namespace gpu
......@@ -15,6 +15,7 @@
#include "gpu/command_buffer/service/shared_image_backing.h"
#include "gpu/command_buffer/service/shared_image_manager.h"
#include "gpu/gpu_gles2_export.h"
#include "media/gpu/buildflags.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/rect.h"
......@@ -28,6 +29,12 @@ namespace gl {
class GLImage;
}
#if BUILDFLAG(USE_VAAPI)
namespace media {
class VASurface;
}
#endif
namespace gpu {
class TextureBase;
......@@ -94,7 +101,7 @@ class GPU_GLES2_EXPORT SharedImageRepresentation {
representation_->has_scoped_access_ = false;
}
RepresentationClass* representation() { return representation_; }
RepresentationClass* representation() const { return representation_; }
private:
RepresentationClass* const representation_;
......@@ -374,6 +381,52 @@ class GPU_GLES2_EXPORT SharedImageRepresentationOverlay
virtual gl::GLImage* GetGLImage() = 0;
};
// Representation of a SharedImageBacking as a VA-API surface.
// This representation is currently only supported by SharedImageBackingOzone.
//
// Synchronized access is currently not required in this representation because:
//
// For reads:
// We will be using this for the destination of decoding work, so no read access
// synchronization is needed from the point of view of the VA-API.
//
// For writes:
// Because of the design of the current video pipeline, we don't start the
// decoding work until we're sure that the destination buffer is not being used
// by the rest of the pipeline. However, we still need to keep track of write
// accesses so that other representations can synchronize with the decoder.
//
// TODO(pwarren): create subclass SharedImageRepresentationVaapiOzone that
// implements EndAccess.
#if BUILDFLAG(USE_VAAPI)
class GPU_GLES2_EXPORT SharedImageRepresentationVaapi
: public SharedImageRepresentation {
public:
class GPU_GLES2_EXPORT ScopedWriteAccess
: public ScopedAccessBase<SharedImageRepresentationVaapi> {
public:
ScopedWriteAccess(util::PassKey<SharedImageRepresentationVaapi> pass_key,
SharedImageRepresentationVaapi* representation);
~ScopedWriteAccess();
const media::VASurface* va_surface() const;
};
SharedImageRepresentationVaapi(SharedImageManager* manager,
SharedImageBacking* backing,
MemoryTypeTracker* tracker,
scoped_refptr<media::VASurface> va_surface);
~SharedImageRepresentationVaapi() override;
std::unique_ptr<ScopedWriteAccess> BeginScopedWriteAccess();
private:
scoped_refptr<media::VASurface> va_surface_;
// TODO(pwarren): Make EndAccess purely virtual.
virtual void EndAccess() {}
};
#endif
} // namespace gpu
#endif // GPU_COMMAND_BUFFER_SERVICE_SHARED_IMAGE_REPRESENTATION_H_
......@@ -100,6 +100,10 @@ gles2::Texture* SharedImageRepresentationGLOzone::GetTexture() {
bool SharedImageRepresentationGLOzone::BeginAccess(GLenum mode) {
// TODO(hob): Synchronize access to the dma-buf by waiting on all semaphores
// tracked by SharedImageBackingOzone.
//
// TODO(pwarren): When this representation is involved with a VA-API decode,
// we must call VaapiWrapper::SyncSurface() to ensure all VA-API work is done
// prior to using the buffer in a graphics API.
return true;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment