问题
In Metal shader, What is the purpose of declaring a variable like const constant Vertex *vertexArray [[buffer(0)]]
(with const constant
I mean)? why constant alone is not enough? also, what is the difference between constant
and const
?
Also in the same way what is the difference between const device
and constant
?
回答1:
const
is a type qualifier. constant
and device
are address spaces.
const
prevents you from modifying the thing to which it applies:
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
Hopefully these examples adequately illustrate the semantics of variables and constants, and how the rules work in the case of pointers.
In Metal, pointers always reside in a particular address space. If you take the address of a variable with automatic storage in a Metal shader function (i.e. a "local" variable), that pointer is in the thread address space. Buffer parameters, on the other hand, are always in the constant or device address space.
device
buffers are used to hold memory whose elements will be accessed roughly once, as you might do when fetching vertex data sequentially in a vertex function. On the other hand, constant
buffers hold data that might be accessed by many invocations of a function, as with uniform data.
You cannot write to a buffer in the constant
address space. Here's the most important sentence in this answer: All pointers in the constant
address space are implicitly const-qualified.
You can form new pointers in the constant address space, and by the rules explained above, you can reassign them. But attempting to write to their pointee will produce a compiler error.
Suppose you write a fragment function with the following parameter:
constant Light *lights [[buffer(0)]]
Then in the function body you could say this:
constant Light *light = &lights[0];
And this:
light = &lights[1];
But not this:
light->color = float4(1, 1, 1, 1); // Error: attempt to write to variable with const-qualified type "const constant Light *"
Again, note that in this last example, even though we didn't say that the constant pointer should be a pointer-to-const, it is. For this reason, further qualifying a constant
pointer with const
(before the asterisk) is redundant.
Now let's talk a bit about device
pointers.
In contrast to constant
buffers, which are always read-only, it is possible in many contexts to write to device
buffers. However, you often treat device buffers as read-only (e.g., in most vertex functions). To indicate this intent to the compiler, you can add const
to a device buffer pointer parameter. This will prevent you from inadvertently writing to a buffer you are only intending to read. Recent versions of the Metal shader compiler emit a warning if you take a device
pointer to non-const type in an inappropriate context, which is why it's generally a good idea to get in the habit of writing const device
for such parameters.
But writing const constant
is redundant and never necessary.
来源:https://stackoverflow.com/questions/59010429/what-the-purpose-of-declaring-a-variable-with-const-constant