计算着色器中的 imageStore 问题
Problem with imageStore in compute shader
我有一个非常简单的计算着色器的问题,它只是使用 imageStore 复制纹理。
#define KS 16 // kernel size
layout (local_size_x = KS, local_size_y = KS) in;
layout(location = 0) uniform sampler2D u_inputTex;
layout(location = 1) uniform writeonly image2D u_outImg;
void main()
{
const ivec2 gid = ivec2(gl_WorkGroupID.xy);
const ivec2 tid = ivec2(gl_LocalInvocationID.xy);
const ivec2 pixelPos = ivec2(KS) * gid + tid;
imageStore(u_outImg, pixelPos,
uvec4(255.0 * texelFetch(u_inputTex, pixelPos, 0).rgb, 255u));
}
在 C++ 方面,我有这个:
int w, h;
u32 inTex = -1;
{
int nc;
auto img = stbi_load("imgs/Windmill_NOAA.png", &w, &h, &nc, 3);
if (img) {
glGenTextures(1, &inTex);
glBindTexture(GL_TEXTURE_2D, inTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, img);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
stbi_image_free(img);
}
else
printf("Error loading img\n");
}
u32 outTex;
{
glGenTextures(1, &outTex);
glBindTexture(GL_TEXTURE_2D, outTex);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8UI, w, h);
}
u32 compProg = easyCreateComputeShaderProg("compute", shader_srcs::computeSrc);
glUseProgram(compProg);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, inTex);
glBindImageTexture(0, outTex, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8UI);
glUniform1i(0, 0);
glUniform1i(1, 0);
glDispatchCompute((w+15)/16, (h+15)/16, 1);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); // make sure the output image has been written
u8* img = new u8[w * h * 4];
glBindTexture(GL_TEXTURE_2D, outTex);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, img);
stbi_write_png("imgs/out.png", w, h, 1, img, w*4);
delete[] img;
输入图像如下所示:
但这是我在输出图像中得到的:
我进一步简化了着色器:我不从输入纹理读取,而是写入一个固定值:
imageStore(u_outImg, pixelPos,
//uvec4(255.0 * texelFetch(u_inputTex, pixelPos, 0).rgb, 255u));
uvec4(1u));
我注意到:
- 如果我写0全黑
- 如果我写255就全白了
- 但是如果我在中间写一些东西(例如100)它不是灰色而是白色
我也这样试过,但也没用:
imageStore(u_outImg, pixelPos,
vec4(texelFetch(u_inputTex, pixelPos, 0).rgb, 255u));
我做错了什么?我的最终目标是制作一个 prostprocessing 过滤器,但我无法让它工作,所以我试图让它尽可能简单,但它不起作用。
最小示例回购:https://github.com/tuket/Whosebug_image_store_problem
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8UI, w, h);
如果要使用非规范化无符号整数图像,必须在sahder中将其声明为uimage2D
。 image2D
仅适用于 floating-point 或规范化整数(范围 [0,1]
)。
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
那是错误的记忆障碍。屏障是关于你将如何访问你的着色器修改的资源在屏障之后,所以正确的是:
GL_TEXTURE_UPDATE_BARRIER_BIT
在 reference page 中解释为(强调我的):
Writes to a texture via glTex(Sub)Image*
, glCopyTex(Sub)Image*
,
glCompressedTex(Sub)Image*
, and reads via glGetTexImage
after the
barrier will reflect data written by shaders prior to the barrier.
Additionally, texture writes from these commands issued after the
barrier will not execute until all shader writes initiated prior to
the barrier complete.
我有一个非常简单的计算着色器的问题,它只是使用 imageStore 复制纹理。
#define KS 16 // kernel size
layout (local_size_x = KS, local_size_y = KS) in;
layout(location = 0) uniform sampler2D u_inputTex;
layout(location = 1) uniform writeonly image2D u_outImg;
void main()
{
const ivec2 gid = ivec2(gl_WorkGroupID.xy);
const ivec2 tid = ivec2(gl_LocalInvocationID.xy);
const ivec2 pixelPos = ivec2(KS) * gid + tid;
imageStore(u_outImg, pixelPos,
uvec4(255.0 * texelFetch(u_inputTex, pixelPos, 0).rgb, 255u));
}
在 C++ 方面,我有这个:
int w, h;
u32 inTex = -1;
{
int nc;
auto img = stbi_load("imgs/Windmill_NOAA.png", &w, &h, &nc, 3);
if (img) {
glGenTextures(1, &inTex);
glBindTexture(GL_TEXTURE_2D, inTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, img);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
stbi_image_free(img);
}
else
printf("Error loading img\n");
}
u32 outTex;
{
glGenTextures(1, &outTex);
glBindTexture(GL_TEXTURE_2D, outTex);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8UI, w, h);
}
u32 compProg = easyCreateComputeShaderProg("compute", shader_srcs::computeSrc);
glUseProgram(compProg);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, inTex);
glBindImageTexture(0, outTex, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8UI);
glUniform1i(0, 0);
glUniform1i(1, 0);
glDispatchCompute((w+15)/16, (h+15)/16, 1);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); // make sure the output image has been written
u8* img = new u8[w * h * 4];
glBindTexture(GL_TEXTURE_2D, outTex);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, img);
stbi_write_png("imgs/out.png", w, h, 1, img, w*4);
delete[] img;
输入图像如下所示:
但这是我在输出图像中得到的:
我进一步简化了着色器:我不从输入纹理读取,而是写入一个固定值:
imageStore(u_outImg, pixelPos,
//uvec4(255.0 * texelFetch(u_inputTex, pixelPos, 0).rgb, 255u));
uvec4(1u));
我注意到:
- 如果我写0全黑
- 如果我写255就全白了
- 但是如果我在中间写一些东西(例如100)它不是灰色而是白色
我也这样试过,但也没用:
imageStore(u_outImg, pixelPos,
vec4(texelFetch(u_inputTex, pixelPos, 0).rgb, 255u));
我做错了什么?我的最终目标是制作一个 prostprocessing 过滤器,但我无法让它工作,所以我试图让它尽可能简单,但它不起作用。
最小示例回购:https://github.com/tuket/Whosebug_image_store_problem
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8UI, w, h);
如果要使用非规范化无符号整数图像,必须在sahder中将其声明为uimage2D
。 image2D
仅适用于 floating-point 或规范化整数(范围 [0,1]
)。
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
那是错误的记忆障碍。屏障是关于你将如何访问你的着色器修改的资源在屏障之后,所以正确的是:
GL_TEXTURE_UPDATE_BARRIER_BIT
在 reference page 中解释为(强调我的):
Writes to a texture via
glTex(Sub)Image*
,glCopyTex(Sub)Image*
,glCompressedTex(Sub)Image*
, and reads viaglGetTexImage
after the barrier will reflect data written by shaders prior to the barrier. Additionally, texture writes from these commands issued after the barrier will not execute until all shader writes initiated prior to the barrier complete.