metal shading language

198 阅读3分钟

1.数据类型

//例如: bool a= true;  char b = 5;  int d = 15;

2.向量支持以下类型

booln, charn, shortn, intn, ucharn, ushortn, uintn, halfn, floatn, n指的是维度
//例如:bool2 A=[1,0]; float4 pos = float4(1.0,2.0,3.0,4.0);
**  float** x = pos[0]; float y = pos[1];
**  float4** vb;
**  for**(int i = 0;i<4;i++){ vb[i] = pos[i] * 2.0f; }

  • 支持通过向量字母来获取对应元素(xyzw和rgba) ,但不允许 rgba和xyzw 混合使用 int4 test = int4(0,1,2,3); int a = test.x; int e = test.r;

  • 分量允许多个分量乱序/重复出现

**        float4** dup = pos.xxyy; float4 swiz = pos.wxyz;

  • 不允许超过其维度去访问变量. xy

**        float2** pos;pos.x = 1.0f;//合法 pos.z = 1.0f;//不合法

  • 多个向量构造器的使用

**       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);
      float2 a1 = float2(1.0,1.0);
**       float2** a2 = float2(2.0,2.0);
**       float2x2** a = float2x2(a1,a2);

3.矩阵支持一下类型

halfnxm, floatnxm, n和m分别指的矩阵的行和列

矩阵不支持从多个标量构造          float2x2(float a00,float a01,float a02,float a00); 非法矩阵不支持标量和向量混合构造         float2x3(float2 a,float b,float c,float d);非法支持这样赋值        float4x4 m;       指的将第二排向量(x,y,z,w)赋值都为2.0f       m[1] = float4(2.0f);       m[0][0] = 1.0f;4.定义一块缓存, metal所谓缓存就是一个块用的指针指向区域(显存)   2个修饰符device(设备空间), constant(设备空间只读)   

device float4 *device_buffer;   

//结构体   struct my_user_data {         float4 a;         float2 c;         int b;   };   constant my_user_data *user_data;

5. 纹理.

//纹理数据类型就是一个句柄. 它指向一个一维/二维/三维纹理数据. 常用的就是texture2d, sample标示此纹理可以被采样
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>

void foo (texture2d<float> imgA[[texture(0)]],          texture2d<float,access::read> imgB[[texture(1)]],          texture2d<float,access::write> imgC[[texture(2)]])
}

6.函数修饰符:

  • kernel: 并行计算函数(开发过程中, 基本上不适用)

    kernel void CCTestKernelFunctionA(int a,int b) { /* 注意: 1. 使用kernel 修饰的函数返回值必须是void 类型  2. 一个被函数修饰符修饰过的函数,不允许在调用其他的被函数修饰过的函数. 非法 3. 被函数修饰符修饰过的函数,只允许在客户端对其进行操作. 不允许被普通的函数调用. *// //不可以的! //一个被函数修饰符修饰过的函数,不允许在调用其他的被函数修饰过的函数. 非法 CCTestKernelFunctionB(1,2);//非法 CCTestVertexFunctionB(1,2);//非法 //可以! 你可以调用普通函数.而且在Metal 不仅仅只有这3种被修饰过的函数.普通函数也可以存在 CCTest()}kernel void CCTestKernelFunctionB(int a,int b){}

  • vertex: 顶点函数

  • vertex int CCTestVertexFunctionB(int a,int b){ }//函数修饰符vertex 返回值类型RasterizerData 函数名字vertexShader //uint vertexID [[ vertex_id ]]是内建的, 我们无法修改, metal规定必须这样, 由它自己处理 vertex RasterizerDatavertexShader(uint vertexID [[ vertex_id ]], constant CCVertex *vertexArray [[ buffer(0) ]], constant vector_uint2 *viewportSizePointer [[buffer(1)]]){ //定点函数的输出 就是片元函数的输入}

  • fragment: 片元函数

  • fragment half4 fragmentShader(RasterizerData input [[stage_in]], texture2d textureColor [[ texture(0) ]]){

    }
    

7.属性修饰符

  1. device buffer(设备缓存)

  2. constant buffer(常量缓存)

  3. texture Object(纹理对象)

  4. sampler Object(采样器对象)

 属性修饰符目的:

  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 可以由开发者来指定.

Metal使用大致分为:

  • build :shader(vertexShader和fragmentShader)
  • initialize :device and Queues Render Objects
  • Render:commandBuffer、ResourceUpdate、renderEncoder、Display

初始化Device

guard let device = MTLCreateSystemDefaultDevice() else {
    fatalError("Could not create Metal Device")
}

创建 CommandQueue 命令队列

guard let commandQueue = self.device.makeCommandQueue() else {
       fatalError("Could not create command queue")
   }

创建 Buffer 数据: 

与 OpenGL 类似的,顶点、索引等数据都通过 Buffer 管理。 比如:vertexBuffer、textureCoordBuffer

/// 纹理坐标buffer
let coordinateBuffer = device.makeBuffer(bytes: inputTextureCoordinates,
                    length: inputTextureCoordinates.count * MemoryLayout<Float>.size,
                    options: [])!
///顶点数据buffer
let vertexBuffer = device.makeBuffer(bytes: imageVertices,
                    length: imageVertices.count * MemoryLayout<Float>.size,
                    options: [])!

创建 Texture

创建 pipline 渲染管线

renderEncoder