Schreiben in eine komprimierte Textur mit einem Compute-Shader ohne zusätzliche Kopien

8

Ich versuche herauszufinden, wie man am besten eine OpenGL-Textur mit einem Compute-Shader generiert. Bisher habe ich gelesen, dass Pixelpufferobjekte für nicht blockierende CPU-> GPU-Übertragungen geeignet sind und dass Compute-Shader Puffer lesen und schreiben können, unabhängig davon, wie sie gebunden sind. Im Idealfall möchte ich so viele Kopien wie möglich vermeiden. Mit anderen Worten, ich möchte einen Puffer auf der GPU zuweisen, komprimierte Texturdaten darauf schreiben und diesen Puffer dann als Texturobjekt in einem Shader verwenden.

Derzeit sieht mein Code ungefähr so ​​aus:

GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
glBufferStorage(GL_SHADER_STORAGE_BUFFER, tex_size_in_bytes, 0, 0);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);

// Bind buffer to resource in compute shader
// execute compute shader

glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer);
glCompressedTexImage2D(GL_TEXTURE_2D, 0, fmt, w, h, 0, tex_size_in_bytes, 0);

Ist das richtig? Ich habe auch irgendwo darüber gelesen, wie man Synchronisation garantiert. Was muss ich hinzufügen, um sicherzustellen, dass mein Compute-Shader die Ausführung vor dem Kopieren aus dem Pufferobjekt abschließt?

Mokosha
quelle
Möchten Sie angeben, welches Texturkomprimierungsformat Sie bevorzugen? Ich vermute, aber Ihre Antwort wird wahrscheinlich eine Textur-Komprimierungsroutine im Rechenmodus beinhalten.
10.

Antworten:

3

Nachdem ich mich eine Weile damit befasst hatte, fand ich ein paar Dinge heraus:

  1. Sie können ein Memcpy nicht vermeiden : Sie können nicht direkt in den Texturspeicher schreiben, der einer komprimierten Textur zugewiesen ist, indem Sie nur OpenGL-API-Aufrufe verwenden. Dies bedeutet, dass Sie den Anruf glCompressedTexImage2Dmit einem gebundenen PBO nicht vermeiden können . Abgesehen davon können Sie möglicherweise eine 16-Bit-RGBA-Textur und einen GLSL-Bildtyp in Ihrem Compute-Shader verwenden.

  2. Sie müssen den Speicher synchronisieren : Um sicherzustellen, dass Ihr Compute-Shader das Schreiben in Ihren Speicherpuffer beendet, müssen Sie sicherstellen, dass alle Lese- und Schreibvorgänge abgeschlossen sind. Dies geschieht durch einen Anruf glMemoryBarriermit GL_SHADER_STORAGE_BARRIER_BIT.

Der vollständige Code für etwas, das in einen Puffer geschrieben wird, um als komprimierte Textur verwendet zu werden, sieht folgendermaßen aus:

GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
glBufferStorage(GL_SHADER_STORAGE_BUFFER, tex_size_in_bytes, 0, 0);

glUseProgram(compute_shader_prog);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, compute_shader_bind_point, buffer);
glDispatchCompute(wg_x, wg_y, wg_z);
glMemoryBarrier(GL_SHADER_STORAGE_BUFFER_BIT);

glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer);
glCompressedTexImage2D(GL_TEXTURE_2D, 0, fmt, w, h, 0, tex_size_in_bytes, 0);
Mokosha
quelle
"Möglicherweise können Sie eine 16-Bit-RGBA-Textur und eine" UND EIN WAS ??? :)
Nathan Reed
2
Haha, das passiert, wenn Sie die Registerkarte offen lassen, um sie später zu beenden. Bearbeitet.
Mokosha
1
GL_SHADER_STORAGE_BARRIER_BITFalsche Barriere. Die Barriere Sie bieten angibt , wie Sie verwenden den Speicher. Nicht wie der Shader darauf geschrieben hat. Sie machen eine Pixelübertragung, also müssen Sie verwendenGL_TEXTURE_UPDATE_BARRIER_BIT
Nicol Bolas
1
Bist du sicher? Nach der Dokumentation , wird GL_TEXTURE_UPDATE_BARRIER_BITverwendet, wenn Anrufe zu synchronisieren glTexImage, und hat nichts mit dem Speicher in Speicherpuffern verwendet zu tun. Ich denke du meintest GL_PIXEL_BUFFER_BARRIER_BIT?
Mokosha