Commit 14b7e6ab authored by David Staessens's avatar David Staessens Committed by Commit Bot

Added support for checking supported image formats to the VAAPI wrapper.

Currently the jpeg decoder always assumes the VAAPI will support decoding to the
I420 format. As this might not be the case for all VAAPI implementations this
change adds a method to the VAAPI wrapper to check whether a specific format is
supported.

Bug: 828119

Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel
Change-Id: I8ad54a27b9e1d560f5590ae778e43f8d75bba8e9
Reviewed-on: https://chromium-review.googlesource.com/1102277
Commit-Queue: David Staessens <dstaessens@chromium.org>
Reviewed-by: default avatarMiguel Casas <mcasas@chromium.org>
Reviewed-by: default avatarHirokazu Honda <hiroh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#580817}
parent 75dbb726
......@@ -24,10 +24,12 @@ VAStatus vaGetConfigAttributes(VADisplay dpy, VAProfile profile, VAEntrypoint en
VAStatus vaGetImage(VADisplay dpy, VASurfaceID surface, int x, int y, unsigned int width, unsigned int height, VAImageID image);
VAStatus vaInitialize(VADisplay dpy, int *major_version, int *minor_version);
VAStatus vaMapBuffer(VADisplay dpy, VABufferID buf_id, void **pbuf);
int vaMaxNumEntrypoints (VADisplay dpy);
int vaMaxNumEntrypoints(VADisplay dpy);
int vaMaxNumImageFormats(VADisplay dpy);
int vaMaxNumProfiles(VADisplay dpy);
VAStatus vaQueryConfigEntrypoints (VADisplay dpy, VAProfile profile, VAEntrypoint *entrypoint_list, int *num_entrypoints);
VAStatus vaQueryConfigEntrypoints(VADisplay dpy, VAProfile profile, VAEntrypoint *entrypoint_list, int *num_entrypoints);
VAStatus vaQueryConfigProfiles(VADisplay dpy, VAProfile *profile_list, int *num_profiles);
VAStatus vaQueryImageFormats(VADisplay dpy, VAImageFormat *format_list, int *num_formats);
VAStatus vaQuerySurfaceAttributes(VADisplay dpy, VAConfigID config, VASurfaceAttrib *attrib_list, unsigned int *num_attribs);
const char* vaQueryVendorString(VADisplay dpy);
VAStatus vaRenderPicture(VADisplay dpy, VAContextID context, VABufferID *buffers, int num_buffers);
......
......@@ -123,8 +123,11 @@ VaapiJpegDecodeAccelerator::VaapiJpegDecodeAccelerator(
const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
: task_runner_(base::ThreadTaskRunnerHandle::Get()),
io_task_runner_(io_task_runner),
client_(nullptr),
decoder_thread_("VaapiJpegDecoderThread"),
va_surface_id_(VA_INVALID_SURFACE),
va_rt_format_(0),
va_image_format_{},
weak_this_factory_(this) {}
VaapiJpegDecodeAccelerator::~VaapiJpegDecodeAccelerator() {
......@@ -141,6 +144,21 @@ bool VaapiJpegDecodeAccelerator::Initialize(Client* client) {
client_ = client;
// Set the image format that will be requested from the VA API. Currently we
// always use I420, as this is the expected output format.
// TODO(crbug.com/828119): Try a list of possible supported formats rather
// than hardcoding the format to I420 here.
VAImageFormat va_image_format = {};
va_image_format.fourcc = VA_FOURCC_I420;
va_image_format.byte_order = VA_LSB_FIRST;
va_image_format.bits_per_pixel = 12;
if (!VaapiWrapper::IsImageFormatSupported(va_image_format)) {
VLOGF(1) << "I420 image format not supported";
return false;
}
va_image_format_ = va_image_format;
vaapi_wrapper_ =
VaapiWrapper::Create(VaapiWrapper::kDecode, VAProfileJPEGBaseline,
base::Bind(&ReportToUMA, VAAPI_ERROR));
......@@ -173,15 +191,10 @@ bool VaapiJpegDecodeAccelerator::OutputPicture(
<< input_buffer_id;
VAImage image = {};
VAImageFormat format = {};
format.fourcc = VA_FOURCC_I420;
format.byte_order = VA_LSB_FIRST;
format.bits_per_pixel = 12; // 12 for I420
uint8_t* mem = nullptr;
gfx::Size coded_size = video_frame->coded_size();
if (!vaapi_wrapper_->GetVaImage(va_surface_id, &format, coded_size, &image,
reinterpret_cast<void**>(&mem))) {
if (!vaapi_wrapper_->GetVaImage(va_surface_id, &va_image_format_, coded_size,
&image, reinterpret_cast<void**>(&mem))) {
VLOGF(1) << "Cannot get VAImage";
return false;
}
......
......@@ -90,6 +90,8 @@ class MEDIA_GPU_EXPORT VaapiJpegDecodeAccelerator
gfx::Size coded_size_;
// The VA RT format associated with |va_surface_id_|.
unsigned int va_rt_format_;
// The VA image format that will be requested from the VA API.
VAImageFormat va_image_format_;
// WeakPtr factory for use in posting tasks from |decoder_task_runner_| back
// to |task_runner_|. Since |decoder_thread_| is a fully owned member of
......
......@@ -510,7 +510,7 @@ VASupportedProfiles::VASupportedProfiles()
base::AutoLock auto_lock(*va_lock_);
VAStatus va_res = VA_STATUS_SUCCESS;
display_state->Deinitialize(&va_res);
VA_LOG_ON_ERROR(va_res, "vaTerminate failed");
VA_LOG_ON_ERROR(va_res, "VADisplayState::Deinitialize failed");
va_display_ = nullptr;
}
}
......@@ -699,6 +699,95 @@ void DestroyVAImage(VADisplay va_display, VAImage image) {
vaDestroyImage(va_display, image.image_id);
}
// This class encapsulates fetching the list of supported output image formats
// from the VAAPI driver, in a singleton way.
class VASupportedImageFormats {
public:
static const VASupportedImageFormats& Get();
bool IsImageFormatSupported(const VAImageFormat& va_format) const;
private:
friend class base::NoDestructor<VASupportedImageFormats>;
VASupportedImageFormats();
~VASupportedImageFormats() = default;
// Initialize the list of supported image formats. The VA display should be
// locked upon calling this function.
bool InitSupportedImageFormats();
std::vector<VAImageFormat> supported_formats_;
const base::RepeatingClosure report_error_to_uma_cb_;
DISALLOW_COPY_AND_ASSIGN(VASupportedImageFormats);
};
// static
const VASupportedImageFormats& VASupportedImageFormats::Get() {
static const base::NoDestructor<VASupportedImageFormats> image_formats;
return *image_formats;
}
bool VASupportedImageFormats::IsImageFormatSupported(
const VAImageFormat& va_image_format) const {
auto it = std::find_if(supported_formats_.begin(), supported_formats_.end(),
[&va_image_format](const VAImageFormat& format) {
return format.fourcc == va_image_format.fourcc;
});
return it != supported_formats_.end();
}
VASupportedImageFormats::VASupportedImageFormats()
: report_error_to_uma_cb_(base::DoNothing()) {
VADisplayState* display_state = VADisplayState::Get();
base::Lock* va_lock = display_state->va_lock();
base::AutoLock auto_lock(*va_lock);
if (!display_state->Initialize())
return;
VADisplay va_display = display_state->va_display();
DCHECK(va_display) << "VADisplayState hasn't been properly initialized";
if (!InitSupportedImageFormats())
LOG(ERROR) << "Failed to get supported image formats";
VAStatus va_res = VA_STATUS_SUCCESS;
display_state->Deinitialize(&va_res);
VA_LOG_ON_ERROR(va_res, "VADisplayState::Deinitialize failed");
}
bool VASupportedImageFormats::InitSupportedImageFormats() {
VADisplayState* display_state = VADisplayState::Get();
display_state->va_lock()->AssertAcquired();
VADisplay va_display = display_state->va_display();
DCHECK(va_display) << "VADisplayState hasn't been properly initialized";
// Query the driver for the max number of image formats and allocate space.
const int max_image_formats = vaMaxNumImageFormats(va_display);
if (max_image_formats < 0) {
LOG(ERROR) << "vaMaxNumImageFormats returned: " << max_image_formats;
return false;
}
supported_formats_.resize(static_cast<size_t>(max_image_formats));
// Query the driver for the list of supported image formats.
int num_image_formats;
VAStatus va_res = vaQueryImageFormats(va_display, supported_formats_.data(),
&num_image_formats);
VA_SUCCESS_OR_RETURN(va_res, "vaQueryImageFormats failed", false);
if (num_image_formats < 0 || num_image_formats > max_image_formats) {
LOG(ERROR) << "vaQueryImageFormats returned: " << num_image_formats;
supported_formats_.clear();
return false;
}
// Resize the list to the actual number of formats returned by the driver.
supported_formats_.resize(static_cast<size_t>(num_image_formats));
return true;
}
} // namespace
// static
......@@ -792,6 +881,11 @@ bool VaapiWrapper::IsJpegEncodeSupported() {
VAProfileJPEGBaseline);
}
// static
bool VaapiWrapper::IsImageFormatSupported(const VAImageFormat& format) {
return VASupportedImageFormats::Get().IsImageFormatSupported(format);
}
bool VaapiWrapper::CreateSurfaces(unsigned int va_format,
const gfx::Size& size,
size_t num_surfaces,
......
......@@ -89,6 +89,9 @@ class MEDIA_GPU_EXPORT VaapiWrapper
// Return true when JPEG encode is supported.
static bool IsJpegEncodeSupported();
// Return true when the specified image format is supported.
static bool IsImageFormatSupported(const VAImageFormat& format);
// Creates |num_surfaces| backing surfaces in driver for VASurfaces of
// |va_format|, each of size |size|. Returns true when successful, with the
// created IDs in |va_surfaces| to be managed and later wrapped in
......
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