Java 在单独的线程中将VBO发送到GPU
我正在开发一个LWJGL游戏,在这个游戏中,世界变化非常频繁,因为它相当大,每次世界更新时,它都会导致游戏冻结几分之一秒,从而更新相应的VBO。我通过将所有逻辑移动到单独的线程(实际上,渲染代码位于单独的线程中),减少了游戏冻结的时间,但将数据推送到图形卡似乎仍然会造成明显的延迟。有没有可能在我的逻辑线程中发送VBO,以免减慢游戏速度Java 在单独的线程中将VBO发送到GPU,java,multithreading,opengl,lwjgl,vbo,Java,Multithreading,Opengl,Lwjgl,Vbo,我正在开发一个LWJGL游戏,在这个游戏中,世界变化非常频繁,因为它相当大,每次世界更新时,它都会导致游戏冻结几分之一秒,从而更新相应的VBO。我通过将所有逻辑移动到单独的线程(实际上,渲染代码位于单独的线程中),减少了游戏冻结的时间,但将数据推送到图形卡似乎仍然会造成明显的延迟。有没有可能在我的逻辑线程中发送VBO,以免减慢游戏速度 此外,如果这属于gamedev.so,请告诉我,以便我可以移动它。我不太确定,所以我决定在这里发布。一般来说,一个GL上下文在任何时候都可以是单个线程的当前上下文
此外,如果这属于gamedev.so,请告诉我,以便我可以移动它。我不太确定,所以我决定在这里发布。一般来说,一个GL上下文在任何时候都可以是单个线程的当前上下文,一个线程在任何时候都可以有一个当前GL上下文。如果要并行更新总账对象,有两个选项:
一般来说,GL上下文可以在任何时间对单个线程是当前的,并且线程可以在任何时间具有一个当前GL上下文。如果要并行更新总账对象,有两个选项:
线程
处理/更新或重新创建浮动缓冲区
(或您使用的其他缓冲区)。因为通常这就是冻结的原因,只是因为创建缓冲区、输入和更改所有数据等需要花费大量时间
这里是我的意思布局
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
将/可能仍然会冻结一点,尽管我以前从未经历过。只是说,告诉你 不能使用多任务处理来使用OpenGL进行渲染。显然,我错了,不过如果您只想使用单个OpenGL上下文来解决问题,答案的其余部分仍然很好
虽然我在制作无限程序地形生成器时遇到了相同的问题,但问题与您的问题相同,每次世界更新或生成新的地形块时,它都会冻结一小部分秒
如何解决这个问题
基本上,我是通过以下步骤来解决这个问题的
创建一个线程池/线程队列,每当世界发生变化时,您都会让一个单独的线程
处理/更新或重新创建浮动缓冲区
(或您使用的其他缓冲区)。因为通常这就是冻结的原因,只是因为创建缓冲区、输入和更改所有数据等需要花费大量时间
这里是我的意思布局
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
将/可能仍然会冻结一点,尽管我以前从未经历过。只是说,告诉你 我决定写我的评论作为答案,因为它与绘图线程上的其他两个答案略有不同。在上载顶点数据或取消映射缓冲区时,我建议使用双缓冲区,并在工作线程完成更新后将用于绘制的VBO与用于提交数据的VBO交换,而不是暂停管道
这种方法需要两个渲染上下文,每个上下文共享资源
在工作线程中,您可以像在当前方法中通常那样将子数据分配/流式传输到VBO中,唯一的区别是您将对不用于绘图的VBO执行此操作。用数据填充此VBO后,请让绘图线程知道,然后在绘图时将用于绘图的VBO与用于流式顶点数据的VBO交换。在这种情况下,工作线程应该阻塞,直到图形线程交换VBO
这样,当必须将新数据提交到GPU时,您将暂停用于流式传输新数据的线程,直到图形线程交换VBO,而不是暂停图形线程。因此,渲染将是平滑的(er),但更新可能以更可变的频率发生。这通常是像游戏这样的交互式软件的一个可取的特征——在某些事情发生之前有一个额外的延迟帧