Page 1 of 2

D3D12Texture Sample - flickering texture

Posted: Mon May 11, 2020 1:04 pm
by MachTwo
Hello,

If you follow the D3D12Texture SDK example, and place the CursorTexture over the Mooney MFD (as per the example instructions) - the entire VC texture object area flickers.

You can easily reproduce this issue by running the above example whilst stressing the CPU/GPU using HeavyLoad:

https://www.jam-software.com/heavyload

We would really like to see this issue resolved for v5 - as it essentially breaks any DX12 RTT implementations.
Regards,

Andrew

Re: D3D12Texture Sample - flickering texture

Posted: Sat May 16, 2020 6:28 am
by MachTwo
Hi Rob / Beau -

Did you have any luck reproducing this?

If it helps - you can have any number of RTT’s; they will all flicker at the same time.

Re: D3D12Texture Sample - flickering texture

Posted: Fri May 29, 2020 10:18 am
by lkalam
Hello guys,

would it be at all possible to have a look at this? It is very easy to reproduce given the steps above... If this is not fixed in HF2, a lot of functionality will be lost.

Thank you,

Re: D3D12Texture Sample - flickering texture

Posted: Fri Jun 19, 2020 7:25 pm
by MachTwo
I've read here that the HF2 release is imminent and yet there has been no word from anyone at LM on this issue.

It will be disappointing to see this issue remain in HF2 having provided very simple steps to reproduce.

Re: D3D12Texture Sample - flickering texture

Posted: Tue Aug 18, 2020 5:15 pm
by Beau Hollis
Sorry we missed this post. Is this still happening in HF2? It may be that we resolved issues with our internal texture plugin based features (radar, AR pass-though cameras, etc) and the change to the dx12 rendering utilities didn't get merged over to the sample. We do have some 3rd parties using texture plugins without flashing issues, so hopefully it's an issue with the sample itself and not the core engine.

Re: D3D12Texture Sample - flickering texture

Posted: Wed Aug 19, 2020 5:32 am
by MachTwo
Hi Beau,

Thanks for your reply.

Yes, we’re still seeing this in HF2. The issue is prominent when VC Mipmaps are selected to OFF, Enhanced Atmosphere selected OFF and the D3D sample is used under load (easy to reproduce whilst stressing the CPU/GPU with HeavyLoad as described above).

If there are updates to be made to the sample, would it be possible to make those available to us so that we can test here with HF2?

Re: D3D12Texture Sample - flickering texture

Posted: Tue Sep 01, 2020 5:39 pm
by Beau Hollis
If we can reproduce the issue and fix it in the sample, I'll post the code changes here on this thread.

Re: D3D12Texture Sample - flickering texture

Posted: Tue Sep 01, 2020 7:46 pm
by Beau Hollis
I looked back over the sample code, and I see the issue. I'll write a ticket to improve the sample, but I can't say for sure when we'll get around to it.

In the meantime, we have a couple of other samples that are more robust and use the PipelineState helper class we use for internal plugins like the VR and the air to ground radar. The OpenGLTexture and OpenCVStereoCamera, both contain a util folder with helpful dx12 utility classes including RenderHelper.h which contains the PipelineState class. This class handles the logic for waiting on your command allocator to be done working on the GPU before reusing it on the CPU. The two functions of interest here are Execute and Reset. Execute signals a fence after the command list is executed and reset, waits for that fence before resetting.

These should work without flicker, but may not perform as well under high load as some of our internal use add-ons. The version of RenderUtil we use internally has been updated to use a pool allocators so that you don't get CPU stalls waiting for the GPU while under heavy load. Below is the newer version of this utility used by our VR add-on. It includes a basic CommandAllocatorQueue that is essentially just a small tripple-buffered ring buffer. Double buffering would be enough in general, but if you plan to execute/reset more than once per frame, you may need to increase the size of the queue to prevent stalls.

Code: Select all


//==========================================================================================================

struct TrackedAllocator
{
    CComPtr<ID3D12CommandAllocator>         m_spCommandAllocator = nullptr;
    UINT                                    m_uFenceValue = 0;
};

#define ALLOCATOR_COUNT 3
struct CommandAllocatorQueue
{
    CommandAllocatorQueue() : m_uCurrent(0) {}

    TrackedAllocator& GetCurrent() {
        return m_aAllocators[m_uCurrent];
    }

    TrackedAllocator& GetNext() {
        m_uCurrent = (m_uCurrent + 1) % ALLOCATOR_COUNT;
        return m_aAllocators[m_uCurrent];
    }

