当前位置: 首页 > 知识库问答 >
问题:

LWJGL glGenVertexArray()正在阻止执行

鲁烨熠
2023-03-14

我最近在论坛上问了一个问题,为什么ExecutorService在获得期货后阻止了我的程序:ExecutorService和Future阻止了主线程

问题是,经过大量的调试,有罪的线不是未来。get()但是int-vaoID=GL30。glgenvertexarray()

我将总结我正在尝试做的事情,然后发布代码。基本上,我在玩家移动时生成地形。为了避免在生成时冻结游戏,我使用callables、ExecutorService和Futures实现了多线程。因此,当我必须生成地形时,我会向ExecutorService提交新任务(任务是计算地形的所有顶点/法线/颜色),然后对于每个未来,如果完成了,我会得到结果并生成地形模型。但在每一帧中,第一个完成的未来都会造成冻结。实际上,并不是未来本身导致了它,而是模型的创建,更准确地说是int vaoID=GL30。glgenvertexarray() 方法。

总而言之,我认为glgenvertexarays();正在阻塞线程,等待其他线程完成,而我对正在发生的事情一无所知。我正在使用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

我打印的每一帧都是“新支票”,正如你所看到的,它并不完全是每一帧的第一帧,有时不是,但当一个生成事件发生时,第一帧总是非常慢。

我的问题是这里发生了什么,我能做什么/测试/更新?

谢谢你的帮助。

编辑

我必须准确地说,GL30.glGenVertexArray()是在主线程中调用的。这是在程序开始时在其他任何事情之前执行的上下文代码:


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。这令人困惑。


共有1个答案

包建义
2023-03-14

好的,所以经过2周的挣扎,我终于找到了一个解决方法。经过长时间的分析会话,我90%确定glGenVertexArray()正在等待一些线程完成他们的任务,我不知道为什么,但它关联了2/3次。解决方法是等待所有的期货出来,然后生成地形(又名调用glGenVertexArray())。这样,glGenVertexArray()就不会暂停主线程,为了避免同时创建几十个地形,我每帧只创建2-3个,这是不明显的。

 类似资料:
  • 我对使用Selenium是新手,在Selenium Grid 2中使用RemoteWebDriver时遇到了一些问题。我想知道我的代码出了什么问题。谢谢 我分3步设置RemoteWebDriver: > 将Chrome驱动程序设置为系统属性,我检查了路径是否正确 设置功能 通过RemoteWebDriver打开驱动程序 结果通过前两步,但在最后一步失败,因为日志没有显示。似乎在设置RemoteWe

  • 在我的Espresso测试执行和AlertDialog会被提示并等待用户响应。Espresso测试只有在我按下“Accept”按钮但我想测试代替用户执行此事件时才会继续。 我注意到我的线程选项卡上有以下状态

  • 问题内容: 当try块中存在时,我对try- finally执行感到困惑。据我了解,finally块将始终执行,即在返回调用方法之前。在考虑以下简单代码时: 实际打印的结果为1。这是否意味着不执行finally块?有人可以帮我吗? 问题答案: 从块返回时,返回值存储在该方法的堆栈帧中。之后,将执行finally块。 更改finally块中的值不会更改堆栈中已存在的值。但是,如果您从finally块

  • 我在Spring Boot应用程序中有以下类: 当我通过GET请求调用它时,我得到一个200 OK的回复,其中包含BBC的HTML源代码。co.uk公司。因此,似乎正在遵循重定向。 根据HTTP规范第10.3.3节: 如果收到302状态码以响应GET或HEAD以外的请求,则除非用户能够确认,否则用户代理不得自动重定向该请求 此外,它还专门针对非GET响应,并不规定GET请求应该重定向。因此,尽管在

  • 问题内容: 我对Go如何处理非阻塞IO感到困惑。API在我看来基本上是同步的,并且在Go上观看演示时,听到诸如“和调用块”之类的注释并不罕见。 从文件或网络读取时,Go是否使用阻塞IO?还是当在Go Routine中使用某种魔术来重写代码? 来自C#背景,这感觉非常不直观,在C#中,当使用异步API时我们使用了关键字。这清楚地表明,API可以产生当前线程,并在以后的延续中继续。 因此,TLDR;当

  • 我们正在针对现有数据库编写一个新的应用程序。我正在使用Spring数据JPA,只需做一个 在我的新实体上,使用 我在日志中注意到,hibernate在插入之前进行了一次选择,而且这需要很长时间,即使在使用索引时也是如此。 我在这里搜索过这个,我找到的答案通常与冬眠有关。我对JPA很陌生,JPA和Hibernate似乎是紧密结合在一起的,至少在Spring数据环境中使用它时是这样。链接的答案建议使用