
constantQp will be 0 according to spec for any rate control method
other than NONE, so it should only be used with NONE rate control and
not when default rate control (which is internally NONE) is used.
Also it shouldn't override min/max QP.
Fixes: 54d499818c
("radv/video: add initial support for encoding with h264.")
Reviewed-by: Dave Airlie <airlied@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/28734>
1930 lines
81 KiB
C
1930 lines
81 KiB
C
/**************************************************************************
|
|
*
|
|
* Copyright 2017 Advanced Micro Devices, Inc.
|
|
* Copyright 2023 Red Hat 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, sub license, 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 (including the
|
|
* next paragraph) 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 NON-INFRINGEMENT.
|
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
|
|
*
|
|
**************************************************************************/
|
|
#include "radv_buffer.h"
|
|
#include "radv_cs.h"
|
|
#include "radv_debug.h"
|
|
#include "radv_device_memory.h"
|
|
#include "radv_entrypoints.h"
|
|
#include "radv_image_view.h"
|
|
#include "radv_physical_device.h"
|
|
#include "radv_video.h"
|
|
|
|
#include "ac_vcn_enc.h"
|
|
|
|
#define RENCODE_V4_FW_INTERFACE_MAJOR_VERSION 1
|
|
#define RENCODE_V4_FW_INTERFACE_MINOR_VERSION 7
|
|
|
|
#define RENCODE_V4_IB_PARAM_ENCODE_STATISTICS 0x0000001a
|
|
|
|
#define RENCODE_V3_FW_INTERFACE_MAJOR_VERSION 1
|
|
#define RENCODE_V3_FW_INTERFACE_MINOR_VERSION 27
|
|
|
|
#define RENCODE_V2_IB_PARAM_SESSION_INFO 0x00000001
|
|
#define RENCODE_V2_IB_PARAM_TASK_INFO 0x00000002
|
|
#define RENCODE_V2_IB_PARAM_SESSION_INIT 0x00000003
|
|
#define RENCODE_V2_IB_PARAM_LAYER_CONTROL 0x00000004
|
|
#define RENCODE_V2_IB_PARAM_LAYER_SELECT 0x00000005
|
|
#define RENCODE_V2_IB_PARAM_RATE_CONTROL_SESSION_INIT 0x00000006
|
|
#define RENCODE_V2_IB_PARAM_RATE_CONTROL_LAYER_INIT 0x00000007
|
|
#define RENCODE_V2_IB_PARAM_RATE_CONTROL_PER_PICTURE 0x00000008
|
|
#define RENCODE_V2_IB_PARAM_QUALITY_PARAMS 0x00000009
|
|
#define RENCODE_V2_IB_PARAM_DIRECT_OUTPUT_NALU 0x0000000a
|
|
#define RENCODE_V2_IB_PARAM_SLICE_HEADER 0x0000000b
|
|
#define RENCODE_V2_IB_PARAM_INPUT_FORMAT 0x0000000c
|
|
#define RENCODE_V2_IB_PARAM_OUTPUT_FORMAT 0x0000000d
|
|
#define RENCODE_V2_IB_PARAM_ENCODE_PARAMS 0x0000000f
|
|
#define RENCODE_V2_IB_PARAM_INTRA_REFRESH 0x00000010
|
|
#define RENCODE_V2_IB_PARAM_ENCODE_CONTEXT_BUFFER 0x00000011
|
|
#define RENCODE_V2_IB_PARAM_VIDEO_BITSTREAM_BUFFER 0x00000012
|
|
#define RENCODE_V2_IB_PARAM_FEEDBACK_BUFFER 0x00000015
|
|
#define RENCODE_V2_IB_PARAM_ENCODE_STATISTICS 0x00000019
|
|
|
|
#define RENCODE_V2_HEVC_IB_PARAM_SLICE_CONTROL 0x00100001
|
|
#define RENCODE_V2_HEVC_IB_PARAM_SPEC_MISC 0x00100002
|
|
#define RENCODE_V2_HEVC_IB_PARAM_LOOP_FILTER 0x00100003
|
|
|
|
#define RENCODE_V2_H264_IB_PARAM_SLICE_CONTROL 0x00200001
|
|
#define RENCODE_V2_H264_IB_PARAM_SPEC_MISC 0x00200002
|
|
#define RENCODE_V2_H264_IB_PARAM_ENCODE_PARAMS 0x00200003
|
|
#define RENCODE_V2_H264_IB_PARAM_DEBLOCKING_FILTER 0x00200004
|
|
|
|
#define RENCODE_V2_FW_INTERFACE_MAJOR_VERSION 1
|
|
#define RENCODE_V2_FW_INTERFACE_MINOR_VERSION 1
|
|
|
|
#define RENCODE_IB_PARAM_SESSION_INFO 0x00000001
|
|
#define RENCODE_IB_PARAM_TASK_INFO 0x00000002
|
|
#define RENCODE_IB_PARAM_SESSION_INIT 0x00000003
|
|
#define RENCODE_IB_PARAM_LAYER_CONTROL 0x00000004
|
|
#define RENCODE_IB_PARAM_LAYER_SELECT 0x00000005
|
|
#define RENCODE_IB_PARAM_RATE_CONTROL_SESSION_INIT 0x00000006
|
|
#define RENCODE_IB_PARAM_RATE_CONTROL_LAYER_INIT 0x00000007
|
|
#define RENCODE_IB_PARAM_RATE_CONTROL_PER_PICTURE 0x00000008
|
|
#define RENCODE_IB_PARAM_QUALITY_PARAMS 0x00000009
|
|
#define RENCODE_IB_PARAM_SLICE_HEADER 0x0000000a
|
|
#define RENCODE_IB_PARAM_ENCODE_PARAMS 0x0000000b
|
|
#define RENCODE_IB_PARAM_INTRA_REFRESH 0x0000000c
|
|
#define RENCODE_IB_PARAM_ENCODE_CONTEXT_BUFFER 0x0000000d
|
|
#define RENCODE_IB_PARAM_VIDEO_BITSTREAM_BUFFER 0x0000000e
|
|
#define RENCODE_IB_PARAM_FEEDBACK_BUFFER 0x00000010
|
|
#define RENCODE_IB_PARAM_DIRECT_OUTPUT_NALU 0x00000020
|
|
#define RENCODE_IB_PARAM_ENCODE_STATISTICS 0x00000024
|
|
|
|
#define RENCODE_HEVC_IB_PARAM_SLICE_CONTROL 0x00100001
|
|
#define RENCODE_HEVC_IB_PARAM_SPEC_MISC 0x00100002
|
|
#define RENCODE_HEVC_IB_PARAM_DEBLOCKING_FILTER 0x00100003
|
|
|
|
#define RENCODE_H264_IB_PARAM_SLICE_CONTROL 0x00200001
|
|
#define RENCODE_H264_IB_PARAM_SPEC_MISC 0x00200002
|
|
#define RENCODE_H264_IB_PARAM_ENCODE_PARAMS 0x00200003
|
|
#define RENCODE_H264_IB_PARAM_DEBLOCKING_FILTER 0x00200004
|
|
|
|
#define RENCODE_FW_INTERFACE_MAJOR_VERSION 1
|
|
#define RENCODE_FW_INTERFACE_MINOR_VERSION 9
|
|
|
|
void
|
|
radv_probe_video_encode(struct radv_physical_device *pdev)
|
|
{
|
|
pdev->video_encode_enabled = false;
|
|
if (pdev->info.vcn_ip_version >= VCN_4_0_0) {
|
|
if (pdev->info.vcn_enc_major_version != RENCODE_V4_FW_INTERFACE_MAJOR_VERSION)
|
|
return;
|
|
if (pdev->info.vcn_enc_minor_version < RENCODE_V4_FW_INTERFACE_MINOR_VERSION)
|
|
return;
|
|
} else if (pdev->info.vcn_ip_version >= VCN_3_0_0) {
|
|
if (pdev->info.vcn_enc_major_version != RENCODE_V3_FW_INTERFACE_MAJOR_VERSION)
|
|
return;
|
|
if (pdev->info.vcn_enc_minor_version < RENCODE_V3_FW_INTERFACE_MINOR_VERSION)
|
|
return;
|
|
} else if (pdev->info.vcn_ip_version >= VCN_2_0_0) {
|
|
if (pdev->info.vcn_enc_major_version != RENCODE_V2_FW_INTERFACE_MAJOR_VERSION)
|
|
return;
|
|
if (pdev->info.vcn_enc_minor_version < RENCODE_V2_FW_INTERFACE_MINOR_VERSION)
|
|
return;
|
|
} else {
|
|
if (pdev->info.vcn_enc_major_version != RENCODE_FW_INTERFACE_MAJOR_VERSION)
|
|
return;
|
|
if (pdev->info.vcn_enc_minor_version < RENCODE_FW_INTERFACE_MINOR_VERSION)
|
|
return;
|
|
}
|
|
|
|
struct radv_instance *instance = radv_physical_device_instance(pdev);
|
|
pdev->video_encode_enabled = !!(instance->perftest_flags & RADV_PERFTEST_VIDEO_ENCODE);
|
|
}
|
|
|
|
void
|
|
radv_init_physical_device_encoder(struct radv_physical_device *pdev)
|
|
{
|
|
if (pdev->info.family >= CHIP_NAVI31) {
|
|
pdev->enc_hw_ver = RADV_VIDEO_ENC_HW_4;
|
|
pdev->encoder_interface_version = ((RENCODE_V4_FW_INTERFACE_MAJOR_VERSION << RENCODE_IF_MAJOR_VERSION_SHIFT) |
|
|
(RENCODE_V4_FW_INTERFACE_MINOR_VERSION << RENCODE_IF_MINOR_VERSION_SHIFT));
|
|
} else if (pdev->info.family >= CHIP_NAVI21) {
|
|
pdev->enc_hw_ver = RADV_VIDEO_ENC_HW_3;
|
|
pdev->encoder_interface_version = ((RENCODE_V3_FW_INTERFACE_MAJOR_VERSION << RENCODE_IF_MAJOR_VERSION_SHIFT) |
|
|
(RENCODE_V3_FW_INTERFACE_MINOR_VERSION << RENCODE_IF_MINOR_VERSION_SHIFT));
|
|
} else if (pdev->info.family >= CHIP_RENOIR) {
|
|
pdev->enc_hw_ver = RADV_VIDEO_ENC_HW_2;
|
|
pdev->encoder_interface_version = ((RENCODE_V2_FW_INTERFACE_MAJOR_VERSION << RENCODE_IF_MAJOR_VERSION_SHIFT) |
|
|
(RENCODE_V2_FW_INTERFACE_MINOR_VERSION << RENCODE_IF_MINOR_VERSION_SHIFT));
|
|
} else {
|
|
pdev->enc_hw_ver = RADV_VIDEO_ENC_HW_1_2;
|
|
pdev->encoder_interface_version = ((RENCODE_FW_INTERFACE_MAJOR_VERSION << RENCODE_IF_MAJOR_VERSION_SHIFT) |
|
|
(RENCODE_FW_INTERFACE_MINOR_VERSION << RENCODE_IF_MINOR_VERSION_SHIFT));
|
|
}
|
|
|
|
if (pdev->info.family >= CHIP_RENOIR) {
|
|
pdev->vcn_enc_cmds.session_info = RENCODE_V2_IB_PARAM_SESSION_INFO;
|
|
pdev->vcn_enc_cmds.task_info = RENCODE_V2_IB_PARAM_TASK_INFO;
|
|
pdev->vcn_enc_cmds.session_init = RENCODE_V2_IB_PARAM_SESSION_INIT;
|
|
pdev->vcn_enc_cmds.layer_control = RENCODE_V2_IB_PARAM_LAYER_CONTROL;
|
|
pdev->vcn_enc_cmds.layer_select = RENCODE_V2_IB_PARAM_LAYER_SELECT;
|
|
pdev->vcn_enc_cmds.rc_session_init = RENCODE_V2_IB_PARAM_RATE_CONTROL_SESSION_INIT;
|
|
pdev->vcn_enc_cmds.rc_layer_init = RENCODE_V2_IB_PARAM_RATE_CONTROL_LAYER_INIT;
|
|
pdev->vcn_enc_cmds.rc_per_pic = RENCODE_V2_IB_PARAM_RATE_CONTROL_PER_PICTURE;
|
|
pdev->vcn_enc_cmds.quality_params = RENCODE_V2_IB_PARAM_QUALITY_PARAMS;
|
|
pdev->vcn_enc_cmds.nalu = RENCODE_V2_IB_PARAM_DIRECT_OUTPUT_NALU;
|
|
pdev->vcn_enc_cmds.slice_header = RENCODE_V2_IB_PARAM_SLICE_HEADER;
|
|
pdev->vcn_enc_cmds.input_format = RENCODE_V2_IB_PARAM_INPUT_FORMAT;
|
|
pdev->vcn_enc_cmds.output_format = RENCODE_V2_IB_PARAM_OUTPUT_FORMAT;
|
|
pdev->vcn_enc_cmds.enc_params = RENCODE_V2_IB_PARAM_ENCODE_PARAMS;
|
|
pdev->vcn_enc_cmds.intra_refresh = RENCODE_V2_IB_PARAM_INTRA_REFRESH;
|
|
pdev->vcn_enc_cmds.ctx = RENCODE_V2_IB_PARAM_ENCODE_CONTEXT_BUFFER;
|
|
pdev->vcn_enc_cmds.bitstream = RENCODE_V2_IB_PARAM_VIDEO_BITSTREAM_BUFFER;
|
|
pdev->vcn_enc_cmds.feedback = RENCODE_V2_IB_PARAM_FEEDBACK_BUFFER;
|
|
pdev->vcn_enc_cmds.slice_control_hevc = RENCODE_V2_HEVC_IB_PARAM_SLICE_CONTROL;
|
|
pdev->vcn_enc_cmds.spec_misc_hevc = RENCODE_V2_HEVC_IB_PARAM_SPEC_MISC;
|
|
pdev->vcn_enc_cmds.deblocking_filter_hevc = RENCODE_V2_HEVC_IB_PARAM_LOOP_FILTER;
|
|
pdev->vcn_enc_cmds.slice_control_h264 = RENCODE_V2_H264_IB_PARAM_SLICE_CONTROL;
|
|
pdev->vcn_enc_cmds.spec_misc_h264 = RENCODE_V2_H264_IB_PARAM_SPEC_MISC;
|
|
pdev->vcn_enc_cmds.enc_params_h264 = RENCODE_V2_H264_IB_PARAM_ENCODE_PARAMS;
|
|
pdev->vcn_enc_cmds.deblocking_filter_h264 = RENCODE_V2_H264_IB_PARAM_DEBLOCKING_FILTER;
|
|
if (pdev->enc_hw_ver == RADV_VIDEO_ENC_HW_4) {
|
|
pdev->vcn_enc_cmds.enc_statistics = RENCODE_V4_IB_PARAM_ENCODE_STATISTICS;
|
|
} else
|
|
pdev->vcn_enc_cmds.enc_statistics = RENCODE_V2_IB_PARAM_ENCODE_STATISTICS;
|
|
} else {
|
|
pdev->vcn_enc_cmds.session_info = RENCODE_IB_PARAM_SESSION_INFO;
|
|
pdev->vcn_enc_cmds.task_info = RENCODE_IB_PARAM_TASK_INFO;
|
|
pdev->vcn_enc_cmds.session_init = RENCODE_IB_PARAM_SESSION_INIT;
|
|
pdev->vcn_enc_cmds.layer_control = RENCODE_IB_PARAM_LAYER_CONTROL;
|
|
pdev->vcn_enc_cmds.layer_select = RENCODE_IB_PARAM_LAYER_SELECT;
|
|
pdev->vcn_enc_cmds.rc_session_init = RENCODE_IB_PARAM_RATE_CONTROL_SESSION_INIT;
|
|
pdev->vcn_enc_cmds.rc_layer_init = RENCODE_IB_PARAM_RATE_CONTROL_LAYER_INIT;
|
|
pdev->vcn_enc_cmds.rc_per_pic = RENCODE_IB_PARAM_RATE_CONTROL_PER_PICTURE;
|
|
pdev->vcn_enc_cmds.quality_params = RENCODE_IB_PARAM_QUALITY_PARAMS;
|
|
pdev->vcn_enc_cmds.nalu = RENCODE_IB_PARAM_DIRECT_OUTPUT_NALU;
|
|
pdev->vcn_enc_cmds.slice_header = RENCODE_IB_PARAM_SLICE_HEADER;
|
|
pdev->vcn_enc_cmds.enc_params = RENCODE_IB_PARAM_ENCODE_PARAMS;
|
|
pdev->vcn_enc_cmds.intra_refresh = RENCODE_IB_PARAM_INTRA_REFRESH;
|
|
pdev->vcn_enc_cmds.ctx = RENCODE_IB_PARAM_ENCODE_CONTEXT_BUFFER;
|
|
pdev->vcn_enc_cmds.bitstream = RENCODE_IB_PARAM_VIDEO_BITSTREAM_BUFFER;
|
|
pdev->vcn_enc_cmds.feedback = RENCODE_IB_PARAM_FEEDBACK_BUFFER;
|
|
pdev->vcn_enc_cmds.slice_control_hevc = RENCODE_HEVC_IB_PARAM_SLICE_CONTROL;
|
|
pdev->vcn_enc_cmds.spec_misc_hevc = RENCODE_HEVC_IB_PARAM_SPEC_MISC;
|
|
pdev->vcn_enc_cmds.deblocking_filter_hevc = RENCODE_HEVC_IB_PARAM_DEBLOCKING_FILTER;
|
|
pdev->vcn_enc_cmds.slice_control_h264 = RENCODE_H264_IB_PARAM_SLICE_CONTROL;
|
|
pdev->vcn_enc_cmds.spec_misc_h264 = RENCODE_H264_IB_PARAM_SPEC_MISC;
|
|
pdev->vcn_enc_cmds.enc_params_h264 = RENCODE_H264_IB_PARAM_ENCODE_PARAMS;
|
|
pdev->vcn_enc_cmds.deblocking_filter_h264 = RENCODE_H264_IB_PARAM_DEBLOCKING_FILTER;
|
|
pdev->vcn_enc_cmds.enc_statistics = RENCODE_IB_PARAM_ENCODE_STATISTICS;
|
|
}
|
|
}
|
|
|
|
/* to process invalid frame rate */
|
|
static void
|
|
radv_vcn_enc_invalid_frame_rate(uint32_t *den, uint32_t *num)
|
|
{
|
|
if (*den == 0 || *num == 0) {
|
|
*den = 1;
|
|
*num = 30;
|
|
}
|
|
}
|
|
|
|
static uint32_t
|
|
radv_vcn_per_frame_integer(uint32_t bitrate, uint32_t den, uint32_t num)
|
|
{
|
|
uint64_t rate_den = (uint64_t)bitrate * (uint64_t)den;
|
|
|
|
return (uint32_t)(rate_den / num);
|
|
}
|
|
|
|
static uint32_t
|
|
radv_vcn_per_frame_frac(uint32_t bitrate, uint32_t den, uint32_t num)
|
|
{
|
|
uint64_t rate_den = (uint64_t)bitrate * (uint64_t)den;
|
|
uint64_t remainder = rate_den % num;
|
|
|
|
return (uint32_t)((remainder << 32) / num);
|
|
}
|
|
|
|
static void
|
|
radv_enc_set_emulation_prevention(struct radv_cmd_buffer *cmd_buffer, bool set)
|
|
{
|
|
struct radv_enc_state *enc = &cmd_buffer->video.enc;
|
|
if (set != enc->emulation_prevention) {
|
|
enc->emulation_prevention = set;
|
|
enc->num_zeros = 0;
|
|
}
|
|
}
|
|
|
|
static uint32_t
|
|
radv_enc_value_bits(uint32_t value)
|
|
{
|
|
uint32_t i = 1;
|
|
|
|
while (value > 1) {
|
|
i++;
|
|
value >>= 1;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
static const unsigned index_to_shifts[4] = {24, 16, 8, 0};
|
|
|
|
static void
|
|
radv_enc_output_one_byte(struct radv_cmd_buffer *cmd_buffer, unsigned char byte)
|
|
{
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
struct radv_enc_state *enc = &cmd_buffer->video.enc;
|
|
if (enc->byte_index == 0)
|
|
cs->buf[cs->cdw] = 0;
|
|
cs->buf[cs->cdw] |= ((unsigned int)(byte) << index_to_shifts[enc->byte_index]);
|
|
enc->byte_index++;
|
|
|
|
if (enc->byte_index >= 4) {
|
|
enc->byte_index = 0;
|
|
cs->cdw++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
radv_enc_emulation_prevention(struct radv_cmd_buffer *cmd_buffer, unsigned char byte)
|
|
{
|
|
struct radv_enc_state *enc = &cmd_buffer->video.enc;
|
|
if (enc->emulation_prevention) {
|
|
if ((enc->num_zeros >= 2) && ((byte == 0x00) || (byte == 0x01) || (byte == 0x02) || (byte == 0x03))) {
|
|
radv_enc_output_one_byte(cmd_buffer, 0x03);
|
|
enc->bits_output += 8;
|
|
enc->num_zeros = 0;
|
|
}
|
|
enc->num_zeros = (byte == 0 ? (enc->num_zeros + 1) : 0);
|
|
}
|
|
}
|
|
|
|
static void
|
|
radv_enc_code_fixed_bits(struct radv_cmd_buffer *cmd_buffer, unsigned int value, unsigned int num_bits)
|
|
{
|
|
struct radv_enc_state *enc = &cmd_buffer->video.enc;
|
|
unsigned int bits_to_pack = 0;
|
|
enc->bits_size += num_bits;
|
|
|
|
while (num_bits > 0) {
|
|
unsigned int value_to_pack = value & (0xffffffff >> (32 - num_bits));
|
|
bits_to_pack = num_bits > (32 - enc->bits_in_shifter) ? (32 - enc->bits_in_shifter) : num_bits;
|
|
|
|
if (bits_to_pack < num_bits)
|
|
value_to_pack = value_to_pack >> (num_bits - bits_to_pack);
|
|
|
|
enc->shifter |= value_to_pack << (32 - enc->bits_in_shifter - bits_to_pack);
|
|
num_bits -= bits_to_pack;
|
|
enc->bits_in_shifter += bits_to_pack;
|
|
|
|
while (enc->bits_in_shifter >= 8) {
|
|
unsigned char output_byte = (unsigned char)(enc->shifter >> 24);
|
|
enc->shifter <<= 8;
|
|
radv_enc_emulation_prevention(cmd_buffer, output_byte);
|
|
radv_enc_output_one_byte(cmd_buffer, output_byte);
|
|
enc->bits_in_shifter -= 8;
|
|
enc->bits_output += 8;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
radv_enc_reset(struct radv_cmd_buffer *cmd_buffer)
|
|
{
|
|
struct radv_enc_state *enc = &cmd_buffer->video.enc;
|
|
enc->emulation_prevention = false;
|
|
enc->shifter = 0;
|
|
enc->bits_in_shifter = 0;
|
|
enc->bits_output = 0;
|
|
enc->num_zeros = 0;
|
|
enc->byte_index = 0;
|
|
enc->bits_size = 0;
|
|
}
|
|
|
|
static void
|
|
radv_enc_byte_align(struct radv_cmd_buffer *cmd_buffer)
|
|
{
|
|
struct radv_enc_state *enc = &cmd_buffer->video.enc;
|
|
unsigned int num_padding_zeros = (32 - enc->bits_in_shifter) % 8;
|
|
|
|
if (num_padding_zeros > 0)
|
|
radv_enc_code_fixed_bits(cmd_buffer, 0, num_padding_zeros);
|
|
}
|
|
|
|
static void
|
|
radv_enc_flush_headers(struct radv_cmd_buffer *cmd_buffer)
|
|
{
|
|
struct radv_enc_state *enc = &cmd_buffer->video.enc;
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
if (enc->bits_in_shifter != 0) {
|
|
unsigned char output_byte = (unsigned char)(enc->shifter >> 24);
|
|
radv_enc_emulation_prevention(cmd_buffer, output_byte);
|
|
radv_enc_output_one_byte(cmd_buffer, output_byte);
|
|
enc->bits_output += enc->bits_in_shifter;
|
|
enc->shifter = 0;
|
|
enc->bits_in_shifter = 0;
|
|
enc->num_zeros = 0;
|
|
}
|
|
|
|
if (enc->byte_index > 0) {
|
|
cs->cdw++;
|
|
enc->byte_index = 0;
|
|
}
|
|
}
|
|
|
|
static void
|
|
radv_enc_code_ue(struct radv_cmd_buffer *cmd_buffer, unsigned int value)
|
|
{
|
|
int x = -1;
|
|
unsigned int ue_code = value + 1;
|
|
value += 1;
|
|
|
|
while (value) {
|
|
value = (value >> 1);
|
|
x += 1;
|
|
}
|
|
|
|
unsigned int ue_length = (x << 1) + 1;
|
|
radv_enc_code_fixed_bits(cmd_buffer, ue_code, ue_length);
|
|
}
|
|
|
|
static void
|
|
radv_enc_code_se(struct radv_cmd_buffer *cmd_buffer, int value)
|
|
{
|
|
unsigned int v = 0;
|
|
|
|
if (value != 0)
|
|
v = (value < 0 ? ((unsigned int)(0 - value) << 1) : (((unsigned int)(value) << 1) - 1));
|
|
|
|
radv_enc_code_ue(cmd_buffer, v);
|
|
}
|
|
|
|
#define ENC_BEGIN \
|
|
{ \
|
|
uint32_t begin = cs->cdw++;
|
|
|
|
#define ENC_END \
|
|
radeon_emit_direct(cs, begin, (cs->cdw - begin) * 4); \
|
|
cmd_buffer->video.enc.total_task_size += cs->buf[begin]; \
|
|
}
|
|
|
|
static void
|
|
radv_enc_session_info(struct radv_cmd_buffer *cmd_buffer)
|
|
{
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, pdev->vcn_enc_cmds.session_info);
|
|
radeon_emit(cs, pdev->encoder_interface_version);
|
|
|
|
radv_cs_add_buffer(device->ws, cs, cmd_buffer->video.vid->sessionctx.mem->bo);
|
|
uint64_t va = radv_buffer_get_va(cmd_buffer->video.vid->sessionctx.mem->bo);
|
|
va += cmd_buffer->video.vid->sessionctx.offset;
|
|
radeon_emit(cs, va >> 32);
|
|
radeon_emit(cs, va & 0xffffffff);
|
|
radeon_emit(cs, RENCODE_ENGINE_TYPE_ENCODE);
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_task_info(struct radv_cmd_buffer *cmd_buffer, bool feedback)
|
|
{
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
struct radv_enc_state *enc = &cmd_buffer->video.enc;
|
|
|
|
enc->task_id++;
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, pdev->vcn_enc_cmds.task_info);
|
|
enc->task_size_offset = cs->cdw++;
|
|
radeon_emit(cs, enc->task_id);
|
|
radeon_emit(cs, feedback ? 1 : 0);
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_session_init(struct radv_cmd_buffer *cmd_buffer, const struct VkVideoEncodeInfoKHR *enc_info)
|
|
{
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radv_video_session *vid = cmd_buffer->video.vid;
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
unsigned alignment = 16;
|
|
if (vid->vk.op == VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR) {
|
|
alignment = 64;
|
|
}
|
|
|
|
uint32_t w = enc_info->srcPictureResource.codedExtent.width;
|
|
uint32_t h = enc_info->srcPictureResource.codedExtent.height;
|
|
uint32_t aligned_picture_width = align(w, alignment);
|
|
uint32_t aligned_picture_height = align(h, alignment);
|
|
uint32_t padding_width = aligned_picture_width - w;
|
|
uint32_t padding_height = aligned_picture_height - h;
|
|
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, pdev->vcn_enc_cmds.session_init);
|
|
radeon_emit(cs, vid->enc_session.encode_standard);
|
|
radeon_emit(cs, aligned_picture_width);
|
|
radeon_emit(cs, aligned_picture_height);
|
|
radeon_emit(cs, padding_width);
|
|
radeon_emit(cs, padding_height);
|
|
radeon_emit(cs, vid->enc_session.pre_encode_mode);
|
|
radeon_emit(cs, vid->enc_session.pre_encode_chroma_enabled);
|
|
if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_3) {
|
|
radeon_emit(cs, 0); // slice output enabled.
|
|
}
|
|
radeon_emit(cs, vid->enc_session.display_remote);
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_layer_control(struct radv_cmd_buffer *cmd_buffer, const rvcn_enc_layer_control_t *rc_layer_control)
|
|
{
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, pdev->vcn_enc_cmds.layer_control);
|
|
radeon_emit(cs, rc_layer_control->max_num_temporal_layers); // max num temporal layesr
|
|
radeon_emit(cs, rc_layer_control->num_temporal_layers); // num temporal layers
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_layer_select(struct radv_cmd_buffer *cmd_buffer, int tl_idx)
|
|
{
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, pdev->vcn_enc_cmds.layer_select);
|
|
radeon_emit(cs, tl_idx); // temporal layer index
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_slice_control(struct radv_cmd_buffer *cmd_buffer, const struct VkVideoEncodeInfoKHR *enc_info)
|
|
{
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
|
|
uint32_t num_mbs_in_slice;
|
|
uint32_t width_in_mbs = enc_info->srcPictureResource.codedExtent.width / 16;
|
|
uint32_t height_in_mbs = enc_info->srcPictureResource.codedExtent.height / 16;
|
|
num_mbs_in_slice = width_in_mbs * height_in_mbs;
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, pdev->vcn_enc_cmds.slice_control_h264);
|
|
radeon_emit(cs, RENCODE_H264_SLICE_CONTROL_MODE_FIXED_MBS); // slice control mode
|
|
radeon_emit(cs, num_mbs_in_slice); // num mbs per slice
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_spec_misc_h264(struct radv_cmd_buffer *cmd_buffer, const struct VkVideoEncodeInfoKHR *enc_info)
|
|
{
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
const struct VkVideoEncodeH264PictureInfoKHR *h264_picture_info =
|
|
vk_find_struct_const(enc_info->pNext, VIDEO_ENCODE_H264_PICTURE_INFO_KHR);
|
|
const StdVideoEncodeH264PictureInfo *pic = h264_picture_info->pStdPictureInfo;
|
|
const StdVideoH264SequenceParameterSet *sps =
|
|
vk_video_find_h264_enc_std_sps(&cmd_buffer->video.params->vk, pic->seq_parameter_set_id);
|
|
const StdVideoH264PictureParameterSet *pps =
|
|
vk_video_find_h264_enc_std_pps(&cmd_buffer->video.params->vk, pic->pic_parameter_set_id);
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, pdev->vcn_enc_cmds.spec_misc_h264);
|
|
radeon_emit(cs, pps->flags.constrained_intra_pred_flag); // constrained_intra_pred_flag
|
|
radeon_emit(cs, pps->flags.entropy_coding_mode_flag); // cabac enable
|
|
radeon_emit(cs, 0); // cabac init idc
|
|
radeon_emit(cs, 1); // half pel enabled
|
|
radeon_emit(cs, 1); // quarter pel enabled
|
|
radeon_emit(cs, cmd_buffer->video.vid->vk.h264.profile_idc); // profile_idc
|
|
radeon_emit(cs, vk_video_get_h264_level(sps->level_idc));
|
|
|
|
if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_3) {
|
|
radeon_emit(cs, 0); // v3 b_picture_enabled
|
|
radeon_emit(cs, pps->weighted_bipred_idc); // v3 weighted bipred idc
|
|
}
|
|
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_spec_misc_hevc(struct radv_cmd_buffer *cmd_buffer, const struct VkVideoEncodeInfoKHR *enc_info)
|
|
{
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
const struct VkVideoEncodeH265PictureInfoKHR *h265_picture_info =
|
|
vk_find_struct_const(enc_info->pNext, VIDEO_ENCODE_H265_PICTURE_INFO_KHR);
|
|
const StdVideoEncodeH265PictureInfo *pic = h265_picture_info->pStdPictureInfo;
|
|
const VkVideoEncodeH265NaluSliceSegmentInfoKHR *h265_slice = &h265_picture_info->pNaluSliceSegmentEntries[0];
|
|
const StdVideoEncodeH265SliceSegmentHeader *slice = h265_slice->pStdSliceSegmentHeader;
|
|
const StdVideoH265SequenceParameterSet *sps =
|
|
vk_video_find_h265_enc_std_sps(&cmd_buffer->video.params->vk, pic->pps_seq_parameter_set_id);
|
|
const StdVideoH265PictureParameterSet *pps =
|
|
vk_video_find_h265_enc_std_pps(&cmd_buffer->video.params->vk, pic->pps_pic_parameter_set_id);
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, pdev->vcn_enc_cmds.spec_misc_hevc);
|
|
radeon_emit(cs, sps->log2_min_luma_coding_block_size_minus3);
|
|
radeon_emit(cs, !sps->flags.amp_enabled_flag);
|
|
radeon_emit(cs, sps->flags.strong_intra_smoothing_enabled_flag);
|
|
radeon_emit(cs, pps->flags.constrained_intra_pred_flag);
|
|
radeon_emit(cs, slice->flags.cabac_init_flag);
|
|
radeon_emit(cs, 1); // enc->enc_pic.hevc_spec_misc.half_pel_enabled
|
|
radeon_emit(cs, 1); // enc->enc_pic.hevc_spec_misc.quarter_pel_enabled
|
|
if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_3) {
|
|
radeon_emit(cs, !pps->flags.transform_skip_enabled_flag);
|
|
radeon_emit(cs, pps->flags.cu_qp_delta_enabled_flag);
|
|
}
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_slice_control_hevc(struct radv_cmd_buffer *cmd_buffer, const struct VkVideoEncodeInfoKHR *enc_info)
|
|
{
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
const struct VkVideoEncodeH265PictureInfoKHR *h265_picture_info =
|
|
vk_find_struct_const(enc_info->pNext, VIDEO_ENCODE_H265_PICTURE_INFO_KHR);
|
|
const StdVideoEncodeH265PictureInfo *pic = h265_picture_info->pStdPictureInfo;
|
|
const StdVideoH265SequenceParameterSet *sps =
|
|
vk_video_find_h265_enc_std_sps(&cmd_buffer->video.params->vk, pic->pps_seq_parameter_set_id);
|
|
|
|
uint32_t width_in_ctb, height_in_ctb, num_ctbs_in_slice;
|
|
|
|
width_in_ctb = sps->pic_width_in_luma_samples / 64;
|
|
height_in_ctb = sps->pic_height_in_luma_samples / 64;
|
|
num_ctbs_in_slice = width_in_ctb * height_in_ctb;
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, pdev->vcn_enc_cmds.slice_control_hevc);
|
|
radeon_emit(cs, RENCODE_HEVC_SLICE_CONTROL_MODE_FIXED_CTBS);
|
|
radeon_emit(cs, num_ctbs_in_slice); // num_ctbs_in_slice
|
|
radeon_emit(cs, num_ctbs_in_slice); // num_ctbs_in_slice_segment
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_rc_session_init(struct radv_cmd_buffer *cmd_buffer)
|
|
{
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
struct radv_video_session *vid = cmd_buffer->video.vid;
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, pdev->vcn_enc_cmds.rc_session_init);
|
|
radeon_emit(cs, vid->enc_rate_control_method); // rate_control_method);
|
|
radeon_emit(cs, 48); // vbv_buffer_level);
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_rc_layer_init(struct radv_cmd_buffer *cmd_buffer, rvcn_enc_rate_ctl_layer_init_t *layer_init)
|
|
{
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, pdev->vcn_enc_cmds.rc_layer_init);
|
|
radeon_emit(cs, layer_init->target_bit_rate); // target bit rate
|
|
radeon_emit(cs, layer_init->peak_bit_rate); // peak bit rate
|
|
radeon_emit(cs, layer_init->frame_rate_num); // frame rate num
|
|
radeon_emit(cs, layer_init->frame_rate_den); // frame rate dem
|
|
radeon_emit(cs, layer_init->vbv_buffer_size); // vbv buffer size
|
|
radeon_emit(cs, layer_init->avg_target_bits_per_picture); // avg target bits per picture
|
|
radeon_emit(cs, layer_init->peak_bits_per_picture_integer); // peak bit per picture int
|
|
radeon_emit(cs, layer_init->peak_bits_per_picture_fractional); // peak bit per picture fract
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_deblocking_filter_h264(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR *enc_info)
|
|
{
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
const struct VkVideoEncodeH264PictureInfoKHR *h264_picture_info =
|
|
vk_find_struct_const(enc_info->pNext, VIDEO_ENCODE_H264_PICTURE_INFO_KHR);
|
|
const VkVideoEncodeH264NaluSliceInfoKHR *h264_slice = &h264_picture_info->pNaluSliceEntries[0];
|
|
const StdVideoEncodeH264SliceHeader *slice = h264_slice->pStdSliceHeader;
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, pdev->vcn_enc_cmds.deblocking_filter_h264);
|
|
radeon_emit(cs, slice->disable_deblocking_filter_idc);
|
|
radeon_emit(cs, slice->slice_alpha_c0_offset_div2);
|
|
radeon_emit(cs, slice->slice_beta_offset_div2);
|
|
radeon_emit(cs, 0); // cb qp offset
|
|
radeon_emit(cs, 0); // cr qp offset
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_deblocking_filter_hevc(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR *enc_info)
|
|
{
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
const struct VkVideoEncodeH265PictureInfoKHR *h265_picture_info =
|
|
vk_find_struct_const(enc_info->pNext, VIDEO_ENCODE_H265_PICTURE_INFO_KHR);
|
|
const StdVideoEncodeH265PictureInfo *pic = h265_picture_info->pStdPictureInfo;
|
|
const VkVideoEncodeH265NaluSliceSegmentInfoKHR *h265_slice = &h265_picture_info->pNaluSliceSegmentEntries[0];
|
|
const StdVideoEncodeH265SliceSegmentHeader *slice = h265_slice->pStdSliceSegmentHeader;
|
|
const StdVideoH265SequenceParameterSet *sps =
|
|
vk_video_find_h265_enc_std_sps(&cmd_buffer->video.params->vk, pic->pps_seq_parameter_set_id);
|
|
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, pdev->vcn_enc_cmds.deblocking_filter_hevc);
|
|
radeon_emit(cs, slice->flags.slice_loop_filter_across_slices_enabled_flag);
|
|
radeon_emit(cs, slice->flags.slice_deblocking_filter_disabled_flag);
|
|
radeon_emit(cs, slice->slice_beta_offset_div2);
|
|
radeon_emit(cs, slice->slice_tc_offset_div2);
|
|
radeon_emit(cs, slice->slice_cb_qp_offset);
|
|
radeon_emit(cs, slice->slice_cr_qp_offset);
|
|
if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_2)
|
|
radeon_emit(cs, !sps->flags.sample_adaptive_offset_enabled_flag);
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_quality_params(struct radv_cmd_buffer *cmd_buffer)
|
|
{
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, pdev->vcn_enc_cmds.quality_params);
|
|
radeon_emit(cs, 0);
|
|
radeon_emit(cs, 0);
|
|
radeon_emit(cs, 0);
|
|
radeon_emit(cs, 0);
|
|
if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_3)
|
|
radeon_emit(cs, 0);
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_slice_header(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR *enc_info)
|
|
{
|
|
struct radv_enc_state *enc = &cmd_buffer->video.enc;
|
|
uint32_t instruction[RENCODE_SLICE_HEADER_TEMPLATE_MAX_NUM_INSTRUCTIONS] = {0};
|
|
uint32_t num_bits[RENCODE_SLICE_HEADER_TEMPLATE_MAX_NUM_INSTRUCTIONS] = {0};
|
|
const struct VkVideoEncodeH264PictureInfoKHR *h264_picture_info =
|
|
vk_find_struct_const(enc_info->pNext, VIDEO_ENCODE_H264_PICTURE_INFO_KHR);
|
|
int slice_count = h264_picture_info->naluSliceEntryCount;
|
|
const StdVideoEncodeH264PictureInfo *pic = h264_picture_info->pStdPictureInfo;
|
|
const StdVideoH264SequenceParameterSet *sps =
|
|
vk_video_find_h264_enc_std_sps(&cmd_buffer->video.params->vk, pic->seq_parameter_set_id);
|
|
const StdVideoH264PictureParameterSet *pps =
|
|
vk_video_find_h264_enc_std_pps(&cmd_buffer->video.params->vk, pic->pic_parameter_set_id);
|
|
const VkVideoEncodeH264NaluSliceInfoKHR *slice_info = &h264_picture_info->pNaluSliceEntries[0];
|
|
|
|
unsigned int inst_index = 0;
|
|
unsigned int cdw_start = 0;
|
|
unsigned int cdw_filled = 0;
|
|
unsigned int bits_copied = 0;
|
|
|
|
assert(slice_count <= 1);
|
|
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, pdev->vcn_enc_cmds.slice_header);
|
|
radv_enc_reset(cmd_buffer);
|
|
radv_enc_set_emulation_prevention(cmd_buffer, false);
|
|
|
|
cdw_start = cs->cdw;
|
|
|
|
if (pic->flags.IdrPicFlag)
|
|
radv_enc_code_fixed_bits(cmd_buffer, 0x65, 8);
|
|
else if (!pic->flags.is_reference)
|
|
radv_enc_code_fixed_bits(cmd_buffer, 0x01, 8);
|
|
else
|
|
radv_enc_code_fixed_bits(cmd_buffer, 0x41, 8);
|
|
|
|
radv_enc_flush_headers(cmd_buffer);
|
|
instruction[inst_index] = RENCODE_HEADER_INSTRUCTION_COPY;
|
|
num_bits[inst_index] = enc->bits_output - bits_copied;
|
|
bits_copied = enc->bits_output;
|
|
inst_index++;
|
|
|
|
instruction[inst_index] = RENCODE_H264_HEADER_INSTRUCTION_FIRST_MB;
|
|
inst_index++;
|
|
|
|
switch (pic->primary_pic_type) {
|
|
case STD_VIDEO_H264_PICTURE_TYPE_I:
|
|
case STD_VIDEO_H264_PICTURE_TYPE_IDR:
|
|
default:
|
|
radv_enc_code_ue(cmd_buffer, 7);
|
|
break;
|
|
case STD_VIDEO_H264_PICTURE_TYPE_P:
|
|
radv_enc_code_ue(cmd_buffer, 5);
|
|
break;
|
|
case STD_VIDEO_H264_PICTURE_TYPE_B:
|
|
radv_enc_code_ue(cmd_buffer, 6);
|
|
break;
|
|
}
|
|
radv_enc_code_ue(cmd_buffer, 0x0);
|
|
radv_enc_code_fixed_bits(cmd_buffer, pic->frame_num % 32, sps->log2_max_frame_num_minus4 + 4);
|
|
#if 0
|
|
if (enc->enc_pic.h264_enc_params.input_picture_structure !=
|
|
RENCODE_H264_PICTURE_STRUCTURE_FRAME) {
|
|
radv_enc_code_fixed_bits(cmd_buffer, 0x1, 1);
|
|
radv_enc_code_fixed_bits(cmd_buffer,
|
|
enc->enc_pic.h264_enc_params.input_picture_structure ==
|
|
RENCODE_H264_PICTURE_STRUCTURE_BOTTOM_FIELD
|
|
? 1
|
|
: 0,
|
|
1);
|
|
}
|
|
#endif
|
|
|
|
if (pic->flags.IdrPicFlag)
|
|
radv_enc_code_ue(cmd_buffer, pic->idr_pic_id);
|
|
|
|
if (sps->pic_order_cnt_type == STD_VIDEO_H264_POC_TYPE_0)
|
|
radv_enc_code_fixed_bits(cmd_buffer, pic->PicOrderCnt % 32, sps->log2_max_pic_order_cnt_lsb_minus4 + 4);
|
|
|
|
if (pps->flags.redundant_pic_cnt_present_flag)
|
|
radv_enc_code_ue(cmd_buffer, 0);
|
|
|
|
if (pic->primary_pic_type == STD_VIDEO_H264_PICTURE_TYPE_B) {
|
|
radv_enc_code_fixed_bits(cmd_buffer, slice_info->pStdSliceHeader->flags.direct_spatial_mv_pred_flag, 1);
|
|
}
|
|
const StdVideoEncodeH264ReferenceListsInfo *ref_lists = pic->pRefLists;
|
|
/* ref_pic_list_modification() */
|
|
if (pic->primary_pic_type != STD_VIDEO_H264_PICTURE_TYPE_IDR &&
|
|
pic->primary_pic_type != STD_VIDEO_H264_PICTURE_TYPE_I) {
|
|
|
|
/* num ref idx active override flag */
|
|
radv_enc_code_fixed_bits(cmd_buffer, slice_info->pStdSliceHeader->flags.num_ref_idx_active_override_flag, 1);
|
|
if (slice_info->pStdSliceHeader->flags.num_ref_idx_active_override_flag) {
|
|
radv_enc_code_ue(cmd_buffer, ref_lists->num_ref_idx_l0_active_minus1);
|
|
if (pic->primary_pic_type == STD_VIDEO_H264_PICTURE_TYPE_B)
|
|
radv_enc_code_ue(cmd_buffer, ref_lists->num_ref_idx_l1_active_minus1);
|
|
}
|
|
|
|
radv_enc_code_fixed_bits(cmd_buffer, ref_lists->flags.ref_pic_list_modification_flag_l0, 1);
|
|
if (ref_lists->flags.ref_pic_list_modification_flag_l0) {
|
|
for (unsigned op = 0; op < ref_lists->refList0ModOpCount; op++) {
|
|
const StdVideoEncodeH264RefListModEntry *entry = &ref_lists->pRefList0ModOperations[op];
|
|
|
|
radv_enc_code_ue(cmd_buffer, entry->modification_of_pic_nums_idc);
|
|
if (entry->modification_of_pic_nums_idc ==
|
|
STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_SHORT_TERM_SUBTRACT ||
|
|
entry->modification_of_pic_nums_idc == STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_SHORT_TERM_ADD)
|
|
radv_enc_code_ue(cmd_buffer, entry->abs_diff_pic_num_minus1);
|
|
else if (entry->modification_of_pic_nums_idc == STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_LONG_TERM)
|
|
radv_enc_code_ue(cmd_buffer, entry->long_term_pic_num);
|
|
}
|
|
}
|
|
|
|
if (pic->primary_pic_type == STD_VIDEO_H264_PICTURE_TYPE_B) {
|
|
radv_enc_code_fixed_bits(cmd_buffer, ref_lists->flags.ref_pic_list_modification_flag_l1, 1);
|
|
if (ref_lists->flags.ref_pic_list_modification_flag_l1) {
|
|
for (unsigned op = 0; op < ref_lists->refList1ModOpCount; op++) {
|
|
const StdVideoEncodeH264RefListModEntry *entry = &ref_lists->pRefList1ModOperations[op];
|
|
|
|
radv_enc_code_ue(cmd_buffer, entry->modification_of_pic_nums_idc);
|
|
if (entry->modification_of_pic_nums_idc ==
|
|
STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_SHORT_TERM_SUBTRACT ||
|
|
entry->modification_of_pic_nums_idc == STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_SHORT_TERM_ADD)
|
|
radv_enc_code_ue(cmd_buffer, entry->abs_diff_pic_num_minus1);
|
|
else if (entry->modification_of_pic_nums_idc == STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_LONG_TERM)
|
|
radv_enc_code_ue(cmd_buffer, entry->long_term_pic_num);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pic->flags.IdrPicFlag) {
|
|
radv_enc_code_fixed_bits(cmd_buffer, 0x0, 1);
|
|
radv_enc_code_fixed_bits(cmd_buffer, pic->flags.long_term_reference_flag, 1); /* long_term_reference_flag */
|
|
} else if (pic->flags.is_reference) {
|
|
radv_enc_code_fixed_bits(cmd_buffer, ref_lists->refPicMarkingOpCount > 0 ? 1 : 0, 1);
|
|
for (unsigned op = 0; op < ref_lists->refPicMarkingOpCount; op++) {
|
|
const StdVideoEncodeH264RefPicMarkingEntry *entry = &ref_lists->pRefPicMarkingOperations[op];
|
|
radv_enc_code_ue(cmd_buffer, entry->memory_management_control_operation);
|
|
if (entry->memory_management_control_operation == STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_UNMARK_SHORT_TERM ||
|
|
entry->memory_management_control_operation == STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_MARK_LONG_TERM)
|
|
radv_enc_code_ue(cmd_buffer, entry->difference_of_pic_nums_minus1);
|
|
if (entry->memory_management_control_operation == STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_UNMARK_LONG_TERM)
|
|
radv_enc_code_ue(cmd_buffer, entry->long_term_pic_num);
|
|
if (entry->memory_management_control_operation == STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_MARK_LONG_TERM ||
|
|
entry->memory_management_control_operation == STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_MARK_CURRENT_AS_LONG_TERM)
|
|
radv_enc_code_ue(cmd_buffer, entry->long_term_frame_idx);
|
|
if (entry->memory_management_control_operation == STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_SET_MAX_LONG_TERM_INDEX)
|
|
radv_enc_code_ue(cmd_buffer, entry->max_long_term_frame_idx_plus1);
|
|
if (entry->memory_management_control_operation == STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_END)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pic->primary_pic_type != STD_VIDEO_H264_PICTURE_TYPE_IDR &&
|
|
pic->primary_pic_type != STD_VIDEO_H264_PICTURE_TYPE_I && pps->flags.entropy_coding_mode_flag)
|
|
radv_enc_code_ue(cmd_buffer, slice_info->pStdSliceHeader->cabac_init_idc);
|
|
|
|
radv_enc_flush_headers(cmd_buffer);
|
|
instruction[inst_index] = RENCODE_HEADER_INSTRUCTION_COPY;
|
|
num_bits[inst_index] = enc->bits_output - bits_copied;
|
|
bits_copied = enc->bits_output;
|
|
inst_index++;
|
|
|
|
instruction[inst_index] = RENCODE_H264_HEADER_INSTRUCTION_SLICE_QP_DELTA;
|
|
inst_index++;
|
|
|
|
if (pps->flags.deblocking_filter_control_present_flag) {
|
|
radv_enc_code_ue(cmd_buffer, slice_info->pStdSliceHeader->disable_deblocking_filter_idc);
|
|
if (!slice_info->pStdSliceHeader->disable_deblocking_filter_idc) {
|
|
radv_enc_code_se(cmd_buffer, slice_info->pStdSliceHeader->slice_alpha_c0_offset_div2);
|
|
radv_enc_code_se(cmd_buffer, slice_info->pStdSliceHeader->slice_beta_offset_div2);
|
|
}
|
|
}
|
|
|
|
radv_enc_flush_headers(cmd_buffer);
|
|
instruction[inst_index] = RENCODE_HEADER_INSTRUCTION_COPY;
|
|
num_bits[inst_index] = enc->bits_output - bits_copied;
|
|
bits_copied = enc->bits_output;
|
|
inst_index++;
|
|
|
|
instruction[inst_index] = RENCODE_HEADER_INSTRUCTION_END;
|
|
|
|
cdw_filled = cs->cdw - cdw_start;
|
|
for (int i = 0; i < RENCODE_SLICE_HEADER_TEMPLATE_MAX_TEMPLATE_SIZE_IN_DWORDS - cdw_filled; i++)
|
|
radeon_emit(cs, 0x00000000);
|
|
for (int j = 0; j < RENCODE_SLICE_HEADER_TEMPLATE_MAX_NUM_INSTRUCTIONS; j++) {
|
|
radeon_emit(cs, instruction[j]);
|
|
radeon_emit(cs, num_bits[j]);
|
|
}
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_slice_header_hevc(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR *enc_info)
|
|
{
|
|
struct radv_enc_state *enc = &cmd_buffer->video.enc;
|
|
uint32_t instruction[RENCODE_SLICE_HEADER_TEMPLATE_MAX_NUM_INSTRUCTIONS] = {0};
|
|
uint32_t num_bits[RENCODE_SLICE_HEADER_TEMPLATE_MAX_NUM_INSTRUCTIONS] = {0};
|
|
const struct VkVideoEncodeH265PictureInfoKHR *h265_picture_info =
|
|
vk_find_struct_const(enc_info->pNext, VIDEO_ENCODE_H265_PICTURE_INFO_KHR);
|
|
const StdVideoEncodeH265PictureInfo *pic = h265_picture_info->pStdPictureInfo;
|
|
const VkVideoEncodeH265NaluSliceSegmentInfoKHR *h265_slice = &h265_picture_info->pNaluSliceSegmentEntries[0];
|
|
const StdVideoEncodeH265SliceSegmentHeader *slice = h265_slice->pStdSliceSegmentHeader;
|
|
const StdVideoH265SequenceParameterSet *sps =
|
|
vk_video_find_h265_enc_std_sps(&cmd_buffer->video.params->vk, pic->pps_seq_parameter_set_id);
|
|
const StdVideoH265PictureParameterSet *pps =
|
|
vk_video_find_h265_enc_std_pps(&cmd_buffer->video.params->vk, pic->pps_pic_parameter_set_id);
|
|
unsigned int inst_index = 0;
|
|
unsigned int cdw_start = 0;
|
|
unsigned int cdw_filled = 0;
|
|
unsigned int bits_copied = 0;
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
unsigned nal_unit_type = vk_video_get_h265_nal_unit(pic->pic_type, pic->flags.IrapPicFlag);
|
|
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, pdev->vcn_enc_cmds.slice_header);
|
|
radv_enc_reset(cmd_buffer);
|
|
radv_enc_set_emulation_prevention(cmd_buffer, false);
|
|
|
|
cdw_start = cs->cdw;
|
|
radv_enc_code_fixed_bits(cmd_buffer, 0x0, 1);
|
|
radv_enc_code_fixed_bits(cmd_buffer, nal_unit_type, 6);
|
|
radv_enc_code_fixed_bits(cmd_buffer, 0x0, 6);
|
|
radv_enc_code_fixed_bits(cmd_buffer, 0x1, 3);
|
|
|
|
radv_enc_flush_headers(cmd_buffer);
|
|
instruction[inst_index] = RENCODE_HEADER_INSTRUCTION_COPY;
|
|
num_bits[inst_index] = enc->bits_output - bits_copied;
|
|
bits_copied = enc->bits_output;
|
|
inst_index++;
|
|
|
|
instruction[inst_index] = RENCODE_HEVC_HEADER_INSTRUCTION_FIRST_SLICE;
|
|
inst_index++;
|
|
|
|
if ((nal_unit_type >= 16) && (nal_unit_type <= 23))
|
|
radv_enc_code_fixed_bits(cmd_buffer, 0x0, 1);
|
|
|
|
radv_enc_code_ue(cmd_buffer, pic->pps_pic_parameter_set_id);
|
|
|
|
radv_enc_flush_headers(cmd_buffer);
|
|
instruction[inst_index] = RENCODE_HEADER_INSTRUCTION_COPY;
|
|
num_bits[inst_index] = enc->bits_output - bits_copied;
|
|
bits_copied = enc->bits_output;
|
|
inst_index++;
|
|
|
|
instruction[inst_index] = RENCODE_HEVC_HEADER_INSTRUCTION_SLICE_SEGMENT;
|
|
inst_index++;
|
|
|
|
instruction[inst_index] = RENCODE_HEVC_HEADER_INSTRUCTION_DEPENDENT_SLICE_END;
|
|
inst_index++;
|
|
|
|
/* slice_type */
|
|
switch (pic->pic_type) {
|
|
case STD_VIDEO_H265_PICTURE_TYPE_I:
|
|
case STD_VIDEO_H265_PICTURE_TYPE_IDR:
|
|
radv_enc_code_ue(cmd_buffer, 0x2);
|
|
break;
|
|
case STD_VIDEO_H265_PICTURE_TYPE_P:
|
|
radv_enc_code_ue(cmd_buffer, 0x1);
|
|
break;
|
|
case STD_VIDEO_H265_PICTURE_TYPE_B:
|
|
radv_enc_code_ue(cmd_buffer, 0x0);
|
|
break;
|
|
default:
|
|
radv_enc_code_ue(cmd_buffer, 0x1);
|
|
}
|
|
|
|
if ((nal_unit_type != 19) && nal_unit_type != 20) {
|
|
/* slice_pic_order_cnt_lsb */
|
|
radv_enc_code_fixed_bits(cmd_buffer, pic->PicOrderCntVal, sps->log2_max_pic_order_cnt_lsb_minus4 + 4);
|
|
radv_enc_code_fixed_bits(cmd_buffer, pic->flags.short_term_ref_pic_set_sps_flag, 0x1);
|
|
if (!pic->flags.short_term_ref_pic_set_sps_flag) {
|
|
int st_rps_idx = sps->num_short_term_ref_pic_sets;
|
|
const StdVideoH265ShortTermRefPicSet *rps = &pic->pShortTermRefPicSet[st_rps_idx];
|
|
|
|
if (st_rps_idx != 0)
|
|
radv_enc_code_fixed_bits(cmd_buffer, rps->flags.inter_ref_pic_set_prediction_flag, 0x1);
|
|
|
|
if (rps->flags.inter_ref_pic_set_prediction_flag) {
|
|
int ref_rps_idx = st_rps_idx - (rps->delta_idx_minus1 + 1);
|
|
if (st_rps_idx == sps->num_short_term_ref_pic_sets)
|
|
radv_enc_code_ue(cmd_buffer, rps->delta_idx_minus1);
|
|
radv_enc_code_fixed_bits(cmd_buffer, rps->flags.delta_rps_sign, 0x1);
|
|
radv_enc_code_ue(cmd_buffer, rps->abs_delta_rps_minus1);
|
|
|
|
const StdVideoH265ShortTermRefPicSet *rps_ref = &sps->pShortTermRefPicSet[ref_rps_idx];
|
|
int num_delta_pocs = rps_ref->num_negative_pics + rps_ref->num_positive_pics;
|
|
for (int j = 0; j < num_delta_pocs; j++) {
|
|
radv_enc_code_fixed_bits(cmd_buffer, !!(rps->used_by_curr_pic_flag & (1 << j)), 0x1);
|
|
if (!(rps->used_by_curr_pic_flag & (1 << j))) {
|
|
radv_enc_code_fixed_bits(cmd_buffer, !!(rps->use_delta_flag & (1 << j)), 0x1);
|
|
}
|
|
}
|
|
} else {
|
|
radv_enc_code_ue(cmd_buffer, rps->num_negative_pics);
|
|
radv_enc_code_ue(cmd_buffer, rps->num_positive_pics);
|
|
|
|
for (int i = 0; i < rps->num_negative_pics; i++) {
|
|
radv_enc_code_ue(cmd_buffer, rps->delta_poc_s0_minus1[i]);
|
|
radv_enc_code_fixed_bits(cmd_buffer, !!(rps->used_by_curr_pic_s0_flag & (1 << i)), 0x1);
|
|
}
|
|
for (int i = 0; i < rps->num_positive_pics; i++) {
|
|
radv_enc_code_ue(cmd_buffer, rps->delta_poc_s1_minus1[i]);
|
|
radv_enc_code_fixed_bits(cmd_buffer, !!(rps->used_by_curr_pic_s1_flag & (1 << i)), 0x1);
|
|
}
|
|
}
|
|
} else if (sps->num_short_term_ref_pic_sets > 1)
|
|
radv_enc_code_ue(cmd_buffer, pic->short_term_ref_pic_set_idx);
|
|
|
|
if (sps->flags.sps_temporal_mvp_enabled_flag)
|
|
radv_enc_code_fixed_bits(cmd_buffer, pic->flags.slice_temporal_mvp_enabled_flag, 1);
|
|
}
|
|
|
|
if (sps->flags.sample_adaptive_offset_enabled_flag) {
|
|
radv_enc_flush_headers(cmd_buffer);
|
|
instruction[inst_index] = RENCODE_HEADER_INSTRUCTION_COPY;
|
|
num_bits[inst_index] = enc->bits_output - bits_copied;
|
|
bits_copied = enc->bits_output;
|
|
inst_index++;
|
|
|
|
instruction[inst_index] = RENCODE_HEVC_HEADER_INSTRUCTION_SAO_ENABLE;
|
|
inst_index++;
|
|
}
|
|
|
|
if ((pic->pic_type == STD_VIDEO_H265_PICTURE_TYPE_P) || (pic->pic_type == STD_VIDEO_H265_PICTURE_TYPE_B)) {
|
|
radv_enc_code_fixed_bits(cmd_buffer, slice->flags.num_ref_idx_active_override_flag, 1);
|
|
if (slice->flags.num_ref_idx_active_override_flag) {
|
|
radv_enc_code_ue(cmd_buffer, pic->pRefLists->num_ref_idx_l0_active_minus1);
|
|
if (pic->pic_type == STD_VIDEO_H265_PICTURE_TYPE_B)
|
|
radv_enc_code_ue(cmd_buffer, pic->pRefLists->num_ref_idx_l1_active_minus1);
|
|
}
|
|
if (pic->pic_type == STD_VIDEO_H265_PICTURE_TYPE_B)
|
|
radv_enc_code_fixed_bits(cmd_buffer, slice->flags.mvd_l1_zero_flag, 1);
|
|
if (pps->flags.cabac_init_present_flag)
|
|
radv_enc_code_fixed_bits(cmd_buffer, slice->flags.cabac_init_flag, 1);
|
|
if (pic->flags.slice_temporal_mvp_enabled_flag) {
|
|
if (pic->pic_type == STD_VIDEO_H265_PICTURE_TYPE_B)
|
|
radv_enc_code_fixed_bits(cmd_buffer, slice->flags.collocated_from_l0_flag, 1);
|
|
}
|
|
radv_enc_code_ue(cmd_buffer, 5 - slice->MaxNumMergeCand);
|
|
}
|
|
|
|
radv_enc_flush_headers(cmd_buffer);
|
|
instruction[inst_index] = RENCODE_HEADER_INSTRUCTION_COPY;
|
|
num_bits[inst_index] = enc->bits_output - bits_copied;
|
|
bits_copied = enc->bits_output;
|
|
inst_index++;
|
|
|
|
instruction[inst_index] = RENCODE_HEVC_HEADER_INSTRUCTION_SLICE_QP_DELTA;
|
|
inst_index++;
|
|
|
|
if (pps->flags.pps_slice_chroma_qp_offsets_present_flag) {
|
|
radv_enc_code_se(cmd_buffer, slice->slice_cb_qp_offset);
|
|
radv_enc_code_se(cmd_buffer, slice->slice_cr_qp_offset);
|
|
}
|
|
|
|
if (pps->flags.pps_slice_act_qp_offsets_present_flag) {
|
|
radv_enc_code_se(cmd_buffer, slice->slice_act_y_qp_offset);
|
|
radv_enc_code_se(cmd_buffer, slice->slice_act_cb_qp_offset);
|
|
radv_enc_code_se(cmd_buffer, slice->slice_act_cr_qp_offset);
|
|
}
|
|
|
|
if (pps->flags.chroma_qp_offset_list_enabled_flag) {
|
|
radv_enc_code_fixed_bits(cmd_buffer, slice->flags.cu_chroma_qp_offset_enabled_flag, 1);
|
|
}
|
|
|
|
if (pps->flags.deblocking_filter_override_enabled_flag) {
|
|
radv_enc_code_fixed_bits(cmd_buffer, slice->flags.deblocking_filter_override_flag, 1);
|
|
if (slice->flags.deblocking_filter_override_flag) {
|
|
radv_enc_code_fixed_bits(cmd_buffer, slice->flags.slice_deblocking_filter_disabled_flag, 1);
|
|
if (!slice->flags.slice_deblocking_filter_disabled_flag) {
|
|
radv_enc_code_se(cmd_buffer, slice->slice_beta_offset_div2);
|
|
radv_enc_code_se(cmd_buffer, slice->slice_tc_offset_div2);
|
|
}
|
|
}
|
|
}
|
|
if ((pps->flags.pps_loop_filter_across_slices_enabled_flag) &&
|
|
(!slice->flags.slice_deblocking_filter_disabled_flag || slice->flags.slice_sao_luma_flag ||
|
|
slice->flags.slice_sao_chroma_flag)) {
|
|
|
|
if (slice->flags.slice_sao_luma_flag || slice->flags.slice_sao_chroma_flag) {
|
|
instruction[inst_index] = RENCODE_HEVC_HEADER_INSTRUCTION_LOOP_FILTER_ACROSS_SLICES_ENABLE;
|
|
inst_index++;
|
|
} else {
|
|
radv_enc_code_fixed_bits(cmd_buffer, slice->flags.slice_loop_filter_across_slices_enabled_flag, 1);
|
|
radv_enc_flush_headers(cmd_buffer);
|
|
instruction[inst_index] = RENCODE_HEADER_INSTRUCTION_COPY;
|
|
num_bits[inst_index] = enc->bits_output - bits_copied;
|
|
bits_copied = enc->bits_output;
|
|
inst_index++;
|
|
}
|
|
}
|
|
|
|
instruction[inst_index] = RENCODE_HEADER_INSTRUCTION_END;
|
|
|
|
cdw_filled = cs->cdw - cdw_start;
|
|
for (int i = 0; i < RENCODE_SLICE_HEADER_TEMPLATE_MAX_TEMPLATE_SIZE_IN_DWORDS - cdw_filled; i++)
|
|
radeon_emit(cs, 0x00000000);
|
|
for (int j = 0; j < RENCODE_SLICE_HEADER_TEMPLATE_MAX_NUM_INSTRUCTIONS; j++) {
|
|
radeon_emit(cs, instruction[j]);
|
|
radeon_emit(cs, num_bits[j]);
|
|
}
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_ctx(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR *info)
|
|
{
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
struct radv_image_view *dpb_iv = NULL;
|
|
struct radv_image *dpb = NULL;
|
|
struct radv_image_plane *dpb_luma = NULL;
|
|
struct radv_image_plane *dpb_chroma = NULL;
|
|
uint64_t va = 0;
|
|
uint32_t luma_pitch = 0;
|
|
|
|
if (info->pSetupReferenceSlot)
|
|
dpb_iv = radv_image_view_from_handle(info->pSetupReferenceSlot->pPictureResource->imageViewBinding);
|
|
else if (info->referenceSlotCount > 0)
|
|
dpb_iv = radv_image_view_from_handle(info->pReferenceSlots[0].pPictureResource->imageViewBinding);
|
|
|
|
if (dpb_iv) {
|
|
dpb = dpb_iv->image;
|
|
dpb_luma = &dpb->planes[0];
|
|
dpb_chroma = &dpb->planes[1];
|
|
radv_cs_add_buffer(device->ws, cs, dpb->bindings[0].bo);
|
|
va = radv_buffer_get_va(dpb->bindings[0].bo) + dpb->bindings[0].offset; // TODO DPB resource
|
|
luma_pitch = dpb_luma->surface.u.gfx9.surf_pitch * dpb_luma->surface.blk_w; // rec_luma_pitch
|
|
}
|
|
|
|
uint32_t swizzle_mode = 0;
|
|
|
|
if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_4)
|
|
swizzle_mode = RENCODE_REC_SWIZZLE_MODE_256B_D;
|
|
else if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_2)
|
|
swizzle_mode = RENCODE_REC_SWIZZLE_MODE_256B_S;
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, pdev->vcn_enc_cmds.ctx);
|
|
radeon_emit(cs, va >> 32);
|
|
radeon_emit(cs, va & 0xffffffff);
|
|
radeon_emit(cs, swizzle_mode);
|
|
radeon_emit(cs, luma_pitch); // rec_luma_pitch
|
|
radeon_emit(cs, luma_pitch); // rec_luma_pitch0); //rec_chromma_pitch
|
|
radeon_emit(cs, info->referenceSlotCount + 1); // num_reconstructed_pictures
|
|
|
|
int i;
|
|
for (i = 0; i < info->referenceSlotCount + 1; i++) {
|
|
radeon_emit(cs, dpb_luma ? dpb_luma->surface.u.gfx9.surf_offset + i * dpb_luma->surface.u.gfx9.surf_slice_size
|
|
: 0); // luma offset
|
|
radeon_emit(cs, dpb_chroma
|
|
? dpb_chroma->surface.u.gfx9.surf_offset + i * dpb_chroma->surface.u.gfx9.surf_slice_size
|
|
: 0); // chroma offset
|
|
|
|
if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_4) {
|
|
radeon_emit(cs, 0); /* unused offset 1 */
|
|
radeon_emit(cs, 0); /* unused offset 2 */
|
|
}
|
|
}
|
|
|
|
for (; i < RENCODE_MAX_NUM_RECONSTRUCTED_PICTURES; i++) {
|
|
radeon_emit(cs, 0);
|
|
radeon_emit(cs, 0);
|
|
if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_4) {
|
|
radeon_emit(cs, 0); /* unused offset 1 */
|
|
radeon_emit(cs, 0); /* unused offset 2 */
|
|
}
|
|
}
|
|
|
|
if (pdev->enc_hw_ver == RADV_VIDEO_ENC_HW_3) {
|
|
radeon_emit(cs, 0); // colloc buffer offset
|
|
}
|
|
radeon_emit(cs, 0); // enc pic pre encode luma pitch
|
|
radeon_emit(cs, 0); // enc pic pre encode chroma pitch
|
|
|
|
for (i = 0; i < RENCODE_MAX_NUM_RECONSTRUCTED_PICTURES; i++) {
|
|
radeon_emit(cs, 0); // pre encode luma offset
|
|
radeon_emit(cs, 0); // pre encode chroma offset
|
|
if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_4) {
|
|
radeon_emit(cs, 0); /* unused offset 1 */
|
|
radeon_emit(cs, 0); /* unused offset 2 */
|
|
}
|
|
}
|
|
|
|
if (pdev->enc_hw_ver == RADV_VIDEO_ENC_HW_2) {
|
|
radeon_emit(cs, 0); // enc pic yuv luma offset
|
|
radeon_emit(cs, 0); // enc pic yuv chroma offset
|
|
|
|
radeon_emit(cs, 0); // two pass search center map offset
|
|
|
|
// rgboffsets
|
|
radeon_emit(cs, 0); // red
|
|
radeon_emit(cs, 0); // green
|
|
radeon_emit(cs, 0); // blue
|
|
} else if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_3) {
|
|
radeon_emit(cs, 0); // red
|
|
radeon_emit(cs, 0); // green
|
|
radeon_emit(cs, 0); // blue
|
|
radeon_emit(cs, 0); // v3 two pass search center map offset
|
|
radeon_emit(cs, 0);
|
|
if (pdev->enc_hw_ver == RADV_VIDEO_ENC_HW_3) {
|
|
radeon_emit(cs, 0);
|
|
}
|
|
}
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_bitstream(struct radv_cmd_buffer *cmd_buffer, struct radv_buffer *buffer, VkDeviceSize offset)
|
|
{
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
uint64_t va = radv_buffer_get_va(buffer->bo) + buffer->offset;
|
|
radv_cs_add_buffer(device->ws, cs, buffer->bo);
|
|
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, pdev->vcn_enc_cmds.bitstream);
|
|
radeon_emit(cs, RENCODE_REC_SWIZZLE_MODE_LINEAR);
|
|
radeon_emit(cs, va >> 32);
|
|
radeon_emit(cs, va & 0xffffffff);
|
|
radeon_emit(cs, buffer->vk.size - offset);
|
|
radeon_emit(cs, offset);
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_feedback(struct radv_cmd_buffer *cmd_buffer)
|
|
{
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
ENC_BEGIN;
|
|
|
|
radeon_emit(cs, pdev->vcn_enc_cmds.feedback);
|
|
radeon_emit(cs, RENCODE_FEEDBACK_BUFFER_MODE_LINEAR);
|
|
radeon_emit(cs, cmd_buffer->video.feedback_query_va >> 32);
|
|
radeon_emit(cs, cmd_buffer->video.feedback_query_va & 0xffffffff);
|
|
radeon_emit(cs, 16); // buffer_size
|
|
radeon_emit(cs, 40); // data_size
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_intra_refresh(struct radv_cmd_buffer *cmd_buffer)
|
|
{
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, pdev->vcn_enc_cmds.intra_refresh);
|
|
radeon_emit(cs, 0); // intra refresh mode
|
|
radeon_emit(cs, 0); // intra ref offset
|
|
radeon_emit(cs, 0); // intra region size
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_rc_per_pic(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR *enc_info,
|
|
rvcn_enc_rate_ctl_per_picture_t *per_pic)
|
|
{
|
|
struct radv_video_session *vid = cmd_buffer->video.vid;
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
|
|
unsigned qp = per_pic->qp_i;
|
|
|
|
if (vid->enc_rate_control_method == RENCODE_RATE_CONTROL_METHOD_NONE && !vid->enc_rate_control_default) {
|
|
switch (vid->vk.op) {
|
|
case VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR: {
|
|
const struct VkVideoEncodeH264PictureInfoKHR *h264_picture_info =
|
|
vk_find_struct_const(enc_info->pNext, VIDEO_ENCODE_H264_PICTURE_INFO_KHR);
|
|
const VkVideoEncodeH264NaluSliceInfoKHR *h264_slice = &h264_picture_info->pNaluSliceEntries[0];
|
|
qp = h264_slice->constantQp;
|
|
break;
|
|
}
|
|
case VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR: {
|
|
const struct VkVideoEncodeH265PictureInfoKHR *h265_picture_info =
|
|
vk_find_struct_const(enc_info->pNext, VIDEO_ENCODE_H265_PICTURE_INFO_KHR);
|
|
const VkVideoEncodeH265NaluSliceSegmentInfoKHR *h265_slice = &h265_picture_info->pNaluSliceSegmentEntries[0];
|
|
qp = h265_slice->constantQp;
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, pdev->vcn_enc_cmds.rc_per_pic);
|
|
radeon_emit(cs, qp); // qp
|
|
radeon_emit(cs, per_pic->min_qp_i); // min qp
|
|
radeon_emit(cs, per_pic->max_qp_i); // max qp
|
|
radeon_emit(cs, per_pic->max_au_size_i); // max au
|
|
radeon_emit(cs, per_pic->enabled_filler_data); // enabled filler
|
|
radeon_emit(cs, per_pic->skip_frame_enable); // skip frame eanble
|
|
radeon_emit(cs, per_pic->enforce_hrd); // enforce hrd
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_params(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR *enc_info)
|
|
{
|
|
const struct VkVideoEncodeH264PictureInfoKHR *h264_picture_info =
|
|
vk_find_struct_const(enc_info->pNext, VIDEO_ENCODE_H264_PICTURE_INFO_KHR);
|
|
const struct VkVideoEncodeH265PictureInfoKHR *h265_picture_info =
|
|
vk_find_struct_const(enc_info->pNext, VIDEO_ENCODE_H265_PICTURE_INFO_KHR);
|
|
const StdVideoEncodeH264PictureInfo *h264_pic = h264_picture_info ? h264_picture_info->pStdPictureInfo : NULL;
|
|
const StdVideoEncodeH265PictureInfo *h265_pic = h265_picture_info ? h265_picture_info->pStdPictureInfo : NULL;
|
|
struct radv_image_view *src_iv = radv_image_view_from_handle(enc_info->srcPictureResource.imageViewBinding);
|
|
struct radv_image *src_img = src_iv->image;
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
uint64_t va = radv_buffer_get_va(src_img->bindings[0].bo) + src_img->bindings[0].offset;
|
|
uint64_t luma_va = va + src_img->planes[0].surface.u.gfx9.surf_offset;
|
|
uint64_t chroma_va = va + src_img->planes[1].surface.u.gfx9.surf_offset;
|
|
uint32_t pic_type;
|
|
unsigned int slot_idx = 0xffffffff;
|
|
|
|
radv_cs_add_buffer(device->ws, cs, src_img->bindings[0].bo);
|
|
if (h264_pic) {
|
|
switch (h264_pic->primary_pic_type) {
|
|
case STD_VIDEO_H264_PICTURE_TYPE_P:
|
|
slot_idx = enc_info->pReferenceSlots[0].slotIndex;
|
|
pic_type = RENCODE_PICTURE_TYPE_P;
|
|
break;
|
|
case STD_VIDEO_H264_PICTURE_TYPE_B:
|
|
slot_idx = enc_info->pReferenceSlots[0].slotIndex;
|
|
pic_type = RENCODE_PICTURE_TYPE_B;
|
|
break;
|
|
case STD_VIDEO_H264_PICTURE_TYPE_I:
|
|
case STD_VIDEO_H264_PICTURE_TYPE_IDR:
|
|
default:
|
|
pic_type = RENCODE_PICTURE_TYPE_I;
|
|
break;
|
|
}
|
|
} else if (h265_pic) {
|
|
switch (h265_pic->pic_type) {
|
|
case STD_VIDEO_H265_PICTURE_TYPE_P:
|
|
slot_idx = enc_info->pReferenceSlots[0].slotIndex;
|
|
pic_type = RENCODE_PICTURE_TYPE_P;
|
|
break;
|
|
case STD_VIDEO_H265_PICTURE_TYPE_B:
|
|
slot_idx = enc_info->pReferenceSlots[0].slotIndex;
|
|
pic_type = RENCODE_PICTURE_TYPE_B;
|
|
break;
|
|
case STD_VIDEO_H265_PICTURE_TYPE_I:
|
|
case STD_VIDEO_H265_PICTURE_TYPE_IDR:
|
|
default:
|
|
pic_type = RENCODE_PICTURE_TYPE_I;
|
|
break;
|
|
}
|
|
} else {
|
|
assert(0);
|
|
return;
|
|
}
|
|
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, pdev->vcn_enc_cmds.enc_params);
|
|
radeon_emit(cs, pic_type); // pic type
|
|
radeon_emit(cs, enc_info->dstBufferRange); // allowed max bitstream size
|
|
radeon_emit(cs, luma_va >> 32);
|
|
radeon_emit(cs, luma_va & 0xffffffff);
|
|
radeon_emit(cs, chroma_va >> 32);
|
|
radeon_emit(cs, chroma_va & 0xffffffff);
|
|
radeon_emit(cs, src_img->planes[0].surface.u.gfx9.surf_pitch); // luma pitch
|
|
radeon_emit(cs, src_img->planes[1].surface.u.gfx9.surf_pitch); // chroma pitch
|
|
radeon_emit(cs, src_img->planes[0].surface.u.gfx9.swizzle_mode); // swizzle mode
|
|
radeon_emit(cs, slot_idx); // ref0_idx
|
|
|
|
if (enc_info->pSetupReferenceSlot)
|
|
radeon_emit(cs, enc_info->pSetupReferenceSlot->slotIndex); // reconstructed picture index
|
|
else
|
|
radeon_emit(cs, 0);
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_params_h264(struct radv_cmd_buffer *cmd_buffer)
|
|
{
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, pdev->vcn_enc_cmds.enc_params_h264);
|
|
|
|
if (pdev->enc_hw_ver < RADV_VIDEO_ENC_HW_3) {
|
|
radeon_emit(cs, RENCODE_H264_PICTURE_STRUCTURE_FRAME);
|
|
radeon_emit(cs, RENCODE_H264_INTERLACING_MODE_PROGRESSIVE);
|
|
radeon_emit(cs, RENCODE_H264_PICTURE_STRUCTURE_FRAME);
|
|
radeon_emit(cs, 0xffffffff); // reference_picture1_index
|
|
} else {
|
|
// V3
|
|
radeon_emit(cs, RENCODE_H264_PICTURE_STRUCTURE_FRAME);
|
|
radeon_emit(cs, 0); // input pic order cnt
|
|
radeon_emit(cs, RENCODE_H264_INTERLACING_MODE_PROGRESSIVE);
|
|
radeon_emit(cs, 0); // l0 ref pic0 pic_type
|
|
radeon_emit(cs, 0); // l0 ref pic0 is long term
|
|
radeon_emit(cs, 0); // l0 ref pic0 picture structure
|
|
radeon_emit(cs, 0); // l0 ref pic0 pic order cnt
|
|
radeon_emit(cs, 0xffffffff); // l0 ref pic1 index
|
|
radeon_emit(cs, 0); // l0 ref pic1 pic_type
|
|
radeon_emit(cs, 0); // l0 ref pic1 is long term
|
|
radeon_emit(cs, 0); // l0 ref pic1 picture structure
|
|
radeon_emit(cs, 0); // l0 ref pic1 pic order cnt
|
|
radeon_emit(cs, 0xffffffff); // l1 ref pic0 index
|
|
radeon_emit(cs, 0); // l1 ref pic0 pic_type
|
|
radeon_emit(cs, 0); // l1 ref pic0 is long term
|
|
radeon_emit(cs, 0); // l1 ref pic0 picture structure
|
|
radeon_emit(cs, 0); // l1 ref pic0 pic order cnt
|
|
}
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_op_init(struct radv_cmd_buffer *cmd_buffer)
|
|
{
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, RENCODE_IB_OP_INITIALIZE);
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_op_close(struct radv_cmd_buffer *cmd_buffer)
|
|
{
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, RENCODE_IB_OP_CLOSE_SESSION);
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_op_enc(struct radv_cmd_buffer *cmd_buffer)
|
|
{
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, RENCODE_IB_OP_ENCODE);
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_op_init_rc(struct radv_cmd_buffer *cmd_buffer)
|
|
{
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, RENCODE_IB_OP_INIT_RC);
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_op_init_rc_vbv(struct radv_cmd_buffer *cmd_buffer)
|
|
{
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, RENCODE_IB_OP_INIT_RC_VBV_BUFFER_LEVEL);
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_op_preset(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR *enc_info)
|
|
{
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
struct radv_video_session *vid = cmd_buffer->video.vid;
|
|
uint32_t preset_mode;
|
|
|
|
switch (vid->vk.op) {
|
|
case VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR: {
|
|
const struct VkVideoEncodeH265PictureInfoKHR *h265_picture_info =
|
|
vk_find_struct_const(enc_info->pNext, VIDEO_ENCODE_H265_PICTURE_INFO_KHR);
|
|
const StdVideoEncodeH265PictureInfo *pic = h265_picture_info->pStdPictureInfo;
|
|
const StdVideoH265SequenceParameterSet *sps =
|
|
vk_video_find_h265_enc_std_sps(&cmd_buffer->video.params->vk, pic->pps_seq_parameter_set_id);
|
|
if (sps->flags.sample_adaptive_offset_enabled_flag && vid->enc_preset_mode == RENCODE_PRESET_MODE_SPEED) {
|
|
preset_mode = RENCODE_IB_OP_SET_BALANCE_ENCODING_MODE;
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (vid->enc_preset_mode == RENCODE_PRESET_MODE_QUALITY)
|
|
preset_mode = RENCODE_IB_OP_SET_QUALITY_ENCODING_MODE;
|
|
else if (vid->enc_preset_mode == RENCODE_PRESET_MODE_BALANCE)
|
|
preset_mode = RENCODE_IB_OP_SET_BALANCE_ENCODING_MODE;
|
|
else
|
|
preset_mode = RENCODE_IB_OP_SET_SPEED_ENCODING_MODE;
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, preset_mode);
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_input_format(struct radv_cmd_buffer *cmd_buffer)
|
|
{
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, pdev->vcn_enc_cmds.input_format);
|
|
radeon_emit(cs, 0); // input color volume
|
|
radeon_emit(cs, 0); // input color space
|
|
radeon_emit(cs, RENCODE_COLOR_RANGE_STUDIO); // input color range
|
|
radeon_emit(cs, 0); // input chroma subsampling
|
|
radeon_emit(cs, 0); // input chroma location
|
|
radeon_emit(cs, 0); // input color bit depth
|
|
radeon_emit(cs, 0); // input color packing format
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_output_format(struct radv_cmd_buffer *cmd_buffer)
|
|
{
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radeon_cmdbuf *cs = cmd_buffer->cs;
|
|
ENC_BEGIN;
|
|
radeon_emit(cs, pdev->vcn_enc_cmds.output_format);
|
|
radeon_emit(cs, 0); // output color volume
|
|
radeon_emit(cs, RENCODE_COLOR_RANGE_STUDIO); // output color range
|
|
radeon_emit(cs, 0); // output chroma location
|
|
radeon_emit(cs, 0); // output color bit depth
|
|
ENC_END;
|
|
}
|
|
|
|
static void
|
|
radv_enc_headers_h264(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR *enc_info)
|
|
{
|
|
radv_enc_slice_header(cmd_buffer, enc_info);
|
|
radv_enc_params(cmd_buffer, enc_info);
|
|
radv_enc_params_h264(cmd_buffer);
|
|
}
|
|
|
|
static void
|
|
radv_enc_headers_hevc(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR *enc_info)
|
|
{
|
|
radv_enc_slice_header_hevc(cmd_buffer, enc_info);
|
|
radv_enc_params(cmd_buffer, enc_info);
|
|
}
|
|
|
|
static void
|
|
begin(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR *enc_info)
|
|
{
|
|
struct radv_enc_state *enc = &cmd_buffer->video.enc;
|
|
struct radv_video_session *vid = cmd_buffer->video.vid;
|
|
|
|
radv_enc_session_info(cmd_buffer);
|
|
cmd_buffer->video.enc.total_task_size = 0;
|
|
radv_enc_task_info(cmd_buffer, false);
|
|
radv_enc_op_init(cmd_buffer);
|
|
radv_enc_session_init(cmd_buffer, enc_info);
|
|
if (vid->vk.op == VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR) {
|
|
radv_enc_slice_control(cmd_buffer, enc_info);
|
|
radv_enc_spec_misc_h264(cmd_buffer, enc_info);
|
|
radv_enc_deblocking_filter_h264(cmd_buffer, enc_info);
|
|
} else if (vid->vk.op == VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR) {
|
|
radv_enc_slice_control_hevc(cmd_buffer, enc_info);
|
|
radv_enc_spec_misc_hevc(cmd_buffer, enc_info);
|
|
radv_enc_deblocking_filter_hevc(cmd_buffer, enc_info);
|
|
}
|
|
radv_enc_layer_control(cmd_buffer, &vid->rc_layer_control);
|
|
radv_enc_rc_session_init(cmd_buffer);
|
|
radv_enc_quality_params(cmd_buffer);
|
|
// temporal layers init
|
|
unsigned i = 0;
|
|
do {
|
|
radv_enc_layer_select(cmd_buffer, i);
|
|
radv_enc_rc_layer_init(cmd_buffer, &vid->rc_layer_init[i]);
|
|
radv_enc_layer_select(cmd_buffer, i);
|
|
radv_enc_rc_per_pic(cmd_buffer, enc_info, &vid->rc_per_pic[i]);
|
|
} while (++i < vid->rc_layer_control.num_temporal_layers);
|
|
radv_enc_op_init_rc(cmd_buffer);
|
|
radv_enc_op_init_rc_vbv(cmd_buffer);
|
|
radeon_emit_direct(cmd_buffer->cs, enc->task_size_offset, enc->total_task_size);
|
|
}
|
|
|
|
static void
|
|
destroy(struct radv_cmd_buffer *cmd_buffer)
|
|
{
|
|
struct radv_enc_state *enc = &cmd_buffer->video.enc;
|
|
radv_enc_session_info(cmd_buffer);
|
|
cmd_buffer->video.enc.total_task_size = 0;
|
|
radv_enc_task_info(cmd_buffer, false);
|
|
radv_enc_op_close(cmd_buffer);
|
|
radeon_emit_direct(cmd_buffer->cs, enc->task_size_offset, enc->total_task_size);
|
|
}
|
|
|
|
static void
|
|
radv_vcn_encode_video(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR *enc_info)
|
|
{
|
|
VK_FROM_HANDLE(radv_buffer, dst_buffer, enc_info->dstBuffer);
|
|
struct radv_video_session *vid = cmd_buffer->video.vid;
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radv_enc_state *enc = &cmd_buffer->video.enc;
|
|
|
|
switch (vid->vk.op) {
|
|
case VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR:
|
|
case VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR:
|
|
break;
|
|
default:
|
|
assert(0);
|
|
return;
|
|
}
|
|
|
|
begin(cmd_buffer, enc_info);
|
|
// before encode
|
|
// session info
|
|
radv_enc_session_info(cmd_buffer);
|
|
|
|
cmd_buffer->video.enc.total_task_size = 0;
|
|
// task info
|
|
radv_enc_task_info(cmd_buffer, true);
|
|
|
|
// encode headers
|
|
// ctx
|
|
if (vid->vk.op == VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR) {
|
|
radv_enc_headers_h264(cmd_buffer, enc_info);
|
|
radv_enc_ctx(cmd_buffer, enc_info);
|
|
} else if (vid->vk.op == VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR) {
|
|
radv_enc_headers_hevc(cmd_buffer, enc_info);
|
|
radv_enc_ctx(cmd_buffer, enc_info);
|
|
}
|
|
// bitstream
|
|
radv_enc_bitstream(cmd_buffer, dst_buffer, enc_info->dstBufferOffset);
|
|
|
|
// feedback
|
|
radv_enc_feedback(cmd_buffer);
|
|
|
|
// v2 encode statistics
|
|
if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_2) {
|
|
}
|
|
// intra_refresh
|
|
radv_enc_intra_refresh(cmd_buffer);
|
|
// v2 input format
|
|
if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_2) {
|
|
radv_enc_input_format(cmd_buffer);
|
|
radv_enc_output_format(cmd_buffer);
|
|
}
|
|
// v2 output format
|
|
|
|
// op_preset
|
|
radv_enc_op_preset(cmd_buffer, enc_info);
|
|
// op_enc
|
|
radv_enc_op_enc(cmd_buffer);
|
|
|
|
radeon_emit_direct(cmd_buffer->cs, enc->task_size_offset, enc->total_task_size);
|
|
|
|
destroy(cmd_buffer);
|
|
}
|
|
|
|
static void
|
|
set_rate_control_defaults(struct radv_video_session *vid)
|
|
{
|
|
uint32_t frame_rate_den = 1, frame_rate_num = 30;
|
|
vid->enc_rate_control_method = RENCODE_RATE_CONTROL_METHOD_NONE;
|
|
vid->rc_layer_control.num_temporal_layers = 1;
|
|
vid->rc_layer_control.max_num_temporal_layers = 1;
|
|
vid->rc_per_pic[0].qp_i = 26;
|
|
vid->rc_per_pic[0].min_qp_i = 0;
|
|
vid->rc_per_pic[0].max_qp_i = 51;
|
|
vid->rc_per_pic[0].max_au_size_i = 0;
|
|
vid->rc_per_pic[0].enabled_filler_data = 1;
|
|
vid->rc_per_pic[0].skip_frame_enable = 0;
|
|
vid->rc_per_pic[0].enforce_hrd = 1;
|
|
vid->rc_layer_init[0].frame_rate_den = frame_rate_den;
|
|
vid->rc_layer_init[0].frame_rate_num = frame_rate_num;
|
|
vid->rc_layer_init[0].vbv_buffer_size = 20000000; // rate_control->virtualBufferSizeInMs;
|
|
vid->rc_layer_init[0].target_bit_rate = 16000;
|
|
vid->rc_layer_init[0].peak_bit_rate = 32000;
|
|
vid->rc_layer_init[0].avg_target_bits_per_picture =
|
|
radv_vcn_per_frame_integer(16000, frame_rate_den, frame_rate_num);
|
|
vid->rc_layer_init[0].peak_bits_per_picture_integer =
|
|
radv_vcn_per_frame_integer(32000, frame_rate_den, frame_rate_num);
|
|
vid->rc_layer_init[0].peak_bits_per_picture_fractional =
|
|
radv_vcn_per_frame_frac(32000, frame_rate_den, frame_rate_num);
|
|
return;
|
|
}
|
|
|
|
void
|
|
radv_video_enc_control_video_coding(struct radv_cmd_buffer *cmd_buffer, const VkVideoCodingControlInfoKHR *control_info)
|
|
{
|
|
struct radv_video_session *vid = cmd_buffer->video.vid;
|
|
|
|
switch (vid->vk.op) {
|
|
case VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR:
|
|
case VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR:
|
|
break;
|
|
default:
|
|
unreachable("Unsupported\n");
|
|
}
|
|
|
|
if (control_info->flags & VK_VIDEO_CODING_CONTROL_RESET_BIT_KHR) {
|
|
set_rate_control_defaults(vid);
|
|
}
|
|
|
|
if (control_info->flags & VK_VIDEO_CODING_CONTROL_ENCODE_RATE_CONTROL_BIT_KHR) {
|
|
const VkVideoEncodeRateControlInfoKHR *rate_control = (VkVideoEncodeRateControlInfoKHR *)vk_find_struct_const(
|
|
control_info->pNext, VIDEO_ENCODE_RATE_CONTROL_INFO_KHR);
|
|
|
|
assert(rate_control);
|
|
const VkVideoEncodeH264RateControlInfoKHR *h264_rate_control =
|
|
(VkVideoEncodeH264RateControlInfoKHR *)vk_find_struct_const(rate_control->pNext,
|
|
VIDEO_ENCODE_H264_RATE_CONTROL_INFO_KHR);
|
|
const VkVideoEncodeH265RateControlInfoKHR *h265_rate_control =
|
|
(VkVideoEncodeH265RateControlInfoKHR *)vk_find_struct_const(rate_control->pNext,
|
|
VIDEO_ENCODE_H265_RATE_CONTROL_INFO_KHR);
|
|
|
|
vid->enc_rate_control_method = RENCODE_RATE_CONTROL_METHOD_NONE;
|
|
vid->enc_rate_control_default = false;
|
|
|
|
if (rate_control->rateControlMode == VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DEFAULT_KHR) {
|
|
vid->enc_rate_control_default = true;
|
|
set_rate_control_defaults(vid);
|
|
return;
|
|
}
|
|
if (rate_control->rateControlMode == VK_VIDEO_ENCODE_RATE_CONTROL_MODE_CBR_BIT_KHR)
|
|
vid->enc_rate_control_method = RENCODE_RATE_CONTROL_METHOD_CBR;
|
|
else if (rate_control->rateControlMode == VK_VIDEO_ENCODE_RATE_CONTROL_MODE_VBR_BIT_KHR)
|
|
vid->enc_rate_control_method = RENCODE_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR;
|
|
|
|
if (h264_rate_control) {
|
|
vid->rc_layer_control.max_num_temporal_layers = h264_rate_control->temporalLayerCount;
|
|
vid->rc_layer_control.num_temporal_layers = h264_rate_control->temporalLayerCount;
|
|
} else if (h265_rate_control) {
|
|
vid->rc_layer_control.max_num_temporal_layers = 1;
|
|
vid->rc_layer_control.num_temporal_layers = 1;
|
|
}
|
|
|
|
for (unsigned l = 0; l < rate_control->layerCount; l++) {
|
|
const VkVideoEncodeRateControlLayerInfoKHR *layer = &rate_control->pLayers[l];
|
|
const VkVideoEncodeH264RateControlLayerInfoKHR *h264_layer =
|
|
(VkVideoEncodeH264RateControlLayerInfoKHR *)vk_find_struct_const(
|
|
layer->pNext, VIDEO_ENCODE_H264_RATE_CONTROL_LAYER_INFO_KHR);
|
|
const VkVideoEncodeH265RateControlLayerInfoKHR *h265_layer =
|
|
(VkVideoEncodeH265RateControlLayerInfoKHR *)vk_find_struct_const(
|
|
layer->pNext, VIDEO_ENCODE_H265_RATE_CONTROL_LAYER_INFO_KHR);
|
|
uint32_t frame_rate_den, frame_rate_num;
|
|
vid->rc_layer_init[l].target_bit_rate = layer->averageBitrate;
|
|
vid->rc_layer_init[l].peak_bit_rate = layer->maxBitrate;
|
|
frame_rate_den = layer->frameRateDenominator;
|
|
frame_rate_num = layer->frameRateNumerator;
|
|
radv_vcn_enc_invalid_frame_rate(&frame_rate_den, &frame_rate_num);
|
|
vid->rc_layer_init[l].frame_rate_den = frame_rate_den;
|
|
vid->rc_layer_init[l].frame_rate_num = frame_rate_num;
|
|
vid->rc_layer_init[l].vbv_buffer_size = 20000000; // rate_control->virtualBufferSizeInMs;
|
|
vid->rc_layer_init[l].avg_target_bits_per_picture =
|
|
radv_vcn_per_frame_integer(layer->averageBitrate, frame_rate_den, frame_rate_num);
|
|
vid->rc_layer_init[l].peak_bits_per_picture_integer =
|
|
radv_vcn_per_frame_integer(layer->maxBitrate, frame_rate_den, frame_rate_num);
|
|
vid->rc_layer_init[l].peak_bits_per_picture_fractional =
|
|
radv_vcn_per_frame_frac(layer->maxBitrate, frame_rate_den, frame_rate_num);
|
|
|
|
if (h264_layer) {
|
|
vid->rc_per_pic[l].min_qp_i = h264_layer->useMinQp ? h264_layer->minQp.qpI : 0;
|
|
vid->rc_per_pic[l].max_qp_i = h264_layer->useMaxQp ? h264_layer->maxQp.qpI : 51;
|
|
vid->rc_per_pic[l].max_au_size_i = h264_layer->useMaxFrameSize ? h264_layer->maxFrameSize.frameISize : 0;
|
|
} else if (h265_layer) {
|
|
vid->rc_per_pic[l].min_qp_i = h265_layer->useMinQp ? h265_layer->minQp.qpI : 0;
|
|
vid->rc_per_pic[l].max_qp_i = h265_layer->useMaxQp ? h265_layer->maxQp.qpI : 51;
|
|
vid->rc_per_pic[l].max_au_size_i = h265_layer->useMaxFrameSize ? h265_layer->maxFrameSize.frameISize : 0;
|
|
}
|
|
|
|
vid->rc_per_pic[l].enabled_filler_data = 1;
|
|
vid->rc_per_pic[l].skip_frame_enable = 0;
|
|
vid->rc_per_pic[l].enforce_hrd = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
radv_CmdEncodeVideoKHR(VkCommandBuffer commandBuffer, const VkVideoEncodeInfoKHR *pEncodeInfo)
|
|
{
|
|
VK_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer);
|
|
radv_vcn_encode_video(cmd_buffer, pEncodeInfo);
|
|
}
|
|
|
|
VKAPI_ATTR VkResult VKAPI_CALL
|
|
radv_GetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR(
|
|
VkPhysicalDevice physicalDevice, const VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR *pQualityLevelInfo,
|
|
VkVideoEncodeQualityLevelPropertiesKHR *pQualityLevelProperties)
|
|
{
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
void
|
|
radv_video_patch_encode_session_parameters(struct vk_video_session_parameters *params)
|
|
{
|
|
switch (params->op) {
|
|
case VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR:
|
|
break;
|
|
case VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR: {
|
|
/*
|
|
* AMD firmware requires these flags to be set in h265 with RC modes,
|
|
* VCN 3 need 1.27 and VCN 4 needs 1.7 or newer to pass the CTS tests,
|
|
* dEQP-VK.video.encode.h265_rc_*.
|
|
*/
|
|
for (unsigned i = 0; i < params->h265_enc.h265_pps_count; i++) {
|
|
params->h265_enc.h265_pps[i].base.flags.cu_qp_delta_enabled_flag = 1;
|
|
params->h265_enc.h265_pps[i].base.diff_cu_qp_delta_depth = 0;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
VKAPI_ATTR VkResult VKAPI_CALL
|
|
radv_GetEncodedVideoSessionParametersKHR(VkDevice device,
|
|
const VkVideoEncodeSessionParametersGetInfoKHR *pVideoSessionParametersInfo,
|
|
VkVideoEncodeSessionParametersFeedbackInfoKHR *pFeedbackInfo,
|
|
size_t *pDataSize, void *pData)
|
|
{
|
|
VK_FROM_HANDLE(radv_video_session_params, templ, pVideoSessionParametersInfo->videoSessionParameters);
|
|
size_t total_size = 0;
|
|
size_t size_limit = 0;
|
|
|
|
if (pData)
|
|
size_limit = *pDataSize;
|
|
|
|
switch (templ->vk.op) {
|
|
case VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR: {
|
|
const struct VkVideoEncodeH264SessionParametersGetInfoKHR *h264_get_info =
|
|
vk_find_struct_const(pVideoSessionParametersInfo->pNext, VIDEO_ENCODE_H264_SESSION_PARAMETERS_GET_INFO_KHR);
|
|
if (h264_get_info->writeStdSPS) {
|
|
const StdVideoH264SequenceParameterSet *sps =
|
|
vk_video_find_h264_enc_std_sps(&templ->vk, h264_get_info->stdSPSId);
|
|
assert(sps);
|
|
vk_video_encode_h264_sps(sps, size_limit, &total_size, pData);
|
|
}
|
|
if (h264_get_info->writeStdPPS) {
|
|
const StdVideoH264PictureParameterSet *pps =
|
|
vk_video_find_h264_enc_std_pps(&templ->vk, h264_get_info->stdPPSId);
|
|
assert(pps);
|
|
vk_video_encode_h264_pps(pps, templ->vk.h264_enc.profile_idc == STD_VIDEO_H264_PROFILE_IDC_HIGH, size_limit,
|
|
&total_size, pData);
|
|
}
|
|
break;
|
|
}
|
|
case VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR: {
|
|
const struct VkVideoEncodeH265SessionParametersGetInfoKHR *h265_get_info =
|
|
vk_find_struct_const(pVideoSessionParametersInfo->pNext, VIDEO_ENCODE_H265_SESSION_PARAMETERS_GET_INFO_KHR);
|
|
if (h265_get_info->writeStdVPS) {
|
|
const StdVideoH265VideoParameterSet *vps = vk_video_find_h265_enc_std_vps(&templ->vk, h265_get_info->stdVPSId);
|
|
assert(vps);
|
|
vk_video_encode_h265_vps(vps, size_limit, &total_size, pData);
|
|
}
|
|
if (h265_get_info->writeStdSPS) {
|
|
const StdVideoH265SequenceParameterSet *sps =
|
|
vk_video_find_h265_enc_std_sps(&templ->vk, h265_get_info->stdSPSId);
|
|
assert(sps);
|
|
vk_video_encode_h265_sps(sps, size_limit, &total_size, pData);
|
|
}
|
|
if (h265_get_info->writeStdPPS) {
|
|
const StdVideoH265PictureParameterSet *pps =
|
|
vk_video_find_h265_enc_std_pps(&templ->vk, h265_get_info->stdPPSId);
|
|
assert(pps);
|
|
vk_video_encode_h265_pps(pps, size_limit, &total_size, pData);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
*pDataSize = total_size;
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
void
|
|
radv_video_enc_begin_coding(struct radv_cmd_buffer *cmd_buffer)
|
|
{
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
radeon_check_space(device->ws, cmd_buffer->cs, 1024);
|
|
|
|
if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_4)
|
|
radv_vcn_sq_header(cmd_buffer->cs, &cmd_buffer->video.sq, true);
|
|
}
|
|
|
|
void
|
|
radv_video_enc_end_coding(struct radv_cmd_buffer *cmd_buffer)
|
|
{
|
|
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_4)
|
|
radv_vcn_sq_tail(cmd_buffer->cs, &cmd_buffer->video.sq);
|
|
}
|
|
|
|
#define VCN_ENC_SESSION_SIZE 128 * 1024
|
|
|
|
VkResult
|
|
radv_video_get_encode_session_memory_requirements(struct radv_device *device, struct radv_video_session *vid,
|
|
uint32_t *pMemoryRequirementsCount,
|
|
VkVideoSessionMemoryRequirementsKHR *pMemoryRequirements)
|
|
{
|
|
struct radv_physical_device *pdev = radv_device_physical(device);
|
|
uint32_t memory_type_bits = (1u << pdev->memory_properties.memoryTypeCount) - 1;
|
|
|
|
VK_OUTARRAY_MAKE_TYPED(VkVideoSessionMemoryRequirementsKHR, out, pMemoryRequirements, pMemoryRequirementsCount);
|
|
|
|
vk_outarray_append_typed(VkVideoSessionMemoryRequirementsKHR, &out, m)
|
|
{
|
|
m->memoryBindIndex = 0;
|
|
m->memoryRequirements.size = VCN_ENC_SESSION_SIZE;
|
|
m->memoryRequirements.alignment = 0;
|
|
m->memoryRequirements.memoryTypeBits = memory_type_bits;
|
|
}
|
|
|
|
return vk_outarray_status(&out);
|
|
}
|