【问题标题】:glMapBufferRange freezing OpenGL driverglMapBufferRange 冻结 OpenGL 驱动程序
【发布时间】:2017-12-04 20:26:41
【问题描述】:

在使用计算着色器生成一组数据并将其存储在着色器存储缓冲区中后,我尝试从该缓冲区读取数据以使用代码打印出数据:

#define INDEX_AT(x,y,z,i)   (xyzToId(Vec3i((x), (y), (z)),\
                                     Vec3i(NUM_RAYS_X,\
                                           NUM_RAYS_Y,\
                                           POINTS_ON_RAY))\
                             * 3 + (i))
PRINT_GL_ERRORS();
glBindBuffer(GL_SHADER_STORAGE_BUFFER, dPositionBuffer);
float* data_ptr = NULL;
for (int ray_i = 0; ray_i < POINTS_ON_RAY; ray_i++)
{
    for (int y = 0; y < NUM_RAYS_Y; y++)
    {
        int x = 0;
        data_ptr = NULL;
        data_ptr = (float*)glMapBufferRange(
            GL_SHADER_STORAGE_BUFFER,
            INDEX_AT(x, y, ray_i, 0) * sizeof(float),
            3 * (NUM_RAYS_X) * sizeof(float),
            GL_MAP_READ_BIT);
        if (data_ptr == NULL)
        {
            PRINT_GL_ERRORS();
            return false;
        }
        else
        {
            for (int x = 0; x < NUM_RAYS_X; x++)
            {
                std::cout << "("
                    << data_ptr[x * 3 + 0] << ","
                    << data_ptr[x * 3 + 1] << ","
                    << data_ptr[x * 3 + 2] << ") , ";
            }
        }

        glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
        PRINT_GL_ERRORS();
        std::cout << std::endl;
    }

    std::cout << "\n" << std::endl;
}

其中函数 xyzToId 将三维坐标转换为一维索引。

但是,当我尝试运行此程序时,程序在调用 glMapBufferRange 时崩溃,并给出错误消息:

The NVIDIA OpenGL driver lost connection with the display driver due to exceeding the Windows Time-Out limit and is unable to continue.
The application must close.

Error code: 7
Would you like to visit
http://nvidia.custhelp.com/cgi-bin/nvidia.cfg/php/enduser/std_adp.php?p_faqid=3007
for help?

我正在映射的缓冲区根本不是很大,只有 768 个浮点数,并且之前在另一个着色器存储缓冲区(只有两个浮点数)上对 glMapBuffer 的调用没有问题完成。我似乎无法在网上找到与此错误相关的任何信息,并且我所阅读的有关 glMapBufferRange 速度的所有信息都表明,这种大小的缓冲区应该只需要几十毫秒的时间来映射,而不是两秒程序崩溃的超时时间。

我是否遗漏了有关如何使用 glMapBufferRange 的内容?

【问题讨论】:

  • "我是否遗漏了有关如何使用 glMapBufferRange 的内容?" 是的。您不应在循环中 映射缓冲区。这是一个重量级的操作;它不仅仅是返回一个指针。仅当您完成从存储范围读取时,才应取消映射。永远不要映射几个字节。这可能会或可能不会解决您的问题,但无论如何,这是错误的工作方式。
  • 问题是,虽然在这个特定的应用程序中缓冲区不是很大(我用它来调试较小数据集上的代码),但预期的使用涉及一个太大的缓冲区适合我可用的内存。将其分解成更小的部分是避免该问题的唯一方法。不管上面怎么样,我用glMapBuffer测试了一下,一次性使用了整个buffer,并没有解决问题。
  • "缓冲区太大,无法放入我可用的内存中" 那么如何分配这样的缓冲区呢?如果它太大而无法映射,那么它对于glBufferData 来说太大了。此外,这仍然不能证明一次映射几个浮点数是合理的。如果您无法映射整个范围,则映射范围的部分。
  • OpenGL 缓冲区驻留在 GPU 的内存中,而不是 CPU 的 RAM 中。然而,它们被映射到 RAM 中。我在这里一次映射几个浮点数只是为了测试系统。一次做一行数据集很小,但在最终系统中会足够大,足以用完我的内存预算。
  • "OpenGL 缓冲区驻留在 GPU 的内存中,而不是 CPU 的 RAM 中。" 不正确。缓冲区驻留在 GPU-可访问 内存中。这可能是实际的视频 RAM,也可能是设置供 GPU 访问的 CPU RAM(例如,通过 PCIe 总线)。实现倾向于根据您使用它们的方式来移动缓冲区。在大多数实现中,如果您映射一个缓冲区,该缓冲区将位于 CPU RAM 中。此外,大多数计算机的 CPU 内存比 GPU 内存多,所以即使你说的是真的,我也看不出你如何分配一个如此大的缓冲区,以至于无法将其复制到 CPU 内存。

标签: c++ opengl crash timeout driver


【解决方案1】:

这是一个不相关的错误。今天我了解到 OpenGL 有时会缓冲命令,并且有几个动作(例如映射缓冲区)会强制它完成队列中的所有命令。在这种情况下,它是实际调度计算着色器本身的操作。

今天我还了解到,越界索引着色器存储缓冲区将导致 OpenGL 驱动程序冻结,就像它需要很长时间才能完成一样。

总而言之,这主要是错误伪装成不同的错误并出现在错误的位置。

【讨论】:

    猜你喜欢
    • 2019-01-19
    • 1970-01-01
    • 2021-12-26
    • 1970-01-01
    • 2013-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多