Lost Buffer Bindings

Recently we found a strange behavior on some of our computers when executing our programs. Some computers lost their buffer bindings and so the shader programs were not able to write their results back.

We were able to identify the problem by writing a small test application in plain C++ that shows that error. See below.
It writes in a simple loop the loop index in a constant buffer and the shader writes the parameter simply back to its output buffer. After a few times (e.g. in the 48th iteration) the shader loses its binding
to the output buffer and the previous results won’t be updated again. So the value (in the example ‘48’) will be reported since then.

Does anyone have seen such behaviour? It won’t work on laptops with GTX 5xx series, 6xx and 7xx series. The same strange results also on Quadro 2000m.

The test code in C++ can be found in the attachment in file GpuDispatchBugTestC++.cpp and screenshots of the results in “Screenshot1-Buggy.jpg” and “Screenshot2-Working.jpg” in the attachment of this post.

Thank you for your reply :-)

#include "cstdlib"
#include "iostream"

using namespace std;

#include <d3d11.h>
#include <d3dcompiler.h>

// include the Direct3D Library file
#pragma comment (lib, "d3d11.lib")
#pragma comment (lib, "d3dcompiler.lib")

ID3D11Device *dev;
ID3D11DeviceContext *devcon;

ID3D11Buffer *parameterBuffer;
ID3D11Buffer *outputBuffer;
ID3D11Buffer *stagingBuffer;
ID3D11UnorderedAccessView *uav;

void CreateBuffers()
{
    D3D11_BUFFER_DESC bdesc;
    bdesc.ByteWidth = 4;
    bdesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS;
    bdesc.MiscFlags = 0;
    bdesc.CPUAccessFlags = 0;
    bdesc.StructureByteStride = 0;
    bdesc.Usage = D3D11_USAGE_DEFAULT;

    dev->CreateBuffer(&bdesc, nullptr, &outputBuffer);

    D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc;

    uavDesc.ViewDimension = D3D11_UAV_DIMENSION::D3D11_UAV_DIMENSION_BUFFER;
    uavDesc.Format = DXGI_FORMAT::DXGI_FORMAT_R32_FLOAT;
    uavDesc.Buffer.FirstElement = 0;
    uavDesc.Buffer.NumElements = 1;
    uavDesc.Buffer.Flags = 0;

    dev->CreateUnorderedAccessView(outputBuffer, &uavDesc, &uav);

    D3D11_BUFFER_DESC sdesc;
    sdesc.ByteWidth = 4;
    sdesc.BindFlags = 0;
    sdesc.MiscFlags = 0;
    sdesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
    sdesc.StructureByteStride = 0;
    sdesc.Usage = D3D11_USAGE_STAGING;

    dev->CreateBuffer(&sdesc, nullptr, &stagingBuffer);

    D3D11_BUFFER_DESC pdesc;
    pdesc.ByteWidth = 16;
    pdesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    pdesc.MiscFlags = 0;
    pdesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
    pdesc.StructureByteStride = 0;
    pdesc.Usage = D3D11_USAGE_DYNAMIC;

    dev->CreateBuffer(&pdesc, nullptr, &parameterBuffer);
}

void RenderSlice(int slice)
{
    D3D11_MAPPED_SUBRESOURCE mappedResource;

    devcon->Map(parameterBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
    *((int*)mappedResource.pData) = slice;
    devcon->Unmap(parameterBuffer, 0);

    devcon->Dispatch(1, 1, 1);

    devcon->CopyResource(stagingBuffer, outputBuffer);

    D3D11_MAPPED_SUBRESOURCE stagingResource;

    devcon->Map(stagingBuffer, 0, D3D11_MAP_READ, 0, &stagingResource);
    float value = *((float*)stagingResource.pData);
    devcon->Unmap(stagingBuffer, 0);

    cout << value << ", ";
}

void main()
{
    cout << "Hello World!" << endl;

    string shaderSource = "RWBuffer<float> outputBuffer;\
\
    cbuffer Parameters\
    {\
        int StartIndex;\
    }\
\
        [numthreads(32, 1, 1)]\
    void Generate(uint3 id : SV_DispatchThreadID)\
    {\
        outputBuffer[id.x] = StartIndex;\
    }\
";

    D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE::D3D_DRIVER_TYPE_HARDWARE, nullptr, 0,
        new D3D_FEATURE_LEVEL[1]{ D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_11_0 }, 1, D3D11_SDK_VERSION, &dev, nullptr, &devcon);

    ID3DBlob *shaderCode, *errorMsg;
    D3DCompile((void*)shaderSource.c_str(), shaderSource.size(), nullptr, nullptr, nullptr, "Generate", "cs_5_0", 0, 0, &shaderCode, &errorMsg);

    ID3D11ComputeShader *shader;
    dev->CreateComputeShader(shaderCode->GetBufferPointer(), shaderCode->GetBufferSize(), nullptr, &shader);

    CreateBuffers();

    devcon->CSSetShader(shader, nullptr, 0);
    devcon->CSSetConstantBuffers(0, 1, new ID3D11Buffer*[1]{ parameterBuffer });    

	// *****************************************************************************************
	//       buggy - version
	// *****************************************************************************************
	// PROBLEM: UnorderedAccessView is set once but somehow lost during the 48th iteration.
	//			The shader's output is the slice-nr.
	// DirectX is designed to be a state-machine and hence it should not be necessary to 
	// reset the UnorderedAccessView 'uav' every time in the for-loop.
	// -----------------------------------------------------------------------------------------
	devcon->CSSetUnorderedAccessViews(0, 1, new ID3D11UnorderedAccessView*[1]{ uav }, nullptr);
    for (int i = 0; i < 100; i++) { RenderSlice(i); }
	// *****************************************************************************************

	/* *****************************************************************************************
		     U N C O M M E N T    M E    F O R    A    W O R K I N G     V E R S I O N
	   *****************************************************************************************

	// *****************************************************************************************
	//       working - version
	// *****************************************************************************************
	// OUTCOME: UnorderedAccessView is set every iteration and so it is not lost during the
	//			100 iterations.
	// -----------------------------------------------------------------------------------------
	for (int i = 0; i < 100; i++)
	{
		devcon->CSSetUnorderedAccessViews(0, 1, new ID3D11UnorderedAccessView*[1]{ uav }, nullptr);
		RenderSlice(i);
	}
	// *****************************************************************************************
	*/

	cout << "Press any key..." << endl;
	getchar();
}

GpuDispatchBugTestC++.cpp (5.12 KB)