Gravando em uma textura compactada usando um sombreador de computação, sem cópias extras

8

Estou tentando descobrir qual é a melhor maneira de gerar uma textura OpenGL usando um sombreador de computação. Até agora, eu li que os objetos de buffer de pixel são bons para transferências de CPU -> GPU sem bloqueio e que os sombreadores de computação são capazes de ler e escrever buffers, independentemente de como eles estejam vinculados. Idealmente, gostaria de evitar o maior número possível de cópias. Em outras palavras, eu gostaria de alocar um buffer na GPU, gravar dados de textura compactados e usá-lo como objeto de textura em um shader.

Atualmente, meu código é algo como isto:

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

Isso está correto? Também li em algum lugar sobre a garantia de sincronização. O que preciso adicionar para garantir que meu sombreador de computação conclua a execução antes de copiar do objeto de buffer?

Mokosha
fonte
Deseja especificar qual formato de compactação de textura você prefere? Estou supondo, mas sua resposta provavelmente envolverá uma rotina de compactação de textura no modo de computação.
ap_

Respostas:

3

Depois de analisar isso por um tempo, descobri algumas coisas:

  1. Você não pode evitar um memcpy : não é possível gravar diretamente no armazenamento de textura alocado para uma textura compactada usando apenas chamadas da API OpenGL. Isso significa que você não pode evitar a chamada glCompressedTexImage2Dcom um PBO vinculado. Dito isto, você poderá usar uma textura RGBA de 16 bits e um tipo de imagem GLSL no seu sombreador de computação.

  2. Você precisa sincronizar a memória : Para garantir que o seu sombreador de computação termine de gravar no buffer de armazenamento, verifique se todas as leituras e gravações nele terminam. Isso é feito chamando glMemoryBarriercom GL_SHADER_STORAGE_BARRIER_BIT.

O código completo de algo que grava em um buffer para ser usado como uma textura compactada se parece com isso:

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
fonte
"você pode usar uma textura RGBA de 16 bits e uma" AND A WHAT ??? :)
Nathan Reed
2
Haha, é isso que acontece quando você deixa a guia aberta para terminar mais tarde. Editado.
Mokosha 19/09/2015
11
GL_SHADER_STORAGE_BARRIER_BITBarreira errada. A barreira que você fornece indica como você usará a memória. Não como o shader escreveu para ele. Você está fazendo uma transferência pixel, então você precisa para usoGL_TEXTURE_UPDATE_BARRIER_BIT
Nicol Bolas
11
Você tem certeza? De acordo com os documentos , GL_TEXTURE_UPDATE_BARRIER_BITé usado ao sincronizar chamadas glTexImagee não tem nada a ver com a memória usada nos buffers de armazenamento. Eu acho que você quis dizer GL_PIXEL_BUFFER_BARRIER_BIT?
Mokosha