使用 imageStore 从计算着色器写入后使用 glGetTexImage 读取纹理数据
Reading texture data with glGetTexImage after writing from compute shader with imageStore
我在计算着色器中为 3D 纹理生成噪声,然后在 CPU 上构建网格。当我在主循环中执行此操作时它工作正常,但我注意到我在第一次渲染时只填充了 ~1% 的噪声。这是最小的例子,我试图用着色器中的纹理填充 3D 纹理,但在 return:
中得到零或噪声
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stdio.h>
#include <stdlib.h>
void error(const char* message) { ... }
const char* slurp_file(const char* filename) { ... }
int main() {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(100, 100, "", NULL, NULL);
glfwMakeContextCurrent(window);
gladLoadGL();
// create texture
GLuint texture;
glGenTextures(1, &texture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_3D, texture);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
// allocate it
size_t size = 4;
glTexImage3D(GL_TEXTURE_3D, 0, GL_R32F, size, size, size, 0, GL_RED, GL_FLOAT, NULL);
// create shader
const char* shader_source = slurp_file("shaders/example.comp");
GLuint shader = glCreateShader(GL_COMPUTE_SHADER);
glShaderSource(shader, 1, &shader_source, NULL);
glCompileShader(shader);
// check it
int code;
glGetShaderiv(shader, GL_COMPILE_STATUS, &code);
if (!code) error("shader compilation failed");
// create program
int program = glCreateProgram();
glAttachShader(program, shader);
glLinkProgram(program);
// check it
glGetProgramiv(program, GL_LINK_STATUS, &code);
if (!code) error("program linkage failed");
// run shader
glUseProgram(program);
// i don't think it's needed, as 0 would be a default value
int uniform_loc = glGetUniformLocation(program, "img_output");
glUniform1i(uniform_loc, 0);
// dispatch and sync
glDispatchCompute(size, size, size);
// originally i had GL_TEXTURE_FETCH_BARRIER_BIT here
glMemoryBarrier(GL_ALL_BARRIER_BITS);
// read texture data
float* data = malloc(size * size * size * sizeof(float));
glBindImageTexture(0, texture, 0, GL_TRUE, 0, GL_READ_WRITE, GL_R32F);
glGetTexImage(GL_TEXTURE_3D, 0, GL_RED, GL_FLOAT, data);
// prints 0s or noise, but i expect all 1s
for (int i = 0; i < size * size * size; i++)
printf("%f ", data[i]);
}
这是着色器:
#version 430
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(binding = 0, r32f) writeonly uniform image3D img_output;
void main() {
ivec3 texture_coords = ivec3(gl_GlobalInvocationID.xyz);
vec4 pixel = vec4(1, 0, 0, 0);
imageStore(img_output, texture_coords, pixel);
}
只是在 glDispatchCompute
之后添加 sleep 没有任何作用,所以我想我缺少一些锁定?或者纹理应该以其他方式配置?
在执行计算着色器之前,您需要将纹理绑定到图像单元。纹理对象和着色器之间的绑定是通过纹理图像单元建立的。着色器知道单位,因为你设置了单位变量或用布局限定符指定绑定点,但你还需要将对象绑定到单位:
glBindImageTexture(0, texture, 0, GL_TRUE, 0, GL_READ_WRITE, GL_R32F);
glDispatchCompute(size, size, size);
我在计算着色器中为 3D 纹理生成噪声,然后在 CPU 上构建网格。当我在主循环中执行此操作时它工作正常,但我注意到我在第一次渲染时只填充了 ~1% 的噪声。这是最小的例子,我试图用着色器中的纹理填充 3D 纹理,但在 return:
中得到零或噪声#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stdio.h>
#include <stdlib.h>
void error(const char* message) { ... }
const char* slurp_file(const char* filename) { ... }
int main() {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(100, 100, "", NULL, NULL);
glfwMakeContextCurrent(window);
gladLoadGL();
// create texture
GLuint texture;
glGenTextures(1, &texture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_3D, texture);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
// allocate it
size_t size = 4;
glTexImage3D(GL_TEXTURE_3D, 0, GL_R32F, size, size, size, 0, GL_RED, GL_FLOAT, NULL);
// create shader
const char* shader_source = slurp_file("shaders/example.comp");
GLuint shader = glCreateShader(GL_COMPUTE_SHADER);
glShaderSource(shader, 1, &shader_source, NULL);
glCompileShader(shader);
// check it
int code;
glGetShaderiv(shader, GL_COMPILE_STATUS, &code);
if (!code) error("shader compilation failed");
// create program
int program = glCreateProgram();
glAttachShader(program, shader);
glLinkProgram(program);
// check it
glGetProgramiv(program, GL_LINK_STATUS, &code);
if (!code) error("program linkage failed");
// run shader
glUseProgram(program);
// i don't think it's needed, as 0 would be a default value
int uniform_loc = glGetUniformLocation(program, "img_output");
glUniform1i(uniform_loc, 0);
// dispatch and sync
glDispatchCompute(size, size, size);
// originally i had GL_TEXTURE_FETCH_BARRIER_BIT here
glMemoryBarrier(GL_ALL_BARRIER_BITS);
// read texture data
float* data = malloc(size * size * size * sizeof(float));
glBindImageTexture(0, texture, 0, GL_TRUE, 0, GL_READ_WRITE, GL_R32F);
glGetTexImage(GL_TEXTURE_3D, 0, GL_RED, GL_FLOAT, data);
// prints 0s or noise, but i expect all 1s
for (int i = 0; i < size * size * size; i++)
printf("%f ", data[i]);
}
这是着色器:
#version 430
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(binding = 0, r32f) writeonly uniform image3D img_output;
void main() {
ivec3 texture_coords = ivec3(gl_GlobalInvocationID.xyz);
vec4 pixel = vec4(1, 0, 0, 0);
imageStore(img_output, texture_coords, pixel);
}
只是在 glDispatchCompute
之后添加 sleep 没有任何作用,所以我想我缺少一些锁定?或者纹理应该以其他方式配置?
在执行计算着色器之前,您需要将纹理绑定到图像单元。纹理对象和着色器之间的绑定是通过纹理图像单元建立的。着色器知道单位,因为你设置了单位变量或用布局限定符指定绑定点,但你还需要将对象绑定到单位:
glBindImageTexture(0, texture, 0, GL_TRUE, 0, GL_READ_WRITE, GL_R32F);
glDispatchCompute(size, size, size);