LWJGL glGenVertexArrays() 正在阻止执行
LWJGL glGenVertexArrays() is blocking the execution
最近在论坛上问了一个问题,为什么ExecutorService在获取到futures后会阻塞我的程序:
ExecutorService and Future are blocking the main thread
问题是经过大量调试后,有罪的行不是 future.get() 而是 int vaoID = GL30.glGenVertexArrays();
我将总结我正在尝试做的事情,然后 post 代码。基本上,我在玩家移动时生成地形。为了避免在生成发生时冻结游戏,我使用可调用对象、ExecutorService 和 Futures 实现了多线程。因此,当我必须生成地形时,我会向 ExecutorService 提交新任务(任务是计算地形的所有 vertices/normals/colors),然后对于每个未来,如果完成,我就会得到结果并生成地形模型。但是在每一帧,第一个完成的未来会导致冻结。实际上,造成这种情况的不是未来本身,而是模型的创建,更准确地说是 int vaoID = GL30.glGenVertexArrays();
方法。
综上所述,我认为 glGenVertexArrays();正在阻塞线程,等待其他线程完成,而我对发生的事情一无所知。我正在使用 LWJGL 2 和 OpenGL 3.0+。
这里是处理多线程的代码:
//method called each frame
private void checkForFutures(List<Future<SomeClass>> terrainsInCreation) {
try
{
List<Future<SomeClass>> futuresToRemove = new ArrayList<Future<SomeClass>>();
for(Future<SomeClass> future:terrainsInCreation) {
if(future.isDone()) {
float time = DisplayManager.getCurrentTime();
try {
SomeClass t = future.get();
Key key = new Key(t.terrain.getChunkX(),t.terrain.getChunkZ());
t.terrain.generateTerrain(loader, t.vertices, t.indices,t.colors, t.normals); // Guilty line !
futuresToRemove.add(future);
} catch (ExecutionException e) {
e.printStackTrace();
Thread.sleep(1000000);
}
}
}
terrainsInCreation.removeAll(futuresToRemove);
}
catch (InterruptedException ie)
{
System.err.println("BIG PROBLEM ON TERRAIN MANAGER");
}
}
//method called when I have terrains to generate
private void generate(List<Callable<SomeClass>> terrainsToCreate) {
for(int i = 0; i < terrainsToCreate.size();i++) {
terrainsInCreation.add(executor.submit(terrainsToCreate.get(i)));
}
}
这是 generateTerrain() 方法:
int vaoID = createVAO();
bindIndicesBuffer(indices);
storeDataInAttributeList(0,3, positions);
storeDataInAttributeList(1,3, colors);
storeDataInAttributeList(2, 3, normals);
unbindVAO();
return new RawModel(vaoID, indices.length);
(我简化了代码)
这里是 createVao() 方法:
private int createVAO() {
long start = DisplayManager.getCurrentTime();
int vaoID = GL30.glGenVertexArrays(); // The first of each frame takes ~40-200ms
long glGen = DisplayManager.getCurrentTime();
vaos.add(vaoID);
long add = DisplayManager.getCurrentTime();
GL30.glBindVertexArray(vaoID);
long bind = DisplayManager.getCurrentTime();
System.out.println(String.format("Vao: gen: %d + add: %d + bind: %d = %d",
(glGen-start),
(add-glGen),
(bind-add),
(DisplayManager.getCurrentTime()-start)));
return vaoID;
}
最后是常规生成的打印输出:
NEW CHECK
NEW CHECK
Vao: gen: 7 + add: 0 + bind: 0 = 7
Vao: gen: 1 + add: 0 + bind: 0 = 1
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
NEW CHECK
Vao: gen: 209 + add: 0 + bind: 0 = 209 (why????)
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 1 + add: 0 + bind: 0 = 1
Vao: gen: 1 + add: 0 + bind: 0 = 1
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 1 = 1
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
NEW CHECK
Vao: gen: 4 + add: 0 + bind: 0 = 4
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
NEW CHECK
NEW CHECK
我正在打印“NEW CHECK”的每一帧,正如你所看到的,它并不是每一帧的第一帧,有时它不是,但是当发生生成事件时,第一帧总是非常慢。
我的问题是这里发生了什么,我可以做什么/测试/更新?
感谢您的帮助。
编辑
我必须准确地说 GL30.glGenVertexArrays() 是在主线程中调用的。
这是程序开始时先于其他任何内容执行的上下文代码:
ContextAttribs attribs = new ContextAttribs(3,2)
.withForwardCompatible(true)
.withProfileCore(true);
Mouse.setGrabbed(true);
try {
DisplayMode displayMode = new DisplayMode(WIDTH, HEIGHT);
Display.setDisplayMode(displayMode);
Display.create(new PixelFormat(),attribs);
Display.setTitle("CubeLand");
} catch (LWJGLException e) {
e.printStackTrace();
}
编辑 2
我删除了多线程,通过在主线程中执行所有操作,并且在生成时发生大约相同的冻结,这是正常的,因为计算量很大,但是 GL30.glGenVertexArrays() 不需要任何时间来计算。
这证明此方法正在等待所有其他线程结束,但为什么以及如何避免这种情况?
NEW CHECK
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
NEW CHECK
编辑 3
一些消息,当我拔掉我的笔记本电脑时,图形卡被关闭并且主板图形芯片组取代了它。突然,这个问题就消失了。当然,我仍然会卡住,因为现在我的性能被切断了,处理器即使在多线程下也很难生成地形,但是 vao gen 时间又回到了 0。这令人困惑。
好的,经过 2 周的努力,我终于找到了解决方法。经过长时间的分析会话后,我 90% 确定 glGenVertexArrays() 正在等待一些线程完成它们的任务,我不知道为什么,但它关联了 2/3 次。解决方法是等待所有未来出现,然后生成地形(也称为调用 glGenVertexArrays())。这样,glGenVertexArrays() 就不会暂停主线程,并且为了避免同时创建数十个地形,我每帧只创建 2-3 个地形,这是不明显的。
最近在论坛上问了一个问题,为什么ExecutorService在获取到futures后会阻塞我的程序: ExecutorService and Future are blocking the main thread
问题是经过大量调试后,有罪的行不是 future.get() 而是 int vaoID = GL30.glGenVertexArrays();
我将总结我正在尝试做的事情,然后 post 代码。基本上,我在玩家移动时生成地形。为了避免在生成发生时冻结游戏,我使用可调用对象、ExecutorService 和 Futures 实现了多线程。因此,当我必须生成地形时,我会向 ExecutorService 提交新任务(任务是计算地形的所有 vertices/normals/colors),然后对于每个未来,如果完成,我就会得到结果并生成地形模型。但是在每一帧,第一个完成的未来会导致冻结。实际上,造成这种情况的不是未来本身,而是模型的创建,更准确地说是 int vaoID = GL30.glGenVertexArrays();
方法。
综上所述,我认为 glGenVertexArrays();正在阻塞线程,等待其他线程完成,而我对发生的事情一无所知。我正在使用 LWJGL 2 和 OpenGL 3.0+。
这里是处理多线程的代码:
//method called each frame
private void checkForFutures(List<Future<SomeClass>> terrainsInCreation) {
try
{
List<Future<SomeClass>> futuresToRemove = new ArrayList<Future<SomeClass>>();
for(Future<SomeClass> future:terrainsInCreation) {
if(future.isDone()) {
float time = DisplayManager.getCurrentTime();
try {
SomeClass t = future.get();
Key key = new Key(t.terrain.getChunkX(),t.terrain.getChunkZ());
t.terrain.generateTerrain(loader, t.vertices, t.indices,t.colors, t.normals); // Guilty line !
futuresToRemove.add(future);
} catch (ExecutionException e) {
e.printStackTrace();
Thread.sleep(1000000);
}
}
}
terrainsInCreation.removeAll(futuresToRemove);
}
catch (InterruptedException ie)
{
System.err.println("BIG PROBLEM ON TERRAIN MANAGER");
}
}
//method called when I have terrains to generate
private void generate(List<Callable<SomeClass>> terrainsToCreate) {
for(int i = 0; i < terrainsToCreate.size();i++) {
terrainsInCreation.add(executor.submit(terrainsToCreate.get(i)));
}
}
这是 generateTerrain() 方法:
int vaoID = createVAO();
bindIndicesBuffer(indices);
storeDataInAttributeList(0,3, positions);
storeDataInAttributeList(1,3, colors);
storeDataInAttributeList(2, 3, normals);
unbindVAO();
return new RawModel(vaoID, indices.length);
(我简化了代码)
这里是 createVao() 方法:
private int createVAO() {
long start = DisplayManager.getCurrentTime();
int vaoID = GL30.glGenVertexArrays(); // The first of each frame takes ~40-200ms
long glGen = DisplayManager.getCurrentTime();
vaos.add(vaoID);
long add = DisplayManager.getCurrentTime();
GL30.glBindVertexArray(vaoID);
long bind = DisplayManager.getCurrentTime();
System.out.println(String.format("Vao: gen: %d + add: %d + bind: %d = %d",
(glGen-start),
(add-glGen),
(bind-add),
(DisplayManager.getCurrentTime()-start)));
return vaoID;
}
最后是常规生成的打印输出:
NEW CHECK
NEW CHECK
Vao: gen: 7 + add: 0 + bind: 0 = 7
Vao: gen: 1 + add: 0 + bind: 0 = 1
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
NEW CHECK
Vao: gen: 209 + add: 0 + bind: 0 = 209 (why????)
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 1 + add: 0 + bind: 0 = 1
Vao: gen: 1 + add: 0 + bind: 0 = 1
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 1 = 1
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
NEW CHECK
Vao: gen: 4 + add: 0 + bind: 0 = 4
Vao: gen: 0 + add: 0 + bind: 0 = 0
Vao: gen: 0 + add: 0 + bind: 0 = 0
NEW CHECK
NEW CHECK
我正在打印“NEW CHECK”的每一帧,正如你所看到的,它并不是每一帧的第一帧,有时它不是,但是当发生生成事件时,第一帧总是非常慢。
我的问题是这里发生了什么,我可以做什么/测试/更新?
感谢您的帮助。
编辑
我必须准确地说 GL30.glGenVertexArrays() 是在主线程中调用的。 这是程序开始时先于其他任何内容执行的上下文代码:
ContextAttribs attribs = new ContextAttribs(3,2)
.withForwardCompatible(true)
.withProfileCore(true);
Mouse.setGrabbed(true);
try {
DisplayMode displayMode = new DisplayMode(WIDTH, HEIGHT);
Display.setDisplayMode(displayMode);
Display.create(new PixelFormat(),attribs);
Display.setTitle("CubeLand");
} catch (LWJGLException e) {
e.printStackTrace();
}
编辑 2
我删除了多线程,通过在主线程中执行所有操作,并且在生成时发生大约相同的冻结,这是正常的,因为计算量很大,但是 GL30.glGenVertexArrays() 不需要任何时间来计算。 这证明此方法正在等待所有其他线程结束,但为什么以及如何避免这种情况?
NEW CHECK
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
Vao gen: 0
NEW CHECK
编辑 3 一些消息,当我拔掉我的笔记本电脑时,图形卡被关闭并且主板图形芯片组取代了它。突然,这个问题就消失了。当然,我仍然会卡住,因为现在我的性能被切断了,处理器即使在多线程下也很难生成地形,但是 vao gen 时间又回到了 0。这令人困惑。
好的,经过 2 周的努力,我终于找到了解决方法。经过长时间的分析会话后,我 90% 确定 glGenVertexArrays() 正在等待一些线程完成它们的任务,我不知道为什么,但它关联了 2/3 次。解决方法是等待所有未来出现,然后生成地形(也称为调用 glGenVertexArrays())。这样,glGenVertexArrays() 就不会暂停主线程,并且为了避免同时创建数十个地形,我每帧只创建 2-3 个地形,这是不明显的。