Module: Mesa Branch: main Commit: 917044db98ed3c6f9bed2941efad07cc93aa1173 URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=917044db98ed3c6f9bed2941efad07cc93aa1173
Author: Sil Vilerino <[email protected]> Date: Tue Dec 19 17:26:05 2023 -0500 d3d12: Implement Delta QP ROI In h264, hevc and av1 video encode Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26766> --- src/gallium/drivers/d3d12/d3d12_video_enc.cpp | 69 ++++++++++++++++++++++ src/gallium/drivers/d3d12/d3d12_video_enc.h | 13 ++++ src/gallium/drivers/d3d12/d3d12_video_enc_av1.cpp | 19 ++++++ src/gallium/drivers/d3d12/d3d12_video_enc_h264.cpp | 19 ++++++ src/gallium/drivers/d3d12/d3d12_video_enc_hevc.cpp | 19 ++++++ 5 files changed, 139 insertions(+) diff --git a/src/gallium/drivers/d3d12/d3d12_video_enc.cpp b/src/gallium/drivers/d3d12/d3d12_video_enc.cpp index 2b5f1cb13b7..dc6d3e9f91f 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_enc.cpp +++ b/src/gallium/drivers/d3d12/d3d12_video_enc.cpp @@ -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); + } + } +} + diff --git a/src/gallium/drivers/d3d12/d3d12_video_enc.h b/src/gallium/drivers/d3d12/d3d12_video_enc.h index 3972ee19ad9..2c1bb72ff56 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_enc.h +++ b/src/gallium/drivers/d3d12/d3d12_video_enc.h @@ -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 /// diff --git a/src/gallium/drivers/d3d12/d3d12_video_enc_av1.cpp b/src/gallium/drivers/d3d12/d3d12_video_enc_av1.cpp index b7260c3bf5d..88237e8885d 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_enc_av1.cpp +++ b/src/gallium/drivers/d3d12/d3d12_video_enc_av1.cpp @@ -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 diff --git a/src/gallium/drivers/d3d12/d3d12_video_enc_h264.cpp b/src/gallium/drivers/d3d12/d3d12_video_enc_h264.cpp index 42b09090e58..8804b80cf49 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_enc_h264.cpp +++ b/src/gallium/drivers/d3d12/d3d12_video_enc_h264.cpp @@ -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 diff --git a/src/gallium/drivers/d3d12/d3d12_video_enc_hevc.cpp b/src/gallium/drivers/d3d12/d3d12_video_enc_hevc.cpp index 4c5f5f6f1ad..019bcf0551d 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_enc_hevc.cpp +++ b/src/gallium/drivers/d3d12/d3d12_video_enc_hevc.cpp @@ -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
