LWJGL:缓冲内存管理

LWJGL: Buffer Memory Management

我正在寻找一些 memory/performance 关于哪种方法更好的建议。

如果假设我有一个网格的 4 个属性

Vertex    3f
Normal    3f
TexCoords 2f
jointID   4i [Integer Joint Indices For Skeleton Animation]

我需要这些在 cpu 内存中,因为它们可以随时修改

是不是更好

a.Create 每个组件 4 个单独的缓冲区

//3,2,4 are the strides i.e vertex is 3 floats,texCoord is 2 floats so on
FloatBuffer vertices=BufferUtils.createFloatBuffer(numOfVertices*3);
FloatBuffer normals=BufferUtils.createFloatBuffer(numOfVertices*3);
FloatBuffer texCoords=BufferUtils.createFloatBuffer(numOfVertices*2);
IntBuffer   vertexJoints=BufferUtils.createIntBuffer(numOfVertices*4);

或者

b.Create 一个大字节缓冲区,其容量足以存储所有 4 个属性并为每个属性创建单独的 Float/Int 缓冲区视图

 ByteBuffer  meshData=BufferUtils.createByteBuffer(((numOfVertices*3)+(numOfVertices*3)+(numOfVertices*2)+(numOfVertices*4))*4); //*4 because both float/int is 4 bytes
 FloatBuffer vertices=meshData.position(0).limit(endVertexByte).asFloatBuffer();
 FloatBuffer normals=meshData.position(endVertexByte).limit(endNormalByte).asFloatBuffer();
 FloatBuffer texCoords=meshData.position(endNormalByte).limit(endTexCoordByte).asFloatBuffer();
 IntBuffer   jointIDs=meshData.position(endTexCoordByte).limit(endJointIndexByte or end of buffer in this case).asIntBuffer();

根据文档,所有 BufferUtils 方法都会创建一个存储在本机内存中的 directBuffer,尽管第二种方法创建的缓冲区比所有单个属性缓冲区的总和还要大[因为我们乘以 4],它只创建与第一种方法中的 4 个独立内存区域相比,一个较大的本机内存块。

但这只是我的意见,想法?

当我们只从 CPU 的角度查看您如何将(新)数据写入这些缓冲区时,性能不会有差异。 在任何一种情况下,当您更新顶点的属性数据时,您都只有四个连续的内存区域。只是在前一种情况下,这些内存区域偏移了未知数量的字节(因为 JVM 的内存分配器将分别分配每个区域),而在后一种情况下,您知道每两个连续内存区域之间的偏移量,因为您分配了那些在单个 JVM 缓冲区内存分配中。

但是, 的不同之处在于您实际将这些客户端主机内存区域映射到服务器端 OpenGL 缓冲对象内存的方式。 我想一旦您更新了主机端内存,您实际上会将其上传到服务器端 OpenGL 缓冲区对象中,而不是将 client/host-side 内存指针用于 OpenGL 顶点规范命令(仅在 OpenGL 兼容性上下文中可用)。

在那种情况下,创建四个独立的连续客户端内存区域将需要您执行四个 OpenGL 缓冲内存上传命令 (glBufferSubData()) 并且 OpenGL 驱动程序执行四个不同的直接内存访问 ( DMA)通过 PCIe 上传。 如果您只有一个连续的客户端内存区域,您可以只发出一个 glBufferSubData() 调用,将所有顶点属性的数据放入一个缓冲区对象中,您只需在 OpenGL 顶点规范中使用字节偏移量调用(例如 glVertexAttribPointer())。

另一种可能性也是不自己分配客户端主机内存,而是让 OpenGL (glBufferStorage() + glMapBufferRange()) 为您提供主机可见的、持久映射的缓冲区,这然后您可以写入并显式刷新或让它们 implicitly/coherently 由 OpenGL 驱动程序更新。 与四个单独的客户端内存区域一样,当您映射和刷新四个不同的 OpenGL 缓冲区对象区域时,您也可能会支付“四个不同的 DMA 传输”成本。

因此,最终,客户端内存上是否有一个或四个 NIO 缓冲区视图并不重要,但与映射这些内存区域的服务器端 OpenGL 缓冲区对象的数量有关 - 越少越多越好。