ConsumeStructuredBuffer, was mache ich falsch?

7

Ich versuche , die dritte Übung in Kapitel 12 zu implementieren Einführung in der 3D - Game Programming mit DirectX 11 , das heißt:

  • Implementieren Sie einen Compute Shader, um die Länge von 64 Vektoren zu berechnen.

In früheren Übungen wurden Sie gebeten, dasselbe mit typisierten Puffern und regulären strukturierten Puffern zu tun, und ich hatte keine Probleme damit.

Für das, was ich gelesen habe, werden [Consume | Append] StructuredBuffers mithilfe von UnorderedAccessViews an die Pipeline gebunden (sofern sie D3D11_BUFFER_UAV_FLAG_APPEND verwenden und die Puffer sowohl D3D11_BIND_SHADER_RESOURCE als auch D3D11_BIND_UNORDERED_AC haben).

Das Problem ist: Mein AppendStructuredBuffer funktioniert, da ich Daten an ihn anhängen und aus der Anwendung abrufen kann, um in eine Ergebnisdatei zu schreiben, aber der ConsumeStructuredBuffer gibt immer nullte Daten zurück. Daten befinden sich im Puffer, da es funktioniert, wenn ich das UAV in ein ShaderResourceView und in einen StructuredBuffer auf der HLSL-Seite ändere.

Ich weiß nicht, was mir fehlt:

  • Sollte ich den ConsumeStructuredBuffer auf der GPU initialisieren oder kann ich dies tun, wenn ich den Puffer erstelle (wie ich es gerade tue)?.
  • Ist es in Ordnung, den Puffer wie oben beschrieben mit einem UAV zu binden? Muss ich es irgendwie als ShaderResourceView binden?
  • Vielleicht fehlt mir ein Schritt?

Dies ist die Deklaration der Puffer im Compute Shader:

struct Data
{
    float3 v;
};

struct Result
{
    float l;
};

ConsumeStructuredBuffer<Data> gInput;
AppendStructuredBuffer<Result> gOutput;

Und hier die Erstellung des Puffers und des UAV für Eingabedaten:

D3D11_BUFFER_DESC inputDesc;
inputDesc.Usage = D3D11_USAGE_DEFAULT;
inputDesc.ByteWidth = sizeof(Data) * mNumElements;
inputDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS;
inputDesc.CPUAccessFlags = 0;
inputDesc.StructureByteStride = sizeof(Data);
inputDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;

D3D11_SUBRESOURCE_DATA vinitData;
vinitData.pSysMem = &data[0];

HR(md3dDevice->CreateBuffer(&inputDesc, &vinitData, &mInputBuffer));

D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc;
uavDesc.Format = DXGI_FORMAT_UNKNOWN;
uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
uavDesc.Buffer.FirstElement = 0;
uavDesc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_APPEND;
uavDesc.Buffer.NumElements = mNumElements;

md3dDevice->CreateUnorderedAccessView(mInputBuffer, &uavDesc, &mInputUAV);

Anfangsdaten sind ein Array von Datenstrukturen, die einen XMFLOAT3 mit zufälligen Daten enthalten.

Ich binde das UAV mithilfe des Effekt-Frameworks an den Shader:

ID3DX11EffectUnorderedAccessViewVariable* Input = mFX->GetVariableByName("gInput")->AsUnorderedAccessView();

Input->SetUnorderedAccessView(uav); // uav is mInputUAV

Irgendwelche Ideen?

Vielen Dank.

Marc Costa
quelle

Antworten:

3

Ich begann zu glauben, das Problem liege in der Idee, "einen ConsumeStructuredBuffer von der CPU aus zu initialisieren".

Wenn Sie Ihr UAV für den Verbrauchspuffer binden, legen Sie die Anzahl fest? In OMSetRenderTargetsAndUnorderedAccessViews gibt es einen Parameter, um die anfängliche Zählung für jedes UAV zu übergeben. Ich glaube, mit einem Verbrauchspuffer, der auf der CPU eingerichtet ist, müssen Sie die anfängliche Anzahl sowohl hier als auch in uavDesc festlegen. (Die Anzahl in uavDesc ist die maximale Anzahl, dh die Anzahl der Elemente, für die Speicher zugewiesen werden soll, während die Anzahl in OMSetRenderTargetsAndUnorderedAccessViews die aktuelle tatsächliche Anzahl von Elementen mit gültigen Daten ist.) Ohne dies wird wahrscheinlich angenommen, dass die anfängliche Anzahl Null ist Dies führt dazu, dass beim Versuch, aus dem Verbrauchspuffer zu lesen, einfach Nullen zurückgegeben werden.

