在单独的线程中将VBO发送到GPU

时间:2013-09-12 22:20:28

标签: java multithreading opengl lwjgl vbo

我正在研究LWJGL游戏,其中世界经常变化,并且因为它相当大,它导致游戏每次世界时都会冻结几分之一秒,从而更新相应的VBO。我通过将所有逻辑移动到一个单独的线程来减少游戏冻结的时间(好吧,它实际上是在一个单独的线程中的渲染代码),但是将数据推送到图形卡似乎仍然会产生明显的延迟。是否有可能在我的逻辑线程中发送VBO以免减慢游戏速度?

此外,如果这属于gamedev.so,请告诉我,我可以移动它。我不太确定,所以我决定在这里发帖。

3 个答案:

答案 0 :(得分:2)

你不能使用多任务处理来使用OpenGL进行渲染。 显然我错了,虽然其余的答案仍然很好,如果你想只用一个修复问题OpenGL上下文。

虽然我在制作无限程序地形生成器时遇到了同样的问题,但问题与您的问题相同,每次世界更新或生成新的 Terrain Chunk < / em>它会冻结只有几分之一秒。

如何解决此问题

基本上我是如何通过以下方式解决这个问题的。

创建线程池/线程队列,每次世界更改时,您都会单独Thread进程/更新或重新创建FloatBuffer(或其他缓冲区)你用)。因为通常这就是冻结的原因,因为它需要花费大量时间来创建缓冲区,输入和更改所有数据等。

这是我的意思的布局。

class VBOAntiFreeze {
    FloatBuffer vertex_data;
    // Just add the rest of the FloatBuffers you use as well, like FloatBuffer
    // normal_data; FloatBuffer color_data; etc.

    // You would also have all the other variables as the vbo_handle, vertices count, etc.

    boolean fresh = true;
    boolean dirty, updating;

    public void updateVBO() {
        if (fresh && !updating) {
            updating = true;

            // You could execute new Threads by creating a
            // Thread Pool/Thread Queue, that way, you will
            // have some more control over all the threads.

            new Thread(new Runnable() {
                public void run() {
                    // Update and process all the FloatBuffers here!

                    dirty = true;
                    fresh = false;
                    updating = false;
                }
            }).start();
        }
    }

    public void renderVBO() {
        if (updating) {
            return;
        }
        else if (fresh) {
            updateVBO();

            return;
        }

        if (dirty) {
            // Buffer all the newly updated data
        }

        // Render the VBO here
    }
}

通过使用这个想法,你可能不会遇到随机冻结,除非你的VBO非常庞大,因此if (dirty) buffer new data将会/可能仍然会冻结一点,尽管我以前从未经历过这种情况。 但只是说,通知你!

答案 1 :(得分:1)

通常,GL上下文可以在任何时间对单个线程是最新的,并且线程可以随时具有一个当前GL上下文。如果要对GL对象进行并行更新,则有两种选择:

  1. 使用共享上下文。这样,每个trhead都可以拥有自己的GL上下文,但是两个线程都可以使用(和修改)像buffers texture,......这样的对象。
  2. 针对您的特定情况。它可能足以使用(可能是环形缓冲区)映射的VBO。您只需要GL上下文来映射/取消映射缓冲区,但在映射时,您可以在任意线程中访问它 - 根本不需要GL上下文。通常,在这种情况下使用VBO的环形缓冲区以避免线程之间的过度同步。

答案 2 :(得分:1)

我决定把我的评论写成答案,因为它与绘图线程的开销中的其他两个答案略有不同。在上传顶点数据或取消映射缓冲区时,我建议使用双缓冲并将用于绘图的VBO与工作线程完成更新后用于提交数据的VBO交换,而不是停止管道。

此方法需要两个渲染上下文,每个渲染上下文共享资源。

在您的工作线程中,您可以像在当前方法中一样将子数据分配/流式传输到VBO中,唯一的区别是您将对未用于绘制的VBO执行此操作。当你用数据完成这个VBO的填充时,让你的绘图线程知道,然后在绘制时将用于绘图的VBO与用于流顶点数据的VBO交换。您的工作线程应该阻塞,直到绘图线程在这种情况下交换VBO。

这样,当新数据必须提交给GPU时,不会停止绘制线程,而是停止用于流式处理新数据的线程,直到绘图线程交换VBO。结果渲染将是平滑的(呃),但更新可能以更多可变频率发生。这通常是游戏等交互式软件中的一个理想特征 - 在弹出新内容之前,额外的延迟帧通常比需要两倍长时间完成的帧更好。

如果你想一次排队多个更新,以便你的更新线程不必经常阻塞,我建议实现一个循环缓冲区,如他的答案中提到的derhass。但听起来你只需要问题描述中的前/后缓冲区。