Metal:ShadingLanguare基础语法

1,472 阅读5分钟

基本数据类型

bool a = true;
char b = 5;
int  c = 15;

向量

bool2 A = [1,2];
float4 pos = float4(1.0,2.0,3.0,4.0);
float x = pos[0];
float y = pos[1];

向量的所有可能构造方式

//float2类型向量的所有可能的构造方式

float2(float x);

float2(float x,float y);

float2(float2 x);

//float3类型向量的所有可能的构造的方式

float3(float x);

float3(float x,float y,float z);

float3(float a,float2 b);

float3(float2 a,float b);

float3(float3 x);

//float4类型向量的所有可能构造方式

float4(float x);

float4(float x,float y,float z,float w);

float4(float2 a,float2 b);

float4(float2 a,float b,float c);

float4(float a,float2 b,float c);

float4(float a,float b,float2 c);

float4(float3 a,float b);

float4(float a,float3 b);

float4(float4 x);

//多个向量构造器的使用

float x = 1.0f,y = 2.0f,z = 3.0f,w = 4.0f;

float4 a = float4(0.0f);

float4 b = float4(x,y,z,w);

float2 c = float2(5.0f,6.0f);

float2 a = float2(x,y);

float2 b = float2(z,w);

float4 x = float4(a.xy,b.xy);

通过向量字母来获取元素

使用xyzw获取

int4 zjTest = int4(4,5,6,7);
int x = zjTest.x;
int y = zjTest.y;
int z = zjTest.z;
int w = ziTest.w;

使用rgba获取int r = zjTest.r;
int g = zjTest.g;
int b = zjTest.b;
int a = zjTest.a;

可以对向量进行单个赋值

float4 zz;
zz.xyzw = float4(2.0,2.0,2.0,2.0);
zz.z = 2.0;
zz.xy = float2(2.0,2.0);
zz.xyz = float3(2.0,2.0,2.0);

可以取出实现赋值
float4 pos = float4(1.0,2.0,3.0,4.0);
float4 swiz = pos.wxyz;//swiz = (4.0,1.0,2.0,3.0);
float4 ddp = pos.xxyy; //ddp = (1.0,1.0,2.0,2.0);

pos.xw = float2(6.0,7.0);
pos.wx = float2(7.0,8.0);
pos.xyz = float3(9.0,3.0,5.0);

向量不合法的使用

不能超过向量的 维度
float2 ppo;
ppo.x = 1.0;//合法
ppo.z = 2.0;//不合法

float3 = ppl;
ppl.z = 5.0;//合法
ppl.w = 1.0;//不合法

等式左边不能重复出现
float2 llp;
llp.xx = float2(1.0,1.0);//不合法

等式两边必须等维度
float3 kkl;
kkl.xy = float4(1.0,2.0,3.0,4.0);//不合法

不能出现混合限定符
float4 pod = float4(1.0,2.0,3.0,4.0);
pod.xg = float2(2.0,3.0);//不合法
float3 ffp = pod.xya;//不合法

缓存buffer定义格式

device float4 *device_buffer;

struct my_user_data{   

 float4 a;  

  float b;  

  int2 c;

};

constant my_user_data *user_data;

纹理texture定义格式

enum class access {sample,read,write};

texture1d <T,access a = access::sample>texture1d_array <T,access a = access::sample>

texture2d <T,access a = access::sample>

texture2d_array <T,access a = access::sample>

texture3d <T,access a = access::sample>

texturecube <T,access a = access::sample>

texture2d_ms <T,access a = access::read>


//带有深度格式的纹理必须被声明为下面纹理数据类型中的一个

enum class depth_forma {depth_float};

depth2d <T,access a = depth_format::depth_float>

depth2d_array <T,access a = access::sample,depth_format d = depth_format::depth_float>

depthcube <T,access a = access::sample,depth_format d = depth_format::depth_float>

depth2d_ms <T,access a = access::read,depth_format d = depth_format::depth_float>

