调用glComputeDispatch后,OpenGL计算着色器过早中止

时间:2018-01-04 02:55:49

标签: c++ opengl-es

我一直在尝试运行一个非常简单的计算计算着色器来掌握我的着色器运行的次数以及我可以处理多大的计算数组。

似乎我要么达到一些驱动程序限制,要么我的着色器需要太长时间才能执行该卡,因此它会过早中止或出现问题。似乎从glDispatchCompute至少没有返回任何错误。

我一直在阅读有关计算着色器的所有内容,似乎没有任何地方可以说时间限制会成为一个问题。

硬件是英特尔集成显卡,它相当低端,但确实有计算着色器支持。我希望能够在低端卡上运行计算着色器,我认为这张卡应该可以做到,但我遇到了奇怪的过早中止问题。

glxinfo | grep compute
GL_ARB_compressed_texture_pixel_storage, GL_ARB_compute_shader, 
GL_ARB_compressed_texture_pixel_storage, GL_ARB_compute_shader, 

更多信息:

const GLubyte* renderer = glGetString(GL_RENDERER); // get renderer string
const GLubyte* version = glGetString(GL_VERSION); // version as a string
GLint texture_units = 0;
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &texture_units);
GLint maxAttach = 0;
glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxAttach);
GLint maxDrawBuf = 0;
glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuf);
GLint workGroupCount[3], workGroupSize[3];
GLint maxInvocations;
glGetIntegerv(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS, &maxInvocations);
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, &workGroupCount[0]);
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, &workGroupCount[1]);
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, &workGroupCount[2]);
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &workGroupSize[0]);
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, &workGroupSize[1]);
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, &workGroupSize[2]);

printf("Renderer: %s\n", renderer);
printf("OpenGL version supported: %s\n", version);
printf("Number of texture units: %d\n", texture_units);
printf("Maximum number of color attachments: %d\n", maxAttach);
printf("Maximum number of fragment shader outputs: %d\n", maxDrawBuf);
printf("Maximum work group invocations: %d\n", maxInvocations);
printf("Maximum work group count: %d %d %d\n", workGroupCount[0], workGroupCount[1], workGroupCount[2]);
printf("Maximum work group size: %d %d %d\n", workGroupSize[0], workGroupSize[1], workGroupSize[2]);

输出:

Vendor: Intel Open Source Technology Center (0x8086)
Device: Mesa DRI Intel(R) Haswell Mobile  (0x416)
OpenGL vendor string: Intel Open Source Technology Center
OpenGL renderer string: Mesa DRI Intel(R) Haswell Mobile 
Renderer: Mesa DRI Intel(R) Haswell Mobile 
OpenGL version supported: OpenGL ES 3.1 Mesa 17.0.7
Number of texture units: 32
Maximum number of color attachments: 8
Maximum number of fragment shader outputs: 8
Maximum work group invocations: 2048
Maximum work group count: 65535 65535 65535
Maximum work group size: 2048 2048 2048

着色器:

#version 310 es

layout (local_size_x = 32, local_size_y = 32, local_size_z = 1) in; 

layout (binding=0) uniform atomic_uint counter; 

void main(){
    atomicCounterIncrement(counter);    
}

设定:

GLuint ac_buffer;
glGenBuffers(1, &ac_buffer);
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, ac_buffer);
glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);

GLuint compute_shader = glCreateShader (GL_COMPUTE_SHADER);

std::string ss;
readfile("compute.cs.c", ss);
const char *shader_source = ss.c_str();
glShaderSource (compute_shader, 1, &shader_source, NULL);
glCompileShader (compute_shader);
printShaderInfoLog(compute_shader);
GLuint shader_program = glCreateProgram ();
glAttachShader (shader_program, compute_shader);
glLinkProgram (shader_program);
printProgramInfoLog(shader_program);
glDeleteShader (compute_shader);
glUseProgram (shader_program);

glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, ac_buffer);

glDispatchCompute(1024, 1024, 1);
if(glGetError() != GL_NO_ERROR) {
    printf("There was a problem dispatching compute\n");
}
glMemoryBarrier(GL_ALL_BARRIER_BITS);

glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, ac_buffer);
GLuint *counter = (GLuint*)glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), GL_MAP_READ_BIT);
printf("Counter: %u\n", *counter);
glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);

当我使用小于glDispatchCompute的值调用128时,我似乎得到了合理的结果:

例如glDispatchCompute(128, 128, 1)导致"Counter: 16777216"128*128*32*32一致。但如果我用256, 256, 1调用它,我会得到66811258的结果。这与预期的67108864不一致。

对于较小的计算机集,我总能得到预期的结果,但对于较大的计算机集,计数器很少超过6000万到1亿。我可以达到一些司机限制吗?我虽然因为每个轴的最大组大小是65535,所以我应该能够请求计算大型计算组并期望处理所有元素。

我的原子计数方式是否存在缺陷?为什么小团体仍能获得合理的结果,但对于大团体而言却不尽如人意?我怎样才能更好地调试此问题?

1 个答案:

答案 0 :(得分:0)

您可能只是在计算完成之前读取结果。您需要显式调用glMemoryBarrier()以强制完成,并可以移除对glMemoryBarrier()的调用。对于OpenGL ES CLIENT_MAPPED_BUFFER_BARRIER_BIT仅处理阶段之间GPU上的相对排序,它不会强制执行相对于客户端访问的排序。

桌面OpenGL 4.6规范支持{{1}}同步客户端访问,但这不适用于OpenGL ES。