From 24eb46b720546e6ebde0f31766a6f10890f9643d Mon Sep 17 00:00:00 2001 From: Sil Vilerino Date: Tue, 27 May 2025 17:24:53 -0400 Subject: [PATCH] d3d12: Add video encode PSNR output stats Reviewed-by: Pohsiang (John) Hsu Reviewed-by: Jesse Natalie Part-of: --- src/gallium/drivers/d3d12/d3d12_video_enc.cpp | 35 ++++++++++++++++--- src/gallium/drivers/d3d12/d3d12_video_enc.h | 4 ++- .../drivers/d3d12/d3d12_video_screen.cpp | 31 ++++++++++++---- 3 files changed, 59 insertions(+), 11 deletions(-) diff --git a/src/gallium/drivers/d3d12/d3d12_video_enc.cpp b/src/gallium/drivers/d3d12/d3d12_video_enc.cpp index 14dcdd40f3c..b45c0aec9e4 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_enc.cpp +++ b/src/gallium/drivers/d3d12/d3d12_video_enc.cpp @@ -2277,12 +2277,14 @@ void d3d12_video_encoder_update_output_stats_resources(struct d3d12_video_encoder *pD3D12Enc, struct pipe_resource* qpmap, struct pipe_resource* satdmap, - struct pipe_resource* rcbitsmap) + struct pipe_resource* rcbitsmap, + struct pipe_resource* psnrmap) { #if D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE pD3D12Enc->m_currentEncodeConfig.m_GPUQPStatsResource = d3d12_resource(qpmap); pD3D12Enc->m_currentEncodeConfig.m_GPUSATDStatsResource = d3d12_resource(satdmap); pD3D12Enc->m_currentEncodeConfig.m_GPURCBitAllocationStatsResource = d3d12_resource(rcbitsmap); + pD3D12Enc->m_currentEncodeConfig.m_GPUPSNRAllocationStatsResource = d3d12_resource(psnrmap); #endif // D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE } @@ -2302,7 +2304,8 @@ d3d12_video_encoder_update_current_encoder_config_state(struct d3d12_video_encod d3d12_video_encoder_update_output_stats_resources(pD3D12Enc, ((struct pipe_h264_enc_picture_desc *)picture)->gpu_stats_qp_map, ((struct pipe_h264_enc_picture_desc *)picture)->gpu_stats_satd_map, - ((struct pipe_h264_enc_picture_desc *)picture)->gpu_stats_rc_bitallocation_map); + ((struct pipe_h264_enc_picture_desc *)picture)->gpu_stats_rc_bitallocation_map, + ((struct pipe_h264_enc_picture_desc *)picture)->gpu_stats_psnr); d3d12_video_encoder_update_move_rects(pD3D12Enc, ((struct pipe_h264_enc_picture_desc *)picture)->move_info); d3d12_video_encoder_update_dirty_rects(pD3D12Enc, ((struct pipe_h264_enc_picture_desc *)picture)->dirty_info); @@ -2320,7 +2323,8 @@ d3d12_video_encoder_update_current_encoder_config_state(struct d3d12_video_encod d3d12_video_encoder_update_output_stats_resources(pD3D12Enc, ((struct pipe_h265_enc_picture_desc *)picture)->gpu_stats_qp_map, ((struct pipe_h265_enc_picture_desc *)picture)->gpu_stats_satd_map, - ((struct pipe_h265_enc_picture_desc *)picture)->gpu_stats_rc_bitallocation_map); + ((struct pipe_h265_enc_picture_desc *)picture)->gpu_stats_rc_bitallocation_map, + ((struct pipe_h264_enc_picture_desc *)picture)->gpu_stats_psnr); d3d12_video_encoder_update_move_rects(pD3D12Enc, ((struct pipe_h265_enc_picture_desc *)picture)->move_info); d3d12_video_encoder_update_dirty_rects(pD3D12Enc, ((struct pipe_h265_enc_picture_desc *)picture)->dirty_info); @@ -3641,6 +3645,18 @@ d3d12_video_encoder_encode_bitstream_impl(struct pipe_video_codec *codec, d12_gpu_stats_rc_bitallocation_map = d3d12_resource_resource(pD3D12Enc->m_currentEncodeConfig.m_GPURCBitAllocationStatsResource); } + ID3D12Resource* d12_gpu_stats_psnr = NULL; + if (pD3D12Enc->m_currentEncodeConfig.m_GPUPSNRAllocationStatsResource) { + optionalMetadataFlags |= D3D12_VIDEO_ENCODER_OPTIONAL_METADATA_ENABLE_FLAG_FRAME_PSNR; + d3d12_promote_to_permanent_residency(pD3D12Enc->m_pD3D12Screen, pD3D12Enc->m_currentEncodeConfig.m_GPUPSNRAllocationStatsResource); + d3d12_transition_resource_state(d3d12_context(pD3D12Enc->base.context), + pD3D12Enc->m_currentEncodeConfig.m_GPUPSNRAllocationStatsResource, + D3D12_RESOURCE_STATE_COMMON, + D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS); + d3d12_resource_wait_idle(d3d12_context(pD3D12Enc->base.context), pD3D12Enc->m_currentEncodeConfig.m_GPUPSNRAllocationStatsResource, true /*wantToWrite*/); + d12_gpu_stats_psnr = d3d12_resource_resource(pD3D12Enc->m_currentEncodeConfig.m_GPUPSNRAllocationStatsResource); + } + D3D12_VIDEO_ENCODER_FRAME_ANALYSIS FrameAnalysis = {}; D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE FrameAnalysisReconstructedPicture = {}; std::vector pTwoPassExtraBarriers; @@ -4005,6 +4021,12 @@ d3d12_video_encoder_encode_bitstream_impl(struct pipe_video_codec *codec, D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE)); } + if (d12_gpu_stats_psnr) { + output_stats_barriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(d12_gpu_stats_psnr, + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE)); + } + spEncodeCommandList4->ResourceBarrier(static_cast(output_stats_barriers.size()), output_stats_barriers.data()); const D3D12_VIDEO_ENCODER_RESOLVE_METADATA_INPUT_ARGUMENTS1 inputMetadataCmd = { @@ -4030,7 +4052,12 @@ d3d12_video_encoder_encode_bitstream_impl(struct pipe_video_codec *codec, // ID3D12Resource *pOutputBitAllocationMap; d12_gpu_stats_rc_bitallocation_map, // D3D12_VIDEO_ENCODER_ENCODE_OPERATION_METADATA_BUFFER ResolvedFramePSNRData; - {}, + { + // ID3D12Resource *pBuffer; + d12_gpu_stats_psnr, + // UINT64 Offset; + 0u, + }, // D3D12_VIDEO_ENCODER_ENCODE_OPERATION_METADATA_BUFFER ResolvedSubregionsPSNRData; {}, }; diff --git a/src/gallium/drivers/d3d12/d3d12_video_enc.h b/src/gallium/drivers/d3d12/d3d12_video_enc.h index 8694edc636e..cb6feeb0441 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_enc.h +++ b/src/gallium/drivers/d3d12/d3d12_video_enc.h @@ -378,6 +378,7 @@ struct D3D12EncodeConfiguration struct d3d12_resource *m_GPUQPStatsResource = NULL; struct d3d12_resource *m_GPUSATDStatsResource = NULL; struct d3d12_resource *m_GPURCBitAllocationStatsResource = NULL; + struct d3d12_resource *m_GPUPSNRAllocationStatsResource = NULL; struct { // @@ -737,7 +738,8 @@ void d3d12_video_encoder_update_output_stats_resources(struct d3d12_video_encoder *pD3D12Enc, struct pipe_resource* qpmap, struct pipe_resource* satdmap, - struct pipe_resource* rcbitsmap); + struct pipe_resource* rcbitsmap, + struct pipe_resource* psnrmap); bool d3d12_video_encoder_prepare_input_buffers(struct d3d12_video_encoder *pD3D12Enc); diff --git a/src/gallium/drivers/d3d12/d3d12_video_screen.cpp b/src/gallium/drivers/d3d12/d3d12_video_screen.cpp index 973f53f6b90..c2a320d125c 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_screen.cpp +++ b/src/gallium/drivers/d3d12/d3d12_video_screen.cpp @@ -1274,11 +1274,13 @@ get_gpu_output_stats_support(D3D12_VIDEO_ENCODER_INPUT_MAP_SESSION_INFO sessionI ID3D12VideoDevice3* pD3D12VideoDevice, union pipe_enc_cap_gpu_stats_map &gpu_stats_qp, union pipe_enc_cap_gpu_stats_map &gpu_stats_satd, - union pipe_enc_cap_gpu_stats_map &gpu_stats_rcbits) + union pipe_enc_cap_gpu_stats_map &gpu_stats_rcbits, + union pipe_enc_cap_gpu_stats_psnr& psnr_support) { gpu_stats_qp.bits.supported = ((capEncoderSupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_PER_BLOCK_QP_MAP_METADATA_AVAILABLE)) ? 1u : 0u; gpu_stats_satd.bits.supported = ((capEncoderSupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_PER_BLOCK_SATD_MAP_METADATA_AVAILABLE)) ? 1u : 0u; gpu_stats_rcbits.bits.supported = ((capEncoderSupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_PER_BLOCK_RC_BIT_ALLOCATION_MAP_METADATA_AVAILABLE )) ? 1u : 0u; + psnr_support.bits.supports_y_channel = ((capEncoderSupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_FRAME_PSNR_METADATA_AVAILABLE)) ? 1u : 0u; D3D12_VIDEO_ENCODER_OPTIONAL_METADATA_ENABLE_FLAGS optionalMetadataFlags = D3D12_VIDEO_ENCODER_OPTIONAL_METADATA_ENABLE_FLAG_NONE; if (gpu_stats_qp.bits.supported) @@ -1287,6 +1289,8 @@ get_gpu_output_stats_support(D3D12_VIDEO_ENCODER_INPUT_MAP_SESSION_INFO sessionI optionalMetadataFlags |= D3D12_VIDEO_ENCODER_OPTIONAL_METADATA_ENABLE_FLAG_SATD_MAP; if (gpu_stats_rcbits.bits.supported) optionalMetadataFlags |= D3D12_VIDEO_ENCODER_OPTIONAL_METADATA_ENABLE_FLAG_RC_BIT_ALLOCATION_MAP; + if (psnr_support.bits.supports_y_channel) + optionalMetadataFlags |= D3D12_VIDEO_ENCODER_OPTIONAL_METADATA_ENABLE_FLAG_FRAME_PSNR; D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOURCE_REQUIREMENTS1 capStatsResourceReqs = { @@ -1345,6 +1349,13 @@ get_gpu_output_stats_support(D3D12_VIDEO_ENCODER_INPUT_MAP_SESSION_INFO sessionI uint32_t block_size = static_cast(std::ceil(capStatsResourceReqs.PictureTargetResolution.Width / static_cast(capStatsResourceReqs.EncoderOutputMetadataBitAllocationMapTextureDimensions.Width))); gpu_stats_rcbits.bits.log2_values_block_size = static_cast(std::log2(block_size)); } + + if ((capEncoderSupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_FRAME_PSNR_METADATA_AVAILABLE)) + { + psnr_support.bits.supports_y_channel = (capStatsResourceReqs.EncoderOutputMetadataFramePSNRComponentsNumber >= 1); + psnr_support.bits.supports_u_channel = (capStatsResourceReqs.EncoderOutputMetadataFramePSNRComponentsNumber >= 2); + psnr_support.bits.supports_u_channel = (capStatsResourceReqs.EncoderOutputMetadataFramePSNRComponentsNumber >= 3); + } } } @@ -1479,7 +1490,8 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen, union pipe_enc_cap_dirty_info &dirty_rects_support_gpu, 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_two_pass &two_pass_support, + union pipe_enc_cap_gpu_stats_psnr& psnr_support) { ComPtr spD3D12VideoDevice; struct d3d12_screen *pD3D12Screen = (struct d3d12_screen *) pscreen; @@ -1613,7 +1625,7 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen, dirty_rects_support = get_dirty_rects_support(sessionInfo, spD3D12VideoDevice.Get(), D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_CPU_BUFFER); dirty_rects_support_gpu = get_dirty_rects_support(sessionInfo, spD3D12VideoDevice.Get(), D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_GPU_TEXTURE); move_rects_support = get_move_rects_support(sessionInfo, spD3D12VideoDevice.Get()); - get_gpu_output_stats_support(sessionInfo, capEncoderSupportData1.SupportFlags, spD3D12VideoDevice.Get(), gpu_stats_qp, gpu_stats_satd, gpu_stats_rcbits); + get_gpu_output_stats_support(sessionInfo, capEncoderSupportData1.SupportFlags, spD3D12VideoDevice.Get(), gpu_stats_qp, gpu_stats_satd, gpu_stats_rcbits, psnr_support); sliced_encode_support = get_sliced_encode_support(capEncoderSupportData1.SupportFlags); qpmap_support = get_qpmap_gpuinput_support(sessionInfo, spD3D12VideoDevice.Get()); gpu_motion_input_support = get_motion_gpuinput_support(sessionInfo, spD3D12VideoDevice.Get()); @@ -1943,7 +1955,7 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen, dirty_rects_support = get_dirty_rects_support(sessionInfo, spD3D12VideoDevice.Get(), D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_CPU_BUFFER); dirty_rects_support_gpu = get_dirty_rects_support(sessionInfo, spD3D12VideoDevice.Get(), D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_GPU_TEXTURE); move_rects_support = get_move_rects_support(sessionInfo, spD3D12VideoDevice.Get()); - get_gpu_output_stats_support(sessionInfo, capEncoderSupportData1.SupportFlags, spD3D12VideoDevice.Get(), gpu_stats_qp, gpu_stats_satd, gpu_stats_rcbits); + get_gpu_output_stats_support(sessionInfo, capEncoderSupportData1.SupportFlags, spD3D12VideoDevice.Get(), gpu_stats_qp, gpu_stats_satd, gpu_stats_rcbits, psnr_support); sliced_encode_support = get_sliced_encode_support(capEncoderSupportData1.SupportFlags); gpu_motion_input_support = get_motion_gpuinput_support(sessionInfo, spD3D12VideoDevice.Get()); two_pass_support = query_two_pass_support(pscreen, sessionInfo, spD3D12VideoDevice.Get(), @@ -2467,6 +2479,7 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen, union pipe_enc_cap_qpmap gpu_qpmap_input = {}; 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 = {}; memset(&codec_specific_support, 0, sizeof(codec_specific_support)); switch (param) { case PIPE_VIDEO_CAP_REQUIRES_FLUSH_ON_END_FRAME: @@ -2539,6 +2552,7 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen, case PIPE_VIDEO_CAP_ENC_QP_MAPS: case PIPE_VIDEO_CAP_ENC_MOTION_VECTOR_MAPS: case PIPE_VIDEO_CAP_ENC_TWO_PASS: + case PIPE_VIDEO_CAP_ENC_GPU_STATS_PSNR: { if (d3d12_has_video_encode_support(pscreen, profile, @@ -2568,7 +2582,8 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen, dirty_rects_support_gpu, gpu_qpmap_input, gpu_motion_input, - two_pass_support)) { + two_pass_support, + psnr_support)) { DXGI_FORMAT format = d3d12_convert_pipe_video_profile_to_dxgi_format(profile); auto pipeFmt = d3d12_get_pipe_format(format); @@ -2673,6 +2688,8 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen, return gpu_motion_input.value; } else if (param == PIPE_VIDEO_CAP_ENC_TWO_PASS ) { 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_QUALITY_LEVEL) { @@ -2751,6 +2768,7 @@ d3d12_video_encode_requires_texture_array_dpb(struct d3d12_screen* pScreen, enum union pipe_enc_cap_qpmap gpu_qpmap_input = {}; 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 = {}; if (d3d12_has_video_encode_support(&pScreen->base, profile, maxLvlEncode, @@ -2779,7 +2797,8 @@ d3d12_video_encode_requires_texture_array_dpb(struct d3d12_screen* pScreen, enum dirty_rects_support_gpu, gpu_qpmap_input, gpu_motion_input, - two_pass_support)) + two_pass_support, + psnr_support)) { return bVideoEncodeRequiresTextureArray; }