2016-06-20 8 views
1

Ich habe etwas mit GL3.3 geschrieben, das einen einheitlichen Puffer benötigt, und nutzt die Informationen, um Sprite-Kacheln in einem Frag-Shader auszuwählen. Es funktioniert auf meinem Desktop mit einer Nvidia GTX780, aber mein AMD-basierter Laptop (A6-4455M) hat einige Probleme damit. Beide sind auf den neuesten (oder sehr aktuellen) Treibern.Einheitliche gepufferte Array-Elemente sind falsch

Zurück zum Code, Es richtet zunächst einen einheitlichen Puffer ein, der aus zwei uints und einem uint-Array besteht. Sie werden dann gefüllt und im Shader aufgerufen. Zuerst bekam ich einen GL-Fehler auf dem Laptop, weil ich nicht genug zuzuteilen, aber eine temporäre Änderung, die Padding berücksichtigt, hat das aussortiert, und jetzt werden Daten tatsächlich gepuffert.

Die ersten beiden sind kein Problem. Ich habe auch das Array im Shader etwas lesbar, es gibt nur ein Problem; Die Daten werden mit vier multipliziert! Im Moment ist das Array nur ein paar Testdaten, die auf seinen Index initialisiert wurden, also spriteArr [1] == 1, spriteArr [34] == 34, etc. Allerdings gibt spriteArr [10] im Shader darauf hin 40. Das geht bis zu spriteArr [143] == 572. Darüber hinaus und es ist etwas anderes. Ich weiß nicht genau, warum das so ist, aber es scheint ein falscher Offset zu sein.

Ich verwende das gemeinsame einheitliche Layout und die Uniform Offsets von GL selbst, so dass sie korrekt sein sollten. Ich habe bemerkt, dass die Offsets auf der AMD-Karte viel größer sind, als wenn sie mehr Padding hinzufügen würde. Sie sind immer 0,4,8 auf dem Desktop, aber 0,16,32 auf dem Laptop.

Wenn es einen Unterschied macht, gibt es einen anderen UBO (Bindungspunkt 0), der für die Ansichts- und Projektionsmatrizen verwendet wird. Diese funktionieren wie beabsichtigt. Es wird jedoch nicht im Fragment-Shader verwendet. Es wird auch vor diesem UBO erstellt.

UBO Initialisierungscode:

GLuint spriteUBO; 
glGenBuffers(1, &spriteUBO); 
glBindBuffer(GL_UNIFORM_BUFFER, spriteUBO); 
unsigned maxsize = (2 + 576 + 24) * sizeof(GLuint); 
/*Bad I know, but temporary. AMD's driver adds 24 bytes of padding. Nvidias has none. 
Not the cause of this problem. At least ensures we have enough allocated. */ 

glBufferData(GL_UNIFORM_BUFFER, maxsize, NULL, GL_STATIC_DRAW); 
glBindBuffer(GL_UNIFORM_BUFFER, 0); 
//Set binding point 
GLuint spriteUBOIndex = glGetUniformBlockIndex(programID, "SpriteMatchData"); 
glUniformBlockBinding(programID, spriteUBOIndex, 1); 


static const GLchar *unames[] = 
{ 
    "width", "height", 
    //"size", 
    "spriteArr" 
}; 

GLuint uindices[3]; 
GLint offsets[3]; 
glGetUniformIndices(programID,3,unames,uindices); 
glGetActiveUniformsiv(programID, 3, uindices, GL_UNIFORM_OFFSET, offsets); 

//buffer stuff 
glBindBufferBase(GL_UNIFORM_BUFFER, 1, spriteUBO); 
glBufferSubData(GL_UNIFORM_BUFFER,offsets[0], sizeof(GLuint), tm.getWidth()); 
glBufferSubData(GL_UNIFORM_BUFFER, offsets[1], sizeof(GLuint), tm.getHeight()); 
glBufferSubData(GL_UNIFORM_BUFFER, offsets[2], tm.getTileCount() * sizeof(GLuint), tm.getSpriteArray()); 

Fragment Shader:

layout (shared) uniform SpriteMatchData{ 
uint width, height; 
uint spriteArr[576];}; 

Dann später ich mit so etwas wie dies mit dem Array experimentieren:

if(spriteArr[10] == uint(40)) 
{ 
debug_colour = vec4(0.0,1.0,0.0,0.0);//green 
} 
else 
{ 
debug_colour = vec4(1.0,0.0,0.0,0.0); //red 
} 

Mit debug_colour grün Drehen in diese Instanz.

Gibt es eine Möglichkeit, dies mit etwas zu lösen, das mit beiden Systemen funktioniert? Warum geht der AMD Treiber so anders damit um? Könnte es sich um einen Fehler in der Art und Weise handeln, wie es mit uniformen UInt-Arrays umgeht?

Antwort

1

Warum geht der AMD Treiber so anders damit um?

Denn das ist, was Sie gefragt:

layout (shared) uniform SpriteMatchData 

Sie explizit für shared Layout gefragt. Dieses Layout ist Implementierung definiert. Daher können zwei verschiedene Implementierungen Ihnen zwei verschiedene Layouts geben. Wenn Sie also SpriteMatchData in einer plattformunabhängigen Weise verwenden möchten, müssen Sie sein Layout aus dem Programm abfragen, nachdem Sie es verknüpft haben.

Während Sie die Offsets für die Werte abgefragt haben, haben Sie nicht Abfrage der Array-Schritt: der Byte-Offset von Element zu Element innerhalb des Arrays. In der Spezifikation ist nichts enthalten, was erfordert, dass shared Layouts Arrays dicht zusammenpacken.

Wirklich gibt es aber so ziemlich keinen Grund, nicht std140 Layout zu verwenden. Sie können all diese Abfragen von Offsets vermeiden und einfach C++ - Strukturen entwerfen, die direkt von GLSL konsumiert werden können.

+0

Danke, ich überprüfe die Array-Schritte in ein bisschen, ich vergaß diese und automatisch angenommen, dass sie korrekt sein würden. Es scheint so, als könnte das das Problem sein. – Teaplusplus

+0

Nur einen kurzen Test gemacht, und ja, die Schritte sind anders. 4 auf dem Desktop und 16 auf dem Laptop, was zu dem passt, was ich bekomme. Ich nehme an, der Standard-Array-Schritt ist mehr für Arrays von vec4s als uints eingerichtet. Ich habe std140 nicht früher benutzt, weil ich ein Problem damit hatte, aber ich werde es jetzt noch einmal versuchen. Ich weiß, dass es wahrscheinlich mit dem Array-Schritt zusammenhängt oder nicht genug Platz für seine zusätzliche Auffüllung zuweist. – Teaplusplus