diff --git a/src/rocdecode/roc_decoder.cpp b/src/rocdecode/roc_decoder.cpp index 3480ff74..8e87ff8a 100644 --- a/src/rocdecode/roc_decoder.cpp +++ b/src/rocdecode/roc_decoder.cpp @@ -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; -} diff --git a/src/rocdecode/roc_decoder.h b/src/rocdecode/roc_decoder.h index ad72b743..dce30a2f 100644 --- a/src/rocdecode/roc_decoder.h +++ b/src/rocdecode/roc_decoder.h @@ -34,14 +34,6 @@ THE SOFTWARE. #include #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 @@ class RocDecoder { 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 hip_interop_; }; \ No newline at end of file diff --git a/src/rocdecode/roc_decoder_caps.h b/src/rocdecode/roc_decoder_caps.h deleted file mode 100644 index 7483b7b9..00000000 --- a/src/rocdecode/roc_decoder_caps.h +++ /dev/null @@ -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 -#include -#include -#include -#include -#include "../commons.h" -#include "../../api/rocdecode.h" - - -// The CodecSpec struct contains information for an individual codec (e.g., rocDecVideoCodec_HEVC) -struct CodecSpec { - std::vector chroma_format; - std::vector 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 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 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 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(output_format) + 1)); - } else { - return false; - } - } else { - return false; - } - } else { - return false; - } - } -private: - std::unordered_map 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; -}; \ No newline at end of file diff --git a/src/rocdecode/rocdecode_api.cpp b/src/rocdecode/rocdecode_api.cpp index e24bd703..09e814b4 100644 --- a/src/rocdecode/rocdecode_api.cpp +++ b/src/rocdecode/rocdecode_api.cpp @@ -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); } /*****************************************************************************************************/ diff --git a/src/rocdecode/vaapi/vaapi_videodecoder.cpp b/src/rocdecode/vaapi/vaapi_videodecoder.cpp index c3079b57..a7ccd6c5 100644 --- a/src/rocdecode/vaapi/vaapi_videodecoder.cpp +++ b/src/rocdecode/vaapi/vaapi_videodecoder.cpp @@ -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 visible_devices; - GetVisibleDevices(visible_devices); - GetGpuUuids(); - int offset = 0; - if (gcn_arch_name_base.compare("gfx942") == 0) { - std::vector 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(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 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 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()) { +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; + } +} + +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(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 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; } - 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])); + va_surface_ids_.resize(decoder_create_info_.num_decode_surfaces); + std::vector 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; } -void VaapiVideoDecoder::GetVisibleDevices(std::vector& visible_devices_vetor) { +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 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 visible_devices; + GetVisibleDevices(visible_devices); + + int offset = 0; + if (gcn_arch_name_base.compare("gfx942") == 0) { + std::vector 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 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(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 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& 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& 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 ¤t_compute_partitions) { +void VaContext::GetCurrentComputePartition(std::vector ¤t_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 } } -void VaapiVideoDecoder::GetDrmNodeOffset(std::string device_name, uint8_t device_id, std::vector& visible_devices, - std::vector ¤t_compute_partitions, int &offset) { - +void VaContext::GetDrmNodeOffset(std::string device_name, uint8_t device_id, std::vector& visible_devices, std::vector ¤t_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)) { diff --git a/src/rocdecode/vaapi/vaapi_videodecoder.h b/src/rocdecode/vaapi/vaapi_videodecoder.h index 239f03d2..86f5e99f 100644 --- a/src/rocdecode/vaapi/vaapi_videodecoder.h +++ b/src/rocdecode/vaapi/vaapi_videodecoder.h @@ -29,6 +29,9 @@ THE SOFTWARE. #include #include #include +#include +#include +#include #if __cplusplus >= 201703L && __has_include() #include namespace fs = std::filesystem; @@ -36,13 +39,22 @@ THE SOFTWARE. #include namespace fs = std::experimental::filesystem; #endif +#include +#include #include #include #include -#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 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 va_surface_ids_; bool supports_modifiers_; @@ -88,6 +121,30 @@ class VaapiVideoDecoder { 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 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 @@ class VaapiVideoDecoder { */ std::unordered_map 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& visible_devices_vetor); + void GetCurrentComputePartition(std::vector ¤t_compute_partitions); + void GetDrmNodeOffset(std::string device_name, uint8_t device_id, std::vector& visible_devices, std::vector ¤t_compute_partitions, int &offset); void GetGpuUuids(); - void GetVisibleDevices(std::vector& visible_devices); - void GetCurrentComputePartition(std::vector &currnet_compute_partitions); - void GetDrmNodeOffset(std::string device_name, uint8_t device_id, std::vector& visible_devices, - std::vector ¤t_compute_partitions, int &offset); }; \ No newline at end of file diff --git a/utils/rocvideodecode/roc_video_dec.cpp b/utils/rocvideodecode/roc_video_dec.cpp index 7270d3ed..6ea6fdd9 100644 --- a/utils/rocvideodecode/roc_video_dec.cpp +++ b/utils/rocvideodecode/roc_video_dec.cpp @@ -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() {