    TrackedAllocator m_aAllocators[ALLOCATOR_COUNT];
    
    UINT m_uCurrent = 0;
};

class PipelineState
{
public:

    PipelineState() noexcept;

    HRESULT Initialize(ID3D12Device* pDevice, ID3D12CommandQueue* pQueue);
    HRESULT DeInitialize();
    HRESULT Apply(bool bClearRTV = true);
    HRESULT Clear();
    HRESULT Execute();
    HRESULT Reset();

    void CopySubresourceRegion(P3D::IRenderDataResourceV500* pDestination, UINT DstX, UINT DstY, UINT DstZ,
        P3D::IRenderDataResourceV500* pSource, const D3D12_BOX* pSourceBox);

    void CopyResource(P3D::IRenderDataResourceV500* pDestination, P3D::IRenderDataResourceV500* pSource);

    static const unsigned int MAX_RESOURCES = 4;
    CComPtr<P3D::IRenderDataResourceV500>   m_spResources[MAX_RESOURCES];
    CComPtr<P3D::IRenderDataResourceV500>   m_spRenderTarget;
    CComPtr<P3D::IRenderDataResourceV500>   m_spDepthStencil;
    CComPtr<P3D::IRenderDataResourceV500>   m_spVertexBuffer;
    D3D12_VERTEX_BUFFER_VIEW                m_sVertexBufferView;
    CComPtr<P3D::IRenderDataResourceV500>   m_spConstantBuffer;
    CComPtr<ID3D12Device>                   m_spDevice;
    CComPtr<ID3D12GraphicsCommandList>      m_spCommandList;
    CComPtr<ID3D12CommandQueue>             m_spCommandQueue;
    CComPtr<ID3D12PipelineState>            m_spPipelineState;
    CComPtr<ID3D12RootSignature>            m_spRootSignature;
    CComPtr<ID3D12DescriptorHeap>           m_spDescriptorHeapSRV;
    CComPtr<ID3D12DescriptorHeap>           m_spDescriptorHeapRTV;
    CComPtr<ID3D12DescriptorHeap>           m_spDescriptorHeapDSV;
    CComPtr<ID3D12Fence>                    m_spFence;
    D3D_PRIMITIVE_TOPOLOGY                  m_ePrimitiveTopology;
    D3D12_VIEWPORT                          m_ViewPort;
    HANDLE                                  m_hFenceEvent;
    UINT                                    m_uDepthStencilRef;
    UINT                                    m_uSRVIncrement;
    UINT                                    m_uRTVIncrement;
    UINT                                    m_uDSVIncrement;
    CommandAllocatorQueue                   m_AllocatorQueue;
    UINT                                    m_uFenceValue = 0;
};


//==========================================================================================================

PipelineState::PipelineState() noexcept
    :m_ViewPort()
{
    m_ePrimitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
    m_uDepthStencilRef = 0;
}

HRESULT PipelineState::Initialize(ID3D12Device* pDevice, ID3D12CommandQueue* pQueue)
{
    HRESULT hr = S_OK;

    if (m_spDevice != pDevice || m_spCommandQueue != pQueue)
    {
        m_spDevice = pDevice;
        m_spCommandQueue = pQueue;
        for (int i = 0; i < ALLOCATOR_COUNT; i++)
        {
            hr = m_spDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_AllocatorQueue.m_aAllocators[i].m_spCommandAllocator));
            if (FAILED(hr))
            {
                return hr;
            }
        }

        hr = m_spDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_AllocatorQueue.m_aAllocators[0].m_spCommandAllocator, nullptr, IID_PPV_ARGS(&m_spCommandList));
        if (FAILED(hr))
        {
            return hr;
        }

        //Create Fence and Event
        m_uFenceValue = 0;
        hr = pDevice->CreateFence(m_uFenceValue, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_spFence));
        if (FAILED(hr))
        {
            return hr;
        }

        m_hFenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
    }
    return hr;
}

