D3D12Texture Sample - flickering texture

SDK supports Prepar3D’s philosophy of an open development architecture and encourages third parties to bring new innovations with improved add-ons and training content.
MachTwo
Posts: 68
Joined: Fri Oct 04, 2013 8:21 am

D3D12Texture Sample - flickering texture

Post 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
Andrew Wilson
Flight Sim Labs, Ltd.
---------------------------
www.flightsimlabs.com
MachTwo
Posts: 68
Joined: Fri Oct 04, 2013 8:21 am

Re: D3D12Texture Sample - flickering texture

Post 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.
Andrew Wilson
Flight Sim Labs, Ltd.
---------------------------
www.flightsimlabs.com
User avatar
lkalam
Posts: 268
Joined: Wed Dec 07, 2011 10:23 am

Re: D3D12Texture Sample - flickering texture

Post 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,
Lefteris Kalamaras
Flight Sim Labs, Ltd.
---------------------------
www.flightsimlabs.com
MachTwo
Posts: 68
Joined: Fri Oct 04, 2013 8:21 am

Re: D3D12Texture Sample - flickering texture

Post 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.
Andrew Wilson
Flight Sim Labs, Ltd.
---------------------------
www.flightsimlabs.com
User avatar
Beau Hollis
Lockheed Martin
Posts: 2452
Joined: Wed Oct 06, 2010 3:25 pm

Re: D3D12Texture Sample - flickering texture

Post 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.
Beau Hollis
Prepar3D Software Architect
MachTwo
Posts: 68
Joined: Fri Oct 04, 2013 8:21 am

Re: D3D12Texture Sample - flickering texture

Post 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?
Andrew Wilson
Flight Sim Labs, Ltd.
---------------------------
www.flightsimlabs.com
User avatar
Beau Hollis
Lockheed Martin
Posts: 2452
Joined: Wed Oct 06, 2010 3:25 pm

Re: D3D12Texture Sample - flickering texture

Post 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.
Beau Hollis
Prepar3D Software Architect
User avatar
Beau Hollis
Lockheed Martin
Posts: 2452
Joined: Wed Oct 06, 2010 3:25 pm

Re: D3D12Texture Sample - flickering texture

Post 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);
}
Beau Hollis
Prepar3D Software Architect
User avatar
lkalam
Posts: 268
Joined: Wed Dec 07, 2011 10:23 am

Re: D3D12Texture Sample - flickering texture

Post 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
Lefteris Kalamaras
Flight Sim Labs, Ltd.
---------------------------
www.flightsimlabs.com
User avatar
Beau Hollis
Lockheed Martin
Posts: 2452
Joined: Wed Oct 06, 2010 3:25 pm

Re: D3D12Texture Sample - flickering texture

Post 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.
Beau Hollis
Prepar3D Software Architect
User avatar
lkalam
Posts: 268
Joined: Wed Dec 07, 2011 10:23 am

Re: D3D12Texture Sample - flickering texture

Post 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.
Lefteris Kalamaras
Flight Sim Labs, Ltd.
---------------------------
www.flightsimlabs.com
User avatar
lkalam
Posts: 268
Joined: Wed Dec 07, 2011 10:23 am

Re: D3D12Texture Sample - flickering texture

Post 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,
Lefteris Kalamaras
Flight Sim Labs, Ltd.
---------------------------
www.flightsimlabs.com
User avatar
Beau Hollis
Lockheed Martin
Posts: 2452
Joined: Wed Oct 06, 2010 3:25 pm

Re: D3D12Texture Sample - flickering texture

Post 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.
Beau Hollis
Prepar3D Software Architect
User avatar
Beau Hollis
Lockheed Martin
Posts: 2452
Joined: Wed Oct 06, 2010 3:25 pm

Re: D3D12Texture Sample - flickering texture

Post 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
Beau Hollis
Prepar3D Software Architect
User avatar
lkalam
Posts: 268
Joined: Wed Dec 07, 2011 10:23 am

Re: D3D12Texture Sample - flickering texture

Post 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.
Lefteris Kalamaras
Flight Sim Labs, Ltd.
---------------------------
www.flightsimlabs.com
Post Reply