Wenn ich die Shader-Ressourcenansicht (für die Eingabe in den ersten Shader) mit demselben D3D11_BUFFER_DESC wie die ursprüngliche Eingabe für den ungeordneten Zugriff erstellt habe, wurden keine Daten geladen.

Seltsam; Ich würde erwarten, dass dies funktioniert, obwohl ich es nicht auf meinem eigenen Computer ausprobiert habe. Ich frage mich, ob es möglicherweise funktioniert, die Daten nach dem Erstellen des Puffers zu laden, entweder mithilfe von UpdateSubresource () oder indem Sie Map () / Unmap () ausführen und die Daten manuell kopieren. Es lohnt sich auch sicherzustellen, dass Ihre Treiber auf dem neuesten Stand sind, falls dies ein Treiberfehler ist, der behoben wurde.

Nathan Reed
quelle
Das stimmt, Nathan!
Marc Costa
Obwohl ich ID3D11DeviceContext :: CSSetUnorderedAccessViews benötige , um das UAV auf die Compute Shader-Stufe anstelle der Output Merger-Stufe zu setzen.
Marc Costa
In Bezug auf den letzten Teil habe ich keine weiteren Tests durchgeführt, aber es ist in der Tat seltsam. Ich verwende die neuesten NVidia-Treiber (310.70) mit einer GTX 460.
Marc Costa
2

Ich begann zu glauben, das Problem liege in der Idee, "einen ConsumeStructuredBuffer von der CPU aus zu initialisieren". Da es als Stapel von Elementen "fungiert", ist es sinnvoll, dass die Daten in den Stapel "geschoben" werden müssen, bevor sie "herausspringen".

Also habe ich Folgendes getan: Ich habe einen neuen einfachen Shader erstellt, der einen StructuredBuffer als Eingabe und einen AppendStructuredBuffer als Ausgabe verwendet. Der StructuredBuffer kann von der CPU aus initialisiert werden. Der Shader musste lediglich den AppendStructuredBuffer mit den Daten aus dem StructuredBuffer füllen.

Nun die eigentliche Berechnung: Danach habe ich den oben genannten AppendStructuredBuffer an einen ConsumeStructuredBuffer und den ursprünglichen Ausgabepuffer an eine neue AppendStructuredBuffer HLSL-Variable gebunden.

Und das hat als Charme gewirkt!

Weitere Untersuchungen führten mich zu der Annahme, dass das Vorhandensein des Bindungsflags D3D11_BIND_UNORDERED_ACCESS in einer D3D11_BUFFER_DESC dazu führt, dass die Funktion CreateBuffer alle anfänglichen Daten verwirft: Wenn ich die Shader-Ressourcenansicht (für die Eingabe in den ersten Shader) mit derselben D3D11_BUFFER_DESC wie die ursprüngliche Eingabe Unordered erstellt habe In der Zugriffsansicht wurden keine Daten geladen. Als ich das Bindungsflag D3D11_BIND_UNORDERED_ACCESS entfernte (wobei nur D3D11_BIND_SHADER_RESOURCE übrig blieb), wurden die Daten erfolgreich geladen.

Ich konnte diese "Funktion" jedoch nirgendwo dokumentieren. Kann es jemand bestätigen?

Marc Costa
quelle
2

Benutze das:

// Bind both, the consume buffer UAV and the append buffer UAV to the CS.
ID3D11UnorderedAccessView* UAVArray[2] = { mInputUAV, mOutputUAV };
UINT initialCounts[2] = { mNumElements, 0 };
md3dImmediateContext->CSSetUnorderedAccessViews( 0, 2, UAVArray, initialCounts );

kurz vor dem Anwenden der Tech-Pässe in der öffentlichen Funktion DoComputeWork ().

Dante
quelle