Search code examples
windowsperformancedirectxdirectx-11frame-rate

Performance loss with CopyResource() and then Map()/Unmap()


The problem is that if you do not use these methods, then the FPS differs by about 2 times in a big way. For example, I had about 5000 fps in a 3d scene. And it became about 2500. I know that the problem is that the application is waiting for the copy to wait. But it's only 4 bytes... If you use the D3D11_MAP_FLAG_DO_NOT_WAIT flag, Map() will always return DXGI_ERROR_WAS_STILL_DRAWING. What can be done so that I can use this method without losing fps? Here is my code:

Init

    D3D11_BUFFER_DESC outputDesc;
    outputDesc.Usage = D3D11_USAGE_DEFAULT;
    outputDesc.ByteWidth = sizeof(float);
    outputDesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS;
    outputDesc.CPUAccessFlags = 0;
    outputDesc.StructureByteStride = sizeof(float);
    outputDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
    FOG_TRACE(mDevice->CreateBuffer(&outputDesc, nullptr, &outputBuffer));

    outputDesc.Usage = D3D11_USAGE_STAGING;
    outputDesc.BindFlags = 0;
    outputDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
    FOG_TRACE(mDevice->CreateBuffer(&outputDesc, nullptr, &outputResultBuffer));

    D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc{};
    uavDesc.Buffer.FirstElement = 0;
    uavDesc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_APPEND;
    uavDesc.Buffer.NumElements = 1;
    uavDesc.Format = DXGI_FORMAT_UNKNOWN;
    uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;

    FOG_TRACE(mDevice->CreateUnorderedAccessView(outputBuffer, &uavDesc, &unorderedAccessView));

Update

    const UINT offset = 0;
    mDeviceContext->OMSetRenderTargetsAndUnorderedAccessViews(1, &mRenderTargetView, mDepthStencilView, 1, 1, &unorderedAccessView, &offset);
    mDeviceContext->ClearDepthStencilView(mDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);


    ObjectManager::Draw();


    mDeviceContext->CopyResource(outputResultBuffer, outputBuffer);

    D3D11_MAPPED_SUBRESOURCE mappedBuffer;
    HRESULT hr;
    FOG_TRACE(hr = mDeviceContext->Map(outputResultBuffer, 0, D3D11_MAP_READ, 0/*D3D11_MAP_FLAG_DO_NOT_WAIT*/, &mappedBuffer));

    if (SUCCEEDED(hr))
    {
        float* copy = (float*)(mappedBuffer.pData);
        OutputDebugString(String::ToStr(*copy) + L"\n");
    }

    mDeviceContext->Unmap(outputResultBuffer, 0);

    const UINT var[4]{};
    mDeviceContext->ClearUnorderedAccessViewUint(unorderedAccessView, var);

I've already profiled and checked everything possible, the problem is exactly in pending. I would be very grateful if someone could explain everything in detail :)


Solution

  • The problem was solved very simply but for a long time! I just didn't make copy calls until I had read past data. Here is a small crutch:

        static bool isWait = false;
    
        if (!isWait)
        {
            mDeviceContext->CopyResource(outputResultBuffer, outputBuffer);
        }
    
        D3D11_MAPPED_SUBRESOURCE mappedBuffer;
        HRESULT hr;
    
        FOG_TRACE(hr = mDeviceContext->Map(outputResultBuffer, 0, D3D11_MAP_READ, D3D11_MAP_FLAG_DO_NOT_WAIT, &mappedBuffer));
    
    
        if (SUCCEEDED(hr))
        {
            float* copy = (float*)(mappedBuffer.pData);
            OutputDebugString(String::ToStr(*copy) + L"\n");
            mDeviceContext->Unmap(outputResultBuffer, 0);
    
            const UINT var[4]{};
            mDeviceContext->ClearUnorderedAccessViewUint(unorderedAccessView, var);
    
            isWait = false;
        }
        else
        {
            isWait = true;
        }