Is it possible to have pointer types as members on user defined structs that are arguments to vertex functions?

Is it possible to have pointer types as members on user defined structs that are arguments to vertex functions? I'd like a struct like this:



struct ShapeInfo {
  constant float4* color;
  float4x4 matrix;
  uint numSides;
};


Colors would be a variable array of size numSides colors for a different color for each side of the shape. I would then have a vertex function like so:



vertex ShapeOut shapeVertex(uint vid [[ vertex_id ]],
  const ShapeIn vertices [[stage_in]],
  constant ShapeInfo* shapeInfo [[buffer(0)]]) {


  // code here.
}


But this results in an error as the constant float4* is not allowed in a buffer.


I've read through the documentation. I see that I can't have pointers as members of stage_in structs. I see that members of structs must be in the same address space. But I don't see any restrictions on pointers in structs as arguments to vertex functions. Is such a thing possible somehow? It seems like it ought to be, and I don't have any problem writing this data into the buffer in the application, I just don't know how to tell the shader what I'm doing here I guess.

Answered by MikeAlpha in 191364022

Hello


I suspect that pointers in structs, or as simple data (array of pointers, or pointer to pointer) are not allowed, because no one knows how to set them properly. You certainly can't - because you do not know _where_ in GPU address space your data is going to land. Neither does runtime - because it doesn't know what you intend the pointer to point to. Yeah, there could be some kind of metadata, or some binding convention but ultimately, I don't think this is wanted in low level API like Metal is.


On the other hand, you can get effect you want pretty easily. Just use integer index in color array instead of float4 pointer, and pass said float4 color array as second argument (with different buffer index). This will allow for passing variable number of colors, like this


struct ShapeInfo {

fłoa4x4 matrix;

uint colorIndex, numSides;

};

vertex ShapeOut shapeVertex(

<other arguments>

constant ShapeInfo & shapeInfo [ [ buffer( 0 ) ] ],

constant float4 * colors [ [ buffer( 0 ) ] ]

)

{}


Note that you can use this layout in any function, in fragment shaders too. I've used reference for shapeInfo because I find it nice way to say "only one instance here" and use pointers when I have multiple instances (arrays). Should you want to, you could pass array of ShapeInfo structures and use indices as described above to get multiple shapes with varying number of sides and colors each. All on two input buffers, and no pointers in structs needed.


Hope that helps

MIchal

Accepted Answer

Hello


I suspect that pointers in structs, or as simple data (array of pointers, or pointer to pointer) are not allowed, because no one knows how to set them properly. You certainly can't - because you do not know _where_ in GPU address space your data is going to land. Neither does runtime - because it doesn't know what you intend the pointer to point to. Yeah, there could be some kind of metadata, or some binding convention but ultimately, I don't think this is wanted in low level API like Metal is.


On the other hand, you can get effect you want pretty easily. Just use integer index in color array instead of float4 pointer, and pass said float4 color array as second argument (with different buffer index). This will allow for passing variable number of colors, like this


struct ShapeInfo {

fłoa4x4 matrix;

uint colorIndex, numSides;

};

vertex ShapeOut shapeVertex(

<other arguments>

constant ShapeInfo & shapeInfo [ [ buffer( 0 ) ] ],

constant float4 * colors [ [ buffer( 0 ) ] ]

)

{}


Note that you can use this layout in any function, in fragment shaders too. I've used reference for shapeInfo because I find it nice way to say "only one instance here" and use pointers when I have multiple instances (arrays). Should you want to, you could pass array of ShapeInfo structures and use indices as described above to get multiple shapes with varying number of sides and colors each. All on two input buffers, and no pointers in structs needed.


Hope that helps

MIchal

Thank you Mike, I had the color array originally in the function argument, but I thought it would be nice to combine them into a struct to reduce the number of arguments. I have a bunch of different shape vertex functions and they all take the same function arguments so that I can use any of them with the same shape renderer class I made.


What you've said about the specifics of where in address space the data would land can't be known makes sense. I really appreciate your help. Thank you again.

Glad that I could help. But what it is that you're concerned with? Just number of arguments to shader? I don't think it carries performance penalty.

Well, you could always use age-old trick of putting fixed size array at the end of struct and then "extend it" by putting extra values immediately behind it in buffer, like this:

struct ShapeInfo {

float4x4 matrix;

uint numColors;

float4 colors[ 1 ];

};

But then you'll have to circumvent compiler warnings (for example via casting)...net effect being that your code would get harder to write and understand.


If, on the other hand, number of buffers is of concern, you can put both ShapeInfo and colors into same buffer (taking into account alignment!) and bind said buffer twice to separate shader buffer indices (0 and 1) with apropriate offsets.

Regards

Michal

Is it possible to have pointer types as members on user defined structs that are arguments to vertex functions?
 
 
Q