HRESULT PipelineState::DeInitialize()
{
    for (unsigned int i = 0; i < MAX_RESOURCES; i++)
    {
        m_spResources[i]    = nullptr;
    }

    ZeroMemory(&m_sVertexBufferView, sizeof(m_sVertexBufferView));
    ZeroMemory(&m_ViewPort, sizeof(m_ViewPort));
    m_ePrimitiveTopology    = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;

    m_spRenderTarget        = nullptr;
    m_spDepthStencil        = nullptr;
    m_spVertexBuffer        = nullptr;
    m_spConstantBuffer      = nullptr;
    m_spDevice              = nullptr;
    m_spCommandList         = nullptr;
    m_spCommandQueue        = nullptr;
    m_spPipelineState       = nullptr;
    m_spRootSignature       = nullptr;
    m_spDescriptorHeapSRV   = nullptr;
    m_spDescriptorHeapRTV   = nullptr;
    m_spDescriptorHeapDSV   = nullptr;
    m_spFence               = nullptr;
    m_hFenceEvent           = nullptr;
    m_uDepthStencilRef      = 0;
    m_uSRVIncrement         = 0;
    m_uRTVIncrement         = 0;
    m_uDSVIncrement         = 0;
    m_uFenceValue           = 0;

    for (int i = 0; i < ALLOCATOR_COUNT; i++)
    {
        m_AllocatorQueue.m_aAllocators[i].m_spCommandAllocator = nullptr;
    }

    return S_OK;
}

//==========================================================================================================

HRESULT PipelineState::Apply(bool bClearRTV)
{
    static float ClearColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; // red,green,blue,alpha

    ID3D12DescriptorHeap* ppHeaps[] = { m_spDescriptorHeapSRV };
    m_spCommandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps);
    m_spCommandList->SetGraphicsRootSignature(m_spRootSignature);

    if (bClearRTV && m_spRenderTarget != nullptr)
    {
        D3D12_CPU_DESCRIPTOR_HANDLE hRenderTargetHandle = m_spDescriptorHeapRTV->GetCPUDescriptorHandleForHeapStart();
        m_spCommandList->ClearRenderTargetView(hRenderTargetHandle, ClearColor, 0, nullptr);
    }

    if (m_spDepthStencil != nullptr && m_spRenderTarget != nullptr)
    {
        D3D12_CPU_DESCRIPTOR_HANDLE hDepthStencilHandle = m_spDescriptorHeapDSV->GetCPUDescriptorHandleForHeapStart();
        D3D12_CPU_DESCRIPTOR_HANDLE hRenderTargetHandle = m_spDescriptorHeapRTV->GetCPUDescriptorHandleForHeapStart();

        m_spCommandList->OMSetStencilRef(m_uDepthStencilRef);
        m_spCommandList->OMSetRenderTargets(1, &hRenderTargetHandle, FALSE, &hDepthStencilHandle);
    }
    else if(m_spRenderTarget)
    {
        D3D12_CPU_DESCRIPTOR_HANDLE hRenderTargetHandle = m_spDescriptorHeapRTV->GetCPUDescriptorHandleForHeapStart();
        m_spCommandList->OMSetRenderTargets(1, &hRenderTargetHandle, FALSE, nullptr);
    }
    else
    {
        D3D12_CPU_DESCRIPTOR_HANDLE hDepthStencilHandle = m_spDescriptorHeapDSV->GetCPUDescriptorHandleForHeapStart();
        m_spCommandList->OMSetStencilRef(m_uDepthStencilRef);
        m_spCommandList->OMSetRenderTargets(0, nullptr, FALSE, &hDepthStencilHandle);
    }

    m_spCommandList->SetPipelineState(m_spPipelineState);

    D3D12_RECT sScissorRectFull;
    sScissorRectFull.left = 0;
    sScissorRectFull.top = 0;
    sScissorRectFull.right = static_cast<LONG>(m_ViewPort.Width);
    sScissorRectFull.bottom = static_cast<LONG>(m_ViewPort.Height);

    //Setup the viewport.
    m_spCommandList->RSSetViewports(1, &m_ViewPort);
    m_spCommandList->RSSetScissorRects(1, &sScissorRectFull);

    if (m_spConstantBuffer)
    {
        m_spCommandList->SetGraphicsRootConstantBufferView(0, m_spConstantBuffer->GetD3D12Resource()->GetGPUVirtualAddress());
    }

    m_spCommandList->IASetPrimitiveTopology(m_ePrimitiveTopology);
    m_spCommandList->IASetVertexBuffers(0, 1, &m_sVertexBufferView);

    for (int i = 0; i < MAX_RESOURCES; i++)
    {
        if (m_spResources[i] != nullptr)
        {
            D3D12_GPU_DESCRIPTOR_HANDLE hGpuHandle = m_spDescriptorHeapSRV->GetGPUDescriptorHandleForHeapStart();
            hGpuHandle.ptr += m_uSRVIncrement * i;
            m_spCommandList->SetGraphicsRootDescriptorTable(i + 1, hGpuHandle);
        }
    }

    return S_OK;
}

//==========================================================================================================

