自定义分配器,用于在OpenGL缓冲区对象中存储stl向量

时间:2012-01-14 11:49:18

标签: c++ opengl stl

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

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

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

3 个答案:

答案 0 :(得分:2)

  

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

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

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

答案 1 :(得分:2)

  

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

你可以,但这并不是一个好主意。甚至你可以依赖你的编译器/标准库。

在C ++ 11之前,分配器不能具有状态。它们不能拥有有用的成员,因为容器不需要实际使用传递它的分配器。他们被允许创造自己的。因此,您可以设置分配器的类型,但是您无法为其指定特定的分配器实例并期望始终使用该实例。

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

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

当然,对于实际使用这些缓冲区做任何事情,这将完全无用。您不能使用当前映射的缓冲区。如果你的分配器在内存完成向量后删除了缓冲区,那么你就永远不能真正使用那个缓冲区对象去

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

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

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

使用缓冲区对象重新分配会更加痛苦。由于std::vector对象是决定要存储多少额外内存的对象,因此您不能像分配大型缓冲区对象那样玩游戏,而只是扩展容器使用的内存量。每次std :: vector认为它需要更多内存时,你将不得不创建一个新的缓冲区对象名称,而std :: Vector将从映射内存到映射内存进行逐元素复制。

不是很快。

真的,你想要的只是创建自己的容器类。这并不难。并且在映射时以及不映射时更容易控制。

答案 2 :(得分:1)

  

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

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