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

Reply via email to