[DX11] Shader liest mehr Daten als er soll

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
Degenerated
Beiträge: 10
Registriert: 19.11.2015, 00:04

[DX11] Shader liest mehr Daten als er soll

Beitrag von Degenerated »

Hallo alle zusammen!

Ich bin gerade auf ein sehr merkwürdiges Problem gestoßen und hoffe, dass ich am Ende einfach nur zu blind oder müde war.
Es geht um folgendes: Ich habe einen Pixelshader, dem ich eine Reihe an Lichtinformationen zum Himmel über einen Constantbuffer gebe. In diesem Buffer sind auch noch einige Matrizen und Informationen über die Szene, sodass der Buffer am ende rund 1300bytes groß ist:

Code: Alles auswählen

struct SceneParams
{
	float S_FogStart;
	float S_FogEnd;
	float S_FogRange; // = FogEnd - FogStart
	float S_pad0;
	float4 S_FogColor;
	
	uint S_LightCLUT[256]; // CLUT from gothic
};

cbuffer CB_PerFrame : register( b0 )
{
	matrix M_View;
	matrix M_Proj;
	matrix M_ViewProj;	
	matrix M_InverseView;
	
	SceneParams PF_SceneParams;
	
};
Ich möchte also per Index auf das LightCLUT-Array zugreifen, wobei der Index aus einem Input-Vertex kommt:

Code: Alles auswählen

float4 GetLightCLUT(float lighting)
{
	// This is the way PB computes the index for the CLUT
	uint v = clamp((uint)(lighting.x * 255), 0, 255);
	return DWORDToFloat4(PF_SceneParams.S_LightCLUT[v]);
};
Dort steht eben, dass wir einen Wert von 0..1 auf 0..255 bringen und einmal clampen. Jetzt kommt aber das komische, und das passiert auch, wenn ich den Index hardcode:

Der Debug-Layer schmeißt mir dort eine Warnung, dass ich versuchen würde über die Grenzen des Constantbuffers hinauszulesen (Es werden über 4000bytes erwartet, aber der Buffer hat ja nur knapp 1300.)! Selbst wenn ich dort 64 hineinschreibe, bin ich schon ein paar Bytes drüber. Allerdings ist der Buffer nicht zu klein, denn sogar der Debuglayer kennt die richtige Größe des Buffers, da dort ja steht wie viele vorhanden waren und was tatsächlich gelesen wurde.

Edit: Hier, die Warnung, entstanden aus folgender Zeile:

Code: Alles auswählen

DWORDToFloat4(PF_SceneParams.S_LightCLUT[64])
=>
D3D11 WARNING: ID3D11DeviceContext::DrawIndexed: The size of the Constant Buffer at slot 0 of the Pixel Shader unit is too small (1312 bytes provided, 1328 bytes, at least, expected). This is OK, as out-of-bounds reads are defined to return 0. It is also possible the developer knows the missing data will not be used anyway. This is only a problem if the developer actually intended to bind a sufficiently large Constant Buffer for what the shader expects.  [ EXECUTION WARNING #351: DEVICE_DRAW_CONSTANT_BUFFER_TOO_SMALL]
Liest man dagegen Array-Index 255 aus, wird eine Größe von mindestens 4384 bytes erwartet.

Woher könnte also diese Warnung kommen, und wie bringe ich HLSL dazu, das zu tun, was es eigentlich tun sollte?

Grüße,
Degenerated
Zuletzt geändert von Degenerated am 14.01.2016, 15:18, insgesamt 1-mal geändert.
David_pb
Beiträge: 18
Registriert: 23.07.2014, 20:50

Re: [DX11] Shader liest mehr Daten als er soll

Beitrag von David_pb »

Hi,

der Code dürfte eigentlich gar nicht bauen da du versuchst Werte direkt aus "S_LightCLUT" zu lesen. Richtigerweise sollten die Werte ja aus "PF_SceneParams.S_LightCLUT" kommen (angenommen natürlich, das du keine weitere "Macro-Magic" in DWORDToFloat4 machst). Könntest du die Meldung des Debuglayers auch noch posten, möglicherweise hilft das ja.
Degenerated
Beiträge: 10
Registriert: 19.11.2015, 00:04

Re: [DX11] Shader liest mehr Daten als er soll

Beitrag von Degenerated »

Ach, natürlich. Ich hatte davor mal geschaut ob es daran liegt, dass das Array in einer Struktur ist, und es deswegen mal direkt in den Constant-Buffer geschrieben. Anscheinend habe ich den Code danach nicht wieder Kompiliert. Die Warnung und die Berichtigung habe ich oben mal dazueditiert.

Edit: Anscheinend bekommt jedes uint im Array sein eigenes 16-byte Alignment. Hier ist eine mögliche Lösung: http://stackoverflow.com/questions/2866 ... ked-floats
David_pb
Beiträge: 18
Registriert: 23.07.2014, 20:50

Re: [DX11] Shader liest mehr Daten als er soll

Beitrag von David_pb »

Degenerated hat geschrieben:Edit: Anscheinend bekommt jedes uint im Array sein eigenes 16-byte Alignment. Hier ist eine mögliche Lösung: http://stackoverflow.com/questions/2866 ... ked-floats
Genau, du hast den Grund ja bereits selbst festgestellt. Hier gibts auch nochmal eine Übersicht zu allen Regeln, u.A.:
Arrays are not packed in HLSL by default. To avoid forcing the shader to take on ALU overhead for offset computations, every element in an array is stored in a four-component vector. Note that you can achieve packing for arrays (and incur the addressing calculations) by using casting.
Falls dir der (mögliche) zusätzliche ALU overhead egal ist, kannst du das Array auch gepackt übergeben und in den richtigen typ casten:

Code: Alles auswählen

static const uint SIZE_OF_LUT = 256;

struct SceneParams
{
    float S_FogStart;
    float S_FogEnd;
    float S_FogRange; // = FogEnd - FogStart
    // float S_pad0; padding wird automatisch vom compiler vorgenommen
    float4 S_FogColor;

    uint4 S_LightCLUT[SIZE_OF_LUT/4]; // CLUT from gothic
};

//...

uint lightCLUT[SIZE_OF_LUT] = (uint[SIZE_OF_LUT])PF_SceneParams.S_LightCLUT;
Degenerated
Beiträge: 10
Registriert: 19.11.2015, 00:04

Re: [DX11] Shader liest mehr Daten als er soll

Beitrag von Degenerated »

David_pb hat geschrieben: Falls dir der (mögliche) zusätzliche ALU overhead egal ist, kannst du das Array auch gepackt übergeben und in den richtigen typ casten:
Danek nochmal für die Antwort. Genau so mache ich es jetzt auch. Könnte man das ganze eigentlich lösen, ohne die ALU noch mehr zu beschäftigen? Mir fällt da im Moment nur eine Textur ein.

Jetzt mal davon abgesehen, dass eine Textur für genau diese Geschichte vermutlich die bessere Wahl wäre, würde es trotzdem irgendwie gehen, nur so rein aus Interesse?
Benutzeravatar
Krishty
Establishment
Beiträge: 8237
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [DX11] Shader liest mehr Daten als er soll

Beitrag von Krishty »

Via StructuredBuffer, schätze ich.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Degenerated
Beiträge: 10
Registriert: 19.11.2015, 00:04

Re: [DX11] Shader liest mehr Daten als er soll

Beitrag von Degenerated »

Stimmt, die gibt es ja auch noch! Das wäre wohl genau das, was man für solche Dinge bräuchte.
Antworten