Écriture sur une texture compressée à l'aide d'un shader de calcul, sans copies supplémentaires

8

J'essaie de comprendre quelle est la meilleure façon de générer une texture OpenGL à l'aide d'un shader de calcul. Jusqu'à présent, j'ai lu que les objets tampons en pixels sont bons pour les transferts CPU non bloquants -> GPU, et que les shaders de calcul sont capables de lire et d'écrire des tampons quelle que soit la façon dont ils sont liés. Idéalement, j'aimerais éviter autant de copies que possible. En d'autres termes, j'aimerais allouer un tampon sur le GPU, y écrire des données de texture compressées, puis utiliser ce tampon comme objet de texture dans un shader.

Actuellement, mon code ressemble à ceci:

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);

Est-ce correct? J'ai lu quelque part sur la garantie de la synchronisation aussi. Que dois-je ajouter pour m'assurer que mon shader de calcul termine l'exécution avant de copier à partir de l'objet tampon?

Mokosha
la source
Souhaitez-vous spécifier le format de compression de texture que vous préférez? Je suppose, mais votre réponse impliquera probablement une routine de compression de texture en mode calcul.
ap_

Réponses:

3

Après avoir examiné cela pendant un certain temps, j'ai découvert deux ou trois choses:

  1. Vous ne pouvez pas éviter un memcpy : vous ne pouvez pas écrire directement dans le stockage de texture alloué pour une texture compressée en utilisant uniquement les appels API OpenGL. Cela signifie que vous ne pouvez pas éviter l'appel à glCompressedTexImage2Dun PBO lié. Cela étant dit, vous pouvez peut-être utiliser une texture RGBA 16 bits et un type d'image GLSL dans votre shader de calcul.

  2. Vous devez synchroniser la mémoire : pour vous assurer que votre shader de calcul termine l'écriture dans votre tampon de stockage, vous devez vous assurer que toutes les lectures et écritures y sont terminées. Cela se fait en appelant glMemoryBarrieravec GL_SHADER_STORAGE_BARRIER_BIT.

Le code complet de quelque chose qui écrit dans un tampon à utiliser comme texture compressée ressemble à ceci:

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
la source
"vous pourrez peut-être utiliser une texture RGBA 16 bits et un" ET QUOI ??? :)
Nathan Reed
2
Haha, c'est ce qui se passe lorsque vous laissez l'onglet ouvert pour terminer plus tard. Édité.
Mokosha
1
GL_SHADER_STORAGE_BARRIER_BITMauvaise barrière. La barrière que vous fournissez indique comment vous allez utiliser la mémoire. Pas comment le shader lui a écrit. Vous effectuez un transfert de pixels, vous devez donc utiliserGL_TEXTURE_UPDATE_BARRIER_BIT
Nicol Bolas
1
Êtes-vous sûr? Selon les documents , GL_TEXTURE_UPDATE_BARRIER_BITest utilisé lors de la synchronisation des appels vers glTexImage, et n'a rien à voir avec la mémoire utilisée dans les tampons de stockage. Je pense que tu voulais dire GL_PIXEL_BUFFER_BARRIER_BIT?
Mokosha