Added the new GPU VA context class to handle VA connections to GPU. Removed the hard coded HW decoder capability info. (#415)

* * rocDecode: Removed the hard coded HW decoder capability info.
 - We now probe HW decoder capabilities through VA-API from the driver.

* * rocDecode: Added number of decoder prob and a few missing tear down calls.

* * rocDecode/HW cap change: Added a new singleton class, GpuVaContext, to handle HIP and VA initialization and VA attributes probe for both HW capability check and decoder initialization.

* * rocDecode/HW caps: Removed GpuVaContext class out of vaapi_videodecoder.h and into a new file. Removed debug logs. Removed roc_decoder_caps.h.

* * rocDecode/HW caps: Fixed a crash issue with multi-thread cases. Called to vaInitialize() and vaTerminte() should be paired.

* * rocDecode/HW caps: Added multi-GPU support.

* * rocDecode/HW cap: Moved GpuVaContext class implementation back to VAAPI layer.

* * rocDecode/HW cap: Added changed based on review comments.

* * rocDecode/HW cap: Added changes based on review comments.

* * rocDecode/HW cap: GPU VA context class name change based on review comment.

---------

Co-authored-by: Kiriti Gowda <kiritigowda@gmail.com>
This commit is contained in:
jeffqjiangNew
2025-01-10 14:44:06 -05:00
committed by GitHub
parent 6477cd1100
commit ef06f12dfa
7 changed files with 578 additions and 405 deletions
+1 -20
View File
@@ -45,11 +45,6 @@ RocDecoder::RocDecoder(RocDecoderCreateInfo& decoder_create_info): va_video_deco
rocDecStatus RocDecoder::InitializeDecoder() {
rocDecStatus rocdec_status = ROCDEC_SUCCESS;
rocdec_status = InitHIP(decoder_create_info_.device_id);
if (rocdec_status != ROCDEC_SUCCESS) {
ERR("Failed to initilize the HIP.");
return rocdec_status;
}
if (decoder_create_info_.num_decode_surfaces < 1) {
ERR("Invalid number of decode surfaces.");
return ROCDEC_INVALID_PARAMETER;
@@ -58,8 +53,7 @@ RocDecoder::RocDecoder(RocDecoderCreateInfo& decoder_create_info): va_video_deco
for (auto i = 0; i < hip_interop_.size(); i++) {
memset((void *)&hip_interop_[i], 0, sizeof(hip_interop_[i]));
}
std::string gpu_uuid(hip_dev_prop_.uuid.bytes, sizeof(hip_dev_prop_.uuid.bytes));
rocdec_status = va_video_decoder_.InitializeDecoder(hip_dev_prop_.name, hip_dev_prop_.gcnArchName, gpu_uuid);
rocdec_status = va_video_decoder_.InitializeDecoder();
if (rocdec_status != ROCDEC_SUCCESS) {
ERR("Failed to initilize the VAAPI Video decoder.");
return rocdec_status;
@@ -186,16 +180,3 @@ rocDecStatus RocDecoder::FreeVideoFrame(int pic_idx) {
return ROCDEC_SUCCESS;
}
rocDecStatus RocDecoder::InitHIP(int device_id) {
CHECK_HIP(hipGetDeviceCount(&num_devices_));
if (num_devices_ < 1) {
ERR("Didn't find any GPU.");
return ROCDEC_DEVICE_INVALID;
}
CHECK_HIP(hipSetDevice(device_id));
CHECK_HIP(hipGetDeviceProperties(&hip_dev_prop_, device_id));
return ROCDEC_SUCCESS;
}
-10
View File
@@ -34,14 +34,6 @@ THE SOFTWARE.
#include <hip/hip_runtime.h>
#include "vaapi/vaapi_videodecoder.h"
#define CHECK_HIP(call) {\
hipError_t hip_status = call;\
if (hip_status != hipSuccess) {\
std::cout << "HIP failure: " << #call << " failed with 'status: " << hipGetErrorName(hip_status) << "' at " << __FILE__ << ":" << __LINE__ << std::endl;\
return ROCDEC_RUNTIME_ERROR;\
}\
}
struct HipInteropDeviceMem {
hipExternalMemory_t hip_ext_mem; // Interface to the vaapi-hip interop
uint8_t* hip_mapped_device_mem; // Mapped device memory for the YUV plane
@@ -63,11 +55,9 @@ public:
rocDecStatus GetVideoFrame(int pic_idx, void *dev_mem_ptr[3], uint32_t horizontal_pitch[3], RocdecProcParams *vid_postproc_params);
private:
rocDecStatus InitHIP(int device_id);
rocDecStatus FreeVideoFrame(int pic_idx);
int num_devices_;
RocDecoderCreateInfo decoder_create_info_;
VaapiVideoDecoder va_video_decoder_;
hipDeviceProp_t hip_dev_prop_;
std::vector<HipInteropDeviceMem> hip_interop_;
};
-141
View File
@@ -1,141 +0,0 @@
/*
Copyright (c) 2023 - 2025 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#pragma once
#include <vector>
#include <string>
#include <unordered_map>
#include <mutex>
#include <algorithm>
#include "../commons.h"
#include "../../api/rocdecode.h"
// The CodecSpec struct contains information for an individual codec (e.g., rocDecVideoCodec_HEVC)
struct CodecSpec {
std::vector<rocDecVideoChromaFormat> chroma_format;
std::vector<int> bitdepth_minus8;
uint16_t output_format_mask;
uint32_t max_width;
uint32_t max_height;
uint16_t min_width;
uint16_t min_height;
};
// The VcnCodecsSpec struct contains information for all supported codecs and number of vcn instances per device
struct VcnCodecsSpec {
std::unordered_map<rocDecVideoCodec, CodecSpec> codecs_spec;
uint8_t num_decoders;
};
// The RocDecVcnCodecSpec singleton class for providing access to the the vcn_spec_table
class RocDecVcnCodecSpec {
public:
static RocDecVcnCodecSpec& GetInstance() {
static RocDecVcnCodecSpec instance;
return instance;
}
rocDecStatus GetDecoderCaps(std::string gcn_arch_name, RocdecDecodeCaps *pdc) {
std::lock_guard<std::mutex> lock(mutex);
std::size_t pos = gcn_arch_name.find_first_of(":");
std::string gcn_arch_name_base = (pos != std::string::npos) ? gcn_arch_name.substr(0, pos) : gcn_arch_name;
auto it = vcn_spec_table.find(gcn_arch_name_base);
if (it != vcn_spec_table.end()) {
const VcnCodecsSpec& vcn_spec = it->second;
auto it1 = vcn_spec.codecs_spec.find(pdc->codec_type);
if (it1 != vcn_spec.codecs_spec.end()) {
const CodecSpec& codec_spec = it1->second;
auto it_chroma_format = std::find(codec_spec.chroma_format.begin(), codec_spec.chroma_format.end(), pdc->chroma_format);
auto it_bitdepth_minus8 = std::find(codec_spec.bitdepth_minus8.begin(), codec_spec.bitdepth_minus8.end(), pdc->bit_depth_minus_8);
if (it_chroma_format != codec_spec.chroma_format.end() && it_bitdepth_minus8 != codec_spec.bitdepth_minus8.end()) {
pdc->is_supported = 1;
pdc->num_decoders = vcn_spec.num_decoders;
pdc->output_format_mask = codec_spec.output_format_mask;
pdc->max_width = codec_spec.max_width;
pdc->max_height = codec_spec.max_height;
pdc->min_width = codec_spec.min_width;
pdc->min_height = codec_spec.min_height;
return ROCDEC_SUCCESS;
} else {
return ROCDEC_NOT_SUPPORTED;
}
} else {
return ROCDEC_NOT_SUPPORTED;
}
} else {
ERR("Didn't find the decoder capability for " + gcn_arch_name + " GPU!");
return ROCDEC_NOT_IMPLEMENTED;
}
}
bool IsCodecConfigSupported(std::string gcn_arch_name, rocDecVideoCodec codec_type, rocDecVideoChromaFormat chroma_format, uint32_t bit_depth_minus8, rocDecVideoSurfaceFormat output_format) {
std::lock_guard<std::mutex> lock(mutex);
std::size_t pos = gcn_arch_name.find_first_of(":");
std::string gcn_arch_name_base = (pos != std::string::npos) ? gcn_arch_name.substr(0, pos) : gcn_arch_name;
auto it = vcn_spec_table.find(gcn_arch_name_base);
if (it != vcn_spec_table.end()) {
const VcnCodecsSpec& vcn_spec = it->second;
auto it1 = vcn_spec.codecs_spec.find(codec_type);
if (it1 != vcn_spec.codecs_spec.end()) {
const CodecSpec& codec_spec = it1->second;
auto it_chroma_format = std::find(codec_spec.chroma_format.begin(), codec_spec.chroma_format.end(), chroma_format);
auto it_bitdepth_minus8 = std::find(codec_spec.bitdepth_minus8.begin(), codec_spec.bitdepth_minus8.end(), bit_depth_minus8);
if (it_chroma_format != codec_spec.chroma_format.end() && it_bitdepth_minus8 != codec_spec.bitdepth_minus8.end()) {
return (codec_spec.output_format_mask & (static_cast<int>(output_format) + 1));
} else {
return false;
}
} else {
return false;
}
} else {
return false;
}
}
private:
std::unordered_map<std::string, VcnCodecsSpec> vcn_spec_table;
std::mutex mutex;
RocDecVcnCodecSpec() {
//vcn lookup table format:
//{"gcn_arch_name1",{{{codec1, {{chroma_format1_for_codec1, chroma_format2_for_codec1, ...}, {bit_depth1_minus8_for_codec1, bit_depth2_minus8_for_codec1, ...}, output_format_mask_for_codec1, max_width_for_codec1, max_height_for_codec1, min_width_for_codec1, min_height_for_codec1}},
// {codec2, {{chroma_format1_for_codec2, chroma_format2_for_codec2, ...}, {bit_depth1_minus8_for_codec2, bit_depth2_minus8_for_codec2, ...}, output_format_mask_for_codec2, max_width_for_codec2, max_height_for_codec2, min_width_for_codec2, min_height_for_codec2}}}
// , vcn_instances_for_gcn_arch_name1}},
// av1 is available only on VCN3.0 and above
vcn_spec_table = {
{"gfx908",{{{rocDecVideoCodec_HEVC, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 7680, 4320, 64, 64}}, {rocDecVideoCodec_AVC, {{rocDecVideoChromaFormat_420}, {0}, 1, 4096, 2160, 64, 64}}, {rocDecVideoCodec_VP9, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 7680, 4320, 64, 64}}}, 2}},
{"gfx90a",{{{rocDecVideoCodec_HEVC, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 7680, 4320, 64, 64}}, {rocDecVideoCodec_AVC, {{rocDecVideoChromaFormat_420}, {0}, 1, 4096, 2160, 64, 64}}, {rocDecVideoCodec_VP9, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 7680, 4320, 64, 64}}}, 2}},
{"gfx940",{{{rocDecVideoCodec_HEVC, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 7680, 4320, 64, 64}}, {rocDecVideoCodec_AVC, {{rocDecVideoChromaFormat_420}, {0}, 1, 4096, 2176, 64, 64}}, {rocDecVideoCodec_VP9, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 7680, 4320, 64, 64}}, {rocDecVideoCodec_AV1, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 8192, 4352, 64, 64}}}, 3}},
{"gfx941",{{{rocDecVideoCodec_HEVC, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 7680, 4320, 64, 64}}, {rocDecVideoCodec_AVC, {{rocDecVideoChromaFormat_420}, {0}, 1, 4096, 2176, 64, 64}}, {rocDecVideoCodec_VP9, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 7680, 4320, 64, 64}}, {rocDecVideoCodec_AV1, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 8192, 4352, 64, 64}}}, 4}},
{"gfx942",{{{rocDecVideoCodec_HEVC, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 7680, 4320, 64, 64}}, {rocDecVideoCodec_AVC, {{rocDecVideoChromaFormat_420}, {0}, 1, 4096, 2176, 64, 64}}, {rocDecVideoCodec_VP9, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 7680, 4320, 64, 64}}, {rocDecVideoCodec_AV1, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 8192, 4352, 64, 64}}}, 3}},
{"gfx1030",{{{rocDecVideoCodec_HEVC, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 7680, 4320, 64, 64}}, {rocDecVideoCodec_AVC, {{rocDecVideoChromaFormat_420}, {0}, 1, 4096, 2176, 64, 64}}, {rocDecVideoCodec_VP9, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 7680, 4320, 64, 64}}, {rocDecVideoCodec_AV1, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 8192, 4352, 64, 64}}}, 2}},
{"gfx1031",{{{rocDecVideoCodec_HEVC, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 7680, 4320, 64, 64}}, {rocDecVideoCodec_AVC, {{rocDecVideoChromaFormat_420}, {0}, 1, 4096, 2176, 64, 64}}, {rocDecVideoCodec_VP9, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 7680, 4320, 64, 64}}, {rocDecVideoCodec_AV1, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 8192, 4352, 64, 64}}}, 2}},
{"gfx1032",{{{rocDecVideoCodec_HEVC, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 7680, 4320, 64, 64}}, {rocDecVideoCodec_AVC, {{rocDecVideoChromaFormat_420}, {0}, 1, 4096, 2176, 64, 64}}, {rocDecVideoCodec_VP9, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 7680, 4320, 64, 64}}, {rocDecVideoCodec_AV1, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 8192, 4352, 64, 64}}}, 2}},
{"gfx1100",{{{rocDecVideoCodec_HEVC, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 7680, 4320, 64, 64}}, {rocDecVideoCodec_AVC, {{rocDecVideoChromaFormat_420}, {0}, 1, 4096, 2176, 64, 64}}, {rocDecVideoCodec_VP9, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 7680, 4320, 64, 64}}, {rocDecVideoCodec_AV1, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 8192, 4352, 64, 64}}}, 2}},
{"gfx1101",{{{rocDecVideoCodec_HEVC, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 7680, 4320, 64, 64}}, {rocDecVideoCodec_AVC, {{rocDecVideoChromaFormat_420}, {0}, 1, 4096, 2176, 64, 64}}, {rocDecVideoCodec_VP9, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 7680, 4320, 64, 64}}, {rocDecVideoCodec_AV1, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 8192, 4352, 64, 64}}}, 1}},
{"gfx1102",{{{rocDecVideoCodec_HEVC, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 7680, 4320, 64, 64}}, {rocDecVideoCodec_AVC, {{rocDecVideoChromaFormat_420}, {0}, 1, 4096, 2176, 64, 64}}, {rocDecVideoCodec_VP9, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 7680, 4320, 64, 64}}, {rocDecVideoCodec_AV1, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 8192, 4352, 64, 64}}}, 2}},
{"gfx1200",{{{rocDecVideoCodec_HEVC, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 7680, 4320, 64, 64}}, {rocDecVideoCodec_AVC, {{rocDecVideoChromaFormat_420}, {0}, 1, 4096, 2176, 64, 64}}, {rocDecVideoCodec_VP9, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 8192, 4352, 64, 64}}, {rocDecVideoCodec_AV1, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 8192, 4352, 64, 64}}}, 2}},
{"gfx1201",{{{rocDecVideoCodec_HEVC, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 7680, 4320, 64, 64}}, {rocDecVideoCodec_AVC, {{rocDecVideoChromaFormat_420}, {0}, 1, 4096, 2176, 64, 64}}, {rocDecVideoCodec_VP9, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 8192, 4352, 64, 64}}, {rocDecVideoCodec_AV1, {{rocDecVideoChromaFormat_420}, {0, 2}, 3, 8192, 4352, 64, 64}}}, 2}},
};
}
RocDecVcnCodecSpec(const RocDecVcnCodecSpec&) = delete;
RocDecVcnCodecSpec& operator = (const RocDecVcnCodecSpec) = delete;
~RocDecVcnCodecSpec() = default;
};
+8 -24
View File
@@ -21,7 +21,7 @@ THE SOFTWARE.
*/
#include "dec_handle.h"
#include "rocdecode.h"
#include "roc_decoder_caps.h"
#include "vaapi_videodecoder.h"
#include "../commons.h"
namespace rocdecode {
@@ -72,30 +72,14 @@ rocDecGetDecoderCaps(RocdecDecodeCaps *pdc) {
if (pdc == nullptr) {
return ROCDEC_INVALID_PARAMETER;
}
hipError_t hip_status = hipSuccess;
int num_devices = 0;
hipDeviceProp_t hip_dev_prop;
hip_status = hipGetDeviceCount(&num_devices);
if (hip_status != hipSuccess) {
ERR("ERROR: hipGetDeviceCount failed!" + TOSTR(hip_status));
return ROCDEC_DEVICE_INVALID;
VaContext& va_ctx = VaContext::GetInstance();
rocDecStatus ret = ROCDEC_SUCCESS;
if ((ret = va_ctx.CheckDecCapForCodecType(pdc)) != ROCDEC_SUCCESS) {
ERR("Failed to obtain decoder capabilities from driver.");
return ret;
} else {
return ROCDEC_SUCCESS;
}
if (num_devices < 1) {
ERR("ERROR: didn't find any GPU!");
return ROCDEC_DEVICE_INVALID;
}
if (pdc->device_id >= num_devices) {
ERR("ERROR: the requested device_id is not found! ");
return ROCDEC_DEVICE_INVALID;
}
hip_status = hipGetDeviceProperties(&hip_dev_prop, pdc->device_id);
if (hip_status != hipSuccess) {
ERR("ERROR: hipGetDeviceProperties for device (" +TOSTR(pdc->device_id) + " ) failed! (" + TOSTR(hip_status) + ")" );
return ROCDEC_DEVICE_INVALID;
}
RocDecVcnCodecSpec& vcn_codec_spec = RocDecVcnCodecSpec::GetInstance();
return vcn_codec_spec.GetDecoderCaps(hip_dev_prop.gcnArchName, pdc);
}
/*****************************************************************************************************/
+496 -195
View File
@@ -52,46 +52,27 @@ VaapiVideoDecoder::~VaapiVideoDecoder() {
if (va_status != VA_STATUS_SUCCESS) {
ERR("vaDestroyConfig failed");
}
va_status = vaTerminate(va_display_);
if (va_status != VA_STATUS_SUCCESS) {
ERR("vaTerminate failed");
}
}
}
rocDecStatus VaapiVideoDecoder::InitializeDecoder(std::string device_name, std::string gcn_arch_name, std::string& gpu_uuid) {
rocDecStatus VaapiVideoDecoder::InitializeDecoder() {
rocDecStatus rocdec_status = ROCDEC_SUCCESS;
//Before initializing the VAAPI, first check to see if the requested codec config is supported
RocDecVcnCodecSpec& vcn_codec_spec = RocDecVcnCodecSpec::GetInstance();
if (!vcn_codec_spec.IsCodecConfigSupported(gcn_arch_name, decoder_create_info_.codec_type, decoder_create_info_.chroma_format,
// Before initializing the VAAPI, first check to see if the requested codec config is supported
if (!IsCodecConfigSupported(decoder_create_info_.device_id, decoder_create_info_.codec_type, decoder_create_info_.chroma_format,
decoder_create_info_.bit_depth_minus_8, decoder_create_info_.output_format)) {
ERR("The codec config combination is not supported.");
return ROCDEC_NOT_SUPPORTED;
}
std::size_t pos = gcn_arch_name.find_first_of(":");
std::string gcn_arch_name_base = (pos != std::string::npos) ? gcn_arch_name.substr(0, pos) : gcn_arch_name;
std::vector<int> visible_devices;
GetVisibleDevices(visible_devices);
GetGpuUuids();
int offset = 0;
if (gcn_arch_name_base.compare("gfx942") == 0) {
std::vector<ComputePartition> current_compute_partitions;
GetCurrentComputePartition(current_compute_partitions);
if (!current_compute_partitions.empty()) {
GetDrmNodeOffset(device_name, decoder_create_info_.device_id, visible_devices, current_compute_partitions, offset);
}
}
std::string drm_node = "/dev/dri/renderD";
int render_node_id = (gpu_uuids_to_render_nodes_map_.find(gpu_uuid) != gpu_uuids_to_render_nodes_map_.end()) ? gpu_uuids_to_render_nodes_map_[gpu_uuid] : 128;
drm_node += std::to_string(render_node_id + offset);
rocdec_status = InitVAAPI(drm_node);
if (rocdec_status != ROCDEC_SUCCESS) {
ERR("Failed to initilize the VAAPI.");
VaContext& va_ctx = VaContext::GetInstance();
uint32_t va_ctx_id;
if ((rocdec_status = va_ctx.GetVaContext(decoder_create_info_.device_id, &va_ctx_id)) != ROCDEC_SUCCESS) {
ERR("Failed to get VA context.");
return rocdec_status;
}
if ((rocdec_status = va_ctx.GetVaDisplay(va_ctx_id, &va_display_)) != ROCDEC_SUCCESS) {
ERR("Failed to get VA display.");
return rocdec_status;
}
rocdec_status = CreateDecoderConfig();
@@ -112,157 +93,6 @@ rocDecStatus VaapiVideoDecoder::InitializeDecoder(std::string device_name, std::
return rocdec_status;
}
rocDecStatus VaapiVideoDecoder::InitVAAPI(std::string drm_node) {
drm_fd_ = open(drm_node.c_str(), O_RDWR);
if (drm_fd_ < 0) {
ERR("Failed to open drm node." + drm_node);
return ROCDEC_NOT_INITIALIZED;
}
va_display_ = vaGetDisplayDRM(drm_fd_);
if (!va_display_) {
ERR("Failed to create va_display.");
return ROCDEC_NOT_INITIALIZED;
}
vaSetInfoCallback(va_display_, NULL, NULL);
int major_version = 0, minor_version = 0;
CHECK_VAAPI(vaInitialize(va_display_, &major_version, &minor_version));
return ROCDEC_SUCCESS;
}
rocDecStatus VaapiVideoDecoder::CreateDecoderConfig() {
switch (decoder_create_info_.codec_type) {
case rocDecVideoCodec_HEVC:
if (decoder_create_info_.bit_depth_minus_8 == 0) {
va_profile_ = VAProfileHEVCMain;
} else if (decoder_create_info_.bit_depth_minus_8 == 2) {
va_profile_ = VAProfileHEVCMain10;
}
break;
case rocDecVideoCodec_AVC:
va_profile_ = VAProfileH264Main;
break;
case rocDecVideoCodec_VP9:
if (decoder_create_info_.bit_depth_minus_8 == 0) {
va_profile_ = VAProfileVP9Profile0;
} else if (decoder_create_info_.bit_depth_minus_8 == 2) {
va_profile_ = VAProfileVP9Profile2;
}
break;
case rocDecVideoCodec_AV1:
#if VA_CHECK_VERSION(1,6,0)
va_profile_ = VAProfileAV1Profile0;
#else
va_profile_ = static_cast<VAProfile>(32); // VAProfileAV1Profile0;
#endif
break;
default:
ERR("The codec type is not supported.");
return ROCDEC_NOT_SUPPORTED;
}
va_config_attrib_.type = VAConfigAttribRTFormat;
CHECK_VAAPI(vaGetConfigAttributes(va_display_, va_profile_, VAEntrypointVLD, &va_config_attrib_, 1));
CHECK_VAAPI(vaCreateConfig(va_display_, va_profile_, VAEntrypointVLD, &va_config_attrib_, 1, &va_config_id_));
unsigned int num_attribs = 0;
CHECK_VAAPI(vaQuerySurfaceAttributes(va_display_, va_config_id_, nullptr, &num_attribs));
std::vector<VASurfaceAttrib> attribs(num_attribs);
CHECK_VAAPI(vaQuerySurfaceAttributes(va_display_, va_config_id_, attribs.data(), &num_attribs));
for (auto attrib : attribs) {
if (attrib.type == VASurfaceAttribDRMFormatModifiers) {
supports_modifiers_ = true;
break;
}
}
return ROCDEC_SUCCESS;
}
rocDecStatus VaapiVideoDecoder::CreateSurfaces() {
if (decoder_create_info_.num_decode_surfaces < 1) {
ERR("Invalid number of decode surfaces.");
return ROCDEC_INVALID_PARAMETER;
}
va_surface_ids_.resize(decoder_create_info_.num_decode_surfaces);
std::vector<VASurfaceAttrib> surf_attribs;
VASurfaceAttrib surf_attrib;
surf_attrib.type = VASurfaceAttribPixelFormat;
surf_attrib.flags = VA_SURFACE_ATTRIB_SETTABLE;
surf_attrib.value.type = VAGenericValueTypeInteger;
uint32_t surface_format;
switch (decoder_create_info_.chroma_format) {
case rocDecVideoChromaFormat_Monochrome:
surface_format = VA_RT_FORMAT_YUV400;
surf_attrib.value.value.i = VA_FOURCC_Y800;
break;
case rocDecVideoChromaFormat_420:
if (decoder_create_info_.bit_depth_minus_8 == 2) {
surface_format = VA_RT_FORMAT_YUV420_10;
surf_attrib.value.value.i = VA_FOURCC_P010;
} else if (decoder_create_info_.bit_depth_minus_8 == 4) {
surface_format = VA_RT_FORMAT_YUV420_12;
#if VA_CHECK_VERSION(1,8,0)
surf_attrib.value.value.i = VA_FOURCC_P012;
#else
surf_attrib.value.value.i = 0x32313050; // VA_FOURCC_P012
#endif
} else {
surface_format = VA_RT_FORMAT_YUV420;
surf_attrib.value.value.i = VA_FOURCC_NV12;
}
break;
case rocDecVideoChromaFormat_422:
surface_format = VA_RT_FORMAT_YUV422;
break;
case rocDecVideoChromaFormat_444:
surface_format = VA_RT_FORMAT_YUV444;
break;
default:
ERR("The surface type is not supported");
return ROCDEC_NOT_SUPPORTED;
}
surf_attribs.push_back(surf_attrib);
uint64_t mod_linear = 0;
VADRMFormatModifierList modifier_list = {
.num_modifiers = 1,
.modifiers = &mod_linear,
};
if (supports_modifiers_) {
surf_attrib.type = VASurfaceAttribDRMFormatModifiers;
surf_attrib.value.type = VAGenericValueTypePointer;
surf_attrib.value.value.p = &modifier_list;
surf_attribs.push_back(surf_attrib);
}
CHECK_VAAPI(vaCreateSurfaces(va_display_, surface_format, decoder_create_info_.width,
decoder_create_info_.height, va_surface_ids_.data(), va_surface_ids_.size(), surf_attribs.data(), surf_attribs.size()));
return ROCDEC_SUCCESS;
}
rocDecStatus VaapiVideoDecoder::CreateContext() {
CHECK_VAAPI(vaCreateContext(va_display_, va_config_id_, decoder_create_info_.width, decoder_create_info_.height,
VA_PROGRESSIVE, va_surface_ids_.data(), va_surface_ids_.size(), &va_context_id_));
return ROCDEC_SUCCESS;
}
rocDecStatus VaapiVideoDecoder::DestroyDataBuffers() {
if (pic_params_buf_id_) {
CHECK_VAAPI(vaDestroyBuffer(va_display_, pic_params_buf_id_));
pic_params_buf_id_ = 0;
}
if (iq_matrix_buf_id_) {
CHECK_VAAPI(vaDestroyBuffer(va_display_, iq_matrix_buf_id_));
iq_matrix_buf_id_ = 0;
}
for (int i = 0; i < num_slices_; i++) {
if (slice_params_buf_id_[i]) {
CHECK_VAAPI(vaDestroyBuffer(va_display_, slice_params_buf_id_[i]));
slice_params_buf_id_[i] = 0;
}
}
if (slice_data_buf_id_) {
CHECK_VAAPI(vaDestroyBuffer(va_display_, slice_data_buf_id_));
slice_data_buf_id_ = 0;
}
return ROCDEC_SUCCESS;
}
rocDecStatus VaapiVideoDecoder::SubmitDecode(RocdecPicParams *pPicParams) {
void *pic_params_ptr, *iq_matrix_ptr, *slice_params_ptr;
uint32_t pic_params_size, iq_matrix_size, slice_params_size;
@@ -483,6 +313,18 @@ rocDecStatus VaapiVideoDecoder::ExportSurface(int pic_idx, VADRMPRIMESurfaceDesc
return ROCDEC_SUCCESS;
}
rocDecStatus VaapiVideoDecoder::SyncSurface(int pic_idx) {
if (pic_idx >= va_surface_ids_.size()) {
return ROCDEC_INVALID_PARAMETER;
}
VASurfaceStatus surface_status;
CHECK_VAAPI(vaQuerySurfaceStatus(va_display_, va_surface_ids_[pic_idx], &surface_status));
if (surface_status != VASurfaceReady) {
CHECK_VAAPI(vaSyncSurface(va_display_, va_surface_ids_[pic_idx]));
}
return ROCDEC_SUCCESS;
}
rocDecStatus VaapiVideoDecoder::ReconfigureDecoder(RocdecReconfigureDecoderInfo *reconfig_params) {
if (reconfig_params == nullptr) {
return ROCDEC_INVALID_PARAMETER;
@@ -514,19 +356,480 @@ rocDecStatus VaapiVideoDecoder::ReconfigureDecoder(RocdecReconfigureDecoderInfo
return rocdec_status;
}
rocDecStatus VaapiVideoDecoder::SyncSurface(int pic_idx) {
if (pic_idx >= va_surface_ids_.size()) {
return ROCDEC_INVALID_PARAMETER;
bool VaapiVideoDecoder::IsCodecConfigSupported(int device_id, rocDecVideoCodec codec_type, rocDecVideoChromaFormat chroma_format, uint32_t bit_depth_minus8, rocDecVideoSurfaceFormat output_format) {
RocdecDecodeCaps decode_caps;
decode_caps.device_id = device_id;
decode_caps.codec_type = codec_type;
decode_caps.chroma_format = chroma_format;
decode_caps.bit_depth_minus_8 = bit_depth_minus8;
if((rocDecGetDecoderCaps(&decode_caps) != ROCDEC_SUCCESS) || (decode_caps.is_supported == false) || ((decode_caps.output_format_mask & (1 << output_format)) == 0)) {
return false;
} else {
return true;
}
VASurfaceStatus surface_status;
CHECK_VAAPI(vaQuerySurfaceStatus(va_display_, va_surface_ids_[pic_idx], &surface_status));
if (surface_status != VASurfaceReady) {
CHECK_VAAPI(vaSyncSurface(va_display_, va_surface_ids_[pic_idx]));
}
rocDecStatus VaapiVideoDecoder::CreateDecoderConfig() {
switch (decoder_create_info_.codec_type) {
case rocDecVideoCodec_HEVC:
if (decoder_create_info_.bit_depth_minus_8 == 0) {
va_profile_ = VAProfileHEVCMain;
} else if (decoder_create_info_.bit_depth_minus_8 == 2) {
va_profile_ = VAProfileHEVCMain10;
}
break;
case rocDecVideoCodec_AVC:
va_profile_ = VAProfileH264Main;
break;
case rocDecVideoCodec_VP9:
if (decoder_create_info_.bit_depth_minus_8 == 0) {
va_profile_ = VAProfileVP9Profile0;
} else if (decoder_create_info_.bit_depth_minus_8 == 2) {
va_profile_ = VAProfileVP9Profile2;
}
break;
case rocDecVideoCodec_AV1:
#if VA_CHECK_VERSION(1,6,0)
va_profile_ = VAProfileAV1Profile0;
#else
va_profile_ = static_cast<VAProfile>(32); // VAProfileAV1Profile0;
#endif
break;
default:
ERR("The codec type is not supported.");
return ROCDEC_NOT_SUPPORTED;
}
va_config_attrib_.type = VAConfigAttribRTFormat;
CHECK_VAAPI(vaGetConfigAttributes(va_display_, va_profile_, VAEntrypointVLD, &va_config_attrib_, 1));
CHECK_VAAPI(vaCreateConfig(va_display_, va_profile_, VAEntrypointVLD, &va_config_attrib_, 1, &va_config_id_));
unsigned int num_attribs = 0;
CHECK_VAAPI(vaQuerySurfaceAttributes(va_display_, va_config_id_, nullptr, &num_attribs));
std::vector<VASurfaceAttrib> attribs(num_attribs);
CHECK_VAAPI(vaQuerySurfaceAttributes(va_display_, va_config_id_, attribs.data(), &num_attribs));
for (auto attrib : attribs) {
if (attrib.type == VASurfaceAttribDRMFormatModifiers) {
supports_modifiers_ = true;
break;
}
}
return ROCDEC_SUCCESS;
}
void VaapiVideoDecoder::GetVisibleDevices(std::vector<int>& visible_devices_vetor) {
rocDecStatus VaapiVideoDecoder::CreateSurfaces() {
if (decoder_create_info_.num_decode_surfaces < 1) {
ERR("Invalid number of decode surfaces.");
return ROCDEC_INVALID_PARAMETER;
}
va_surface_ids_.resize(decoder_create_info_.num_decode_surfaces);
std::vector<VASurfaceAttrib> surf_attribs;
VASurfaceAttrib surf_attrib;
surf_attrib.type = VASurfaceAttribPixelFormat;
surf_attrib.flags = VA_SURFACE_ATTRIB_SETTABLE;
surf_attrib.value.type = VAGenericValueTypeInteger;
uint32_t surface_format;
switch (decoder_create_info_.chroma_format) {
case rocDecVideoChromaFormat_Monochrome:
surface_format = VA_RT_FORMAT_YUV400;
surf_attrib.value.value.i = VA_FOURCC_Y800;
break;
case rocDecVideoChromaFormat_420:
if (decoder_create_info_.bit_depth_minus_8 == 2) {
surface_format = VA_RT_FORMAT_YUV420_10;
surf_attrib.value.value.i = VA_FOURCC_P010;
} else if (decoder_create_info_.bit_depth_minus_8 == 4) {
surface_format = VA_RT_FORMAT_YUV420_12;
#if VA_CHECK_VERSION(1,8,0)
surf_attrib.value.value.i = VA_FOURCC_P012;
#else
surf_attrib.value.value.i = 0x32313050; // VA_FOURCC_P012
#endif
} else {
surface_format = VA_RT_FORMAT_YUV420;
surf_attrib.value.value.i = VA_FOURCC_NV12;
}
break;
case rocDecVideoChromaFormat_422:
surface_format = VA_RT_FORMAT_YUV422;
break;
case rocDecVideoChromaFormat_444:
surface_format = VA_RT_FORMAT_YUV444;
break;
default:
ERR("The surface type is not supported");
return ROCDEC_NOT_SUPPORTED;
}
surf_attribs.push_back(surf_attrib);
uint64_t mod_linear = 0;
VADRMFormatModifierList modifier_list = {
.num_modifiers = 1,
.modifiers = &mod_linear,
};
if (supports_modifiers_) {
surf_attrib.type = VASurfaceAttribDRMFormatModifiers;
surf_attrib.value.type = VAGenericValueTypePointer;
surf_attrib.value.value.p = &modifier_list;
surf_attribs.push_back(surf_attrib);
}
CHECK_VAAPI(vaCreateSurfaces(va_display_, surface_format, decoder_create_info_.width,
decoder_create_info_.height, va_surface_ids_.data(), va_surface_ids_.size(), surf_attribs.data(), surf_attribs.size()));
return ROCDEC_SUCCESS;
}
rocDecStatus VaapiVideoDecoder::CreateContext() {
CHECK_VAAPI(vaCreateContext(va_display_, va_config_id_, decoder_create_info_.width, decoder_create_info_.height,
VA_PROGRESSIVE, va_surface_ids_.data(), va_surface_ids_.size(), &va_context_id_));
return ROCDEC_SUCCESS;
}
rocDecStatus VaapiVideoDecoder::DestroyDataBuffers() {
if (pic_params_buf_id_) {
CHECK_VAAPI(vaDestroyBuffer(va_display_, pic_params_buf_id_));
pic_params_buf_id_ = 0;
}
if (iq_matrix_buf_id_) {
CHECK_VAAPI(vaDestroyBuffer(va_display_, iq_matrix_buf_id_));
iq_matrix_buf_id_ = 0;
}
for (int i = 0; i < num_slices_; i++) {
if (slice_params_buf_id_[i]) {
CHECK_VAAPI(vaDestroyBuffer(va_display_, slice_params_buf_id_[i]));
slice_params_buf_id_[i] = 0;
}
}
if (slice_data_buf_id_) {
CHECK_VAAPI(vaDestroyBuffer(va_display_, slice_data_buf_id_));
slice_data_buf_id_ = 0;
}
return ROCDEC_SUCCESS;
}
VaContext::VaContext() {
GetGpuUuids();
}
VaContext::~VaContext() {
for (int i = 0; i < va_contexts_.size(); i++) {
if (va_contexts_[i].va_display) {
if (vaTerminate(va_contexts_[i].va_display) != VA_STATUS_SUCCESS) {
ERR("Failed to termiate VA");
}
}
}
};
rocDecStatus VaContext::GetVaContext(int device_id, uint32_t *va_ctx_id) {
std::lock_guard<std::mutex> lock(mutex);
bool found_existing = false;
uint32_t va_ctx_idx = 0;
hipDeviceProp_t hip_dev_prop;
rocDecStatus rocdec_status = ROCDEC_SUCCESS;
rocdec_status = InitHIP(device_id, hip_dev_prop);
if (rocdec_status != ROCDEC_SUCCESS) {
ERR("Failed to initilize the HIP.");
return rocdec_status;
}
std::string gpu_uuid(hip_dev_prop.uuid.bytes, sizeof(hip_dev_prop.uuid.bytes));
if (!va_contexts_.empty()) {
for (va_ctx_idx = 0; va_ctx_idx < va_contexts_.size(); va_ctx_idx++) {
if (gpu_uuid.compare(va_contexts_[va_ctx_idx].gpu_uuid) == 0) {
found_existing = true;
break;
}
}
}
if (found_existing) {
*va_ctx_id = va_ctx_idx;
return ROCDEC_SUCCESS;
} else {
va_contexts_.resize(va_contexts_.size() + 1);
va_ctx_idx = va_contexts_.size() - 1;
va_contexts_[va_ctx_idx].device_id = device_id;
va_contexts_[va_ctx_idx].gpu_uuid.assign(gpu_uuid);
va_contexts_[va_ctx_idx].hip_dev_prop = hip_dev_prop;
va_contexts_[va_ctx_idx].drm_fd = -1;
va_contexts_[va_ctx_idx].va_display = 0;
va_contexts_[va_ctx_idx].num_dec_engines = 1;
va_contexts_[va_ctx_idx].va_profile = VAProfileNone;
va_contexts_[va_ctx_idx].config_attributes_probed = false;
std::string gcn_arch_name = va_contexts_[va_ctx_idx].hip_dev_prop.gcnArchName;
std::size_t pos = gcn_arch_name.find_first_of(":");
std::string gcn_arch_name_base = (pos != std::string::npos) ? gcn_arch_name.substr(0, pos) : gcn_arch_name;
std::vector<int> visible_devices;
GetVisibleDevices(visible_devices);
int offset = 0;
if (gcn_arch_name_base.compare("gfx942") == 0) {
std::vector<ComputePartition> current_compute_partitions;
GetCurrentComputePartition(current_compute_partitions);
if (!current_compute_partitions.empty()) {
GetDrmNodeOffset(va_contexts_[va_ctx_idx].hip_dev_prop.name, va_contexts_[va_ctx_idx].device_id, visible_devices, current_compute_partitions, offset);
}
}
std::string drm_node = "/dev/dri/renderD";
int render_node_id = (gpu_uuids_to_render_nodes_map_.find(gpu_uuid) != gpu_uuids_to_render_nodes_map_.end()) ? gpu_uuids_to_render_nodes_map_[gpu_uuid] : 128;
drm_node += std::to_string(render_node_id + offset);
rocdec_status = InitVAAPI(va_ctx_idx, drm_node);
if (rocdec_status != ROCDEC_SUCCESS) {
ERR("Failed to initilize the VAAPI.");
return rocdec_status;
}
amdgpu_device_handle dev_handle;
uint32_t major_version = 0, minor_version = 0;
if (amdgpu_device_initialize(va_contexts_[va_ctx_idx].drm_fd, &major_version, &minor_version, &dev_handle)) {
ERR("GPU device initialization failed: " + drm_node);
return ROCDEC_DEVICE_INVALID;
}
if (amdgpu_query_hw_ip_count(dev_handle, AMDGPU_HW_IP_VCN_DEC, &va_contexts_[va_ctx_idx].num_dec_engines)) {
ERR("Failed to get the number of video decode engines.");
}
amdgpu_device_deinitialize(dev_handle);
// Prob VA profiles
va_contexts_[va_ctx_idx].num_va_profiles = vaMaxNumProfiles(va_contexts_[va_ctx_idx].va_display);
va_contexts_[va_ctx_idx].va_profile_list.resize(va_contexts_[va_ctx_idx].num_va_profiles);
CHECK_VAAPI(vaQueryConfigProfiles(va_contexts_[va_ctx_idx].va_display, va_contexts_[va_ctx_idx].va_profile_list.data(), &va_contexts_[va_ctx_idx].num_va_profiles));
*va_ctx_id = va_ctx_idx;
return ROCDEC_SUCCESS;
}
}
rocDecStatus VaContext::GetVaDisplay(uint32_t va_ctx_id, VADisplay *va_display) {
if (va_ctx_id >= va_contexts_.size()) {
ERR("Invalid VA context Id.");
*va_display = 0;
return ROCDEC_INVALID_PARAMETER;
} else {
*va_display = va_contexts_[va_ctx_id].va_display;
return ROCDEC_SUCCESS;
}
}
rocDecStatus VaContext::CheckDecCapForCodecType(RocdecDecodeCaps *dec_cap) {
if (dec_cap == nullptr) {
ERR("Null decode capability struct pointer.");
return ROCDEC_INVALID_PARAMETER;
}
rocDecStatus rocdec_status = ROCDEC_SUCCESS;
uint32_t va_ctx_id;
rocdec_status = GetVaContext(dec_cap->device_id, &va_ctx_id);
if (rocdec_status != ROCDEC_SUCCESS) {
ERR("Failed to initilize.");
return rocdec_status;
}
std::lock_guard<std::mutex> lock(mutex);
dec_cap->is_supported = 1; // init value
VAProfile va_profile = VAProfileNone;
switch (dec_cap->codec_type) {
case rocDecVideoCodec_HEVC: {
if (dec_cap->bit_depth_minus_8 == 0) {
va_profile = VAProfileHEVCMain;
} else if (dec_cap->bit_depth_minus_8 == 2) {
va_profile = VAProfileHEVCMain10;
}
break;
}
case rocDecVideoCodec_AVC: {
va_profile = VAProfileH264Main;
break;
}
case rocDecVideoCodec_VP9: {
if (dec_cap->bit_depth_minus_8 == 0) {
va_profile = VAProfileVP9Profile0;
} else if (dec_cap->bit_depth_minus_8 == 2) {
va_profile = VAProfileVP9Profile2;
}
break;
}
case rocDecVideoCodec_AV1: {
#if VA_CHECK_VERSION(1,6,0)
va_profile = VAProfileAV1Profile0;
#else
va_profile = static_cast<VAProfile>(32); // VAProfileAV1Profile0;
#endif
break;
}
default: {
dec_cap->is_supported = 0;
return ROCDEC_SUCCESS;
}
}
int i;
for (i = 0; i < va_contexts_[va_ctx_id].num_va_profiles; i++) {
if (va_contexts_[va_ctx_id].va_profile_list[i] == va_profile) {
break;
}
}
if (i == va_contexts_[va_ctx_id].num_va_profiles) {
dec_cap->is_supported = 0;
return ROCDEC_SUCCESS;
}
// Check if the config attributes of the profile have been probed before
if (va_profile != va_contexts_[va_ctx_id].va_profile || va_contexts_[va_ctx_id].config_attributes_probed == false) {
va_contexts_[va_ctx_id].va_profile = va_profile;
VAConfigAttrib va_config_attrib;
unsigned int attr_count;
std::vector<VASurfaceAttrib> attr_list;
va_config_attrib.type = VAConfigAttribRTFormat;
CHECK_VAAPI(vaGetConfigAttributes(va_contexts_[va_ctx_id].va_display, va_contexts_[va_ctx_id].va_profile, VAEntrypointVLD, &va_config_attrib, 1));
va_contexts_[va_ctx_id].rt_format_attrib = va_config_attrib.value;
CHECK_VAAPI(vaCreateConfig(va_contexts_[va_ctx_id].va_display, va_contexts_[va_ctx_id].va_profile, VAEntrypointVLD, &va_config_attrib, 1, &va_contexts_[va_ctx_id].va_config_id));
CHECK_VAAPI(vaQuerySurfaceAttributes(va_contexts_[va_ctx_id].va_display, va_contexts_[va_ctx_id].va_config_id, 0, &attr_count));
attr_list.resize(attr_count);
CHECK_VAAPI(vaQuerySurfaceAttributes(va_contexts_[va_ctx_id].va_display, va_contexts_[va_ctx_id].va_config_id, attr_list.data(), &attr_count));
va_contexts_[va_ctx_id].output_format_mask = 0;
CHECK_VAAPI(vaDestroyConfig(va_contexts_[va_ctx_id].va_display, va_contexts_[va_ctx_id].va_config_id));
for (int k = 0; k < attr_count; k++) {
switch (attr_list[k].type) {
case VASurfaceAttribPixelFormat: {
switch (attr_list[k].value.value.i) {
case VA_FOURCC_NV12:
va_contexts_[va_ctx_id].output_format_mask |= 1 << rocDecVideoSurfaceFormat_NV12;
break;
case VA_FOURCC_P016:
va_contexts_[va_ctx_id].output_format_mask |= 1 << rocDecVideoSurfaceFormat_P016;
break;
default:
break;
}
}
break;
case VASurfaceAttribMinWidth:
va_contexts_[va_ctx_id].min_width = attr_list[k].value.value.i;
break;
case VASurfaceAttribMinHeight:
va_contexts_[va_ctx_id].min_height = attr_list[k].value.value.i;
break;
case VASurfaceAttribMaxWidth:
va_contexts_[va_ctx_id].max_width = attr_list[k].value.value.i;
break;
case VASurfaceAttribMaxHeight:
va_contexts_[va_ctx_id].max_height = attr_list[k].value.value.i;
break;
default:
break;
}
}
va_contexts_[va_ctx_id].config_attributes_probed = true;
}
// Check chroma format
switch (dec_cap->chroma_format) {
case rocDecVideoChromaFormat_Monochrome: {
if ((va_contexts_[va_ctx_id].rt_format_attrib & VA_RT_FORMAT_YUV400) == 0) {
dec_cap->is_supported = 0;
return ROCDEC_SUCCESS;
}
break;
}
case rocDecVideoChromaFormat_420: {
if ((va_contexts_[va_ctx_id].rt_format_attrib & (VA_RT_FORMAT_YUV420 | VA_RT_FORMAT_YUV420_10 | VA_RT_FORMAT_YUV420_12)) == 0) {
dec_cap->is_supported = 0;
return ROCDEC_SUCCESS;
}
break;
}
case rocDecVideoChromaFormat_422: {
if ((va_contexts_[va_ctx_id].rt_format_attrib & (VA_RT_FORMAT_YUV422 | VA_RT_FORMAT_YUV422_10 | VA_RT_FORMAT_YUV422_12)) == 0) {
dec_cap->is_supported = 0;
return ROCDEC_SUCCESS;
}
break;
}
case rocDecVideoChromaFormat_444: {
if ((va_contexts_[va_ctx_id].rt_format_attrib & (VA_RT_FORMAT_YUV444 | VA_RT_FORMAT_YUV444_10 | VA_RT_FORMAT_YUV444_12)) == 0) {
dec_cap->is_supported = 0;
return ROCDEC_SUCCESS;
}
break;
}
default: {
dec_cap->is_supported = 0;
return ROCDEC_SUCCESS;
}
}
// Check bit depth
switch (dec_cap->bit_depth_minus_8) {
case 0: {
if ((va_contexts_[va_ctx_id].rt_format_attrib & (VA_RT_FORMAT_YUV420 | VA_RT_FORMAT_YUV422 | VA_RT_FORMAT_YUV444 | VA_RT_FORMAT_YUV400)) == 0) {
dec_cap->is_supported = 0;
return ROCDEC_SUCCESS;
}
break;
}
case 2: {
if ((va_contexts_[va_ctx_id].rt_format_attrib & (VA_RT_FORMAT_YUV420_10 | VA_RT_FORMAT_YUV422_10 | VA_RT_FORMAT_YUV444_10)) == 0) {
dec_cap->is_supported = 0;
return ROCDEC_SUCCESS;
}
break;
}
case 4: {
if ((va_contexts_[va_ctx_id].rt_format_attrib & (VA_RT_FORMAT_YUV420_12 | VA_RT_FORMAT_YUV422_12 | VA_RT_FORMAT_YUV444_12)) == 0) {
dec_cap->is_supported = 0;
return ROCDEC_SUCCESS;
}
break;
}
default: {
dec_cap->is_supported = 0;
return ROCDEC_SUCCESS;
}
}
dec_cap->num_decoders = va_contexts_[va_ctx_id].num_dec_engines;
dec_cap->output_format_mask = va_contexts_[va_ctx_id].output_format_mask;
dec_cap->max_width = va_contexts_[va_ctx_id].max_width;
dec_cap->max_height = va_contexts_[va_ctx_id].max_height;
dec_cap->min_width = va_contexts_[va_ctx_id].min_width;
dec_cap->min_height = va_contexts_[va_ctx_id].min_height;
return ROCDEC_SUCCESS;
}
rocDecStatus VaContext::InitHIP(int device_id, hipDeviceProp_t& hip_dev_prop) {
CHECK_HIP(hipGetDeviceCount(&num_devices_));
if (num_devices_ < 1) {
ERR("Didn't find any GPU.");
return ROCDEC_DEVICE_INVALID;
}
if (device_id >= num_devices_) {
ERR("ERROR: the requested device_id is not found! ");
return ROCDEC_DEVICE_INVALID;
}
CHECK_HIP(hipSetDevice(device_id));
CHECK_HIP(hipGetDeviceProperties(&hip_dev_prop, device_id));
return ROCDEC_SUCCESS;
}
rocDecStatus VaContext::InitVAAPI(int va_ctx_idx, std::string drm_node) {
va_contexts_[va_ctx_idx].drm_fd = open(drm_node.c_str(), O_RDWR);
if (va_contexts_[va_ctx_idx].drm_fd < 0) {
ERR("Failed to open drm node." + drm_node);
return ROCDEC_NOT_INITIALIZED;
}
va_contexts_[va_ctx_idx].va_display = vaGetDisplayDRM(va_contexts_[va_ctx_idx].drm_fd);
if (!va_contexts_[va_ctx_idx].va_display) {
ERR("Failed to create VA display.");
return ROCDEC_NOT_INITIALIZED;
}
vaSetInfoCallback(va_contexts_[va_ctx_idx].va_display, NULL, NULL);
int major_version = 0, minor_version = 0;
CHECK_VAAPI(vaInitialize(va_contexts_[va_ctx_idx].va_display, &major_version, &minor_version));
return ROCDEC_SUCCESS;
}
void VaContext::GetVisibleDevices(std::vector<int>& visible_devices_vetor) {
// First, check if the ROCR_VISIBLE_DEVICES environment variable is present
char *visible_devices = std::getenv("ROCR_VISIBLE_DEVICES");
// If ROCR_VISIBLE_DEVICES is not present, check if HIP_VISIBLE_DEVICES is present
@@ -539,11 +842,11 @@ void VaapiVideoDecoder::GetVisibleDevices(std::vector<int>& visible_devices_veto
visible_devices_vetor.push_back(std::atoi(token));
token = std::strtok(nullptr,",");
}
std::sort(visible_devices_vetor.begin(), visible_devices_vetor.end());
std::sort(visible_devices_vetor.begin(), visible_devices_vetor.end());
}
}
void VaapiVideoDecoder::GetCurrentComputePartition(std::vector<ComputePartition> &current_compute_partitions) {
void VaContext::GetCurrentComputePartition(std::vector<ComputePartition> &current_compute_partitions) {
std::string search_path = "/sys/devices/";
std::string partition_file = "current_compute_partition";
std::error_code ec;
@@ -577,9 +880,7 @@ void VaapiVideoDecoder::GetCurrentComputePartition(std::vector<ComputePartition>
}
}
void VaapiVideoDecoder::GetDrmNodeOffset(std::string device_name, uint8_t device_id, std::vector<int>& visible_devices,
std::vector<ComputePartition> &current_compute_partitions, int &offset) {
void VaContext::GetDrmNodeOffset(std::string device_name, uint8_t device_id, std::vector<int>& visible_devices, std::vector<ComputePartition> &current_compute_partitions, int &offset) {
if (!current_compute_partitions.empty()) {
switch (current_compute_partitions[0]) {
case kSpx:
@@ -638,7 +939,7 @@ void VaapiVideoDecoder::GetDrmNodeOffset(std::string device_name, uint8_t device
* UUID from the corresponding sysfs path. It maps each unique GPU UUID to its
* corresponding render node ID and stores this mapping in the gpu_uuids_to_render_nodes_map_.
*/
void VaapiVideoDecoder::GetGpuUuids() {
void VaContext::GetGpuUuids() {
std::string dri_path = "/dev/dri";
// Iterate through all render nodes
for (const auto& entry : fs::directory_iterator(dri_path, fs::directory_options::skip_permission_denied)) {
+70 -12
View File
@@ -29,6 +29,9 @@ THE SOFTWARE.
#include <fcntl.h>
#include <unistd.h>
#include <cstring>
#include <mutex>
#include <algorithm>
#include <unordered_map>
#if __cplusplus >= 201703L && __has_include(<filesystem>)
#include <filesystem>
namespace fs = std::filesystem;
@@ -36,13 +39,22 @@ THE SOFTWARE.
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#endif
#include <libdrm/amdgpu_drm.h>
#include <libdrm/amdgpu.h>
#include <va/va.h>
#include <va/va_drm.h>
#include <va/va_drmcommon.h>
#include "../roc_decoder_caps.h"
#include "../../commons.h"
#include "../../../api/rocdecode.h"
#define CHECK_HIP(call) {\
hipError_t hip_status = call;\
if (hip_status != hipSuccess) {\
std::cout << "HIP failure: " << #call << " failed with 'status: " << hipGetErrorName(hip_status) << "' at " << __FILE__ << ":" << __LINE__ << std::endl;\
return ROCDEC_RUNTIME_ERROR;\
}\
}
#define CHECK_VAAPI(call) {\
VAStatus va_status = call;\
if (va_status != VA_STATUS_SUCCESS) {\
@@ -61,23 +73,44 @@ typedef enum {
kCpx = 4, // Core Partition Accelerator
} ComputePartition;
typedef struct {
int device_id;
std::string gpu_uuid;
int drm_fd;
VADisplay va_display;
hipDeviceProp_t hip_dev_prop;
uint32_t num_dec_engines;
int num_va_profiles;
std::vector<VAProfile> va_profile_list; // supported profiles by the current GPU
VAProfile va_profile; // current profile used
VAConfigID va_config_id;
bool config_attributes_probed;
uint32_t rt_format_attrib;
uint32_t output_format_mask;
uint32_t max_width;
uint32_t max_height;
uint32_t min_width;
uint32_t min_height;
} VaContextInfo;
class VaapiVideoDecoder {
public:
VaapiVideoDecoder(RocDecoderCreateInfo &decoder_create_info);
~VaapiVideoDecoder();
rocDecStatus InitializeDecoder(std::string device_name, std::string gcn_arch_name, std::string& gpu_uuid);
rocDecStatus InitializeDecoder();
rocDecStatus SubmitDecode(RocdecPicParams *pPicParams);
rocDecStatus GetDecodeStatus(int pic_idx, RocdecDecodeStatus* decode_status);
rocDecStatus ExportSurface(int pic_idx, VADRMPRIMESurfaceDescriptor &va_drm_prime_surface_desc);
rocDecStatus SyncSurface(int pic_idx);
rocDecStatus ReconfigureDecoder(RocdecReconfigureDecoderInfo *reconfig_params);
private:
RocDecoderCreateInfo decoder_create_info_;
int drm_fd_;
VADisplay va_display_;
VAProfile va_profile_;
VAConfigAttrib va_config_attrib_;
VAConfigID va_config_id_;
VAProfile va_profile_;
VAContextID va_context_id_;
std::vector<VASurfaceID> va_surface_ids_;
bool supports_modifiers_;
@@ -88,6 +121,30 @@ private:
uint32_t num_slices_;
VABufferID slice_data_buf_id_;
uint32_t slice_data_buf_size_;
bool IsCodecConfigSupported(int device_id, rocDecVideoCodec codec_type, rocDecVideoChromaFormat chroma_format, uint32_t bit_depth_minus8, rocDecVideoSurfaceFormat output_format);
rocDecStatus CreateDecoderConfig();
rocDecStatus CreateSurfaces();
rocDecStatus CreateContext();
rocDecStatus DestroyDataBuffers();
};
// The VaContext singleton class providing access to the the GPU VA services
class VaContext {
public:
int num_devices_;
std::vector<VaContextInfo> va_contexts_;
static VaContext& GetInstance() {
static VaContext instance;
return instance;
}
rocDecStatus GetVaContext(int device_id, uint32_t *va_ctx_id);
rocDecStatus GetVaDisplay(uint32_t va_ctx_id, VADisplay *va_display);
rocDecStatus CheckDecCapForCodecType(RocdecDecodeCaps *dec_cap);
private:
std::mutex mutex;
/**
* @brief A map that associates GPU UUIDs with their corresponding render node indices.
*
@@ -97,14 +154,15 @@ private:
*/
std::unordered_map<std::string, int> gpu_uuids_to_render_nodes_map_;
rocDecStatus InitVAAPI(std::string drm_node);
rocDecStatus CreateDecoderConfig();
rocDecStatus CreateSurfaces();
rocDecStatus CreateContext();
rocDecStatus DestroyDataBuffers();
VaContext();
VaContext(const VaContext&) = delete;
VaContext& operator = (const VaContext) = delete;
~VaContext();
rocDecStatus InitHIP(int device_id, hipDeviceProp_t& hip_dev_prop);
rocDecStatus InitVAAPI(int va_ctx_idx, std::string drm_node);
void GetVisibleDevices(std::vector<int>& visible_devices_vetor);
void GetCurrentComputePartition(std::vector<ComputePartition> &current_compute_partitions);
void GetDrmNodeOffset(std::string device_name, uint8_t device_id, std::vector<int>& visible_devices, std::vector<ComputePartition> &current_compute_partitions, int &offset);
void GetGpuUuids();
void GetVisibleDevices(std::vector<int>& visible_devices);
void GetCurrentComputePartition(std::vector<ComputePartition> &currnet_compute_partitions);
void GetDrmNodeOffset(std::string device_name, uint8_t device_id, std::vector<int>& visible_devices,
std::vector<ComputePartition> &current_compute_partitions, int &offset);
};
+3 -3
View File
@@ -26,7 +26,6 @@ RocVideoDecoder::RocVideoDecoder(int device_id, OutputSurfaceMemoryType out_mem_
const Rect *p_crop_rect, bool extract_user_sei_Message, uint32_t disp_delay, int max_width, int max_height, uint32_t clk_rate) :
device_id_{device_id}, out_mem_type_(out_mem_type), codec_id_(codec), b_force_zero_latency_(force_zero_latency),
b_extract_sei_message_(extract_user_sei_Message), disp_delay_(disp_delay), max_width_ (max_width), max_height_(max_height) {
if (!InitHIP(device_id_)) {
THROW("Failed to initilize the HIP");
}
@@ -1059,10 +1058,11 @@ bool RocVideoDecoder::CodecSupported(int device_id, rocDecVideoCodec codec_id, u
decode_caps.codec_type = codec_id;
decode_caps.chroma_format = rocDecVideoChromaFormat_420;
decode_caps.bit_depth_minus_8 = bit_depth - 8;
if(rocDecGetDecoderCaps(&decode_caps) != ROCDEC_SUCCESS) {
if((rocDecGetDecoderCaps(&decode_caps) != ROCDEC_SUCCESS) || !decode_caps.is_supported) {
return false;
} else {
return true;
}
return true;
}
void RocVideoDecoder::WaitForDecodeCompletion() {