Fix various D3D12 video decode state issues (#4038)

* Fix D3D12 video decode reference resource states

Transition both NV12 planes of active DPB references to VIDEO_DECODE_READ before DecodeFrame and restore their states afterward.
Exclude unused reference slots while preserving DXVA picture indices and use the actual DPB slot count.

* Fix D3D12 scratch descriptor heap lifetime during growth

Defer replaced heap destruction until the command-list fence completes.
Allow the deferred-release queue to retain IUnknown objects so descriptor
heaps can use the same retirement mechanism as resources.

Fixes OBJECT_DELETED_WHILE_STILL_IN_USE (#921) when draw-load growth
replaces a heap referenced by pending native video conversion commands.
This commit is contained in:
Julian Xhokaxhiu
2026-10-12 05:19:48 +02:00
committed by GitHub
parent 671f00991a
commit 61dda020c6
3 changed files with 47 additions and 8 deletions

View File

@@ -4739,7 +4739,12 @@ namespace bgfx { namespace d3d12
, (void**)&heap
) );
DX_RELEASE(m_heap, 0);
if (NULL != m_heap)
{
BX_TRACE("D3D12 scratch heap grow: retired=%p size=%u replacement=%p size=%u queue=%u"
, m_heap, m_size, heap, _num, s_renderD3D12->m_cmd.m_control.m_current);
s_renderD3D12->m_cmd.release(m_heap);
}
m_heap = heap;
m_size = _num;
m_cpuHandleStart = getCPUHandleHeapStart(m_heap);
@@ -5564,7 +5569,7 @@ namespace bgfx { namespace d3d12
return false;
}
void CommandQueueD3D12::release(ID3D12Resource* _ptr)
void CommandQueueD3D12::release(IUnknown* _ptr)
{
m_release[m_control.m_current].push_back(_ptr);
}

View File

@@ -593,7 +593,7 @@ namespace bgfx { namespace d3d12
uint64_t kick();
void finish(uint64_t _waitFence = UINT64_MAX, bool _finishAll = false);
bool tryFinish(uint64_t _waitFence);
void release(ID3D12Resource* _ptr);
void release(IUnknown* _ptr);
bool consume(uint32_t _ms = UINT32_MAX);
void addExternal(TextureHandle _handle);
@@ -649,7 +649,7 @@ namespace bgfx { namespace d3d12
uint64_t m_completedFence;
ID3D12Fence* m_fence;
CommandList m_commandList[kMaxCommandLists];
typedef stl::vector<ID3D12Resource*> ResourceArray;
typedef stl::vector<IUnknown*> ResourceArray;
ResourceArray m_release[kMaxCommandLists];
typedef stl::vector<TextureHandle> ExternalTextureArray;
ExternalTextureArray m_external;

View File

@@ -956,10 +956,30 @@ namespace bgfx { namespace d3d12
ID3D12Resource* refFrames[kNumDpbSlots] = {};
UINT refSubresources[kNumDpbSlots] = {};
for (uint32_t ii = 0; ii < m_numDpbSlots; ++ii)
refFrames[m_currentSlot] = m_dpb;
refSubresources[m_currentSlot] = UINT(m_currentSlot);
D3D12_RESOURCE_BARRIER referenceBarriers[2 * kNumDpbSlots];
uint32_t numReferenceBarriers = 0;
for (uint32_t ii = 0; ii < m_numActiveRefs; ++ii)
{
refFrames[ii] = m_dpb;
refSubresources[ii] = UINT(ii);
const uint32_t refSlot = m_referenceUsage[ii];
refFrames[refSlot] = m_dpb;
refSubresources[refSlot] = UINT(refSlot);
for (uint32_t plane = 0; plane < 2; ++plane)
{
referenceBarriers[numReferenceBarriers++] =
{
.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE,
.Transition =
{
.pResource = m_dpb,
.Subresource = plane * m_numDpbSlots + refSlot,
.StateBefore = m_dpbState[refSlot].state,
.StateAfter = D3D12_RESOURCE_STATE_VIDEO_DECODE_READ,
},
};
}
}
D3D12_VIDEO_DECODE_INPUT_STREAM_ARGUMENTS input
@@ -973,7 +993,7 @@ namespace bgfx { namespace d3d12
},
.ReferenceFrames =
{
.NumTexture2Ds = kNumDpbSlots,
.NumTexture2Ds = m_numDpbSlots,
.ppTexture2Ds = refFrames,
.pSubresources = refSubresources,
.ppHeaps = NULL,
@@ -1009,7 +1029,21 @@ namespace bgfx { namespace d3d12
}
;
if (numReferenceBarriers > 0)
{
m_videoCmd->ResourceBarrier(numReferenceBarriers, referenceBarriers);
}
m_videoCmd->DecodeFrame(m_decoder, &output, &input);
if (numReferenceBarriers > 0)
{
for (uint32_t ii = 0; ii < numReferenceBarriers; ++ii)
{
const D3D12_RESOURCE_STATES previousState = referenceBarriers[ii].Transition.StateBefore;
referenceBarriers[ii].Transition.StateBefore = referenceBarriers[ii].Transition.StateAfter;
referenceBarriers[ii].Transition.StateAfter = previousState;
}
m_videoCmd->ResourceBarrier(numReferenceBarriers, referenceBarriers);
}
if (m_referenceOnly)
{