用 "const constant" 声明变量的目的是什么?
what the purpose of declaring a variable with "const constant"?
在 Metal 着色器中,声明像 const constant Vertex *vertexArray [[buffer(0)]]
这样的变量的目的是什么(我的意思是 const constant
)?为什么只有常数是不够的?另外, constant
和 const
有什么区别?
同样的道理,const device
和constant
有什么区别?
const
是 类型限定符 。 constant
和device
是地址spaces.
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 中,指针总是位于特定地址 space。如果您在 Metal 着色器函数中使用自动存储的变量地址(即 "local" 变量),该指针位于 thread 地址 space 中。另一方面,缓冲区参数始终位于 constant 或 device 地址 space.
device
缓冲区用于保存其元素将被粗略访问一次的内存,就像您在顶点函数中顺序获取顶点数据时可能会做的那样。另一方面,constant
缓冲区保存的数据可能会被函数的多次调用访问,就像统一数据一样。
您不能写入 constant
地址 space 中的缓冲区。这是这个答案中最重要的一句话:constant
地址 space 中的所有指针都隐含地限定了 const。
你可以在常量地址space中形成新的指针,并根据上面解释的规则,你可以重新分配它们。但是尝试写入他们的指针会产生编译器错误。
假设您使用以下参数编写片段函数:
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
指针是多余的。
现在让我们谈谈 device
指针。
与始终只读的 constant
缓冲区相反,在许多情况下可以写入 device
缓冲区。但是,您经常将设备缓冲区视为只读(例如,在大多数顶点函数中)。要向编译器指示此意图,您可以将 const
添加到设备缓冲区指针参数。这将防止您无意中写入您只打算读取的缓冲区。如果您在不适当的上下文中使用指向非常量类型的 device
指针,Metal 着色器编译器的最新版本会发出警告,这就是为什么养成编写 const device
的习惯通常是个好主意的原因对于这样的参数。
但是写 const constant
是多余的,从来没有必要。
在 Metal 着色器中,声明像 const constant Vertex *vertexArray [[buffer(0)]]
这样的变量的目的是什么(我的意思是 const constant
)?为什么只有常数是不够的?另外, constant
和 const
有什么区别?
同样的道理,const device
和constant
有什么区别?
const
是 类型限定符 。 constant
和device
是地址spaces.
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 中,指针总是位于特定地址 space。如果您在 Metal 着色器函数中使用自动存储的变量地址(即 "local" 变量),该指针位于 thread 地址 space 中。另一方面,缓冲区参数始终位于 constant 或 device 地址 space.
device
缓冲区用于保存其元素将被粗略访问一次的内存,就像您在顶点函数中顺序获取顶点数据时可能会做的那样。另一方面,constant
缓冲区保存的数据可能会被函数的多次调用访问,就像统一数据一样。
您不能写入 constant
地址 space 中的缓冲区。这是这个答案中最重要的一句话:constant
地址 space 中的所有指针都隐含地限定了 const。
你可以在常量地址space中形成新的指针,并根据上面解释的规则,你可以重新分配它们。但是尝试写入他们的指针会产生编译器错误。
假设您使用以下参数编写片段函数:
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
指针是多余的。
现在让我们谈谈 device
指针。
与始终只读的 constant
缓冲区相反,在许多情况下可以写入 device
缓冲区。但是,您经常将设备缓冲区视为只读(例如,在大多数顶点函数中)。要向编译器指示此意图,您可以将 const
添加到设备缓冲区指针参数。这将防止您无意中写入您只打算读取的缓冲区。如果您在不适当的上下文中使用指向非常量类型的 device
指针,Metal 着色器编译器的最新版本会发出警告,这就是为什么养成编写 const device
的习惯通常是个好主意的原因对于这样的参数。
但是写 const constant
是多余的,从来没有必要。