控制OpenGL应用程序中的FPS限制

Tsa*_*ras 11 opengl 3d frame-rate

我试图找到一个可靠的方法,能够准确设置我希望我的OpenGL应用程序在屏幕上呈现多少FPS.我可以通过休眠1000/fps毫秒在某种程度上做到这一点,但这没有考虑渲染所需的时间.哪种是将fps限制在所需数量的最一致方法?

biz*_*dee 7

您可以在opengl中使用wglSwapIntervalEXT同步到vblank.它不是很好的代码,但确实有效.

http://www.gamedev.net/topic/360862-wglswapintervalext/#entry3371062

bool WGLExtensionSupported(const char *extension_name) {
    PFNWGLGETEXTENSIONSSTRINGEXTPROC _wglGetExtensionsStringEXT = NULL;

    _wglGetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)wglGetProcAddress("wglGetExtensionsStringEXT");

    if (strstr(_wglGetExtensionsStringEXT(), extension_name) == NULL) {
        return false;
    }

    return true;
}
Run Code Online (Sandbox Code Playgroud)

PFNWGLSWAPINTERVALEXTPROC       wglSwapIntervalEXT = NULL;
PFNWGLGETSWAPINTERVALEXTPROC    wglGetSwapIntervalEXT = NULL;

if (WGLExtensionSupported("WGL_EXT_swap_control"))
{
// Extension is supported, init pointers.
    wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");

// this is another function from WGL_EXT_swap_control extension
    wglGetSwapIntervalEXT = (PFNWGLGETSWAPINTERVALEXTPROC)wglGetProcAddress("wglGetSwapIntervalEXT");
}
Run Code Online (Sandbox Code Playgroud)

  • 这是同步到显示器刷新率的正确方法,这通常是您想要的.不幸的是,WGL(以及wglSwapIntervalEXT)是特定于Windows的.虽然有一个等效的GLX扩展:http://www.opengl.org/registry/specs/EXT/swap_control.txt.如果你正在使用EGL,那就是eglSwapInterval. (3认同)

And*_*sen 5

由于OpenGL只是一个低级图形API,因此您不会直接在OpenGL中找到这样的内容.

但是,我认为你的逻辑有点缺陷.而不是以下:

  1. 画框
  2. 等待1000/fps毫秒
  3. 重复

你应该做这个:

  1. 启动计时器
  2. 画框
  3. 停止计时器
  4. 等待(1000/fps - (停止 - 开始))毫秒
  5. 重复

这样一来,如果你只是等待你应该的数量,那么你应该每秒非常接近60(或者你的目标)帧数.


Bar*_*icz 5

OpenGL本身没有任何允许限制帧速率的功能.期.

然而,在现代GPU上有许多功能,包括帧速率,帧预测等等.有一些John Carmack的问题,他推动了为它提供一些功能.还有NVidia的自适应同步.

这对你意味着什么?把它留给GPU.假设绘图是完全不可预测的(就像你只坚持使用OpenGL时那样),自己定时事件并将逻辑更新(如物理)与绘图分开.这样,用户将能够从所有这些先进技术中受益,您将不再需要担心这一点.

  • 但是你什么时候画的?如果我把它留给OpenGL我得到1000+ fps,因为我的屏幕只刷新60 fps,这是浪费资源.. (6认同)
  • 怎么绝对地狱这个答案得到了赏金?虽然第一部分是正确的:OpenGL _itself_没有限制帧率的功能,但第二部分是完全错误的.非常希望启用vsync(请注意,用户应该可以选择将其关闭).这是通过OpenGL上下文api(WGL,GLX,EGL等),通过调用(例如)`wglSwapIntervalEXT`来完成的._Every正常游戏使用了这个._供应商甚至在以后添加了[负交换间隔](https://www.opengl.org/registry/specs/EXT/wgl_swap_control_tear.txt) (4认同)

tam*_*ato 5

不要使用睡眠。如果您这样做,那么您的应用程序的其余部分必须等待他们完成。

相反,跟踪已经过去了多少时间并仅在满足 1000/fps 时进行渲染。如果计时器尚未达到,则跳过它并执行其他操作。

在单线程环境中,很难确保您以精确的 1000/fps 进行绘制,除非这绝对是您所做的唯一事情。一种更通用和更可靠的方法是在单独的线程中完成所有渲染,并在计时器上启动/运行该线程。这是一个更复杂的问题,但会让您最接近您的要求。

此外,跟踪发出渲染所需的时间将有助于动态调整渲染的时间。

static unsigned int render_time=0;
now = timegettime();
elapsed_time = last_render_time - now - render_time;
if ( elapsed_time > 1000/fps ){
    render(){
        start_render = timegettime();

        issue rendering commands...

        end_render = timegettime();
        render_time = end_render - start_render;
    }
    last_render_time = now;
}
Run Code Online (Sandbox Code Playgroud)