我正在努力将OpenGL应用程序移植到Metal。在我的旧应用程序中,我曾经绑定两个缓冲区,一个绑定有顶点和各自的颜色,一个绑定有顶点和各自的纹理,并根据某些应用程序逻辑在这两个缓冲区之间切换。现在在Metal中,我从Hello Triangle示例开始,我尝试运行此顶点着色器
vertex RasterizerData
vertexShader(uint vertexID [[vertex_id]],
constant AAPLVertex1 *vertices1 [[buffer(AAPLVertexInputIndexVertices1)]],
constant AAPLVertex2 *vertices2 [[buffer(AAPLVertexInputIndexVertices2)]],
constant bool &useFirstBuffer [[buffer(AAPLVertexInputIndexUseFirstBuffer)]])
{
float2 pixelSpacePosition;
if (useFirstBuffer) {
pixelSpacePosition = vertices1[vertexID].position.xy;
} else {
pixelSpacePosition = vertices2[vertexID].position.xy;
}
...
和此Objective-C代码
bool useFirstBuffer = true;
[renderEncoder setVertexBytes:&useFirstBuffer
length:sizeof(bool)
atIndex:AAPLVertexInputIndexUseFirstBuffer];
[renderEncoder setVertexBytes:triangleVertices
length:sizeof(triangleVertices)
atIndex:AAPLVertexInputIndexVertices1];
(其中AAPLVertexInputIndexVertices1 = 0
,AAPLVertexInputIndexVertices2 = 1
和AAPLVertexInputIndexUseFirstBuffer = 3
),这将导致vertices2
永远不会被访问,但是仍然出现错误:failed assertion 'Vertex Function(vertexShader): missing buffer binding at index 1 for vertices2[0].'
< / p>
如果我在Metal代码中将if (useFirstBuffer)
替换为if (true)
,则一切正常。怎么了?
答案 0 :(得分:1)
当您对条件语句进行硬编码时,编译器足够聪明,可以消除引用缺少缓冲区的分支(通过dead-code elimination),但是当必须在运行时评估条件语句时,编译器不会不知道该分支永远不会被采用。
由于必须绑定所有声明的缓冲区参数,因此,未绑定的缓冲区将不受约束地跳到验证层。如果不遵循该路径,可以在Vertices2
插槽(使用-setVertexBytes:length:atIndex:
)上绑定一些“虚拟”字节。缓冲区的长度相同并不重要,因为毕竟虚拟缓冲区永远不会真正被访问。
答案 1 :(得分:0)
在atIndex参数中,您使用值AAPLVertexInputIndexUseFirstBuffer和AAPLVertexInputIndexVertices1调用代码,但在Metal代码中,值AAPLVertexInputIndexVertices1和AAPLVertexInputIndexVertices2出现在buffer()规范中。看来您需要在调用代码中使用AAPLVertexInputIndexVertices1而不是AAPLVertexInputIndexUseFirstBuffer。