我写了一个程序,在一个计算着色器上做一些计算,然后显示返回的数据。这工作得很完美,除了程序执行在着色器运行时被阻塞(见下面的代码),并且根据参数,这可能需要一段时间:
void CalculateSomething(GLfloat* Result)
{
// load some uniform variables
glDispatchCompute(X, Y, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
GLfloat* mapped = (GLfloat*)(glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY));
memcpy(Result, mapped, sizeof(GLfloat) * X * Y);
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
}
void main
{
// Initialization stuff
// ...
while (glfwWindowShouldClose(Window) == 0)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glfwPollEvents();
glfwSwapInterval(2); // Doesn't matter what I put here
CalculatateSomething(Result);
Render(Result);
glfwSwapBuffers(Window.WindowHandle);
}
}
为了在计算着色器进行计算时保持主循环运行,我将CalculateSomething
更改为如下形式:
void CalculateSomething(GLfloat* Result)
{
// load some uniform variables
glDispatchCompute(X, Y, 1);
GPU_sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
}
bool GPU_busy()
{
GLint GPU_status;
if (GPU_sync == NULL)
return false;
else
{
glGetSynciv(GPU_sync, GL_SYNC_STATUS, 1, nullptr, &GPU_status);
return GPU_status == GL_UNSIGNALED;
}
}
这两个函数是一个类的一部分,如果我必须在这里发布所有这些函数,那么它会变得有点混乱和复杂(如果需要更多代码,请告诉我)。因此,每次循环,当类被告知执行计算时,它首先检查GPU是否繁忙。如果已完成,则将结果复制到CPU内存(或者开始计算),否则返回到main
,不做任何其他事情。无论如何,这种方法的工作原理是它产生正确的结果。但是我的主循环仍然被阻塞。
做了一些计时后发现,CalculateSomething
、Render
(以及其他所有东西)运行速度很快(正如我所期望的那样),但现在glfwSwapBuffers
需要〉3000ms(取决于计算着色器的计算时间)。
在计算着色器运行时,是否可以切换缓冲区?渲染结果似乎工作正常,没有延迟(只要计算着色器还没有完成,旧的结果就应该被渲染)。或者我错过了什么(排队的OpenGL调用在glfwSwapBuffers
执行某些操作之前得到处理?)
- 编辑:**
我不知道为什么这个问题被关闭了,还需要什么额外的信息(也许除了操作系统,应该是Windows)。至于"期望的行为":我希望glfwSwapBuffers
-调用不会阻塞我的主循环。要了解更多信息,请询问...
正如Erdal Küçük所指出的,glFlush
的隐式调用可能会导致延迟。出于测试目的,我确实将此调用放在glfwSwapBuffer
之前,并对其进行了计时-这里没有延迟...
我确定,我不可能是唯一一个遇到这个问题的人。也许有人可以尝试重现它?简单地把一个计算着色器放在主循环中,它需要几秒钟来完成它的计算。我在哪里读到过类似的问题发生,特别是在调用glMapBuffer
时。这似乎是GPU驱动程序的问题(我的将是一个集成的英特尔GPU)。但没有任何地方我读到有关延迟超过200毫秒...
1条答案
按热度按时间gk7wooem1#
解决了
GL_PIXEL_PACK_BUFFER
有效用作屏幕外计算着色器的类似问题。使用围栏的方法是正确的,但您需要有一个单独的函数,使用glGetSynciv
来读取GL_SYNC_STATUS
,以检查围栏的状态。解决方案(在Java中公认)can be found here。为什么这是必要的解释可以在:在@Nick Clark评论中回答:
OpenGL中的每个调用都是异步的,除了帧缓冲区交换,它会暂停调用线程,直到所有提交的函数都执行完毕。因此,glfwSwapBuffers似乎需要这么长时间。
溶液的相关部分为:
基本上,关闭计算机着色器,然后等待
GL_SYNC_STATUS
的glGetSynciv
检查等于GL_SIGNALED
,然后重新绑定GL_SHADER_STORAGE_BUFFER
并执行glMapBuffer
操作。