d3d12: Implement Delta QP ROI In h264, hevc and av1 video encode

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26766>
This commit is contained in:
Sil Vilerino
2023-12-19 17:26:05 -05:00
committed by Marge Bot
parent 37e83a93d7
commit 917044db98
5 changed files with 139 additions and 0 deletions
@@ -1092,6 +1092,12 @@ d3d12_video_encoder_disable_rc_qualitylevels(struct D3D12EncodeRateControlState
}
}
static void
d3d12_video_encoder_disable_rc_deltaqp(struct D3D12EncodeRateControlState & rcState)
{
rcState.m_Flags &= ~D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP;
}
static void
d3d12_video_encoder_disable_rc_minmaxqp(struct D3D12EncodeRateControlState & rcState)
{
@@ -1177,6 +1183,14 @@ bool d3d12_video_encoder_negotiate_requested_features_and_d3d12_driver_caps(stru
d3d12_video_encoder_disable_rc_minmaxqp(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc);
}
bool isRequestingDeltaQPSupported = ((capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_DELTA_QP_AVAILABLE) != 0);
bool isClientRequestingDeltaQP = ((pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP) != 0);
if(isClientRequestingDeltaQP && !isRequestingDeltaQPSupported) {
debug_printf("[d3d12_video_encoder] WARNING: Requested D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP but the feature is not supported, will continue encoding unsetting this feature as fallback.\n");
d3d12_video_encoder_disable_rc_deltaqp(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc);
}
bool isRequestingExtended1RCSupported = ((capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_EXTENSION1_SUPPORT) != 0);
bool isClientRequestingExtended1RC = ((pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT) != 0);
@@ -2653,3 +2667,58 @@ int d3d12_video_encoder_get_encode_headers([[maybe_unused]] struct pipe_video_co
return ENOTSUP;
#endif
}
template void
d3d12_video_encoder_update_picparams_region_of_interest_qpmap(struct d3d12_video_encoder *pD3D12Enc,
const struct pipe_enc_roi *roi_config,
int32_t min_delta_qp,
int32_t max_delta_qp,
std::vector<int16_t>& pQPMap);
template void
d3d12_video_encoder_update_picparams_region_of_interest_qpmap(struct d3d12_video_encoder *pD3D12Enc,
const struct pipe_enc_roi *roi_config,
int32_t min_delta_qp,
int32_t max_delta_qp,
std::vector<int8_t>& pQPMap);
template<typename T>
void
d3d12_video_encoder_update_picparams_region_of_interest_qpmap(struct d3d12_video_encoder *pD3D12Enc,
const struct pipe_enc_roi *roi_config,
int32_t min_delta_qp,
int32_t max_delta_qp,
std::vector<T>& pQPMap)
{
static_assert(ARRAY_SIZE(roi_config->region) == PIPE_ENC_ROI_REGION_NUM_MAX);
assert(roi_config->num > 0);
assert(roi_config->num <= PIPE_ENC_ROI_REGION_NUM_MAX);
assert(min_delta_qp < 0);
assert(max_delta_qp > 0);
// Set all the QP blocks with zero QP Delta, then only fill in the regions that have a non-zero delta value
uint32_t QPMapRegionPixelsSize = pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.QPMapRegionPixelsSize;
uint64_t pic_width_in_qpmap_block_units = static_cast<uint64_t>(std::ceil(pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width /
static_cast<double>(QPMapRegionPixelsSize)));
uint64_t pic_height_in_qpmap_block_units = static_cast<uint64_t>(std::ceil(pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Height /
static_cast<double>(QPMapRegionPixelsSize)));
uint64_t total_picture_qpmap_block_units = pic_width_in_qpmap_block_units * pic_height_in_qpmap_block_units;
pQPMap.resize(total_picture_qpmap_block_units, 0u);
// Loop in reverse for priority of overlapping regions as per p_video_state roi parameter docs
for (int32_t i = (roi_config->num - 1); i >= 0 ; i--)
{
auto& cur_region = roi_config->region[i];
if (cur_region.valid)
{
uint32_t bucket_start_block_x = cur_region.x / QPMapRegionPixelsSize;
uint32_t bucket_start_block_y = cur_region.y / QPMapRegionPixelsSize;
uint32_t bucket_end_block_x = std::ceil((cur_region.x + cur_region.width) / static_cast<double>(QPMapRegionPixelsSize)) - 1;
uint32_t bucket_end_block_y = std::ceil((cur_region.y + cur_region.height) / static_cast<double>(QPMapRegionPixelsSize)) - 1;
for (uint32_t i = bucket_start_block_x; i <= bucket_end_block_x; i++)
for (uint32_t j = bucket_start_block_y; j <= bucket_end_block_y; j++)
pQPMap[(j * pic_width_in_qpmap_block_units) + i] = CLAMP(cur_region.qp_value, min_delta_qp, max_delta_qp);
}
}
}
@@ -191,6 +191,10 @@ struct D3D12EncodeRateControlState
D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR1 m_Configuration_VBR1;
D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR1 m_Configuration_QVBR1;
} m_Config;
// AV1 uses 16 bit integers, H26x uses 8 bit integers
std::vector<int8_t> m_pRateControlQPMap8Bit;
std::vector<int16_t> m_pRateControlQPMap16Bit;
};
struct D3D12EncodeConfiguration
@@ -496,6 +500,15 @@ void
d3d12_video_encoder_store_current_picture_references(d3d12_video_encoder *pD3D12Enc,
uint64_t current_metadata_slot);
// Implementation here to prevent template linker issues
template<typename T>
void
d3d12_video_encoder_update_picparams_region_of_interest_qpmap(struct d3d12_video_encoder *pD3D12Enc,
const struct pipe_enc_roi *roi_config,
int32_t min_delta_qp,
int32_t max_delta_qp,
std::vector<T>& pQPMap);
///
/// d3d12_video_encoder functions ends
///
@@ -39,6 +39,10 @@ d3d12_video_encoder_update_current_rate_control_av1(struct d3d12_video_encoder *
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_FrameRate.Denominator = picture->rc[0].frame_rate_den;
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags = D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_NONE;
if (picture->roi.num > 0)
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP;
switch (picture->rc[0].rate_ctrl_method) {
case PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE_SKIP:
case PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE:
@@ -1588,6 +1592,21 @@ d3d12_video_encoder_update_current_frame_pic_params_info_av1(struct d3d12_video_
// the libva spec may be retro-fitted to allow this given existing apps in the wild doing it.
// pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot]
// .m_CodecSpecificData.AV1HeadersInfo.temporal_delim_rendered = pAV1Pic->temporal_delim_rendered;
if ((pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP) != 0)
{
// Use 16 bit qpmap array for AV1 picparams (-255, 255 range and int16_t pRateControlQPMap type)
const int32_t av1_min_delta_qp = -255;
const int32_t av1_max_delta_qp = 255;
d3d12_video_encoder_update_picparams_region_of_interest_qpmap(
pD3D12Enc,
&pAV1Pic->roi,
av1_min_delta_qp,
av1_max_delta_qp,
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_pRateControlQPMap16Bit);
picParams.pAV1PicData->pRateControlQPMap = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_pRateControlQPMap16Bit.data();
picParams.pAV1PicData->QPMapValuesCount = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_pRateControlQPMap16Bit.size();
}
}
void
@@ -42,6 +42,10 @@ d3d12_video_encoder_update_current_rate_control_h264(struct d3d12_video_encoder
picture->rate_ctrl[0].frame_rate_den;
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags = D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_NONE;
if (picture->roi.num > 0)
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP;
switch (picture->rate_ctrl[0].rate_ctrl_method) {
case PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE_SKIP:
case PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE:
@@ -345,6 +349,21 @@ d3d12_video_encoder_update_current_frame_pic_params_info_h264(struct d3d12_video
picParams.pH264PicData->List1ReferenceFramesCount = h264Pic->num_ref_idx_l1_active_minus1 + 1;
picParams.pH264PicData->pList1ReferenceFrames = h264Pic->ref_idx_l1_list;
}
if ((pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP) != 0)
{
// Use 8 bit qpmap array for H264 picparams (-51, 51 range and int8_t pRateControlQPMap type)
const int32_t h264_min_delta_qp = -51;
const int32_t h264_max_delta_qp = 51;
d3d12_video_encoder_update_picparams_region_of_interest_qpmap(
pD3D12Enc,
&h264Pic->roi,
h264_min_delta_qp,
h264_max_delta_qp,
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_pRateControlQPMap8Bit);
picParams.pH264PicData->pRateControlQPMap = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_pRateControlQPMap8Bit.data();
picParams.pH264PicData->QPMapValuesCount = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_pRateControlQPMap8Bit.size();
}
}
D3D12_VIDEO_ENCODER_FRAME_TYPE_H264
@@ -42,6 +42,10 @@ d3d12_video_encoder_update_current_rate_control_hevc(struct d3d12_video_encoder
picture->rc.frame_rate_den;
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags = D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_NONE;
if (picture->roi.num > 0)
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP;
switch (picture->rc.rate_ctrl_method) {
case PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE_SKIP:
case PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE:
@@ -349,6 +353,21 @@ d3d12_video_encoder_update_current_frame_pic_params_info_hevc(struct d3d12_video
if ((pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_HEVCConfig.ConfigurationFlags
& D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ALLOW_REQUEST_INTRA_CONSTRAINED_SLICES) != 0)
picParams.pHEVCPicData->Flags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_REQUEST_INTRA_CONSTRAINED_SLICES;
if ((pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP) != 0)
{
// Use 8 bit qpmap array for HEVC picparams (-51, 51 range and int8_t pRateControlQPMap type)
const int32_t hevc_min_delta_qp = -51;
const int32_t hevc_max_delta_qp = 51;
d3d12_video_encoder_update_picparams_region_of_interest_qpmap(
pD3D12Enc,
&hevcPic->roi,
hevc_min_delta_qp,
hevc_max_delta_qp,
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_pRateControlQPMap8Bit);
picParams.pHEVCPicData->pRateControlQPMap = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_pRateControlQPMap8Bit.data();
picParams.pHEVCPicData->QPMapValuesCount = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_pRateControlQPMap8Bit.size();
}
}
D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC