用“常量常量”声明变量的目的是什么?

问题描述 投票:0回答:1

在金属着色器中,声明像const constant Vertex *vertexArray [[buffer(0)]]这样的变量的目的是什么(我的意思是const constant)?为什么仅靠常数还不够?另外,constantconst有什么区别?

也以相同的方式const deviceconstant之间有什么区别?

ios objective-c metal metalkit
1个回答
0
投票

const类型限定符constantdevice地址空间

const阻止您修改其适用的内容:

int a = 15;
a = 16; // Fine; reassigning to a non-const variable

const int b = 15;
b = a; // Error: attempt to write to a read-only constant

int d = 18;
int const* c = &a;
*c = 17; // Error: attempt to write value through a pointer to const int
c = &d;  // Fine; reassigning (a different address) to a (non-const) pointer

int *const e = &d;
*e = a; // Fine; assigning to pointee through pointer to non-const int
e = c;  // Error: attempt to reassign const pointer

希望这些示例充分说明了变量和常量的语义,以及在指针情况下规则如何工作。

在Metal中,指针始终位于特定的地址空间中。如果您在Metal着色器函数中采用自动存储的变量的地址(即“局部”变量),则该指针位于thread地址空间中。另一方面,缓冲区参数始终位于constantdevice地址空间中。

device缓冲区用于保存大约要访问一次其元素的内存,就像在顶点函数中按顺序获取顶点数据时可能会做的那样。另一方面,与统一数据一样,constant缓冲区保存可能由函数的多次调用访问的数据。

您无法写入constant地址空间中的缓冲区。这是此答案中最重要的一句话:constant地址空间中的所有指针都是隐式const限定的。

您可以在恒定地址空间中形成新的指针,并且根据上述规则,您可以重新分配它们。但是尝试写给他们的对象将产生编译器错误。

假设您使用以下参数编写一个片段函数:

constant Light *lights [[buffer(0)]]

然后您可以在函数主体中这样说:

constant Light *light = &lights[0];

还有这个:

light = &lights[1];

但不是这个:

light->color = float4(1, 1, 1, 1); // Error: attempt to write to variable with const-qualified type "const constant Light *"

同样,请注意,在最后一个示例中,即使我们没有说常量指针应该是指向const的指针,也是如此。

由于这个原因,用constant进一步限定const指针(在星号之前是多余且不必要的。

现在让我们谈谈device指针。

与始终为只读的constant缓冲区相反,在许多情况下都可以写入device缓冲区。但是,您通常会将设备缓冲区视为只读(例如,在大多数顶点函数中)。为了向编译器指示此意图,可以将const添加到设备缓冲区指针参数。这将防止您无意中写入只打算读取的缓冲区。如果在不适当的上下文中使用device指向非常量类型的指针,则Metal着色器编译器的最新版本会发出警告,这就是为什么养成为此类参数编写const device的习惯通常是一个好主意的原因。

但是写const constant是多余的,从不需要。

© www.soinside.com 2019 - 2024. All rights reserved.