except for vertex|fragment|kernel functions in metal shader, how to define functions with a referenced parameter

When porting some basic OpenGL ES 2.0 shader to Metal shader, I don't know how to convert the in/inout/out qualifier in glsl to metal shader language(MSL). For example,


//OpenGL vertex shader


...


void getPositionAndNormal(out vec4 position, out vec3 normal, out vec3 tangent, out vec3 binormal)

{

position = vec4(1.0, 0.0, 1.0, 1.0);

normal = vec3(1.0, 0.0, 1.0);

tangent = vec3(1.0, 0.0, 1.0);

binormal = vec3(1.0, 0.0, 1.0);

}


void main()

{

...

vec4 position;

vec3 normal;

vec3 tangent;

vec3 binormal;

getPositionAndNormal(position, normal, tangent, binormal);

...

}


when attempting convert to MSL, I try to use reference in the getPositionAndNormal parameters:

void getPositionAndNormal(float4 & position, float3 & normal, float3 & tangent, float3 & binormal);

I get the following compile error infomation: reference type must have explicit address space qualifier


According to section 4.2 in https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf, I use device address space to reference the getPositionAndNormal parameters in the following forms:

void getPositionAndNormal(device float4 & position, device float3 & normal, device float3 & tangent, device float3 & binormal);


This time, the error message I got was no matching function for call to 'getPositionAndNormal'.

void getPositionAndNormal (

device float4 & position,

device float3 & normal,

device float3 & tangent,

device float3 & binormal)

{

position = float4(1.0, 0.0, 1.0, 1.0);

normal = float3(1.0, 0.0, 1.0);

tangent = float3(1.0, 0.0, 1.0);

binormal = float3(1.0, 0.0, 1.0);

}


vertex ShaderOutput vertexShader (ShaderInput inputMTL [[stage_in]], constant ShaderUniform& uniformMTL [[buffer(1)]])

{

...

float3 binormal = 0;

float3 tangent = 0;

float3 normal = 0;

float4 position = 0;

getPositionAndNormal (position, normal, tangent, binormal);

...

}


What's the right 'metal' way to do this?

Replies

Been converting a lot of opengles shaders myself.


I believe the metal way is to have your "getPositionAndNormal" function return a structure:


struct sPosNormal

{

float3 pos;

float3 normal;

float3 tangent;

float3 otherTangent;

};


sPosNormal getPositionAndNormal()

{

sPosNormal out;

// set values

return out;

}

Use 'thread' instead of 'device'. A good explanation is here

https://stackoverflow.com/questions/54665905/how-to-define-functions-with-a-referenced-parameter-in-metal-shader-language-exc