glMapBufferRange отображает только 1 из 4 значений. Зачем?
Я пытался запустить вычислительный шейдер - демонстрационная версия префикса суммы представлена на:
https://github.com/openglsuperbible/sb7code/blob/master/src/prefixsum/prefixsum.cpp
Я использовал точный код:
#define NUM_ELEMENTS 2048
float random_float()
{
static unsigned int seed = 0x13371337;
float res;
unsigned int tmp;
seed *= 16807;
tmp = seed ^ (seed >> 4) ^ (seed << 15);
*((unsigned int *)&res) = (tmp >> 9) | 0x3F800000;
return (res - 1.0f);
}
static int PrefixSum(int programHandle)
{
GLuint data_buffer[2];
float input_data[NUM_ELEMENTS];
float output_data[NUM_ELEMENTS];
glGenBuffers(2, data_buffer);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, data_buffer[0]);
glBufferData(GL_SHADER_STORAGE_BUFFER, NUM_ELEMENTS * sizeof(float), NULL, GL_DYNAMIC_DRAW);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, data_buffer[1]);
glBufferData(GL_SHADER_STORAGE_BUFFER, NUM_ELEMENTS * sizeof(float), NULL, GL_DYNAMIC_COPY);
int i;
for (i = 0; i < NUM_ELEMENTS; i++)
{
input_data[i] = random_float();
}
glShaderStorageBlockBinding(programHandle, 0, 0);
glShaderStorageBlockBinding(programHandle, 1, 1);
float * ptr;
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, data_buffer[0], 0, sizeof(float) * NUM_ELEMENTS);
glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(float) * NUM_ELEMENTS, input_data);
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 1, data_buffer[1], 0, sizeof(float) * NUM_ELEMENTS);
glUseProgram(programHandle);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
glFinish();
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, data_buffer[1], 0, sizeof(float) * NUM_ELEMENTS);
ptr = (float *)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(float) * NUM_ELEMENTS, GL_MAP_READ_BIT);
char buffer[1024];
sprintf(buffer, "SUM: %2.2f %2.2f %2.2f %2.2f %2.2f %2.2f %2.2f %2.2f "
"%2.2f %2.2f %2.2f %2.2f %2.2f %2.2f %2.2f %2.2f",
ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7],
ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15]);
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
}
И это шейдер:
#version 430 core
layout (local_size_x = 1024) in;
layout (binding = 0) coherent readonly buffer block1
{
float input_data[gl_WorkGroupSize.x];
};
layout (binding = 1) coherent writeonly buffer block2
{
float output_data[gl_WorkGroupSize.x];
};
shared float shared_data[gl_WorkGroupSize.x * 2];
void main(void)
{
uint id = gl_LocalInvocationID.x;
uint rd_id;
uint wr_id;
uint mask;
const uint steps = uint(log2(gl_WorkGroupSize.x)) + 1;
uint step = 0;
shared_data[id * 2] = input_data[id * 2];
shared_data[id * 2 + 1] = input_data[id * 2 + 1];
barrier();
for (step = 0; step < steps; step++)
{
mask = (1 << step) - 1;
rd_id = ((id >> step) << (step + 1)) + mask;
wr_id = rd_id + 1 + (id & mask);
shared_data[wr_id] += shared_data[rd_id];
barrier();
}
output_data[id * 2] = shared_data[id * 2];
output_data[id * 2 + 1] = shared_data[id * 2 + 1];
}
Проблема в том, что вывод записывается в 1 из 4 мест:
SUM: 0.70 0.00 0.00 0.00 1.69 0.00 0.00 0.00 1.81 0.00 0.00 0.00 2.59 0.00 0.00 0.00
Это вход:
[0] 0.700959682 float
[1] 0.837353945 float
[2] 0.403481007 float
[3] 0.856583834 float
[4] 0.993326187 float
[5] 0.727316380 float
[6] 0.768217087 float
[7] 0.0675410032 float
[8] 0.112720609 float
[9] 0.703838706 float
[10] 0.365846157 float
[11] 0.504367113 float
[12] 0.778576016 float
[13] 0.217134356 float
[14] 0.944752693 float
[15] 0.575236082 float
[16] 0.795839429 float
[17] 0.707037449 float
[18] 0.181974053 float
[19] 0.745973587 float
[20] 0.281350732 float
2 ответа
Решение
Решено: указание стандарта упаковки для буфера решило проблему:
layout (std430, binding = 1) coherent writeonly buffer block2
{
float output_data[gl_WorkGroupSize.x];
};
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
Барьер памяти определяет способ доступа к объекту после записи, а не способ записи в него. Вы собираетесь читать с объекта, сопоставляя его для чтения, поэтому вы должны сказать это. В частности, вы должны использовать GL_BUFFER_UPDATE_BARRIER_BIT
,
Также:
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, data_buffer[1], 0, sizeof(float) * NUM_ELEMENTS);
Это должно быть просто glBindBuffer(GL_SHADER_STORAGE_BUFFER)
, Вы связываете это, чтобы отобразить это, а не использовать в операции хранения.