Metal中的函数修饰符

 函数修饰符:

       1. kernel : 并行计算函数

       2. vertex : 顶点函数

        3. fragment : 片元函数

//kernel 修饰的并行计算着色函数kernel void CCTestFouncitionA(int a,int b)

{

}

//vertex 修饰顶点着色函数vertex int CCTestFouncitionC(int a,int b)

{

}
//fragment 修饰片元着色函数fragment int CCTestFouncitionD(int a,int b)

{

}

注意:

1. 使用kernel 修饰的函数返回值必须是void 类型

2. 一个被函数修饰符修饰过的函数,不允许在调用其他的被函数修饰过的函数. 非法

3. 被函数修饰符修饰过的函数,只允许在客户端对齐进行操作. 不允许被普通的函数调用.


变量/函数参数地址空间修饰符

 1. device

// 设备地址空间: device 用来修饰指针.引用

//1.修饰指针变量

device float4 *color;

//2.修饰结构体类的指针变量

struct CCStruct{
  
  float a[3];  

  int b[2];

};

device CCStruct *my_CS;

 2. threadgroup

3. thread

/* 

1. threadgroup 被并行计算计算分配内存变量, 这些变量被一个线程组的所有线程共享. 在线程组分配变量不能被用于图像绘制. 

2. thread 指向每个线程准备的地址空间. 在其他线程是不可见切不可用的

 */

kernel void CCTestFouncitionF(threadgroup float *a){   

 //在线程组地址空间分配一个浮点类型变量x    

threadgroup float x;   

 //在线程组地址空间分配一个10个浮点类型数的数组y;    

threadgroup float y[10];

}


constant float sampler[] = {1.0f,2.0f,3.0f,4.0f};

kernel void CCTestFouncitionG(void){  

  //在线程空间分配空间给x,p  

  float x;  

  thread float p = &x;

}

 4. constant  显存,但是它是只读.

//变量/参数地址空间修饰符void CCTestFouncitionE(

                      device int *g_data, 

                      threadgroup int *l_data, 

                      constant float *c_data)

{

}

 注意:

1. 所有被(kernel,vertex,fragment)所修饰的参数变量,如果其类型是指针/引用 都必须带有地址空间修饰符.

2. 被fragment修饰的片元函数, 指针/引用必须被device/constant/threadgroup


属性修饰符

1. device buffer(设备缓存)

2. constant buffer(常量缓存)

3. texture Object(纹理对象)

4. sampler Object(采样器对象)

5. 线程组 threadgroup

属性修饰符目的:

1. 参数表示资源如何定位? 可以理解为端口

2. 在固定管线和可编程管线进行内建变量的传递

3. 将数据沿着渲染管线从顶点函数传递片元函数.

在代码中如何表现:

1.已知条件:device buffer(设备缓存)/constant buffer(常量缓存)

代码表现:[[buffer(index)]]

解读:不变的buffer ,index 可以由开发者来指定.


2.已知条件:texture Object(纹理对象)

代码表现: [[texture(index)]]

解读:不变的texture ,index 可以由开发者来指定.


3.已知条件:sampler Object(采样器对象)

代码表示: [[sampler(index)]]

解读:不变的sampler ,index 可以由开发者来指定.


4.已知条件:threadgroup Object(线程组对象)

代码表示: [[threadgroup(index)]]

解读:不变的threadgroup ,index 可以由开发者来指定.

//并行计算着色器函数add_vectros ,实现2个设备地址空间中的缓存A与缓存B相加.然后将结果写入到缓存out.

//属性修饰符"(buffer(index))" 为着色函数参数设定了缓存的位置

kernel void add_vectros(                

        const device float4 *inA [[buffer(0)]],                       

        const device float4 *inB [[buffer(1)]],     

        device float4 *out [[buffer(2)]]   

        uint id[[thread_position_in_grid]])

{    

out[id] = inA[id] + inB[id];

}


参考文档地址:https://github.com/ZJ-Sandy/FN_ZJ.git