Вычислить шейдер не пишет в SSBO
Я пишу простой тестовый вычислительный шейдер, который записывает значение 5,0 для каждого элемента в буфере. Значения буфера инициализируются в -1, так что я знаю, являются ли проблема созданием буфера и чтением буфера.
class ComputeShaderWindow : public QOpenGLWindow {
public:
void initializeGL() {
// Create the opengl functions object
gl = context()->versionFunctions<QOpenGLFunctions_4_3_Core>();
m_compute_program = new QOpenGLShaderProgram(this);
auto compute_shader_s = fs::readFile(
"test_assets/example_compute_shader.comp");
// Adds the compute shader, then links and binds it
m_compute_program->addShaderFromSourceCode(QOpenGLShader::Compute,
compute_shader_s);
m_compute_program->link();
m_compute_program->bind();
// Fills the buffer with -1, so we know whether the problem
// is the compute shader not being invoked or not reading
// the buffer correctly afterwards.
GLfloat* default_values = new GLfloat[NUM_INVOCATIONS];
std::fill(default_values, default_values + NUM_INVOCATIONS, -1.0);
GLuint ssbo;
gl->glGenBuffers(1, &ssbo);
gl->glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
gl->glBufferData(GL_SHADER_STORAGE_BUFFER,
NUM_INVOCATIONS,
default_values,
GL_DYNAMIC_DRAW);
gl->glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
gl->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0);
gl->glDispatchCompute(NUM_INVOCATIONS / WORKGROUP_SIZE, 1, 1);
gl->glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
gl->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0);
gl->glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
// Now map the buffer so that we can check its values
GLfloat* read_data = (GLfloat*) gl->glMapBuffer(GL_SHADER_STORAGE_BUFFER,
GL_READ_ONLY);
std::vector<GLfloat> buffer_data(NUM_INVOCATIONS);
for (int i = 0; i < NUM_INVOCATIONS; i++) {
buffer_data[i] = read_data[i];
}
gl->glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
for (int i = 0; i < NUM_INVOCATIONS; i++) {
DEBUG(buffer_data[i]);
}
assert(gl->glGetError() == GL_NO_ERROR);
}
void resizeGL(int width, int height) {
}
void paintGL() {
}
void teardownGL() {
}
private:
QOpenGLFunctions_4_3_Core* gl;
QOpenGLShaderProgram* m_compute_program;
static constexpr int NUM_INVOCATIONS = 9000;
static constexpr int WORKGROUP_SIZE = 128;
};
Мой вычислительный шейдер довольно прост:
#version 430 core
layout(std430, binding = 0) writeonly buffer SSBO {
float data[];
};
layout(local_size_x = 128) in;
void main() {
uint ident = gl_GlobalInvocationID.x;
data[ident] = 5.0f;
}
Когда я читаю буфер, чаще всего это -1, но некоторые данные состоят из случайных значений с плавающей запятой (-nan, 0 и т. Д.). Что тут происходит?
РЕДАКТИРОВАТЬ: изменение барьера памяти на GL_BUFFER_UPDATE_BARRIER_BIT
(или даже GL_ALL_BARRIER_BITS
) не решает проблему; Я не понимаю, как этот вопрос является дубликатом.
1 ответ
Эта маленькая проблема заняла у меня слишком много времени, чтобы понять. Здесь есть пара ошибок.
Эта линия
gl->glBufferData(GL_SHADER_STORAGE_BUFFER,
NUM_INVOCATIONS,
default_values,
GL_DYNAMIC_DRAW);
должно быть
gl->glBufferData(GL_SHADER_STORAGE_BUFFER,
NUM_INVOCATIONS * sizeof(float),
default_values,
GL_DYNAMIC_DRAW);
чтобы мы скопировали правильное количество байтов. И этот блок должен быть
gl->glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
gl->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0);
gl->glDispatchCompute(NUM_INVOCATIONS / WORKGROUP_SIZE, 1, 1);
gl->glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
gl->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0);
gl->glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
должно быть
gl->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo);
gl->glDispatchCompute(NUM_INVOCATIONS / WORKGROUP_SIZE, 1, 1);
gl->glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
gl->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo);
Вызовы glBindBufferBase принимают объект ssbo в качестве третьего параметра. Не знаю, почему я это дал 0
первоначально. Также вызовы glBindBuffer не нужны (для целей вычислительного шейдера нам просто нужно привязаться к индексируемому целевому буферу).