美文网首页
Metal 语言

Metal 语言

作者: tp夕阳武士 | 来源:发表于2020-05-26 17:30 被阅读0次
    1.介绍

    Metal基于C++ 11.0标准设计的着色器语言,在C++的基础上进行了一些拓展和限制.

    Metal 的限制

    • Lambda表达式
    • 地柜函数调用
    • 动态转换操作符
    • 类型识别
    • 创建对象:new 和释放对象 dealloc操作
    • 操作符 noexcept
    • goto跳转符
    • 虚函数修饰符
    • 派生类
    • 异常处理
    • C++的标准款不可以在Metal着色语言中使用
    • Metal语言有对指针的使用限制
    • Metal图形和并行计算函数用到的入参如果是指针,使用地址空间修饰符(device , threadgroup , constant)
    • 不支持函数指针
    • Metal 函数名不能命名为Main
    2.基础类型
    类型 解释
    bool 布尔类型
    char 有符号8-bit 整数
    unsigned char uchar 无符号8-bit 整数
    short 有符号16-bit 整数
    unsigned short ushort 无符号16-bit 整数
    int 有符号32-bit 整数
    unsigned int uint 无符号32-bit 整数
    half 16-bit 浮点数
    float 32-bit 浮点数
    size-t 64-bit 无符号整数,表示sizeof操作符结果;
    ptrdiff_t 64-bit 有符号整数,表示2个指针的查
    void 表示一个空的集合
    支持的向量类型 解释
    booln bool型向量n是一个数字,表示多少个坐标组成的向量
    charn char型向量n是一个数字,表示多少个坐标组成的向量
    shortn short型向量n是一个数字,表示多少个坐标组成的向量
    intn int型向量n是一个数字,表示多少个坐标组成的向量
    ucharn uchar型向量n是一个数字,表示多少个坐标组成的向量
    ushortn ushort型向量n是一个数字,表示多少个坐标组成的向量
    uintn uint型向量n是一个数字,表示多少个坐标组成的向量
    halfn half型向量n是一个数字,表示多少个坐标组成的向量
    floatn float型向量n是一个数字,表示多少个坐标组成的向量
    矩阵的描述方式 解释 矩阵只支持两种类型
    halfxm xm分别指的是矩阵的行数和列数
    floatxm xm分别指的是矩阵的行数和列数
    //基本数据类型
    bool a = true;
    char b = 5;
    int  d = 15;
    size_t c = 1;
    ptrdiff_t f = 2;
    
    //向量
    bool2 A= [1,0];
    float4 pos = float4(1.0f,2.0f,3.0f,4.0f);
    float x = pos[0];
    float y = pos[1];
    
    //利用 pos 向量的规律变化得到一个新的向量VB
    float4 VB;
    for(int i = 0; i < 4 ; i++)
        VB[i] = pos[i] * 2.0f;
    
    //通过向量字母来获取元素
    int4 test = int4(0,1,2,3,4);
    int a = test.x;
    int b = test.y;
    int c = test.z;
    int d = test.w;
    
    int e = test.r;
    int f = test.g;
    int g = test.b;
    int h = test.a;
    
    //多维向量的赋值
    float4 c; //c是一个四维向量 x,y,z,w坐标
    c.xyzw = float4(1.0f,2.0f,3.0f,4.0f);
    c.z = 1.0f; //单独为某一个方向坐标赋值
    c.xy = float2(3.0f,4.0f);
    c.xyz = float3(3.0f,4.0f,5.0f);
    
    float4 pos = float4(1.0f,2.0f,3.0f,4.0f);
    //分量语法,允许分量乱序 或者 分量重复出现
    float4 swiz = pos.wxyz;  //swiz = (4.0,1.0,2.0,3.0);
    float4 dup = pos.xxyy;  //dup = (1.0f,1.0f,2.0f,2.0f)
    
    //pos = (5.0f,2.0,3.0,6.0)
    pos.xw = float2(5.0f,6.0f);
    
    //pos = (8.0f,2.0f,3.0f,7.0f)
    pos.wx = float2(7.0f,8.0f);
    
    //pos = (3.0f,5.0f,9.0f,7.0f);
    pos.xyz = float3(3.0f,5.0f,9.0f);
    
    float2 pos;
    pos.x = 1.0f; //合法
    pos.z = 1.0f; //非法 - 超范围 二维向量没有z坐标
    
    float3 pos2;
    pos2.z = 1.0f; //合法
    pos2.w = 1.0f; //非法
    
    //非法,x出现2次
    pos.xx = float2(3.0,4.0f);
    //不合法-使用混合限定符
    pos.xy = float4(1.0f,2.0,3.0,4.0);
    
    float4 pos4 = float4(1.0f,2.0f,3.0f,4.0f);
    pos4.x = 1.0f;
    pos4.y = 2.0f;
    //非法,.rgba与.xyzw 混合使用
    pos4.xg = float2(2.0f,3.0f);
    ////非法,.rgba与.xyzw 混合使用
    float3 coord = pos4.ryz;
    
    float4 pos5 = float4(1.0f,2.0f,3.0f,4.0f);
    //非法,使用指针来指向向量/分量
    my_func(&pos5.xy);
    
    float4x4 m;
    //将第二排的值设置为0
    m[1] = float4(2.0f);
    
    //设置第一行/第一列为1.0f
    m[0][0] = 1.0f;
    
    //设置第三行第四列的元素为3.0f
    m[2][3] = 3.0f;
    
    //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);
    
    //float3类型向量的所有可能的构造的方式
    float3(float x);
    float3(float x,float y,float z);
    float3(float a,float2 b);
    float3(float2 a,float b);
    float3(float3 x);
    
    //float2类型向量的所有可能的构造方式
    float2(float x);
    float2(float x,float y);
    float2(float2 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);
    
    //定义一个缓存
    //Metal 所谓的缓存,就是一块用指针指向的区域 (显存)
    //在客户端代码中,使用指针指向的一块代码区域(内存)
    
    //2个修饰符 : device (设备空间,其实就是GPU) , constant (设备空间只读)
    //作用:当做函数的参数来传递
    
    device float4 *device_buffer ;
    
    //结构体
    struct my_user_data{
        float4 a;
        float b;
        int2 c;
    };
    my_user_data *a;
    constant my_user_data *user_data;  // 只读
    
    //纹理
    //纹理数据就是一个句柄,它指向一个 一维/二维/三维 纹理数据\
    
    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>
    
    //T表示类型: int , float 
    
    //带有深度格式的纹理必须被声明为下面纹理数据类型中的一个
    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)]])
    {
        
        //...
    }
    
    //函数修饰符.
    /*
     3个函数修饰符:
     1. kernel : 并行计算函数
     2. vertex : 顶点函数
     3. fragment : 片元函数
     */
    
    
    //1.并行计算函数(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 int CCTestVertexFunctionB(int a,int b){
        
    }
    
    //片元函数
    fragment int CCTestVertexFunctionB(int a,int b){
        
    }
    
    void CCTest()
    {
        
    }
    
    //变量/函数参数地址空间修饰符
    /*
     1.device
     2.threadgroup
     3.constant
     4.thread
     */
    
    /*
     注意:
     1. 所有被(kernel,vertex,fragment)所修饰的参数变量,如果其类型是指针/引用 都必须带有地址空间修饰符.
     2. 被fragment修饰的片元函数, 指针/引用必须被device/constant/threadgroup
     */
        
    //变量/参数地址空间修饰符
    void CCTestFouncitionE(device int *g_data,
                           threadgroup int *l_data,
                           constant float *c_data
                           )
    {
        //...
        
    }
    
    // 设备地址空间: device 用来修饰指针.引用
    //1.修饰指针变量
    device float4 *color;
    
    struct CCStruct{
        float a[3];
        int b[2];
    };
    //2.修饰结构体类的指针变量
    device CCStruct *my_CS;
    
    /*
     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;
        
    }
    
    //常量地址修饰空间
    //constant 显存,但是它是只读.
    
    
    //属性修饰符
    /*
     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];
    }
    
    
    
    

    相关文章

      网友评论

          本文标题:Metal 语言

          本文链接:https://www.haomeiwen.com/subject/geqvahtx.html