HRESULT PipelineState::Clear()
{
    m_spCommandList->ClearState(m_spPipelineState);
    m_spCommandList->OMSetRenderTargets(0, nullptr, false, nullptr);
    return S_OK;
}

//==========================================================================================================

HRESULT PipelineState::Execute()
{
    HRESULT hr = S_OK;
    hr = m_spCommandList->Close();
    if (FAILED(hr))
    {
        return hr;
    }

    ID3D12CommandList* ppCommandLists[] = { m_spCommandList };
    m_spCommandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
    hr = m_spCommandQueue->Signal(m_spFence, m_uFenceValue);
    if (FAILED(hr))
    {
        return hr;
    }

    return hr;
}

//==========================================================================================================

HRESULT PipelineState::Reset()
{
    HRESULT hr = S_OK;
    TrackedAllocator& alloc = m_AllocatorQueue.GetNext();
    if (m_spFence->GetCompletedValue() < (alloc.m_uFenceValue))
    {
        hr = m_spFence->SetEventOnCompletion(alloc.m_uFenceValue, m_hFenceEvent);
        if (FAILED(hr))
        {
            return hr;
        }

        WaitForSingleObjectEx(m_hFenceEvent, INFINITE, FALSE);
    }

    m_uFenceValue++;
    alloc.m_uFenceValue = m_uFenceValue;
    hr = alloc.m_spCommandAllocator->Reset();
    if (FAILED(hr))
    {
        return hr;
    }

    hr = m_spCommandList->Reset(alloc.m_spCommandAllocator, nullptr);

    return hr;
}

void PipelineState::CopySubresourceRegion(P3D::IRenderDataResourceV500* pDestination, UINT DstX, UINT DstY, UINT DstZ,
    P3D::IRenderDataResourceV500* pSource, const D3D12_BOX* pSourceBox)
{
    if (pDestination == nullptr || pSource == nullptr || m_spCommandList == nullptr)
        return;

    
    D3D12_RESOURCE_STATES destState = pDestination->GetResourceState();
    D3D12_RESOURCE_STATES srcState = pSource->GetResourceState();

    D3D12_RESOURCE_BARRIER sBarriersBefore[2];
    sBarriersBefore[0] = CD3DX12_RESOURCE_BARRIER::Transition(pDestination->GetD3D12Resource(), destState, D3D12_RESOURCE_STATE_COPY_DEST);
    sBarriersBefore[1] = CD3DX12_RESOURCE_BARRIER::Transition(pSource->GetD3D12Resource(), srcState, D3D12_RESOURCE_STATE_COPY_SOURCE);
    pDestination->SetResourceState(D3D12_RESOURCE_STATE_COPY_DEST);
    pSource->SetResourceState(D3D12_RESOURCE_STATE_COPY_SOURCE);

    m_spCommandList->ResourceBarrier(2, sBarriersBefore);

    if (pDestination->GetD3D12Resource()->GetDesc().Format == D3D12_RESOURCE_DIMENSION_BUFFER)
    {
        D3D12_PLACED_SUBRESOURCE_FOOTPRINT PlacedFootprint;
        m_spDevice->GetCopyableFootprints(&pDestination->GetD3D12Resource()->GetDesc(), 0, 1, 0, &PlacedFootprint, nullptr, nullptr, nullptr);
        m_spCommandList->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(pDestination->GetD3D12Resource(), PlacedFootprint), DstX, DstY, DstZ,
            &CD3DX12_TEXTURE_COPY_LOCATION(pSource->GetD3D12Resource()), pSourceBox);
    }
    else
    {
        m_spCommandList->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(pDestination->GetD3D12Resource()), DstX, DstY, DstZ,
            &CD3DX12_TEXTURE_COPY_LOCATION(pSource->GetD3D12Resource()), pSourceBox);
    }

    D3D12_RESOURCE_BARRIER sBarriersAfter[2];
    sBarriersAfter[0] = CD3DX12_RESOURCE_BARRIER::Transition(pDestination->GetD3D12Resource(), D3D12_RESOURCE_STATE_COPY_DEST, destState);
    sBarriersAfter[1] = CD3DX12_RESOURCE_BARRIER::Transition(pSource->GetD3D12Resource(), D3D12_RESOURCE_STATE_COPY_SOURCE, srcState);
    pDestination->SetResourceState(destState);
    pSource->SetResourceState(srcState);

    m_spCommandList->ResourceBarrier(2, sBarriersAfter);
}

