我能从我的Metal着色器中获取缓冲区的大小吗?

4

在我的iOS应用程序中,使用Swift编写,我使用以下代码生成Metal缓冲区:

vertexBuffer = device.newBufferWithBytes(vertices, length: vertices.count * sizeofValue(vertices[0]), options: nil)

使用以下代码将其绑定到我的着色器程序中:

renderCommandEncoder.setVertexBuffer(vertexBuffer, offset: 0, atIndex: 1)

在我的Metal着色语言编写的着色器程序中,我能否访问缓冲区的大小?我想要访问缓冲区中的下一个顶点,以进行一些微分计算。类似于以下代码:
vertex float4 my_vertex(const device packed_float3* vertices [[buffer(1)]],
                         unsigned int vid[[vertex_id]]) {
    float4 vertex = vertices[vid];
    // Need to clamp this to not go beyond buffer, 
    // but how do I know the max value of vid? 
    float4 nextVertex = vertices[vid + 1]; 
    float4 tangent = nextVertex - vertex;
    // ...
}

我的唯一选择是将顶点数量作为一个uniform传递吗?


Swift编写的应用程序。Shader使用Metal着色语言编写,该语言是C++的子集。 - Hallgrim
你需要更好地标记这个问题。 - Droppy
3个回答

7
据我所知,不行,因为顶点指向一个地址。就像C++一样,必须知道数组的两个基本信息才能确定数组的大小或者数量:
1)了解数组的数据类型(例如float或某些结构体)

2a)确定该数据类型下的数组数量 或者
2b)确定整个数组的字节数。
所以是的,你需要将数组计数作为一个uniform传递。

1
对于纹理缓冲区,您可以在着色器代码中获取纹理缓冲区的大小。纹理缓冲区有一个`get_width()`和`get_height()`函数,它们返回一个`uint`。但这可能无法回答OP关于顶点缓冲区的问题。

-1

事实上,你可以。你可以使用生成的值用于循环或条件语句。但不能用它来初始化对象(所以动态数组会失败)。

uint tempUint = 0; // some random type
uint uintSize = sizeof(tempUint); // get the size for the type
uint aVectorSize = sizeof(aVector) / uintSize; // divide the buffer by the type.

float dynamicArray[aVectorSize]; // this fails

for (uint counter = 0; counter < aVectorSize; ++ counter) {
    // do stuff
};

if (aVectorSize > 10) {
    // do more stuff
} 

如果sizeof()有效,我会感到惊讶。您确认sizeof()返回完整的向量大小而不是类型的大小或指针的大小吗?据我所知,这些向量都被声明为指针,因此sizeof()只会返回指针的大小?显然,这必须是运行时检查,因为实际大小是在运行时设置的,而不是编译时。 - ldoogy
确认在Metal着色器中,sizeof()返回的是数据类型的大小,而不是实际对象的大小,因此这个答案是完全错误的。 - ldoogy
@Idoogy 不知道呢。你能否创建一个存储库来分享你的代码?我很想看看。已经有很长时间没有玩过 Metal 了。 - R Menke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接