radv/video: add initial support for encoding with h264.
This adds the encoding infrastructure along with support for h264. Acked-by: Samuel Pitoiset <samuel.pitoiset@gmail.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25900>
This commit is contained in:
@@ -162,6 +162,7 @@ libradv_files = files(
|
||||
'radv_query.h',
|
||||
'radv_video.c',
|
||||
'radv_video.h',
|
||||
'radv_video_enc.c',
|
||||
'radv_wsi.c',
|
||||
'radv_wsi.h',
|
||||
)
|
||||
|
@@ -437,6 +437,21 @@ struct radv_cmd_state {
|
||||
bool uses_dynamic_vertex_binding_stride;
|
||||
};
|
||||
|
||||
struct radv_enc_state {
|
||||
uint32_t task_size_offset;
|
||||
uint32_t total_task_size;
|
||||
unsigned shifter;
|
||||
unsigned bits_in_shifter;
|
||||
uint32_t num_zeros;
|
||||
uint32_t byte_index;
|
||||
unsigned bits_output;
|
||||
unsigned bits_size;
|
||||
bool emulation_prevention;
|
||||
bool is_even_frame;
|
||||
unsigned task_id;
|
||||
uint32_t copy_start_offset;
|
||||
};
|
||||
|
||||
struct radv_cmd_buffer_upload {
|
||||
uint8_t *map;
|
||||
unsigned offset;
|
||||
@@ -537,6 +552,7 @@ struct radv_cmd_buffer {
|
||||
struct radv_video_session_params *params;
|
||||
struct rvcn_sq_var sq;
|
||||
struct rvcn_decode_buffer_s *decode_buffer;
|
||||
struct radv_enc_state enc;
|
||||
uint64_t feedback_query_va;
|
||||
} video;
|
||||
|
||||
|
@@ -17,7 +17,7 @@
|
||||
#include "radv_instance.h"
|
||||
#include "radv_queue.h"
|
||||
#include "radv_radeon_winsys.h"
|
||||
|
||||
#include "ac_vcn_enc.h"
|
||||
#include "wsi_common.h"
|
||||
|
||||
#include "nir.h"
|
||||
@@ -69,6 +69,13 @@ struct radv_physical_device_cache_key {
|
||||
uint32_t use_ngg_culling : 1;
|
||||
};
|
||||
|
||||
enum radv_video_enc_hw_ver {
|
||||
RADV_VIDEO_ENC_HW_1_2,
|
||||
RADV_VIDEO_ENC_HW_2,
|
||||
RADV_VIDEO_ENC_HW_3,
|
||||
RADV_VIDEO_ENC_HW_4,
|
||||
};
|
||||
|
||||
struct radv_physical_device {
|
||||
struct vk_physical_device vk;
|
||||
|
||||
@@ -171,6 +178,9 @@ struct radv_physical_device {
|
||||
uint32_t stream_handle_base;
|
||||
uint32_t stream_handle_counter;
|
||||
uint32_t av1_version;
|
||||
rvcn_enc_cmd_t vcn_enc_cmds;
|
||||
enum radv_video_enc_hw_ver enc_hw_ver;
|
||||
uint32_t encoder_interface_version;
|
||||
|
||||
struct radv_physical_device_cache_key cache_key;
|
||||
};
|
||||
|
@@ -337,6 +337,9 @@ radv_video_patch_session_parameters(struct vk_video_session_parameters *params)
|
||||
case VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR:
|
||||
default:
|
||||
return;
|
||||
case VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR:
|
||||
radv_video_patch_encode_session_parameters(params);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,6 +382,31 @@ radv_CreateVideoSessionKHR(VkDevice _device, const VkVideoSessionCreateInfoKHR *
|
||||
vid->stream_type = RDECODE_CODEC_AV1;
|
||||
vid->dpb_type = DPB_DYNAMIC_TIER_2;
|
||||
break;
|
||||
case VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR:
|
||||
vid->encode = true;
|
||||
vid->enc_session.encode_standard = RENCODE_ENCODE_STANDARD_H264;
|
||||
vid->enc_session.aligned_picture_width = align(vid->vk.max_coded.width, 16);
|
||||
vid->enc_session.aligned_picture_height = align(vid->vk.max_coded.height, 16);
|
||||
vid->enc_session.padding_width = vid->enc_session.aligned_picture_width - vid->vk.max_coded.width;
|
||||
vid->enc_session.padding_height = vid->enc_session.aligned_picture_height - vid->vk.max_coded.height;
|
||||
vid->enc_session.display_remote = 0;
|
||||
vid->enc_session.pre_encode_mode = 0;
|
||||
vid->enc_session.pre_encode_chroma_enabled = 0;
|
||||
switch (vid->vk.enc_usage.tuning_mode) {
|
||||
case VK_VIDEO_ENCODE_TUNING_MODE_DEFAULT_KHR:
|
||||
default:
|
||||
vid->enc_preset_mode = RENCODE_PRESET_MODE_BALANCE;
|
||||
break;
|
||||
case VK_VIDEO_ENCODE_TUNING_MODE_LOW_LATENCY_KHR:
|
||||
case VK_VIDEO_ENCODE_TUNING_MODE_ULTRA_LOW_LATENCY_KHR:
|
||||
vid->enc_preset_mode = RENCODE_PRESET_MODE_SPEED;
|
||||
break;
|
||||
case VK_VIDEO_ENCODE_TUNING_MODE_HIGH_QUALITY_KHR:
|
||||
case VK_VIDEO_ENCODE_TUNING_MODE_LOSSLESS_KHR:
|
||||
vid->enc_preset_mode = RENCODE_PRESET_MODE_QUALITY;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return VK_ERROR_FEATURE_NOT_PRESENT;
|
||||
}
|
||||
@@ -451,6 +479,7 @@ radv_GetPhysicalDeviceVideoCapabilitiesKHR(VkPhysicalDevice physicalDevice, cons
|
||||
{
|
||||
VK_FROM_HANDLE(radv_physical_device, pdev, physicalDevice);
|
||||
const struct video_codec_cap *cap = NULL;
|
||||
bool is_encode = false;
|
||||
|
||||
switch (pVideoProfile->videoCodecOperation) {
|
||||
#ifndef _WIN32
|
||||
@@ -463,6 +492,10 @@ radv_GetPhysicalDeviceVideoCapabilitiesKHR(VkPhysicalDevice physicalDevice, cons
|
||||
case VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR:
|
||||
cap = &pdev->info.dec_caps.codec_info[AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_AV1];
|
||||
break;
|
||||
case VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR:
|
||||
cap = &pdev->info.enc_caps.codec_info[AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC];
|
||||
is_encode = true;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
unreachable("unsupported operation");
|
||||
@@ -472,17 +505,40 @@ radv_GetPhysicalDeviceVideoCapabilitiesKHR(VkPhysicalDevice physicalDevice, cons
|
||||
cap = NULL;
|
||||
|
||||
pCapabilities->flags = 0;
|
||||
pCapabilities->minBitstreamBufferOffsetAlignment = 128;
|
||||
pCapabilities->minBitstreamBufferSizeAlignment = 128;
|
||||
pCapabilities->pictureAccessGranularity.width = VL_MACROBLOCK_WIDTH;
|
||||
pCapabilities->pictureAccessGranularity.height = VL_MACROBLOCK_HEIGHT;
|
||||
pCapabilities->minCodedExtent.width = VL_MACROBLOCK_WIDTH;
|
||||
pCapabilities->minCodedExtent.height = VL_MACROBLOCK_HEIGHT;
|
||||
|
||||
struct VkVideoDecodeCapabilitiesKHR *dec_caps =
|
||||
(struct VkVideoDecodeCapabilitiesKHR *)vk_find_struct(pCapabilities->pNext, VIDEO_DECODE_CAPABILITIES_KHR);
|
||||
if (dec_caps)
|
||||
dec_caps->flags = VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_DISTINCT_BIT_KHR;
|
||||
struct VkVideoDecodeCapabilitiesKHR *dec_caps = NULL;
|
||||
struct VkVideoEncodeCapabilitiesKHR *enc_caps = NULL;
|
||||
if (!is_encode) {
|
||||
dec_caps =
|
||||
(struct VkVideoDecodeCapabilitiesKHR *)vk_find_struct(pCapabilities->pNext, VIDEO_DECODE_CAPABILITIES_KHR);
|
||||
if (dec_caps)
|
||||
dec_caps->flags = VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_DISTINCT_BIT_KHR;
|
||||
pCapabilities->minBitstreamBufferOffsetAlignment = 128;
|
||||
pCapabilities->minBitstreamBufferSizeAlignment = 128;
|
||||
} else {
|
||||
enc_caps =
|
||||
(struct VkVideoEncodeCapabilitiesKHR *)vk_find_struct(pCapabilities->pNext, VIDEO_ENCODE_CAPABILITIES_KHR);
|
||||
|
||||
if (enc_caps) {
|
||||
enc_caps->flags = 0;
|
||||
enc_caps->rateControlModes = VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR |
|
||||
VK_VIDEO_ENCODE_RATE_CONTROL_MODE_CBR_BIT_KHR |
|
||||
VK_VIDEO_ENCODE_RATE_CONTROL_MODE_VBR_BIT_KHR;
|
||||
enc_caps->maxRateControlLayers = RADV_ENC_MAX_RATE_LAYER;
|
||||
enc_caps->maxBitrate = 0;
|
||||
enc_caps->maxQualityLevels = 2;
|
||||
enc_caps->encodeInputPictureGranularity.width = 1;
|
||||
enc_caps->encodeInputPictureGranularity.height = 1;
|
||||
enc_caps->supportedEncodeFeedbackFlags = VK_VIDEO_ENCODE_FEEDBACK_BITSTREAM_BUFFER_OFFSET_BIT_KHR |
|
||||
VK_VIDEO_ENCODE_FEEDBACK_BITSTREAM_BYTES_WRITTEN_BIT_KHR;
|
||||
}
|
||||
pCapabilities->minBitstreamBufferOffsetAlignment = 16;
|
||||
pCapabilities->minBitstreamBufferSizeAlignment = 16;
|
||||
}
|
||||
|
||||
switch (pVideoProfile->videoCodecOperation) {
|
||||
case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR: {
|
||||
@@ -573,6 +629,33 @@ radv_GetPhysicalDeviceVideoCapabilitiesKHR(VkPhysicalDevice physicalDevice, cons
|
||||
pCapabilities->stdHeaderVersion.specVersion = VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_SPEC_VERSION;
|
||||
break;
|
||||
}
|
||||
case VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR: {
|
||||
struct VkVideoEncodeH264CapabilitiesKHR *ext = (struct VkVideoEncodeH264CapabilitiesKHR *)vk_find_struct(
|
||||
pCapabilities->pNext, VIDEO_ENCODE_H264_CAPABILITIES_KHR);
|
||||
pCapabilities->maxDpbSlots = NUM_H2645_REFS;
|
||||
pCapabilities->maxActiveReferencePictures = NUM_H2645_REFS;
|
||||
ext->flags = VK_VIDEO_ENCODE_H264_CAPABILITY_HRD_COMPLIANCE_BIT_KHR;
|
||||
ext->maxLevelIdc = cap ? cap->max_level : 0;
|
||||
ext->maxSliceCount = 128;
|
||||
ext->maxPPictureL0ReferenceCount = 1;
|
||||
ext->maxBPictureL0ReferenceCount = 0;
|
||||
ext->maxL1ReferenceCount = 0;
|
||||
ext->maxTemporalLayerCount = 4;
|
||||
ext->expectDyadicTemporalLayerPattern = false;
|
||||
ext->minQp = 0;
|
||||
ext->maxQp = 51;
|
||||
ext->prefersGopRemainingFrames = false;
|
||||
ext->requiresGopRemainingFrames = false;
|
||||
ext->stdSyntaxFlags = VK_VIDEO_ENCODE_H264_STD_CONSTRAINED_INTRA_PRED_FLAG_SET_BIT_KHR |
|
||||
VK_VIDEO_ENCODE_H264_STD_ENTROPY_CODING_MODE_FLAG_UNSET_BIT_KHR |
|
||||
VK_VIDEO_ENCODE_H264_STD_ENTROPY_CODING_MODE_FLAG_SET_BIT_KHR;
|
||||
if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_3)
|
||||
ext->stdSyntaxFlags |= VK_VIDEO_ENCODE_H264_STD_WEIGHTED_BIPRED_IDC_EXPLICIT_BIT_KHR;
|
||||
|
||||
strcpy(pCapabilities->stdHeaderVersion.extensionName, VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_EXTENSION_NAME);
|
||||
pCapabilities->stdHeaderVersion.specVersion = VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_SPEC_VERSION;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -666,6 +749,10 @@ radv_GetVideoSessionMemoryRequirementsKHR(VkDevice _device, VkVideoSessionKHR vi
|
||||
|
||||
uint32_t memory_type_bits = (1u << pdev->memory_properties.memoryTypeCount) - 1;
|
||||
|
||||
if (vid->encode) {
|
||||
return radv_video_get_encode_session_memory_requirements(device, vid, pMemoryRequirementsCount,
|
||||
pMemoryRequirements);
|
||||
}
|
||||
VK_OUTARRAY_MAKE_TYPED(VkVideoSessionMemoryRequirementsKHR, out, pMemoryRequirements, pMemoryRequirementsCount);
|
||||
/* 1 buffer for session context */
|
||||
if (pdev->info.family >= CHIP_POLARIS10) {
|
||||
@@ -2751,6 +2838,9 @@ radv_CmdBeginVideoCodingKHR(VkCommandBuffer commandBuffer, const VkVideoBeginCod
|
||||
|
||||
cmd_buffer->video.vid = vid;
|
||||
cmd_buffer->video.params = params;
|
||||
|
||||
if (vid->encode)
|
||||
radv_video_enc_begin_coding(cmd_buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -2833,6 +2923,10 @@ radv_CmdControlVideoCodingKHR(VkCommandBuffer commandBuffer, const VkVideoCoding
|
||||
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
||||
struct radv_physical_device *pdev = radv_device_physical(device);
|
||||
|
||||
if (cmd_buffer->video.vid->encode) {
|
||||
radv_video_enc_control_video_coding(cmd_buffer, pCodingControlInfo);
|
||||
return;
|
||||
}
|
||||
if (pCodingControlInfo->flags & VK_VIDEO_CODING_CONTROL_RESET_BIT_KHR) {
|
||||
if (radv_has_uvd(pdev))
|
||||
radv_uvd_cmd_reset(cmd_buffer);
|
||||
@@ -2844,6 +2938,12 @@ radv_CmdControlVideoCodingKHR(VkCommandBuffer commandBuffer, const VkVideoCoding
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
radv_CmdEndVideoCodingKHR(VkCommandBuffer commandBuffer, const VkVideoEndCodingInfoKHR *pEndCodingInfo)
|
||||
{
|
||||
VK_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer);
|
||||
|
||||
if (cmd_buffer->video.vid->encode) {
|
||||
radv_video_enc_end_coding(cmd_buffer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -13,11 +13,16 @@
|
||||
|
||||
#include "vk_video.h"
|
||||
|
||||
#include "ac_vcn.h"
|
||||
|
||||
#define VL_MACROBLOCK_WIDTH 16
|
||||
#define VL_MACROBLOCK_HEIGHT 16
|
||||
|
||||
struct radv_physical_device;
|
||||
struct rvcn_sq_var;
|
||||
struct radv_cmd_buffer;
|
||||
|
||||
#define RADV_ENC_MAX_RATE_LAYER 4
|
||||
|
||||
struct radv_vid_mem {
|
||||
struct radv_device_memory *mem;
|
||||
@@ -31,6 +36,7 @@ struct radv_video_session {
|
||||
uint32_t stream_handle;
|
||||
unsigned stream_type;
|
||||
bool interlaced;
|
||||
bool encode;
|
||||
enum { DPB_MAX_RES = 0, DPB_DYNAMIC_TIER_1, DPB_DYNAMIC_TIER_2 } dpb_type;
|
||||
unsigned db_alignment;
|
||||
|
||||
@@ -38,6 +44,13 @@ struct radv_video_session {
|
||||
struct radv_vid_mem ctx;
|
||||
|
||||
unsigned dbg_frame_cnt;
|
||||
rvcn_enc_session_init_t enc_session;
|
||||
rvcn_enc_layer_control_t rc_layer_control;
|
||||
rvcn_enc_rate_ctl_layer_init_t rc_layer_init[RADV_ENC_MAX_RATE_LAYER];
|
||||
rvcn_enc_rate_ctl_per_picture_t rc_per_pic[RADV_ENC_MAX_RATE_LAYER];
|
||||
uint32_t enc_preset_mode;
|
||||
uint32_t enc_rate_control_method;
|
||||
bool enc_rate_control_default;
|
||||
};
|
||||
|
||||
VK_DEFINE_NONDISP_HANDLE_CASTS(radv_video_session, vk.base, VkVideoSessionKHR, VK_OBJECT_TYPE_VIDEO_SESSION_KHR)
|
||||
@@ -58,4 +71,14 @@ void radv_vcn_sq_header(struct radeon_cmdbuf *cs, struct rvcn_sq_var *sq, bool e
|
||||
|
||||
void radv_vcn_sq_tail(struct radeon_cmdbuf *cs, struct rvcn_sq_var *sq);
|
||||
|
||||
void radv_init_physical_device_encoder(struct radv_physical_device *pdevice);
|
||||
void radv_video_enc_begin_coding(struct radv_cmd_buffer *cmd_buffer);
|
||||
void radv_video_enc_end_coding(struct radv_cmd_buffer *cmd_buffer);
|
||||
void radv_video_enc_control_video_coding(struct radv_cmd_buffer *cmd_buffer,
|
||||
const VkVideoCodingControlInfoKHR *pCodingControlInfo);
|
||||
VkResult radv_video_get_encode_session_memory_requirements(struct radv_device *device, struct radv_video_session *vid,
|
||||
uint32_t *pMemoryRequirementsCount,
|
||||
VkVideoSessionMemoryRequirementsKHR *pMemoryRequirements);
|
||||
void radv_video_patch_encode_session_parameters(struct vk_video_session_parameters *params);
|
||||
|
||||
#endif /* RADV_VIDEO_H */
|
||||
|
1478
src/amd/vulkan/radv_video_enc.c
Normal file
1478
src/amd/vulkan/radv_video_enc.c
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user