void PipelineState::CopyResource(P3D::IRenderDataResourceV500* pDestination, P3D::IRenderDataResourceV500* pSource)
{
    if (pDestination == nullptr || pSource == nullptr || m_spCommandList == nullptr)
        return;

    D3D12_RESOURCE_STATES destState = pDestination->GetResourceState();
    D3D12_RESOURCE_STATES srcState = pSource->GetResourceState();

    D3D12_PLACED_SUBRESOURCE_FOOTPRINT PlacedFootprint;
    m_spDevice->GetCopyableFootprints(&pDestination->GetD3D12Resource()->GetDesc(), 0, 1, 0, &PlacedFootprint, nullptr, nullptr, nullptr);

    D3D12_RESOURCE_BARRIER sBarriersBefore[2];
    sBarriersBefore[0] = CD3DX12_RESOURCE_BARRIER::Transition(pDestination->GetD3D12Resource(), destState, D3D12_RESOURCE_STATE_COPY_DEST);
    sBarriersBefore[1] = CD3DX12_RESOURCE_BARRIER::Transition(pSource->GetD3D12Resource(), srcState, D3D12_RESOURCE_STATE_COPY_SOURCE);
    pDestination->SetResourceState(D3D12_RESOURCE_STATE_COPY_DEST);
    pSource->SetResourceState(D3D12_RESOURCE_STATE_COPY_SOURCE);

    m_spCommandList->ResourceBarrier(2, sBarriersBefore);

    m_spCommandList->CopyResource(pDestination->GetD3D12Resource(), pSource->GetD3D12Resource());

    D3D12_RESOURCE_BARRIER sBarriersAfter[2];
    sBarriersAfter[0] = CD3DX12_RESOURCE_BARRIER::Transition(pDestination->GetD3D12Resource(), D3D12_RESOURCE_STATE_COPY_DEST, destState);
    sBarriersAfter[1] = CD3DX12_RESOURCE_BARRIER::Transition(pSource->GetD3D12Resource(), D3D12_RESOURCE_STATE_COPY_SOURCE, srcState);
    pDestination->SetResourceState(destState);
    pSource->SetResourceState(srcState);

    m_spCommandList->ResourceBarrier(2, sBarriersAfter);
}

Re: D3D12Texture Sample - flickering texture

Posted: Mon Sep 28, 2020 10:45 am
by lkalam
Hi Beau,

we have included your updated code into the OpenGLTexture sample and unfortunately, the result is that the code freezes.Here is the OpenGLTexture sample, updated with the RenderHelper code that includes your new PipelineState, so you can test on your end, but we've tried it on different machines and the result is the same.

https://we.tl/t-UsG0Dk6VFo

Would appreciate updated code, possibly on the D3D12Texture sample as that's simpler.

Regards

Re: D3D12Texture Sample - flickering texture

Posted: Tue Sep 29, 2020 12:18 pm
by Beau Hollis
Thanks. We're in the process or updating our d3d12 util classes and making a shared utility project that all 3 dx projects can share. We'll be testing that out soon. The plan is to update the d3d12Texture project as well.

Re: D3D12Texture Sample - flickering texture

Posted: Wed Sep 30, 2020 7:05 am
by lkalam
Hi Beau,

thanks for the reply - any hints as to how we can get your sample code to work rather than to freeze? It's imperative to get our RTT implementation going.

Re: D3D12Texture Sample - flickering texture

Posted: Sat Oct 17, 2020 7:45 am
by lkalam
Hello,

just wanted to bring this back to your attention as we've not heard from you still and we are very concerned that the flickering issue is not resolved.

Can you please share your revised sample code if you have it, so we can test and let you know if it's fixed?

Our upcoming products require that we use D3D12 Textures and we need to ensure that they will work without this happening.

Thank you,

Re: D3D12Texture Sample - flickering texture

Posted: Mon Oct 19, 2020 12:59 pm
by Beau Hollis
We've updated the dx12 and opengl samples and are testing them in beta. The freeze in the OpenGL sample, is because it made assumptions about how the pipeline wrappers fence was being used. In the updated sample I've added an additional fence specifically for tracking the shared resource.

Re: D3D12Texture Sample - flickering texture

Posted: Wed Oct 28, 2020 7:45 pm
by Beau Hollis
Updated samples are included with 5.1. Also with 5.1 we found and fixed a core issue that caused black flickering with texture elements like this, especially if mipmap vc panels was disabled.

Thanks

Re: D3D12Texture Sample - flickering texture

Posted: Wed Oct 28, 2020 8:55 pm
by lkalam
Thank you Beau,

we appreciate it. The Mipmap VC panels "off" was mentioned back in August, I guess that was the issue after all.