我的目标是使用计算着色器生成类似于this的亮度波形。
我的设置是:
计算着色器:
#version 310 es
layout(local_size_x = 16, local_size_y = 16) in;
layout(binding = 0, rgba8ui) uniform highp readonly uimage2D u_sourceTexture;
layout(binding = 1, rgba8ui) uniform highp writeonly uimage2D u_waveformTexture;
void main() {
ivec2 sourceSize = imageSize(u_sourceTexture);
ivec2 waveformSize = imageSize(u_waveformTexture);
ivec2 gid = ivec2(gl_GlobalInvocationID.xy);
if (gid.x < sourceSize.x && gid.y < sourceSize.y) {
uvec4 color = imageLoad(u_sourceTexture, gid);
float luminance = dot(vec3(color.rgb) / 255.0, vec3(0.299, 0.587, 0.114));
int waveformY = int(clamp(luminance * float(waveformSize.y-1), 0.0, float(waveformSize.y - 1)));
int waveformX = int(clamp(float(gid.x) * float(waveformSize.x) / float(sourceSize.x), 0.0, float(waveformSize.x - 1)));
// Compute the position in the waveform texture
ivec2 waveformPos = ivec2(waveformX, waveformY);
// Write the color to the waveform texture
// this line causes the crash
imageStore(u_waveformTexture, waveformPos, color);
}
}
我的渲染循环的一部分:
glUseProgram(m_shaderprog_compute_luma_waveform);
glBindImageTexture(
0, // image unit (not texture unit)
m_tex_source,
0,
GL_FALSE,
0,
GL_READ_ONLY,
GL_RGBA8UI
);
glBindImageTexture(
1, // image unit (not texture unit)
m_tex_luma_waveform,
0,
GL_FALSE,
0,
GL_WRITE_ONLY,
GL_RGBA8UI
);
const int groupSize = 16;
unsigned int sourceWidth = m_source_width();
unsigned int sourceHeight = m_source_height();
GLuint numGroupsX = (sourceWidth + groupSize - 1) / groupSize;
GLuint numGroupsY = (sourceHeight + groupSize - 1) / groupSize;
glDispatchCompute(numGroupsX, numGroupsY, 1);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
glUseProgram(0);
m_tex_source 中的纹理包含正确的数据,并且可以使用简单的顶点和片段着色器毫无问题地显示。
输出纹理是使用以下方式生成的:
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &m_tex_luma_waveform);
if (m_tex_luma_waveform == 0) {
throw std::runtime_error("Failed to create luma waveform texture");
}
glBindTexture(GL_TEXTURE_2D, m_tex_luma_waveform);
// Set our texture parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// 580 x 256 px with RGBA8ui data
glTexImage2D(
GL_TEXTURE_2D, // target
0, // level
GL_RGBA8UI, // internal format
m_luma_waveform_width, // width
m_luma_waveform_height, // height
0, // border
GL_RGBA_INTEGER, // format
GL_UNSIGNED_BYTE, // type
NULL // data
);
glBindTexture(GL_TEXTURE_2D, 0);
输入/源纹理类似地使用以下方式生成:
... // generate and bind texture, set filters and wrap
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGBA,
image->width,
image->height,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
image->pixels
);
崩溃发生在这里:
glDispatchCompute(numGroupsX, numGroupsY, 1);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
异常显示在 glMemoryBarrier 行中,但可能仍然属于着色器执行。
这是一个例外:
Exception thrown at 0x00007FFA387FBE36 (libGLESv2.dll) in angle_test.exe: 0xC0000005: Access violation reading location 0x00000000000000C8.
当我从计算着色器中删除包含
imageStore
的行时,崩溃消失了。
感谢您提前提供的所有帮助。
在调试模式下从源代码编译 ANGLE 有所帮助,并提供了有用的错误消息,表明我没有使用不可变纹理。
改变
glTexImage2D(
GL_TEXTURE_2D, // target
0, // level
GL_RGBA8UI, // internal format
m_luma_waveform_width, // width
m_luma_waveform_height, // height
0, // border
GL_RGBA_INTEGER, // format
GL_UNSIGNED_BYTE, // type
NULL // data
);
到
glTexStorage2D(
GL_TEXTURE_2D, // target
1, // levels of mipmapping
GL_RGBA8UI, // internal format
m_luma_waveform_width, // width
m_luma_waveform_height // height
);
解决了这个问题,因为
glTexStorage2D
创建了一个具有固定大小和格式的不可变纹理,这是渲染循环中 glBindImageTexture
所需要的。