【问题标题】:Custom allocator to store stl vector in OpenGL buffer objects自定义分配器将 stl 向量存储在 OpenGL 缓冲区对象中
【发布时间】:2012-01-15 03:09:56
【问题描述】:

我想自定义 std::vector 类,以便使用 OpenGL 缓冲区对象作为存储。

是否可以在不依赖 STL 的特定实现的情况下通过编写自定义分配器和/或子类化容器来做到这一点?

我的问题是如何为glMapBuffer/glUnmapBuffer 创建包装器方法,以便使用缓冲区对象进行渲染,从而使容器保持一致状态。

【问题讨论】:

标签: c++ opengl stl


【解决方案1】:

是否可以在不依赖 STL 的特定实现的情况下通过编写自定义分配器和/或子类化容器来做到这一点?

你可以,但这并不是一个好主意。即使你能做到这一点也取决于你的编译器/标准库。

在 C++11 之前,分配器不能有状态。它们不能有有用的成员,因为容器不需要实际使用您传递给它的分配器。他们被允许创建自己的。所以你可以设置分配器的type,但是你不能给它一个特定的分配器instance并期望那个实例总是被使用。

所以你的分配器不能仅仅创建一个缓冲区对象并在内部存储该对象。它必须使用全局(或私有静态或其他)缓冲区。即使这样,多个实例也会使用 same 缓冲区。

您可以通过让分配器存储(在私有静态变量中)一系列缓冲区对象和映射指针来解决这个问题。这将允许您分配一个特定大小的缓冲区对象,并返回一个映射指针。释放器将使用指针来确定它来自哪个缓冲区对象并对其进行适当的清理。

当然,对于实际使用这些缓冲区进行任何操作,这将完全无用。您不能使用当前映射的缓冲区。而且,如果您的分配器在向量用完内存后删除缓冲区,那么您将永远无法真正使用该缓冲区对象来一些事情。

另外,不要忘记:取消映射缓冲区可能失败,原因不明。如果它确实失败了,你就无法知道它确实失败了,因为 unmap 调用被包裹在分配器中。并且析构函数不应该抛出异常。

C++11 确实使分配器可以拥有状态。这意味着它或多或少是可能的。您可以让分配器在构建数据的std::vector 中继续存在,因此,您可以在映射后查询分配器以获取缓冲区对象。也可以存储unmap是否失败。

这仍然不是一个好主意。总体而言,使用普通的旧std::vector 并使用glBufferSubData 上传会容易得多。毕竟,使用 READ_WRITE 映射缓冲区几乎可以保证它将是常规内存而不是 GPU 地址。这意味着取消映射只会执行 DMA,glBufferSubData 会这样做。映射不会获得太多性能。

使用缓冲区对象重新分配会更加痛苦。由于std::vector 对象是决定要存储多少额外内存的对象,因此您不能玩诸如分配大缓冲区对象然后只是扩展容器使用的内存量之类的游戏。每次 std::vector 认为它需要更多内存时,您都必须创建一个新的缓冲区对象名称,并且 std::Vector 将按元素从映射内存复制到映射内存。

不是很快。

真的,您想要的只是创建自己的容器类。这并不难。并且它会更容易控制何时映射和何时不映射。

【讨论】:

  • 关于让 cpu 在映射内存上执行逐元素复制的论点是令人信服的。使用向量我没有更多的收获。你让我手头没有任何牌。
【解决方案2】:

我想自定义 std::vector 类,以便使用 OpenGL 缓冲区对象作为存储。

虽然这当然是可能的,但我强烈反对这样做。映射的缓冲区对象必须先取消映射,然后才能被 OpenGL 用作数据输入。因此,这样一个派生的,我们称之为glbuffervector 必须为每次访问映射/取消映射缓冲区对象。此外,获取取消引用元素的地址也不起作用,因为在取消引用后缓冲区对象将再次被取消映射。

我不会尝试创建一个存储在缓冲区对象中的向量,而是实现一个引用容器,它可以从现有的缓冲区对象以及布局一起创建,以便可以获得迭代器。遵循 RAII 方案,缓冲区对象将被映射创建一个实例,并通过实例释放来取消映射。

【讨论】:

  • 在我的设计中可以接受在更新顶点数据的过程的开始和结束时手动映射/取消映射一次向量(或使用 RAII 对象来获得它的价值)。这在概念上并不比在多线程环境中使用互斥的vector 更危险和不同,并且仍然会给我使用vector 的方法访问缓冲区的优势(包括缓冲区大小时的自动重新分配如果与适当的分配器结合使用会增加容量)
【解决方案3】:

是否可以在不依赖特定实现的情况下这样做 STL,通过编写自定义分配器和/或子类化 容器?

如果您使用的是 Microsoft Visual C++,有一篇博客文章描述了如何定义自定义 STL 分配器:"The Mallocator"。 我认为编写自定义分配器是特定于 STL 实现的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-24
    • 2014-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多