From 1c31fc30917120e800e6c8932bf0e2be955544a5 Mon Sep 17 00:00:00 2001 From: Sil Vilerino Date: Thu, 30 Jan 2025 13:34:34 -0500 Subject: [PATCH] d3d12: Implement GPU Input Motion vectors Reviewed-By: Pohsiang Hsu Part-of: --- src/gallium/drivers/d3d12/d3d12_video_enc.cpp | 251 +++++++++++++++--- src/gallium/drivers/d3d12/d3d12_video_enc.h | 22 +- .../drivers/d3d12/d3d12_video_screen.cpp | 70 ++++- 3 files changed, 301 insertions(+), 42 deletions(-) diff --git a/src/gallium/drivers/d3d12/d3d12_video_enc.cpp b/src/gallium/drivers/d3d12/d3d12_video_enc.cpp index ded61eaea05..3f934bb1fa6 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_enc.cpp +++ b/src/gallium/drivers/d3d12/d3d12_video_enc.cpp @@ -337,50 +337,86 @@ d3d12_video_encoder_friendly_frame_type_h264(D3D12_VIDEO_ENCODER_FRAME_TYPE_H264 } } +#if D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE +static D3D12_VIDEO_ENCODER_FRAME_INPUT_MOTION_UNIT_PRECISION +d3d12_video_encoder_convert_move_precision(enum pipe_enc_move_info_precision_unit precision) +{ + switch (precision) + { + case PIPE_ENC_MOVE_INFO_PRECISION_UNIT_FULL_PIXEL: + { + return D3D12_VIDEO_ENCODER_FRAME_INPUT_MOTION_UNIT_PRECISION_FULL_PIXEL; + } break; + case PIPE_ENC_MOVE_INFO_PRECISION_UNIT_HALF_PIXEL: + { + return D3D12_VIDEO_ENCODER_FRAME_INPUT_MOTION_UNIT_PRECISION_HALF_PIXEL; + } break; + case PIPE_ENC_MOVE_INFO_PRECISION_UNIT_QUARTER_PIXEL: + { + return D3D12_VIDEO_ENCODER_FRAME_INPUT_MOTION_UNIT_PRECISION_QUARTER_PIXEL; + } break; + default: + { + unreachable("Unsupported pipe_enc_move_info"); + return D3D12_VIDEO_ENCODER_FRAME_INPUT_MOTION_UNIT_PRECISION_FULL_PIXEL; + } break; + } +} +#endif // D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE + void d3d12_video_encoder_update_move_rects(struct d3d12_video_encoder *pD3D12Enc, const struct pipe_enc_move_info& rects) { #if D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE - assert(rects.num_rects <= PIPE_ENC_MOVE_RECTS_NUM_MAX); - pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.NumMoveRegions = std::min(rects.num_rects, static_cast(PIPE_ENC_MOVE_RECTS_NUM_MAX)); - pD3D12Enc->m_currentEncodeConfig.m_MoveRectsArray.resize(pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.NumMoveRegions); - for (uint32_t i = 0; i < pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.NumMoveRegions; i++) { - pD3D12Enc->m_currentEncodeConfig.m_MoveRectsArray[i].SourcePoint.x = rects.rects[i].source_point.x; - pD3D12Enc->m_currentEncodeConfig.m_MoveRectsArray[i].SourcePoint.y = rects.rects[i].source_point.y; - pD3D12Enc->m_currentEncodeConfig.m_MoveRectsArray[i].DestRect.top = rects.rects[i].dest_rect.top; - pD3D12Enc->m_currentEncodeConfig.m_MoveRectsArray[i].DestRect.left = rects.rects[i].dest_rect.left; - pD3D12Enc->m_currentEncodeConfig.m_MoveRectsArray[i].DestRect.right = rects.rects[i].dest_rect.right; - pD3D12Enc->m_currentEncodeConfig.m_MoveRectsArray[i].DestRect.bottom = rects.rects[i].dest_rect.bottom; - } - pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.pMoveRegions = pD3D12Enc->m_currentEncodeConfig.m_MoveRectsArray.data(); + memset(&pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc, 0, sizeof(pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc)); + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapSource = rects.input_mode == PIPE_ENC_MOVE_INFO_INPUT_MODE_RECTS ? + D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_CPU_BUFFER : D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_GPU_TEXTURE; - pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MotionSearchModeConfiguration.MotionSearchMode = D3D12_VIDEO_ENCODER_FRAME_MOTION_SEARCH_MODE_FULL_SEARCH; - pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MotionSearchModeConfiguration.SearchDeviationLimit = 0u; - pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.SourceDPBFrameReference = rects.dpb_reference_index; - - pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.Flags = rects.overlapping_rects ? D3D12_VIDEO_ENCODER_MOVEREGION_INFO_FLAG_MULTIPLE_HINTS : - D3D12_VIDEO_ENCODER_MOVEREGION_INFO_FLAG_NONE; - - switch (rects.precision) + if (rects.input_mode == PIPE_ENC_MOVE_INFO_INPUT_MODE_RECTS) { - case PIPE_ENC_MOVE_INFO_PRECISION_UNIT_FULL_PIXEL: + assert(rects.num_rects <= PIPE_ENC_MOVE_RECTS_NUM_MAX); + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.RectsInfo.NumMoveRegions = std::min(rects.num_rects, static_cast(PIPE_ENC_MOVE_RECTS_NUM_MAX)); + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsArray.resize(pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.RectsInfo.NumMoveRegions); + for (uint32_t i = 0; i < pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.RectsInfo.NumMoveRegions; i++) { + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsArray[i].SourcePoint.x = rects.rects[i].source_point.x; + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsArray[i].SourcePoint.y = rects.rects[i].source_point.y; + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsArray[i].DestRect.top = rects.rects[i].dest_rect.top; + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsArray[i].DestRect.left = rects.rects[i].dest_rect.left; + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsArray[i].DestRect.right = rects.rects[i].dest_rect.right; + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsArray[i].DestRect.bottom = rects.rects[i].dest_rect.bottom; + } + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.RectsInfo.pMoveRegions = pD3D12Enc->m_currentEncodeConfig.m_MoveRectsArray.data(); + + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.RectsInfo.MotionSearchModeConfiguration.MotionSearchMode = D3D12_VIDEO_ENCODER_FRAME_MOTION_SEARCH_MODE_FULL_SEARCH; + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.RectsInfo.MotionSearchModeConfiguration.SearchDeviationLimit = 0u; + + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.RectsInfo.SourceDPBFrameReference = rects.dpb_reference_index; + + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.RectsInfo.Flags = rects.overlapping_rects ? D3D12_VIDEO_ENCODER_MOVEREGION_INFO_FLAG_MULTIPLE_HINTS : + D3D12_VIDEO_ENCODER_MOVEREGION_INFO_FLAG_NONE; + + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.RectsInfo.MotionUnitPrecision = d3d12_video_encoder_convert_move_precision(rects.precision); + } + else if (rects.input_mode == PIPE_ENC_MOVE_INFO_INPUT_MODE_MAP) + { + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.MotionSearchModeConfiguration.MotionSearchMode = D3D12_VIDEO_ENCODER_FRAME_MOTION_SEARCH_MODE_FULL_SEARCH; + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.MotionSearchModeConfiguration.SearchDeviationLimit = 0u; + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.NumHintsPerPixel = rects.num_hints; + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.ppMotionVectorMaps.resize(rects.num_hints); + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.ppMotionVectorMapsMetadata.resize(rects.num_hints); + for (unsigned i = 0; i < rects.num_hints; i++) { - pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MotionUnitPrecision = D3D12_VIDEO_ENCODER_FRAME_INPUT_MOTION_UNIT_PRECISION_FULL_PIXEL; - } break; - case PIPE_ENC_MOVE_INFO_PRECISION_UNIT_HALF_PIXEL: - { - pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MotionUnitPrecision = D3D12_VIDEO_ENCODER_FRAME_INPUT_MOTION_UNIT_PRECISION_HALF_PIXEL; - } break; - case PIPE_ENC_MOVE_INFO_PRECISION_UNIT_QUARTER_PIXEL: - { - pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MotionUnitPrecision = D3D12_VIDEO_ENCODER_FRAME_INPUT_MOTION_UNIT_PRECISION_QUARTER_PIXEL; - } break; - default: - { - unreachable("Unsupported pipe_enc_move_info"); - } break; + assert(i < PIPE_ENC_MOVE_MAP_MAX_HINTS); + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.ppMotionVectorMaps[i] = d3d12_resource_resource(d3d12_resource(rects.gpu_motion_vectors_map[i])); + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.pMotionVectorMapsSubresources = NULL; + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.ppMotionVectorMapsMetadata[i] = d3d12_resource_resource(d3d12_resource(rects.gpu_motion_metadata_map[i])); + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.pMotionVectorMapsMetadataSubresources = NULL; + } + + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.MotionUnitPrecision = d3d12_video_encoder_convert_move_precision(rects.precision); + // pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.PictureControlConfiguration is set later as not all the params are ready at this stage } #endif } @@ -1385,6 +1421,24 @@ d3d12_video_encoder_disable_rc_minmaxqp(struct D3D12EncodeRateControlState & rcS } } +static bool d3d12_video_encoder_is_move_regions_feature_enabled(struct d3d12_video_encoder* pD3D12Enc, D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE mapSource) +{ + if (pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapSource != mapSource) + { + return false; + } + + if (mapSource == D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_CPU_BUFFER) + { + return pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.RectsInfo.NumMoveRegions > 0; + } + else if (mapSource == D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_GPU_TEXTURE) + { + return pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.NumHintsPerPixel > 0; + } + return false; +} + static bool d3d12_video_encoder_is_dirty_regions_feature_enabled(struct d3d12_video_encoder* pD3D12Enc, D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE mapSource) { if (pD3D12Enc->m_currentEncodeConfig.m_DirtyRectsDesc.MapSource != mapSource) @@ -1618,6 +1672,14 @@ bool d3d12_video_encoder_query_d3d12_driver_caps(struct d3d12_video_encoder *pD3 d3d12_video_encoder_is_gpu_qmap_input_feature_enabled(pD3D12Enc, /*output param*/ capEncoderSupportData1.QPMap.Enabled, /*output param*/ capEncoderSupportData1.QPMap.MapSource); + capEncoderSupportData1.MotionSearch.MapSource = pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapSource; + capEncoderSupportData1.MotionSearch.Enabled = d3d12_video_encoder_is_move_regions_feature_enabled(pD3D12Enc, pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapSource); + if (capEncoderSupportData1.MotionSearch.Enabled) + { + capEncoderSupportData1.MotionSearch.MotionSearchMode = D3D12_VIDEO_ENCODER_FRAME_MOTION_SEARCH_MODE_FULL_SEARCH; + capEncoderSupportData1.MotionSearch.BidirectionalRefFrameEnabled = TRUE; + } + #endif enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile); @@ -1814,6 +1876,43 @@ bool d3d12_video_encoder_query_d3d12_driver_caps(struct d3d12_video_encoder *pD3 } } + if ((capEncoderSupportData1.MotionSearch.MapSource == D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_GPU_TEXTURE) && + (capEncoderSupportData1.MotionSearch.Enabled)) + { + // Query specifics of staging resource for move regions + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.capInputLayoutMotionVectors = + { + // UINT NodeIndex; + 0u, + // D3D12_VIDEO_ENCODER_INPUT_MAP_SESSION_INFO SessionInfo; + { + capEncoderSupportData1.Codec, + d3d12_video_encoder_get_current_profile_desc(pD3D12Enc), + d3d12_video_encoder_get_current_level_desc(pD3D12Enc), + pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format, + // D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC + pD3D12Enc->m_currentEncodeConfig.m_currentResolution, + d3d12_video_encoder_get_current_codec_config_desc(pD3D12Enc), + capEncoderSupportData1.SubregionFrameEncoding, + capEncoderSupportData1.SubregionFrameEncodingData + }, + // D3D12_VIDEO_ENCODER_INPUT_MAP_TYPE MapType; + D3D12_VIDEO_ENCODER_INPUT_MAP_TYPE_MOTION_VECTORS, + // BOOL IsSupported; + FALSE, + // UINT64 MaxResolvedBufferAllocationSize; + 0u, + }; + + hr = pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_RESOLVE_INPUT_PARAM_LAYOUT, + &pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.capInputLayoutMotionVectors, + sizeof(pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.capInputLayoutMotionVectors)); + + if (FAILED(hr)) { + debug_printf("CheckFeatureSupport D3D12_FEATURE_VIDEO_ENCODER_RESOLVE_INPUT_PARAM_LAYOUT failed with HR %x\n", hr); + return false; + } + } return true; } @@ -2289,6 +2388,28 @@ d3d12_video_encoder_prepare_input_buffers(struct d3d12_video_encoder *pD3D12Enc) } } + if (d3d12_video_encoder_is_move_regions_feature_enabled(pD3D12Enc, D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_GPU_TEXTURE)) + { + bool bNeedsCreation = (pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].m_spMotionVectorsResolvedOpaqueMap == NULL) || + (GetDesc(pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].m_spMotionVectorsResolvedOpaqueMap.Get()).Width < + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.capInputLayoutMotionVectors.MaxResolvedBufferAllocationSize); + if (bNeedsCreation) + { + pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].m_spMotionVectorsResolvedOpaqueMap.Reset(); + CD3DX12_RESOURCE_DESC desc = CD3DX12_RESOURCE_DESC::Buffer(pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.capInputLayoutMotionVectors.MaxResolvedBufferAllocationSize); + hr = pD3D12Enc->m_pD3D12Screen->dev->CreateCommittedResource(&Properties, + D3D12_HEAP_FLAG_NONE, + &desc, + D3D12_RESOURCE_STATE_COMMON, + nullptr, + IID_PPV_ARGS(&pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].m_spMotionVectorsResolvedOpaqueMap)); + if (FAILED(hr)) + { + debug_printf("CreateCommittedResource for m_spMotionVectorsResolvedOpaqueMap failed with HR %x\n", hr); + } + } + } + return SUCCEEDED(hr); } @@ -3132,10 +3253,64 @@ d3d12_video_encoder_encode_bitstream_impl(struct pipe_video_codec *codec, } D3D12_VIDEO_ENCODER_FRAME_MOTION_VECTORS motionRegions = { }; - motionRegions.MapSource = D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_CPU_BUFFER; - motionRegions.pCPUBuffer = &pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc; - if (motionRegions.pCPUBuffer->NumMoveRegions > 0) + motionRegions.MapSource = pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapSource; + if (d3d12_video_encoder_is_move_regions_feature_enabled(pD3D12Enc, motionRegions.MapSource)) + { picCtrlFlags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAG_ENABLE_MOTION_VECTORS_INPUT; + if (motionRegions.MapSource == D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_CPU_BUFFER) + { + motionRegions.MapSource = D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_CPU_BUFFER; + motionRegions.pCPUBuffer = &pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.RectsInfo; + } + else if (motionRegions.MapSource == D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_GPU_TEXTURE) + { + motionRegions.pOpaqueLayoutBuffer = pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].m_spMotionVectorsResolvedOpaqueMap.Get(); + pResolveInputDataBarriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(motionRegions.pOpaqueLayoutBuffer, + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE)); + + for (unsigned i = 0; i < pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.NumHintsPerPixel; i++) + { + pResolveInputDataBarriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.ppMotionVectorMaps[i], + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ)); + pResolveInputDataBarriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.ppMotionVectorMapsMetadata[i], + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ)); + } + + // see below std::swap for reversal to common after ResolveInputParamLayout is done + pD3D12Enc->m_spEncodeCommandList->ResourceBarrier(static_cast(pResolveInputDataBarriers.size()), + pResolveInputDataBarriers.data()); + D3D12_VIDEO_ENCODER_INPUT_MAP_DATA ResolveInputData = {}; + ResolveInputData.MapType = D3D12_VIDEO_ENCODER_INPUT_MAP_TYPE_MOTION_VECTORS; + ResolveInputData.MotionVectors.MotionSearchModeConfiguration = pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.MotionSearchModeConfiguration; + ResolveInputData.MotionVectors.NumHintsPerPixel = pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.NumHintsPerPixel; + ResolveInputData.MotionVectors.ppMotionVectorMaps = pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.ppMotionVectorMaps.data(); + ResolveInputData.MotionVectors.ppMotionVectorMapsMetadata = pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.ppMotionVectorMapsMetadata.data(); + ResolveInputData.MotionVectors.pMotionVectorMapsSubresources = pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.pMotionVectorMapsSubresources; + ResolveInputData.MotionVectors.pMotionVectorMapsMetadataSubresources = pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.pMotionVectorMapsMetadataSubresources; + ResolveInputData.MotionVectors.MotionUnitPrecision = pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.MotionUnitPrecision; + ResolveInputData.MotionVectors.PictureControlConfiguration = currentPicParams; + + D3D12_VIDEO_ENCODER_RESOLVE_INPUT_PARAM_LAYOUT_INPUT_ARGUMENTS resolveInputParamLayoutInput = + { + pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc.MapInfo.capInputLayoutMotionVectors.SessionInfo, + ResolveInputData, + }; + D3D12_VIDEO_ENCODER_RESOLVE_INPUT_PARAM_LAYOUT_OUTPUT_ARGUMENTS resolveInputParamLayoutOutput = + { + motionRegions.pOpaqueLayoutBuffer, + }; + + pD3D12Enc->m_spEncodeCommandList->ResolveInputParamLayout(&resolveInputParamLayoutInput, &resolveInputParamLayoutOutput); + for (auto &BarrierDesc : pResolveInputDataBarriers) { + std::swap(BarrierDesc.Transition.StateBefore, BarrierDesc.Transition.StateAfter); + } + pD3D12Enc->m_spEncodeCommandList->ResourceBarrier(static_cast(pResolveInputDataBarriers.size()), + pResolveInputDataBarriers.data()); + } + } ID3D12Resource* d12_gpu_stats_qp_map = NULL; D3D12_VIDEO_ENCODER_OPTIONAL_METADATA_ENABLE_FLAGS optionalMetadataFlags = D3D12_VIDEO_ENCODER_OPTIONAL_METADATA_ENABLE_FLAG_NONE; diff --git a/src/gallium/drivers/d3d12/d3d12_video_enc.h b/src/gallium/drivers/d3d12/d3d12_video_enc.h index 5ae26d8e109..6405eef06f4 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_enc.h +++ b/src/gallium/drivers/d3d12/d3d12_video_enc.h @@ -349,8 +349,27 @@ struct D3D12EncodeConfiguration std::vector m_pRateControlQPMap16Bit; } CPUInput; } m_QuantizationMatrixDesc = {}; + struct{ + D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE MapSource; + struct { // union doesn't play well with std::vector + // D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_CPU_BUFFER + D3D12_VIDEO_ENCODER_MOVEREGION_INFO RectsInfo; + // D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_GPU_TEXTURE + struct + { + D3D12_VIDEO_ENCODER_FRAME_MOTION_SEARCH_MODE_CONFIG MotionSearchModeConfiguration; + UINT NumHintsPerPixel; + std::vector ppMotionVectorMaps; + UINT* pMotionVectorMapsSubresources; + std::vector ppMotionVectorMapsMetadata; + UINT* pMotionVectorMapsMetadataSubresources; + D3D12_VIDEO_ENCODER_FRAME_INPUT_MOTION_UNIT_PRECISION MotionUnitPrecision; + D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA PictureControlConfiguration; + D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOLVE_INPUT_PARAM_LAYOUT capInputLayoutMotionVectors; + } MapInfo; + }; + } m_MoveRectsDesc = {}; 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; @@ -533,6 +552,7 @@ struct d3d12_video_encoder ComPtr m_spDirtyRectsResolvedOpaqueMap; // output of ID3D12VideoEncodeCommandList::ResolveInputParamLayout ComPtr m_spQPMapResolvedOpaqueMap; // output of ID3D12VideoEncodeCommandList::ResolveInputParamLayout + ComPtr m_spMotionVectorsResolvedOpaqueMap; // output of ID3D12VideoEncodeCommandList::ResolveInputParamLayout }; std::vector m_inflightResourcesPool; diff --git a/src/gallium/drivers/d3d12/d3d12_video_screen.cpp b/src/gallium/drivers/d3d12/d3d12_video_screen.cpp index 4f11225b639..08cf74071a7 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_screen.cpp +++ b/src/gallium/drivers/d3d12/d3d12_video_screen.cpp @@ -1069,6 +1069,60 @@ get_sliced_encode_support(D3D12_VIDEO_ENCODER_SUPPORT_FLAGS capEncoderSupportFla return sliced_encode_support; } +static +union pipe_enc_cap_motion_vector_map +get_motion_gpuinput_support(D3D12_VIDEO_ENCODER_INPUT_MAP_SESSION_INFO sessionInfo, + ID3D12VideoDevice3* pD3D12VideoDevice) +{ + D3D12_FEATURE_DATA_VIDEO_ENCODER_MOTION_SEARCH capMotionInput = + { + // UINT NodeIndex; + 0u, + // D3D12_VIDEO_ENCODER_INPUT_MAP_SESSION_INFO SessionInfo; + sessionInfo, + // D3D12_VIDEO_ENCODER_FRAME_MOTION_SEARCH_MODE MotionSearchMode; + D3D12_VIDEO_ENCODER_FRAME_MOTION_SEARCH_MODE_FULL_SEARCH, + // D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE MapSource; + D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_GPU_TEXTURE, + // BOOL BidirectionalRefFrameEnabled; + false, + // D3D12_VIDEO_ENCODER_MOTION_SEARCH_SUPPORT_FLAGS SupportFlags; + D3D12_VIDEO_ENCODER_MOTION_SEARCH_SUPPORT_FLAG_NONE, + // UINT MaxMotionHints; + 0u, + // UINT MinDeviation; + 0u, + // UINT MaxDeviation; + 0u, + // UINT MapSourcePreferenceRanking; + 0u, + // D3D12_VIDEO_ENCODER_FRAME_INPUT_MOTION_UNIT_PRECISION_SUPPORT_FLAGS MotionUnitPrecisionSupport; + D3D12_VIDEO_ENCODER_FRAME_INPUT_MOTION_UNIT_PRECISION_SUPPORT_FLAG_NONE + }; + + union pipe_enc_cap_motion_vector_map motion_gpu_support = {}; + if (SUCCEEDED(pD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_MOTION_SEARCH, &capMotionInput, sizeof(capMotionInput)))) + { + + if (capMotionInput.SupportFlags & D3D12_VIDEO_ENCODER_MOTION_SEARCH_SUPPORT_FLAG_SUPPORTED) + { + motion_gpu_support.bits.max_motion_hints = std::min(31u, capMotionInput.MaxMotionHints); + assert(motion_gpu_support.bits.max_motion_hints <= PIPE_ENC_MOVE_MAP_MAX_HINTS); + if (motion_gpu_support.bits.max_motion_hints > 0) + { + motion_gpu_support.bits.supports_precision_full_pixel = (capMotionInput.MotionUnitPrecisionSupport & D3D12_VIDEO_ENCODER_FRAME_INPUT_MOTION_UNIT_PRECISION_SUPPORT_FLAG_FULL_PIXEL) ? 1u : 0u; + motion_gpu_support.bits.supports_precision_half_pixel = (capMotionInput.MotionUnitPrecisionSupport & D3D12_VIDEO_ENCODER_FRAME_INPUT_MOTION_UNIT_PRECISION_SUPPORT_FLAG_HALF_PIXEL) ? 1u : 0u; + motion_gpu_support.bits.supports_precision_quarter_pixel = (capMotionInput.MotionUnitPrecisionSupport & D3D12_VIDEO_ENCODER_FRAME_INPUT_MOTION_UNIT_PRECISION_SUPPORT_FLAG_QUARTER_PIXEL) ? 1u : 0u; + motion_gpu_support.bits.support_multiple_dpb_refs = 0u; // (capMotionInput.SupportFlags & D3D12_VIDEO_ENCODER_MOTION_SEARCH_SUPPORT_FLAG_GPU_TEXTURE_MULTIPLE_REFERENCES) ? 1u : 0u; + motion_gpu_support.bits.pipe_pixel_vectors_map_format = PIPE_FORMAT_R16G16_SINT; // As per DX12 spec + motion_gpu_support.bits.pipe_pixel_vectors_metadata_map_format = PIPE_FORMAT_R8_UINT; // As per DX12 spec + } + } + } + + return motion_gpu_support; +} + static union pipe_enc_cap_qpmap get_qpmap_gpuinput_support(D3D12_VIDEO_ENCODER_INPUT_MAP_SESSION_INFO sessionInfo, @@ -1133,7 +1187,8 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen, union pipe_enc_cap_gpu_stats_map &gpu_stats_rcbits, union pipe_enc_cap_sliced_notifications &sliced_encode_support, union pipe_enc_cap_dirty_info &dirty_rects_support_gpu, - union pipe_enc_cap_qpmap &qpmap_support) + union pipe_enc_cap_qpmap &qpmap_support, + union pipe_enc_cap_motion_vector_map &gpu_motion_input_support) { ComPtr spD3D12VideoDevice; struct d3d12_screen *pD3D12Screen = (struct d3d12_screen *) pscreen; @@ -1270,6 +1325,7 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen, get_gpu_output_stats_support(sessionInfo, capEncoderSupportData1.SupportFlags, spD3D12VideoDevice.Get(), gpu_stats_qp, gpu_stats_satd, gpu_stats_rcbits); 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()); #endif } } break; @@ -1580,6 +1636,7 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen, 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); sliced_encode_support = get_sliced_encode_support(capEncoderSupportData1.SupportFlags); + gpu_motion_input_support = get_motion_gpuinput_support(sessionInfo, spD3D12VideoDevice.Get()); #endif } } @@ -2169,6 +2226,7 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen, union pipe_enc_cap_gpu_stats_map gpu_stats_rcbits = {}; union pipe_enc_cap_sliced_notifications sliced_encode_support = {}; union pipe_enc_cap_qpmap gpu_qpmap_input = {}; + union pipe_enc_cap_motion_vector_map gpu_motion_input = {}; memset(&codec_specific_support, 0, sizeof(codec_specific_support)); switch (param) { case PIPE_VIDEO_CAP_REQUIRES_FLUSH_ON_END_FRAME: @@ -2239,6 +2297,7 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen, case PIPE_VIDEO_CAP_ENC_SLICED_NOTIFICATIONS: case PIPE_VIDEO_CAP_ENC_DIRTY_MAPS: case PIPE_VIDEO_CAP_ENC_QP_MAPS: + case PIPE_VIDEO_CAP_ENC_MOTION_VECTOR_MAPS: { if (d3d12_has_video_encode_support(pscreen, profile, @@ -2266,7 +2325,8 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen, gpu_stats_rcbits, sliced_encode_support, dirty_rects_support_gpu, - gpu_qpmap_input)) { + gpu_qpmap_input, + gpu_motion_input)) { DXGI_FORMAT format = d3d12_convert_pipe_video_profile_to_dxgi_format(profile); auto pipeFmt = d3d12_get_pipe_format(format); @@ -2367,6 +2427,8 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen, return dirty_rects_support_gpu.value; } else if (param == PIPE_VIDEO_CAP_ENC_QP_MAPS) { return gpu_qpmap_input.value; + } else if (param == PIPE_VIDEO_CAP_ENC_MOTION_VECTOR_MAPS) { + return gpu_motion_input.value; } } } else if (param == PIPE_VIDEO_CAP_ENC_QUALITY_LEVEL) { @@ -2443,6 +2505,7 @@ d3d12_video_encode_requires_texture_array_dpb(struct d3d12_screen* pScreen, enum union pipe_enc_cap_gpu_stats_map gpu_stats_rcbits = {}; union pipe_enc_cap_sliced_notifications sliced_encode_support = {}; union pipe_enc_cap_qpmap gpu_qpmap_input = {}; + union pipe_enc_cap_motion_vector_map gpu_motion_input = {}; if (d3d12_has_video_encode_support(&pScreen->base, profile, maxLvlEncode, @@ -2469,7 +2532,8 @@ d3d12_video_encode_requires_texture_array_dpb(struct d3d12_screen* pScreen, enum gpu_stats_rcbits, sliced_encode_support, dirty_rects_support_gpu, - gpu_qpmap_input)) + gpu_qpmap_input, + gpu_motion_input)) { return bVideoEncodeRequiresTextureArray; }