问题描述
我正在尝试寻找一种方法来减少简单的Metal渲染器中的绘制调用次数。目前,我对每个实体使用抽奖电话。仅作说明,我知道对于少量的绘制和三角形,对每个对象使用绘制调用的幼稚方法是完全可以的。这个问题更具探索性,需要大量的投入。
这是我的系统当前的工作方式:
我有一个大的顶点和索引缓冲区“汤”,其中存储了所有实体。我还有一个大的统一缓冲区,包含与顶点/索引汤中的对象相对应的矩阵变换。对于每个Render_Command
,如下所示,我得到了正确的顶点和索引偏移。我在大型统一缓冲区中设置了一个偏移量,以便下一个绘制调用知道正确的矩阵变换在哪里。然后我画画。
代码:
for (usize i = 0; i < render_layer->render_commands_polygon_count; i += 1) {
Render_Command* const rc = &render_layer->render_commands_polygon[i];
[renderEncoder setVertexBufferOffset:
_entity_uniform_buffer_offset +
((i_uniform_offset + i) * sizeof(InstanceUniforms))
atIndex:kBufferIndexEntityUniforms];
[renderEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle
indexCount:rc->i_buffer_count
indexType:MTLIndexTypeUInt32
indexBuffer:((id<MTLBuffer>)[
_index_buffer_list objectAtIndex:layer_idx
])
indexBufferOffset:rc->i_buffer_offset * sizeof(uint32)];
}
在两次绘制调用之间我要更改的只是统一缓冲区中的偏移量,因此绘制调用使用了顶点着色器中的正确变换矩阵。
但是,我想知道在这种情况下是否有更好的方法。我也可以想象在材质和纹理访问上存在相同的问题。
我想做的是将所有转换的连续缓冲区上传到GPU。每个顶点可以有一个实体ID嵌入到一个属性中。在着色器中,我将使用此属性将索引插入到转换缓冲区中,以获得正确的矩阵(也许对材质缓冲区也是如此)
但是,我不确定此动态索引是否有效/是否可能比这些连续的绘制调用差。关于Metal可能优化调用的方式的稀疏文档,它们之间的调用之间的变化很小(例如,我正在做的只是将偏移量重新设置为相同的缓冲区而已,仅此而已)。有一种叫做indirect command buffer的东西,但这会使更改数据变得更加困难(我需要使用印迹,而且我不确定当前的性能特征)。我不认为这是解决方案。
我认为动态索引会比较慢的原因是,现在着色器无法针对访问同一位置进行优化。它有一些额外的间接。例如,回到glsl,我认为这是不允许的。但是,我目前对每个对象进行偏移和绘制调用的方法可能还会更糟。
我想象私有缓冲区可能会被用于进一步优化,以保持不变的数据,但这超出了范围,因为大多数数据 都会发生变化。
有没有人有经验来描述如何实现动态索引解决方案以及需要进行哪些权衡?在某种程度上相关的注释上,我将如何对纹理描述符执行相同的操作? Vulkan在最新版本中具有动态描述符索引。 Metal有一个称为Argument Buffer的东西,但是我不确定这是否有意义。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)