diff --git a/src/gallium/drivers/d3d12/d3d12_video_enc.cpp b/src/gallium/drivers/d3d12/d3d12_video_enc.cpp index a72af22b8fe..01ccb52691e 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_enc.cpp +++ b/src/gallium/drivers/d3d12/d3d12_video_enc.cpp @@ -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(&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 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(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(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); } diff --git a/src/gallium/drivers/d3d12/d3d12_video_enc.h b/src/gallium/drivers/d3d12/d3d12_video_enc.h index 51e801afbf5..de15d0cd247 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_enc.h +++ b/src/gallium/drivers/d3d12/d3d12_video_enc.h @@ -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 m_DirtyRectsArray; D3D12_VIDEO_ENCODER_MOVEREGION_INFO m_MoveRectsDesc = {}; std::vector 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 /// diff --git a/src/gallium/drivers/d3d12/d3d12_video_screen.cpp b/src/gallium/drivers/d3d12/d3d12_video_screen.cpp index 6dced8132ea..c857bc1a12d 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_screen.cpp +++ b/src/gallium/drivers/d3d12/d3d12_video_screen.cpp @@ -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 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(std::ceil(capStatsResourceReqs.PictureTargetResolution.Width / static_cast(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(std::ceil(capStatsResourceReqs.PictureTargetResolution.Width / static_cast(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(std::ceil(capStatsResourceReqs.PictureTargetResolution.Width / static_cast(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(std::ceil(capStatsResourceReqs.PictureTargetResolution.Width / static_cast(capStatsResourceReqs.EncoderOutputMetadataQPMapTextureDimensions.Width))); + gpu_stats_qp.bits.log2_values_block_size = static_cast(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(std::ceil(capStatsResourceReqs.PictureTargetResolution.Width / static_cast(capStatsResourceReqs.EncoderOutputMetadataSATDMapTextureDimensions.Width))); + gpu_stats_satd.bits.log2_values_block_size = static_cast(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(std::ceil(capStatsResourceReqs.PictureTargetResolution.Width / static_cast(capStatsResourceReqs.EncoderOutputMetadataBitAllocationMapTextureDimensions.Width))); + gpu_stats_rcbits.bits.log2_values_block_size = static_cast(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; }