From 7e1982a7eb1a7b122548874aef40e2d77da710d9 Mon Sep 17 00:00:00 2001 From: Silvio Vilerino Date: Thu, 23 Oct 2025 10:40:00 -0400 Subject: [PATCH] d3d12: Use EnqueueMakeResident with GPU Wait for video permanent residency promotions Reviewed-by: Pohsiang (John) Hsu Part-of: --- src/gallium/drivers/d3d12/d3d12_residency.cpp | 57 ++++++++++++++++--- src/gallium/drivers/d3d12/d3d12_residency.h | 15 ++++- src/gallium/drivers/d3d12/d3d12_video_enc.cpp | 29 +++++++--- src/gallium/drivers/d3d12/d3d12_video_enc.h | 2 + 4 files changed, 85 insertions(+), 18 deletions(-) diff --git a/src/gallium/drivers/d3d12/d3d12_residency.cpp b/src/gallium/drivers/d3d12/d3d12_residency.cpp index ffdf4d151df..63c1ad4b232 100644 --- a/src/gallium/drivers/d3d12/d3d12_residency.cpp +++ b/src/gallium/drivers/d3d12/d3d12_residency.cpp @@ -281,8 +281,26 @@ d3d12_deinit_residency(struct d3d12_screen *screen) } void -d3d12_promote_to_permanent_residency(struct d3d12_screen *screen, struct d3d12_resource** resources, unsigned count) +d3d12_promote_to_permanent_residency( + struct d3d12_screen *screen, + struct d3d12_resource** resources, + unsigned count, + ID3D12Fence* pResidencyFence, /* NULL implies usage of synchronous MakeResident */ + uint64_t *pResidencyFenceValue /* Out: value to wait on for residency for this call */ +) { +#if MESA_DEBUG + if (pResidencyFence && !pResidencyFenceValue) + { + debug_printf("D3D12: d3d12_promote_to_permanent_residency called with a fence but no fence value out parameter!\n"); + assert(false); + } + + if (pResidencyFence && pResidencyFenceValue) { + debug_printf("D3D12: promote_to_permanent_residency called with %u resources, current fence value: %" PRIu64 "\n", count, *pResidencyFenceValue); + } +#endif // MESA_DEBUG + if (count == 0) return; @@ -291,11 +309,29 @@ d3d12_promote_to_permanent_residency(struct d3d12_screen *screen, struct d3d12_r ID3D12Pageable *pageables_to_make_resident[residency_batch_size]; unsigned num_to_make_resident = 0; - auto flush_batch = [](struct d3d12_screen *screen, ID3D12Pageable **pageables, unsigned count) { + auto flush_batch = [](struct d3d12_screen *screen, ID3D12Pageable **pageables, unsigned count, ID3D12Fence* pResidencyFence, uint64_t *pResidencyFenceValue) { if (count > 0) { - ASSERTED HRESULT hr = screen->dev->MakeResident(count, pageables); + ASSERTED HRESULT hr = S_OK; + + if (!pResidencyFence) + { + hr = screen->dev->MakeResident(count, pageables); + if(SUCCEEDED(hr)) + { + debug_printf("D3D12: Promoted %u resources to permanent residency (synchronous)\n", count); + } + } + else + { + hr = screen->dev->EnqueueMakeResident(D3D12_RESIDENCY_FLAG_NONE, count, pageables, + pResidencyFence, (*pResidencyFenceValue) + 1); + if(SUCCEEDED(hr)) + { + (*pResidencyFenceValue)++; + debug_printf("D3D12: Promoted %u resources to permanent residency (asynchronous) with fence object %p and fence value %" PRIu64 " and hr %x\n", count, pResidencyFence, *pResidencyFenceValue, (unsigned)hr); + } + } assert(SUCCEEDED(hr)); - debug_printf("D3D12: Promoted %u resources to permanent residency\n", count); } }; @@ -311,19 +347,24 @@ d3d12_promote_to_permanent_residency(struct d3d12_screen *screen, struct d3d12_r assert(num_to_make_resident < residency_batch_size); pageables_to_make_resident[num_to_make_resident++] = base_bo->res; if (num_to_make_resident == residency_batch_size) { - flush_batch(screen, pageables_to_make_resident, num_to_make_resident); + flush_batch(screen, pageables_to_make_resident, num_to_make_resident, pResidencyFence, pResidencyFenceValue); num_to_make_resident = 0; } } } } - flush_batch(screen, pageables_to_make_resident, num_to_make_resident); + flush_batch(screen, pageables_to_make_resident, num_to_make_resident, pResidencyFence, pResidencyFenceValue); mtx_unlock(&screen->submit_mutex); } void -d3d12_promote_to_permanent_residency(struct d3d12_screen *screen, struct d3d12_resource* resource) +d3d12_promote_to_permanent_residency( + struct d3d12_screen *screen, + struct d3d12_resource* resource, + ID3D12Fence* pResidencyFence, /* NULL implies usage of synchronous MakeResident */ + uint64_t *pResidencyFenceValue /* Out: value to wait on for residency for this call */ +) { // Early out for null resource or if the bo is already permanently resident if (!resource) @@ -336,5 +377,5 @@ d3d12_promote_to_permanent_residency(struct d3d12_screen *screen, struct d3d12_r return; } - d3d12_promote_to_permanent_residency(screen, &resource, 1); + d3d12_promote_to_permanent_residency(screen, &resource, 1, pResidencyFence, pResidencyFenceValue); } diff --git a/src/gallium/drivers/d3d12/d3d12_residency.h b/src/gallium/drivers/d3d12/d3d12_residency.h index 89213ea69e3..884db79c7b6 100644 --- a/src/gallium/drivers/d3d12/d3d12_residency.h +++ b/src/gallium/drivers/d3d12/d3d12_residency.h @@ -36,7 +36,18 @@ void d3d12_deinit_residency(struct d3d12_screen *screen); void -d3d12_promote_to_permanent_residency(struct d3d12_screen *screen, struct d3d12_resource** resources, unsigned count); +d3d12_promote_to_permanent_residency( + struct d3d12_screen *screen, + struct d3d12_resource** resources, + unsigned count, + ID3D12Fence* pResidencyFence = NULL, + uint64_t *pResidencyFenceValue = NULL +); void -d3d12_promote_to_permanent_residency(struct d3d12_screen *screen, struct d3d12_resource* resource); +d3d12_promote_to_permanent_residency( + struct d3d12_screen *screen, + struct d3d12_resource* resource, + ID3D12Fence* pResidencyFence = NULL, + uint64_t *pResidencyFenceValue = NULL +); diff --git a/src/gallium/drivers/d3d12/d3d12_video_enc.cpp b/src/gallium/drivers/d3d12/d3d12_video_enc.cpp index 295f19eb40e..0ec56c4ff50 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_enc.cpp +++ b/src/gallium/drivers/d3d12/d3d12_video_enc.cpp @@ -123,6 +123,9 @@ d3d12_video_encoder_flush(struct pipe_video_codec *codec) pD3D12Enc->m_spEncodeCommandQueue->Wait(casted_completion_fence->cmdqueue_fence, casted_completion_fence->value); pD3D12Enc->m_pD3D12Screen->base.fence_reference(&pD3D12Enc->m_pD3D12Screen->base, &completion_fence, NULL); + // Wait on residency fence for this frame to ensure all resources used in encoding are resident + pD3D12Enc->m_spEncodeCommandQueue->Wait(pD3D12Enc->m_spResidencyFence.Get(), pD3D12Enc->m_ResidencyFenceValue); + struct d3d12_fence *input_surface_fence = pD3D12Enc->m_inflightResourcesPool[current_pool_idx].m_InputSurfaceFence; if (input_surface_fence) d3d12_fence_wait_impl(input_surface_fence, pD3D12Enc->m_spEncodeCommandQueue.Get(), @@ -2378,6 +2381,14 @@ d3d12_video_encoder_create_command_objects(struct d3d12_video_encoder *pD3D12Enc return false; } + hr = pD3D12Enc->m_pD3D12Screen->dev->CreateFence(0, D3D12_FENCE_FLAG_SHARED, IID_PPV_ARGS(&pD3D12Enc->m_spResidencyFence)); + if (FAILED(hr)) { + debug_printf( + "[d3d12_video_encoder] d3d12_video_encoder_create_command_objects - Call to CreateFence failed with HR %x\n", + (unsigned)hr); + return false; + } + hr = pD3D12Enc->m_pD3D12Screen->dev->CreateFence(0, D3D12_FENCE_FLAG_SHARED, IID_PPV_ARGS(&pD3D12Enc->m_spLastSliceFence)); if (FAILED(hr)) { debug_printf( @@ -3293,12 +3304,10 @@ d3d12_video_encoder_encode_bitstream_impl(struct pipe_video_codec *codec, } // Make permanently resident for video use - batch promote all slice buffers - if (num_slice_objects > 0) { - d3d12_promote_to_permanent_residency(pD3D12Enc->m_pD3D12Screen, pD3D12Enc->m_pOutputBitstreamBuffers.data(), num_slice_objects); - } + d3d12_promote_to_permanent_residency(pD3D12Enc->m_pD3D12Screen, pD3D12Enc->m_pOutputBitstreamBuffers.data(), num_slice_objects, pD3D12Enc->m_spResidencyFence.Get(), &pD3D12Enc->m_ResidencyFenceValue); // Make permanently resident for video use - d3d12_promote_to_permanent_residency(pD3D12Enc->m_pD3D12Screen, pInputVideoBuffer->texture); + d3d12_promote_to_permanent_residency(pD3D12Enc->m_pD3D12Screen, &pInputVideoBuffer->texture, 1, pD3D12Enc->m_spResidencyFence.Get(), &pD3D12Enc->m_ResidencyFenceValue); size_t current_metadata_slot = d3d12_video_encoder_metadata_current_index(pD3D12Enc); @@ -3801,7 +3810,8 @@ d3d12_video_encoder_encode_bitstream_impl(struct pipe_video_codec *codec, 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_promote_to_permanent_residency(pD3D12Enc->m_pD3D12Screen, &pD3D12Enc->m_currentEncodeConfig.m_GPUQPStatsResource, + 1, pD3D12Enc->m_spResidencyFence.Get(), &pD3D12Enc->m_ResidencyFenceValue); d3d12_transition_resource_state(d3d12_context(pD3D12Enc->base.context), pD3D12Enc->m_currentEncodeConfig.m_GPUQPStatsResource, D3D12_RESOURCE_STATE_COMMON, @@ -3813,7 +3823,8 @@ d3d12_video_encoder_encode_bitstream_impl(struct pipe_video_codec *codec, 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_promote_to_permanent_residency(pD3D12Enc->m_pD3D12Screen, &pD3D12Enc->m_currentEncodeConfig.m_GPUSATDStatsResource, + 1, pD3D12Enc->m_spResidencyFence.Get(), &pD3D12Enc->m_ResidencyFenceValue); d3d12_transition_resource_state(d3d12_context(pD3D12Enc->base.context), pD3D12Enc->m_currentEncodeConfig.m_GPUSATDStatsResource, D3D12_RESOURCE_STATE_COMMON, @@ -3825,7 +3836,8 @@ d3d12_video_encoder_encode_bitstream_impl(struct pipe_video_codec *codec, 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_promote_to_permanent_residency(pD3D12Enc->m_pD3D12Screen, &pD3D12Enc->m_currentEncodeConfig.m_GPURCBitAllocationStatsResource, + 1, pD3D12Enc->m_spResidencyFence.Get(), &pD3D12Enc->m_ResidencyFenceValue); d3d12_transition_resource_state(d3d12_context(pD3D12Enc->base.context), pD3D12Enc->m_currentEncodeConfig.m_GPURCBitAllocationStatsResource, D3D12_RESOURCE_STATE_COMMON, @@ -3837,7 +3849,8 @@ d3d12_video_encoder_encode_bitstream_impl(struct pipe_video_codec *codec, 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_promote_to_permanent_residency(pD3D12Enc->m_pD3D12Screen, &pD3D12Enc->m_currentEncodeConfig.m_GPUPSNRAllocationStatsResource, + 1, pD3D12Enc->m_spResidencyFence.Get(), &pD3D12Enc->m_ResidencyFenceValue); d3d12_transition_resource_state(d3d12_context(pD3D12Enc->base.context), pD3D12Enc->m_currentEncodeConfig.m_GPUPSNRAllocationStatsResource, D3D12_RESOURCE_STATE_COMMON, diff --git a/src/gallium/drivers/d3d12/d3d12_video_enc.h b/src/gallium/drivers/d3d12/d3d12_video_enc.h index 6fe3eb876f8..34789b9c626 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_enc.h +++ b/src/gallium/drivers/d3d12/d3d12_video_enc.h @@ -581,9 +581,11 @@ struct d3d12_video_encoder size_t m_MaxMetadataBuffersCount = 0; ComPtr m_spFence; + ComPtr m_spResidencyFence; ComPtr m_spLastSliceFence; uint64_t m_fenceValue = 1u; uint64_t m_LastSliceFenceValue = 1u; + uint64_t m_ResidencyFenceValue = 0u; bool m_bPendingWorkNotFlushed = false; ComPtr m_spD3D12VideoDevice;