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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user