diff --git a/src/gallium/drivers/d3d12/d3d12_video_enc.cpp b/src/gallium/drivers/d3d12/d3d12_video_enc.cpp index dbe5993f2fd..9f9bcf6e8ca 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_enc.cpp +++ b/src/gallium/drivers/d3d12/d3d12_video_enc.cpp @@ -424,7 +424,7 @@ d3d12_video_encoder_update_qpmap_input(struct d3d12_video_encoder *pD3D12Enc, // Clear QPDelta context for this frame // memset(&pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc, 0, sizeof(pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc)); - pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[temporal_id].m_Flags = D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_NONE; + pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[temporal_id].m_Flags &= ~D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP; // // Check if CPU/GPU QP Maps are enabled and store it in the context @@ -478,6 +478,23 @@ d3d12_video_encoder_update_qpmap_input(struct d3d12_video_encoder *pD3D12Enc, #endif } +void +d3d12_video_encoder_update_rate_control_saq(struct d3d12_video_encoder *pD3D12Enc, + uint32_t saq_strength, + uint32_t temporal_id) +{ + // + // Clear SAQ flag for this frame and only enable it below if saq_strength > 0 + // + pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[temporal_id].m_Flags &= ~D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_SPATIAL_ADAPTIVE_QP; + + if (saq_strength > 0) + { + pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[temporal_id].m_Flags |= + D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_SPATIAL_ADAPTIVE_QP; + } +} + /* * Called on encoder creation with the encoder creation parameters */ @@ -2310,6 +2327,9 @@ d3d12_video_encoder_update_current_encoder_config_state(struct d3d12_video_encod ((struct pipe_h264_enc_picture_desc *)picture)->roi, ((struct pipe_h264_enc_picture_desc *)picture)->pic_ctrl.temporal_id); d3d12_video_encoder_update_two_pass_frame_settings(pD3D12Enc, codec, picture); + d3d12_video_encoder_update_rate_control_saq(pD3D12Enc, + ((struct pipe_h264_enc_picture_desc *)picture)->rate_ctrl[((struct pipe_h264_enc_picture_desc *)picture)->pic_ctrl.temporal_id].spatial_adaptive_quantization_strength, + ((struct pipe_h264_enc_picture_desc *)picture)->pic_ctrl.temporal_id); // ...encoder_config_state_h264 calls encoder support cap, set any state before this call bCodecUpdatesSuccess = d3d12_video_encoder_update_current_encoder_config_state_h264(pD3D12Enc, srcTextureDesc, picture); } break; @@ -2329,6 +2349,9 @@ d3d12_video_encoder_update_current_encoder_config_state(struct d3d12_video_encod ((struct pipe_h265_enc_picture_desc *)picture)->roi, ((struct pipe_h265_enc_picture_desc *)picture)->pic.temporal_id); d3d12_video_encoder_update_two_pass_frame_settings(pD3D12Enc, codec, picture); + d3d12_video_encoder_update_rate_control_saq(pD3D12Enc, + ((struct pipe_h265_enc_picture_desc *)picture)->rc[((struct pipe_h265_enc_picture_desc *)picture)->pic.temporal_id].spatial_adaptive_quantization_strength, + ((struct pipe_h265_enc_picture_desc *)picture)->pic.temporal_id); // ...encoder_config_state_hevc calls encoder support cap, set any state before this call bCodecUpdatesSuccess = d3d12_video_encoder_update_current_encoder_config_state_hevc(pD3D12Enc, srcTextureDesc, picture); } break; diff --git a/src/gallium/drivers/d3d12/d3d12_video_screen.cpp b/src/gallium/drivers/d3d12/d3d12_video_screen.cpp index 5e2e6bd0dc4..2f1136c4539 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_screen.cpp +++ b/src/gallium/drivers/d3d12/d3d12_video_screen.cpp @@ -627,7 +627,8 @@ d3d12_video_encode_support_caps(const D3D12_VIDEO_ENCODER_CODEC &argTargetCodec, D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOLUTION_SUPPORT_LIMITS &resolutionDepCaps, #endif uint32_t &maxQualityLevels, - struct d3d12_encode_support_cap_allocations &cap_allocations) + struct d3d12_encode_support_cap_allocations &cap_allocations, + union pipe_enc_cap_spatial_adaptive_quantization &saqSupport) { capEncoderSupportData1.NodeIndex = 0; capEncoderSupportData1.Codec = argTargetCodec; @@ -772,6 +773,13 @@ d3d12_video_encode_support_caps(const D3D12_VIDEO_ENCODER_CODEC &argTargetCodec, // consumption, with higher quality corresponds to lower speed and higher power consumption. maxQualityLevels = capEncoderSupportData1.MaxQualityVsSpeed + 1; // VA range starts from 1, D3D12 starts from 0 + saqSupport.bits.max_spatial_adaptive_quantization_strength = 0u; + + if ((capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_SPATIAL_ADAPTIVE_QP_AVAILABLE) != 0) + { + saqSupport.bits.max_spatial_adaptive_quantization_strength = 1u; + } + bool configSupported = (((capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_GENERAL_SUPPORT_OK) != 0) && (capEncoderSupportData1.ValidationFlags == D3D12_VIDEO_ENCODER_VALIDATION_FLAG_NONE)); @@ -1491,7 +1499,8 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen, union pipe_enc_cap_qpmap &qpmap_support, union pipe_enc_cap_motion_vector_map &gpu_motion_input_support, union pipe_enc_cap_two_pass &two_pass_support, - union pipe_enc_cap_gpu_stats_psnr& psnr_support) + union pipe_enc_cap_gpu_stats_psnr& psnr_support, + union pipe_enc_cap_spatial_adaptive_quantization &saqSupport) { ComPtr spD3D12VideoDevice; struct d3d12_screen *pD3D12Screen = (struct d3d12_screen *) pscreen; @@ -1574,7 +1583,8 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen, capEncoderSupportData1, resolutionDepCaps, maxQualityLevels, - cap_allocations); + cap_allocations, + saqSupport); bVideoEncodeRequiresTextureArray = (capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RECONSTRUCTED_FRAMES_REQUIRE_TEXTURE_ARRAYS) != 0; if (supportedSliceStructures == PIPE_VIDEO_CAP_SLICE_STRUCTURE_NONE) maxSlices = 0; @@ -1915,7 +1925,8 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen, capEncoderSupportData1, resolutionDepCaps, maxQualityLevels, - cap_allocations); + cap_allocations, + saqSupport); bVideoEncodeRequiresTextureArray = (capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RECONSTRUCTED_FRAMES_REQUIRE_TEXTURE_ARRAYS) != 0; if (supportedSliceStructures == PIPE_VIDEO_CAP_SLICE_STRUCTURE_NONE) maxSlices = 0; @@ -2219,7 +2230,8 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen, capEncoderSupportData1, resolutionDepCaps, maxQualityLevels, - cap_allocations); + cap_allocations, + saqSupport); bVideoEncodeRequiresTextureArray = (capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RECONSTRUCTED_FRAMES_REQUIRE_TEXTURE_ARRAYS) != 0; if (supportedSliceStructures == PIPE_VIDEO_CAP_SLICE_STRUCTURE_NONE) maxSlices = 0; @@ -2474,6 +2486,7 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen, union pipe_enc_cap_two_pass two_pass_support = {}; union pipe_enc_cap_gpu_stats_psnr psnr_support = {}; memset(&codec_specific_support, 0, sizeof(codec_specific_support)); + union pipe_enc_cap_spatial_adaptive_quantization saqSupport = {}; switch (param) { case PIPE_VIDEO_CAP_REQUIRES_FLUSH_ON_END_FRAME: return 1; @@ -2546,6 +2559,7 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen, case PIPE_VIDEO_CAP_ENC_MOTION_VECTOR_MAPS: case PIPE_VIDEO_CAP_ENC_TWO_PASS: case PIPE_VIDEO_CAP_ENC_GPU_STATS_PSNR: + case PIPE_VIDEO_CAP_ENC_SPATIAL_ADAPTIVE_QUANTIZATION: { if (d3d12_has_video_encode_support(pscreen, profile, @@ -2576,7 +2590,8 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen, gpu_qpmap_input, gpu_motion_input, two_pass_support, - psnr_support)) { + psnr_support, + saqSupport)) { DXGI_FORMAT format = d3d12_convert_pipe_video_profile_to_dxgi_format(profile); auto pipeFmt = d3d12_get_pipe_format(format); @@ -2685,6 +2700,8 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen, return two_pass_support.value; } else if (param == PIPE_VIDEO_CAP_ENC_GPU_STATS_PSNR ) { return psnr_support.value; + } else if (param == PIPE_VIDEO_CAP_ENC_SPATIAL_ADAPTIVE_QUANTIZATION ) { + return saqSupport.value; } } } else if (param == PIPE_VIDEO_CAP_ENC_QUALITY_LEVEL) { @@ -2760,6 +2777,7 @@ d3d12_video_encode_requires_texture_array_dpb(struct d3d12_screen* pScreen, enum union pipe_enc_cap_motion_vector_map gpu_motion_input = {}; union pipe_enc_cap_two_pass two_pass_support = {}; union pipe_enc_cap_gpu_stats_psnr psnr_support = {}; + union pipe_enc_cap_spatial_adaptive_quantization saqSupport = {}; if (d3d12_has_video_encode_support(&pScreen->base, profile, maxLvlEncode, @@ -2789,7 +2807,8 @@ d3d12_video_encode_requires_texture_array_dpb(struct d3d12_screen* pScreen, enum gpu_qpmap_input, gpu_motion_input, two_pass_support, - psnr_support)) + psnr_support, + saqSupport)) { return bVideoEncodeRequiresTextureArray; }