d3d12: Add video encode PSNR output stats

Reviewed-by: Pohsiang (John) Hsu <pohhsu@microsoft.com>
Reviewed-by: Jesse Natalie <jenatali@microsoft.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/35263>
This commit is contained in:
Sil Vilerino
2025-05-27 17:24:53 -04:00
committed by Marge Bot
parent 1b801a95ae
commit 24eb46b720
3 changed files with 59 additions and 11 deletions
+31 -4
View File
@@ -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<D3D12_RESOURCE_BARRIER> 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<uint32_t>(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;
{},
};
+3 -1
View File
@@ -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);
@@ -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<uint32_t>(std::ceil(capStatsResourceReqs.PictureTargetResolution.Width / static_cast<double>(capStatsResourceReqs.EncoderOutputMetadataBitAllocationMapTextureDimensions.Width)));
gpu_stats_rcbits.bits.log2_values_block_size = static_cast<uint32_t>(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<ID3D12VideoDevice3> 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;
}