【问题标题】:Facilities for asynchronous texture loading异步纹理加载工具
【发布时间】:2023-03-08 08:11:01
【问题描述】:

如何在 3D 应用程序运行时异步加载纹理?我所理解的是 OpenGL 上下文不是线程安全的,我应该将它们分开在不同的线程上。

但我的主要问题是选择合适的多线程工具/框架来实际使用 Windows 和 C++ 实现这一点,我听说过很多关于 C++11 的信息,包括其标准库中的线程支持,但有人可以仅列出基本步骤?

最安全的方法是什么?以及如何更新另一个上下文的状态,它注册了在另一个线程上完成的更改?我怀疑glFlushglBind*

【问题讨论】:

  • 实际上 OpenGL 和 OpenGL 上下文线程安全的。您一次只能让一个上下文在多个线程中处于活动状态。

标签: c++ windows visual-c++ opengl c++11


【解决方案1】:

纹理加载最耗时的部分通常是磁盘访问和任何格式转换,这两者都独立于 OpenGL,因此可以安全地在另一个线程上进行。一旦纹理以所需的格式读入内存,实际复制到 OpenGL 缓冲区是相当快的。

深入了解线程编程的细节对于这个答案来说太复杂了,但是周围有很多文档,一旦你想到它,它就很容易(比如指针和内存)。

这里的一般概念是创建一个纹理持有者对象列表(例如,包含文件/名称、初始空缓冲区和加载完成标志),并在创建时将其传递给加载线程。加载线程然后遍历列表,打开每个文件,将其加载到内存中并将缓冲区附加到列表条目,然后设置加载标志并可能增加一个计数器。主线程获取新加载的纹理,将其复制到 OpenGL 纹理中,并增加进度条或任何加载指示器。一旦列表中的所有纹理都有缓冲区并被标记为已加载,其他线程的工作就完成了,它可以停止(或保持活动状态以加载未来的纹理)。

该模型的主要优势在于不必共享实际的图形上下文。在可以是线程安全的 API (DirectX) 中,这样做会降低性能,而 OpenGL 需要您做大量工作才能拥有多个上下文或确保正确共享它们。加载纹理时的繁重工作通常是文件读取和参数检查,除非您进行格式转换或旋转,这甚至可能使磁盘访问相形见绌。实际复制到视频内存是高度优化的,不太可能成为瓶颈(如果您担心这一点,请尝试使用能够识别 GPU 调用成本的工具进行分析,然后查看)。这些工作都没有直接依赖于 OpenGL,因此您可以毫不担心地将其推送到另一个线程。

如果您专门使用 Windows,则可以使用内置的线程函数,使用简单的回调模型(提供函数和初始参数,在本例中为您的纹理列表,并进行 API 调用)。我个人不熟悉 C++11 的线程支持或它在 Visual Studio 中的工作原理(如果有的话),所以你必须检查一下。

【讨论】:

  • 不错的答案。是的,C++11 的 std::thread 适用于 MSVC++。它的用法与boost::thread非常相似
【解决方案2】:

@ssube 对任务的复杂性细分的回答是正确的,但假设“OpenGL 需要您做大量工作才能拥有多个上下文或确保您正确共享它们”,我不同意.

一个简单的解决方案是在程序开始时创建一个主上下文(用于绘图)和一个辅助上下文(用于纹理加载),例如:

m_hRCDrawing = wglCreateContext(m_hDC);
m_hRCSecondary = wglCreateContext(m_hDC);

然后在m_hRCSecondarym_hRCDrawing 上下文之间共享数据可以通过以下方式完成:

wglShareLists(m_hRCSecondary, m_hRCDrawing);

最后,当您要从没有 GL 上下文的“纹理加载”线程中读取纹理时,您可以简单地调用:

wglMakeCurrent(m_hDC, m_hRCSecondary); 

之后,在该线程中加载的所有资源都由绘图线程的上下文共享。

here 提供了更详尽的解释。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-07
    • 2022-01-25
    • 2017-06-25
    • 2021-10-08
    • 1970-01-01
    • 1970-01-01
    • 2020-04-06
    • 1970-01-01
    相关资源
    最近更新 更多