d3d12: Add support for QP, SATD and RC bits output stats

Reviewed-By: Pohsiang Hsu <pohhsu@microsoft.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/34844>
This commit is contained in:
Sil Vilerino 2024-09-16 08:53:25 -04:00 committed by Marge Bot
parent 25726509ff
commit c5f5ee41c8
3 changed files with 310 additions and 9 deletions

View file

@ -1695,6 +1695,19 @@ d3d12_video_encoder_get_current_max_dpb_capacity(struct d3d12_video_encoder *pD3
}
}
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)
{
#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);
#endif // D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE
}
bool
d3d12_video_encoder_update_current_encoder_config_state(struct d3d12_video_encoder *pD3D12Enc,
D3D12_VIDEO_SAMPLE srcTextureDesc,
@ -1708,6 +1721,11 @@ d3d12_video_encoder_update_current_encoder_config_state(struct d3d12_video_encod
#if VIDEO_CODEC_H264ENC
case PIPE_VIDEO_FORMAT_MPEG4_AVC:
{
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);
d3d12_video_encoder_update_move_rects(pD3D12Enc, ((struct pipe_h264_enc_picture_desc *)picture)->move_rects);
d3d12_video_encoder_update_dirty_rects(pD3D12Enc, ((struct pipe_h264_enc_picture_desc *)picture)->dirty_rects);
// ...encoder_config_state_h264 calls encoder support cap, set any state before this call
@ -1717,6 +1735,11 @@ d3d12_video_encoder_update_current_encoder_config_state(struct d3d12_video_encod
#if VIDEO_CODEC_H265ENC
case PIPE_VIDEO_FORMAT_HEVC:
{
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);
d3d12_video_encoder_update_move_rects(pD3D12Enc, ((struct pipe_h265_enc_picture_desc *)picture)->move_rects);
d3d12_video_encoder_update_dirty_rects(pD3D12Enc, ((struct pipe_h265_enc_picture_desc *)picture)->dirty_rects);
// ...encoder_config_state_hevc calls encoder support cap, set any state before this call
@ -1919,10 +1942,35 @@ d3d12_video_encoder_prepare_output_buffers(struct d3d12_video_encoder *pD3D12Enc
pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.PictureTargetResolution =
pD3D12Enc->m_currentEncodeConfig.m_currentResolution;
#if D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE
// Assume all stats will be required and use max allocation to avoid reallocating between frames
pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.OptionalMetadata = D3D12_VIDEO_ENCODER_OPTIONAL_METADATA_ENABLE_FLAG_QP_MAP |
D3D12_VIDEO_ENCODER_OPTIONAL_METADATA_ENABLE_FLAG_SATD_MAP |
D3D12_VIDEO_ENCODER_OPTIONAL_METADATA_ENABLE_FLAG_RC_BIT_ALLOCATION_MAP;
pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.CodecConfiguration = d3d12_video_encoder_get_current_codec_config_desc(pD3D12Enc);
HRESULT hr = pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport(
D3D12_FEATURE_VIDEO_ENCODER_RESOURCE_REQUIREMENTS1,
&pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps,
sizeof(pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps));
if (FAILED(hr)) {
debug_printf("CheckFeatureSupport D3D12_FEATURE_VIDEO_ENCODER_RESOURCE_REQUIREMENTS1 failed with HR %x\n", hr);
debug_printf("Falling back to check previous query version D3D12_FEATURE_VIDEO_ENCODER_RESOURCE_REQUIREMENTS...\n");
// D3D12_FEATURE_VIDEO_ENCODER_RESOURCE_REQUIREMENTS1 extends D3D12_FEATURE_VIDEO_ENCODER_RESOURCE_REQUIREMENTS
// in a binary compatible way, so just cast it and try with the older query D3D12_FEATURE_VIDEO_ENCODER_RESOURCE_REQUIREMENTS
D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOURCE_REQUIREMENTS* casted_down_cap_data = reinterpret_cast<D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOURCE_REQUIREMENTS*>(&pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps);
hr = pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_RESOURCE_REQUIREMENTS,
casted_down_cap_data,
sizeof(*casted_down_cap_data));
}
#else
HRESULT hr = pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport(
D3D12_FEATURE_VIDEO_ENCODER_RESOURCE_REQUIREMENTS,
&pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps,
sizeof(pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps));
#endif
if (FAILED(hr)) {
debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
@ -2467,6 +2515,43 @@ d3d12_video_encoder_encode_bitstream(struct pipe_video_codec * codec,
if (motionRegions.pCPUBuffer->NumMoveRegions > 0)
picCtrlFlags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAG_ENABLE_MOTION_VECTORS_INPUT;
ID3D12Resource* d12_gpu_stats_qp_map = NULL;
D3D12_VIDEO_ENCODER_OPTIONAL_METADATA_ENABLE_FLAGS optionalMetadataFlags = D3D12_VIDEO_ENCODER_OPTIONAL_METADATA_ENABLE_FLAG_NONE;
if (pD3D12Enc->m_currentEncodeConfig.m_GPUQPStatsResource) {
optionalMetadataFlags |= D3D12_VIDEO_ENCODER_OPTIONAL_METADATA_ENABLE_FLAG_QP_MAP;
d3d12_promote_to_permanent_residency(pD3D12Enc->m_pD3D12Screen, pD3D12Enc->m_currentEncodeConfig.m_GPUQPStatsResource);
d3d12_transition_resource_state(d3d12_context(pD3D12Enc->base.context),
pD3D12Enc->m_currentEncodeConfig.m_GPUQPStatsResource,
D3D12_RESOURCE_STATE_COMMON,
D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
d3d12_resource_wait_idle(d3d12_context(pD3D12Enc->base.context), pD3D12Enc->m_currentEncodeConfig.m_GPUQPStatsResource, true /*wantToWrite*/);
d12_gpu_stats_qp_map = d3d12_resource_resource(pD3D12Enc->m_currentEncodeConfig.m_GPUQPStatsResource);
}
ID3D12Resource* d12_gpu_stats_satd_map = NULL;
if (pD3D12Enc->m_currentEncodeConfig.m_GPUSATDStatsResource) {
optionalMetadataFlags |= D3D12_VIDEO_ENCODER_OPTIONAL_METADATA_ENABLE_FLAG_SATD_MAP;
d3d12_promote_to_permanent_residency(pD3D12Enc->m_pD3D12Screen, pD3D12Enc->m_currentEncodeConfig.m_GPUSATDStatsResource);
d3d12_transition_resource_state(d3d12_context(pD3D12Enc->base.context),
pD3D12Enc->m_currentEncodeConfig.m_GPUSATDStatsResource,
D3D12_RESOURCE_STATE_COMMON,
D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
d3d12_resource_wait_idle(d3d12_context(pD3D12Enc->base.context), pD3D12Enc->m_currentEncodeConfig.m_GPUSATDStatsResource, true /*wantToWrite*/);
d12_gpu_stats_satd_map = d3d12_resource_resource(pD3D12Enc->m_currentEncodeConfig.m_GPUSATDStatsResource);
}
ID3D12Resource* d12_gpu_stats_rc_bitallocation_map = NULL;
if (pD3D12Enc->m_currentEncodeConfig.m_GPURCBitAllocationStatsResource) {
optionalMetadataFlags |= D3D12_VIDEO_ENCODER_OPTIONAL_METADATA_ENABLE_FLAG_RC_BIT_ALLOCATION_MAP;
d3d12_promote_to_permanent_residency(pD3D12Enc->m_pD3D12Screen, pD3D12Enc->m_currentEncodeConfig.m_GPURCBitAllocationStatsResource);
d3d12_transition_resource_state(d3d12_context(pD3D12Enc->base.context),
pD3D12Enc->m_currentEncodeConfig.m_GPURCBitAllocationStatsResource,
D3D12_RESOURCE_STATE_COMMON,
D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
d3d12_resource_wait_idle(d3d12_context(pD3D12Enc->base.context), pD3D12Enc->m_currentEncodeConfig.m_GPURCBitAllocationStatsResource, true /*wantToWrite*/);
d12_gpu_stats_rc_bitallocation_map = d3d12_resource_resource(pD3D12Enc->m_currentEncodeConfig.m_GPURCBitAllocationStatsResource);
}
const D3D12_VIDEO_ENCODER_ENCODEFRAME_INPUT_ARGUMENTS1 inputStreamArguments = {
#else
const D3D12_VIDEO_ENCODER_ENCODEFRAME_INPUT_ARGUMENTS inputStreamArguments = {
@ -2511,7 +2596,7 @@ d3d12_video_encoder_encode_bitstream(struct pipe_video_codec * codec,
// ... extra params to initialize D3D12_VIDEO_ENCODER_ENCODEFRAME_INPUT_ARGUMENTS1
, // extra comma from last param above #if
// D3D12_VIDEO_ENCODER_OPTIONAL_METADATA_ENABLE_FLAGS OptionalMetadata;
D3D12_VIDEO_ENCODER_OPTIONAL_METADATA_ENABLE_FLAG_NONE, // must match with ResolveEncodeOutputMetadata flags
optionalMetadataFlags, // must match with ResolveEncodeOutputMetadata flags
#endif
};
@ -2588,6 +2673,31 @@ d3d12_video_encoder_encode_bitstream(struct pipe_video_codec * codec,
pD3D12Enc->m_spEncodeCommandList->ResourceBarrier(_countof(rgResolveMetadataStateTransitions),
rgResolveMetadataStateTransitions);
#if D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE
std::vector<D3D12_RESOURCE_BARRIER> output_stats_barriers;
if (d12_gpu_stats_qp_map) {
output_stats_barriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(d12_gpu_stats_qp_map,
D3D12_RESOURCE_STATE_COMMON,
D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE));
}
if (d12_gpu_stats_satd_map) {
output_stats_barriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(d12_gpu_stats_satd_map,
D3D12_RESOURCE_STATE_COMMON,
D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE));
}
if (d12_gpu_stats_rc_bitallocation_map) {
output_stats_barriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(d12_gpu_stats_rc_bitallocation_map,
D3D12_RESOURCE_STATE_COMMON,
D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE));
}
pD3D12Enc->m_spEncodeCommandList->ResourceBarrier(static_cast<uint32_t>(output_stats_barriers.size()),
output_stats_barriers.data());
#endif
#if D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE
const D3D12_VIDEO_ENCODER_RESOLVE_METADATA_INPUT_ARGUMENTS1 inputMetadataCmd = {
#else
@ -2603,7 +2713,7 @@ d3d12_video_encoder_encode_bitstream(struct pipe_video_codec * codec,
// ... extra params to initialize D3D12_VIDEO_ENCODER_RESOLVE_METADATA_INPUT_ARGUMENTS1
, // extra comma from last param above #if
// D3D12_VIDEO_ENCODER_OPTIONAL_METADATA_ENABLE_FLAGS OptionalMetadata;
D3D12_VIDEO_ENCODER_OPTIONAL_METADATA_ENABLE_FLAG_NONE, // must match with EncodeFrame flags
optionalMetadataFlags, // must match with EncodeFrame flags
// D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION CodecConfiguration;
d3d12_video_encoder_get_current_codec_config_desc(pD3D12Enc),
#endif
@ -2620,11 +2730,11 @@ d3d12_video_encoder_encode_bitstream(struct pipe_video_codec * codec,
// ... extra params to initialize D3D12_VIDEO_ENCODER_RESOLVE_METADATA_OUTPUT_ARGUMENTS
, // extra comma from last param above #if
// ID3D12Resource *pOutputQPMap;
NULL,
d12_gpu_stats_qp_map,
// ID3D12Resource *pOutputSATDMap;
NULL,
d12_gpu_stats_satd_map,
// ID3D12Resource *pOutputBitAllocationMap;
NULL,
d12_gpu_stats_rc_bitallocation_map,
#endif
};
@ -2673,6 +2783,16 @@ d3d12_video_encoder_encode_bitstream(struct pipe_video_codec * codec,
pD3D12Enc->m_spEncodeCommandList->ResourceBarrier(_countof(rgRevertResolveMetadataStateTransitions),
rgRevertResolveMetadataStateTransitions);
#if D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE
// Revert output_stats_barriers
for (auto &BarrierDesc : output_stats_barriers) {
std::swap(BarrierDesc.Transition.StateBefore, BarrierDesc.Transition.StateAfter);
}
pD3D12Enc->m_spEncodeCommandList->ResourceBarrier(static_cast<uint32_t>(output_stats_barriers.size()),
output_stats_barriers.data());
#endif
debug_printf("[d3d12_video_encoder] d3d12_video_encoder_encode_bitstream finalized for fenceValue: %" PRIu64 "\n",
pD3D12Enc->m_fenceValue);
}

View file

@ -185,8 +185,11 @@ struct D3D12EncodeCapabilities
// The maximum number of slices that the output of the current frame to be encoded will contain
uint32_t m_MaxSlicesInOutput = 0;
#if D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE
D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOURCE_REQUIREMENTS1 m_ResourceRequirementsCaps = {};
#else
D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOURCE_REQUIREMENTS m_ResourceRequirementsCaps = {};
#endif
};
struct D3D12EncodeRateControlState
@ -301,6 +304,9 @@ struct D3D12EncodeConfiguration
std::vector<RECT> m_DirtyRectsArray;
D3D12_VIDEO_ENCODER_MOVEREGION_INFO m_MoveRectsDesc = {};
std::vector<D3D12_VIDEO_ENCODER_MOVE_RECT> m_MoveRectsArray;
struct d3d12_resource *m_GPUQPStatsResource = NULL;
struct d3d12_resource *m_GPUSATDStatsResource = NULL;
struct d3d12_resource *m_GPURCBitAllocationStatsResource = NULL;
#endif
};
@ -585,6 +591,11 @@ d3d12_video_encoder_update_dirty_rects(struct d3d12_video_encoder *pD3D12Enc,
void
d3d12_video_encoder_update_move_rects(struct d3d12_video_encoder *pD3D12Enc,
const struct pipe_enc_move_rects& rects);
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);
///
/// d3d12_video_encoder functions ends
///

View file

@ -912,7 +912,10 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen,
union pipe_enc_cap_roi &roi_support,
bool &bVideoEncodeRequiresTextureArray,
union pipe_enc_cap_dirty_rect &dirty_rects_support,
union pipe_enc_cap_move_rect &move_rects_support)
union pipe_enc_cap_move_rect &move_rects_support,
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)
{
ComPtr<ID3D12VideoDevice3> spD3D12VideoDevice;
struct d3d12_screen *pD3D12Screen = (struct d3d12_screen *) pscreen;
@ -1115,6 +1118,79 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen,
move_rects_support.bits.supports_precision_quarter_pixel = (capMotionVectors.MotionUnitPrecisionSupport & D3D12_VIDEO_ENCODER_FRAME_INPUT_MOTION_UNIT_PRECISION_SUPPORT_FLAG_QUARTER_PIXEL) ? 1u : 0u;
}
}
///
/// GPU stats caps
/// QP Map output
/// SATD Map output
/// RC Bit allocation Map output
///
{
gpu_stats_qp.bits.supported = ((capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_PER_BLOCK_QP_MAP_METADATA_AVAILABLE)) ? 1u : 0u;
gpu_stats_satd.bits.supported = ((capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_PER_BLOCK_SATD_MAP_METADATA_AVAILABLE)) ? 1u : 0u;
gpu_stats_rcbits.bits.supported = ((capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_PER_BLOCK_RC_BIT_ALLOCATION_MAP_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)
optionalMetadataFlags |= D3D12_VIDEO_ENCODER_OPTIONAL_METADATA_ENABLE_FLAG_QP_MAP;
if (gpu_stats_satd.bits.supported)
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;
D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOURCE_REQUIREMENTS1 capStatsResourceReqs =
{
// UINT NodeIndex; // input
0u,
// D3D12_VIDEO_ENCODER_CODEC Codec; // input
sessionInfo.Codec,
// D3D12_VIDEO_ENCODER_PROFILE_DESC Profile; // input
sessionInfo.Profile,
// DXGI_FORMAT InputFormat; // input
sessionInfo.InputFormat,
// D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC PictureTargetResolution; // input
sessionInfo.InputResolution,
// BOOL IsSupported; // output
FALSE,
// UINT CompressedBitstreamBufferAccessAlignment; // output
0u,
// UINT EncoderMetadataBufferAccessAlignment; // output
0u,
// UINT MaxEncoderOutputMetadataBufferSize; // output
0u,
// D3D12_VIDEO_ENCODER_OPTIONAL_METADATA_ENABLE_FLAGS OptionalMetadata; // input
optionalMetadataFlags,
// D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION CodecConfiguration; // input
capEncoderSupportData1.CodecConfiguration,
// D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC EncoderOutputMetadataQPMapTextureDimensions; // output
{0u, 0u},
// D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC EncoderOutputMetadataSATDMapTextureDimensions; // output
{0u, 0u},
// D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC EncoderOutputMetadataBitAllocationMapTextureDimensions; // output
{0u, 0u},
};
if (SUCCEEDED(spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_RESOURCE_REQUIREMENTS1, &capStatsResourceReqs, sizeof(capStatsResourceReqs))))
{
if (gpu_stats_qp.bits.supported) {
gpu_stats_qp.bits.pipe_pixel_format = (sessionInfo.Codec == D3D12_VIDEO_ENCODER_CODEC_AV1) ? PIPE_FORMAT_R16_SINT : PIPE_FORMAT_R8_SINT;
uint32_t block_size = static_cast<uint32_t>(std::ceil(capStatsResourceReqs.PictureTargetResolution.Width / static_cast<double>(capStatsResourceReqs.EncoderOutputMetadataQPMapTextureDimensions.Width)));
gpu_stats_qp.bits.log2_values_block_size = std::log2(block_size);
}
if (gpu_stats_satd.bits.supported) {
gpu_stats_satd.bits.pipe_pixel_format = PIPE_FORMAT_R32_UINT;
uint32_t block_size = static_cast<uint32_t>(std::ceil(capStatsResourceReqs.PictureTargetResolution.Width / static_cast<double>(capStatsResourceReqs.EncoderOutputMetadataSATDMapTextureDimensions.Width)));
gpu_stats_satd.bits.log2_values_block_size = std::log2(block_size);
}
if (gpu_stats_rcbits.bits.supported) {
gpu_stats_rcbits.bits.pipe_pixel_format = PIPE_FORMAT_R32_UINT;
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 = std::log2(block_size);
}
}
}
#endif
}
} break;
@ -1491,6 +1567,79 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen,
move_rects_support.bits.supports_precision_quarter_pixel = (capMotionVectors.MotionUnitPrecisionSupport & D3D12_VIDEO_ENCODER_FRAME_INPUT_MOTION_UNIT_PRECISION_SUPPORT_FLAG_QUARTER_PIXEL) ? 1u : 0u;
}
}
///
/// GPU stats caps
/// QP Map output
/// SATD Map output
/// RC Bit allocation Map output
///
{
gpu_stats_qp.bits.supported = ((capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_PER_BLOCK_QP_MAP_METADATA_AVAILABLE)) ? 1u : 0u;
gpu_stats_satd.bits.supported = ((capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_PER_BLOCK_SATD_MAP_METADATA_AVAILABLE)) ? 1u : 0u;
gpu_stats_rcbits.bits.supported = ((capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_PER_BLOCK_RC_BIT_ALLOCATION_MAP_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)
optionalMetadataFlags |= D3D12_VIDEO_ENCODER_OPTIONAL_METADATA_ENABLE_FLAG_QP_MAP;
if (gpu_stats_satd.bits.supported)
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;
D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOURCE_REQUIREMENTS1 capStatsResourceReqs =
{
// UINT NodeIndex; // input
0u,
// D3D12_VIDEO_ENCODER_CODEC Codec; // input
sessionInfo.Codec,
// D3D12_VIDEO_ENCODER_PROFILE_DESC Profile; // input
sessionInfo.Profile,
// DXGI_FORMAT InputFormat; // input
sessionInfo.InputFormat,
// D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC PictureTargetResolution; // input
sessionInfo.InputResolution,
// BOOL IsSupported; // output
FALSE,
// UINT CompressedBitstreamBufferAccessAlignment; // output
0u,
// UINT EncoderMetadataBufferAccessAlignment; // output
0u,
// UINT MaxEncoderOutputMetadataBufferSize; // output
0u,
// D3D12_VIDEO_ENCODER_OPTIONAL_METADATA_ENABLE_FLAGS OptionalMetadata; // input
optionalMetadataFlags,
// D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION CodecConfiguration; // input
capEncoderSupportData1.CodecConfiguration,
// D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC EncoderOutputMetadataQPMapTextureDimensions; // output
{0u, 0u},
// D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC EncoderOutputMetadataSATDMapTextureDimensions; // output
{0u, 0u},
// D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC EncoderOutputMetadataBitAllocationMapTextureDimensions; // output
{0u, 0u},
};
if (SUCCEEDED(spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_RESOURCE_REQUIREMENTS1, &capStatsResourceReqs, sizeof(capStatsResourceReqs))))
{
if (gpu_stats_qp.bits.supported) {
gpu_stats_qp.bits.pipe_pixel_format = (sessionInfo.Codec == D3D12_VIDEO_ENCODER_CODEC_AV1) ? PIPE_FORMAT_R16_SINT : PIPE_FORMAT_R8_SINT;
uint32_t block_size = static_cast<uint32_t>(std::ceil(capStatsResourceReqs.PictureTargetResolution.Width / static_cast<double>(capStatsResourceReqs.EncoderOutputMetadataQPMapTextureDimensions.Width)));
gpu_stats_qp.bits.log2_values_block_size = static_cast<uint32_t>(std::log2(block_size));
}
if (gpu_stats_satd.bits.supported) {
gpu_stats_satd.bits.pipe_pixel_format = PIPE_FORMAT_R32_UINT;
uint32_t block_size = static_cast<uint32_t>(std::ceil(capStatsResourceReqs.PictureTargetResolution.Width / static_cast<double>(capStatsResourceReqs.EncoderOutputMetadataSATDMapTextureDimensions.Width)));
gpu_stats_satd.bits.log2_values_block_size = static_cast<uint32_t>(std::log2(block_size));
}
if (gpu_stats_rcbits.bits.supported) {
gpu_stats_rcbits.bits.pipe_pixel_format = PIPE_FORMAT_R32_UINT;
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));
}
}
}
#endif
}
}
@ -2073,6 +2222,9 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen,
union pipe_enc_cap_dirty_rect dirty_rects_support = {};
union pipe_enc_cap_move_rect move_rects_support = {};
struct d3d12_encode_codec_support codec_specific_support;
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 = {};
memset(&codec_specific_support, 0, sizeof(codec_specific_support));
switch (param) {
case PIPE_VIDEO_CAP_REQUIRES_FLUSH_ON_END_FRAME:
@ -2137,6 +2289,9 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen,
case PIPE_VIDEO_CAP_ENC_MAX_DPB_CAPACITY:
case PIPE_VIDEO_CAP_ENC_DIRTY_RECTS:
case PIPE_VIDEO_CAP_ENC_MOVE_RECTS:
case PIPE_VIDEO_CAP_ENC_GPU_STATS_QP_MAP:
case PIPE_VIDEO_CAP_ENC_GPU_STATS_SATD_MAP:
case PIPE_VIDEO_CAP_ENC_GPU_STATS_RATE_CONTROL_BITS_MAP:
{
if (d3d12_has_video_encode_support(pscreen,
profile,
@ -2158,7 +2313,10 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen,
roi_support,
bVideoEncodeRequiresTextureArray,
dirty_rects_support,
move_rects_support)) {
move_rects_support,
gpu_stats_qp,
gpu_stats_satd,
gpu_stats_rcbits)) {
DXGI_FORMAT format = d3d12_convert_pipe_video_profile_to_dxgi_format(profile);
auto pipeFmt = d3d12_get_pipe_format(format);
@ -2247,6 +2405,12 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen,
return dirty_rects_support.value;
} else if (param == PIPE_VIDEO_CAP_ENC_MOVE_RECTS) {
return move_rects_support.value;
} else if (param == PIPE_VIDEO_CAP_ENC_GPU_STATS_QP_MAP) {
return gpu_stats_qp.value;
} else if (param == PIPE_VIDEO_CAP_ENC_GPU_STATS_SATD_MAP) {
return gpu_stats_satd.value;
} else if (param == PIPE_VIDEO_CAP_ENC_GPU_STATS_RATE_CONTROL_BITS_MAP) {
return gpu_stats_rcbits.value;
}
}
} else if (param == PIPE_VIDEO_CAP_ENC_QUALITY_LEVEL) {
@ -2317,6 +2481,9 @@ d3d12_video_encode_requires_texture_array_dpb(struct d3d12_screen* pScreen, enum
memset(&codec_specific_support, 0, sizeof(codec_specific_support));
union pipe_enc_cap_dirty_rect dirty_rects_support = {};
union pipe_enc_cap_move_rect move_rects_support = {};
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 = {};
if (d3d12_has_video_encode_support(&pScreen->base,
profile,
maxLvlEncode,
@ -2337,7 +2504,10 @@ d3d12_video_encode_requires_texture_array_dpb(struct d3d12_screen* pScreen, enum
roi_support,
bVideoEncodeRequiresTextureArray,
dirty_rects_support,
move_rects_support))
move_rects_support,
gpu_stats_qp,
gpu_stats_satd,
gpu_stats_rcbits))
{
return bVideoEncodeRequiresTextureArray;
}