简体   繁体   中英

what the purpose of declaring a variable with "const constant"?

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 ?

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 (ie 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 (eg, 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM