苹果开发语言OpenCL 变量地址限定符详解 附源码

移动开发 iOS
本文介绍的是苹果开发语言OpenCL 变量地址限定符详解,富有源码可以参考学习,先来看内容。

苹果开发语言OpenCL 变量地址限定符详解是本文要介绍的内容,首先我们先来了解OpenCL,即:Open Computing Language,是由苹果公司起草设计的用于大规模并行计算的计算编程语言。CocoaChina 版主 “zenny_chen” 今天为我们带来新的一篇 OpenCL 教程:变量地址限定符。

我们的示例程序是通过OpenCL来实现一个正方形的颜色渐变着色。这里,我们将牵涉到变量存储属性,另外还引入了向量数据,向量数据是如何操作的,向量数据与标量数据是如何交叉操作的。

请先下载完整的工程文件 OpenCL_shading.zip (36 K) ,下面是 OpenCL 内核代码。

  1. // Render a square  
  2. // left-top:    red(1, 0, 0)  
  3. // left-bottom: green(0, 1, 0)  
  4. // right-top:   blue(0, 0, 1)  
  5. // right-bottom:black(0, 0, 0)  
  6.  
  7. __constant float4 left_top        = (float4)(1.0f, 0.0f, 0.0f, 0.0f);  
  8. __constant float4 left_bottom     = (float4)(0.0f, 1.0f, 0.0f, 0.0f);  
  9. __constant float4 right_top       = (float4)(0.0f, 0.0f, 1.0f, 0.0f);  
  10. __constant float4 right_bottom    = (float4)(0.0f, 0.0f, 0.0f, 0.0f);  
  11. __kernel void ColorShading(  
  12.                     __global float4 output[256][256]  
  13.                     )  
  14. {  
  15.     int dimX = get_global_id(0);  
  16.     int dimY = get_global_id(1);  
  17.     __local float4 deltaLeft = (left_top - left_bottom) / 255.0f;  
  18.     __local float4 deltaRight = (right_top - right_bottom) / 255.0f;  
  19.  
  20.     float4 left = left_bottom + deltaLeft * (float)dimY;  
  21.     float4 right = right_bottom + deltaRight * (float)dimY;  
  22.     float4 delta = (right - left) / 255.0f;  
  23.     float4 result = left + delta * (float)dimX;  
  24.  
  25. // clamp  
  26.     if(result.x > 1.0f)  
  27.         result.x = 1.0;  
  28.     if(result.y > 1.0f)  
  29.         result.y = 1.0f;  
  30.     if(result.x < 0.0f)  
  31.         result.x = 0.0f;  
  32.     if(result.y < 0.0f)  
  33.         result.y = 0.0f;  
  34.  
  35.     output[dimY][dimX] = result + (float4)(0.0f, 0.0f, 0.0f, 1.0f);  

我们首先来谈谈向量类型

上述代码中,我们引入了float4类型。它是一个向量类型。向量类型的定义规则是在基本类型后加n,n可以是2,4,8,16。比如:uchar8,float2,int16,long4等等。

而对于向量类型各分量的访问,如果向量的分量个数在4个以内,我们可以依次用x,y,z,w来表示。这种标识法是与OpenGL Shader中的vertex shader对向量分量的访问形式一样。

另外,我们还可以用数值索引来访问一个向量的各个分量。这个时候,我们可以将一个向量变量视为一个数组。如果向量的元素个数是16,那么第0到第9个元素分别用索引0到9表示;而第10到第15个元素,我们用a到f或A到F(即十六进制)来表示。而当我们用索引来表示的话,向量变量的.的后面必须跟一个字母 s。

下面举些例子:

  1. int4 a = int4(1, 2, 3, 4); 

那么a.x是1;a.y是2;a.z是3;a.w是4。同样,a.s0是1;a.s1是2;a.s2是3;a.s3是4。

对于向量变量,我们还能非常灵活地对其各个分量进行赋值。我们这里再引入一个swizzle的概念。swizzle是指可以对一个向量用另一个向量所对应的任意元素进行赋值。比如说:

  1. int4 a = int4(1, 2, 3, 4);  
  2. int4 b = a.wzyx; 

这表示用a的第3个元素赋给b的第0个元素;a的第2个元素赋给b的第1个元素;用a的第1个元素赋给b的第2个元素;用a的第0个元素赋给b的第3个元素。然后,我们还能这么做:

  1. b.xz = a.s32; 

表示将a的第三个元素给b的第0个元素;a的第2个元素赋给b的第2个元素。是不是很灵活呢?呵呵。

向量变量之间的加、减、乘、除以及逻辑运算都是针对向量所对应的各个分量进行的。比如说上面的int4 a; int4 b;a *= b; 相当于:a.x *= b.x; a.y *= b.y; a.z *= b.z; a.w *= b.w;

如果一个向量与一个标量进行计算,那么是将该标量与向量的没个分量做相同的运算,比如:

  1. int4 a;  
  2. int i;  
  3. a *= i; 

相当于:a.x *= i; a.y *= i; a.z *= i; a.w *= i;

而i *= a;则是非法的。因此我们必须注意,在用向量与标量做算术逻辑操作时,必须把向量放在操作符的左边,而标量要放在操作符的右边。

上述代码中:

  1. // clamp  
  2.     if(result.x > 1.0f)  
  3.         result.x = 1.0;  
  4.     if(result.y > 1.0f)  
  5.         result.y = 1.0f;  
  6.     if(result.x < 0.0f)  
  7.         result.x = 0.0f;  
  8.     if(result.y < 0.0f)  
  9.         result.y = 0.0f;  

这部分是分别对结果的r分量和g分量做饱和。那么这里,我们将引入一个OpenCL内建函数来取代这些代码。OpenCL内建函数一般是GPU指 令集直接支持的,因此一个调用基本上只需要1条指令就能完成。所以我们在写OpenCL时可以尽量使用内建函数。当然,有些数学内建函数为了效率会牺牲精 度,此时我们要自己判断取舍。

我们接下去再介绍一个OpenCL的内建函数——

  1. gentype clamp (gentype x, gentype minval,  
  2. gentype maxval) 

其语义是返回:fmin(fmax(x, minval), maxval),即对一个向量的每个分量取minval和maxval范围内的值。如果超出下界,那么取minval;如果超出上界,那么取maxval。

那么我再对OpenCL程序做次更新:

  1. // Render a square  
  2. // left-top:    red(1, 0, 0)  
  3. // left-bottom: green(0, 1, 0)  
  4. // right-top:   blue(0, 0, 1)  
  5. // right-bottom:black(0, 0, 0)  
  6.    
  7. __constant float4 left_top        = (float4)(1.0f, 0.0f, 0.0f, 0.0f);  
  8. __constant float4 left_bottom     = (float4)(0.0f, 1.0f, 0.0f, 0.0f);  
  9. __constant float4 right_top       = (float4)(0.0f, 0.0f, 1.0f, 0.0f);  
  10. __constant float4 right_bottom    = (float4)(0.0f, 0.0f, 0.0f, 0.0f);  
  11.    
  12. __constant float4 minValue = (float4)(0.0f, 0.0f, 0.0f, 0.0f);  
  13. __constant float4 maxValue = (float4)(1.0f, 1.0f, 1.0f, 0.0f);  
  14.    
  15. __kernel void ColorShading(  
  16.                     __global float4 output[256][256]  
  17.                     )  
  18. {  
  19.     int dimX = get_global_id(0);  
  20.     int dimY = get_global_id(1);  
  21.    
  22.     __local float4 deltaLeft = (left_top - left_bottom) / 255.0f;  
  23.     __local float4 deltaRight = (right_top - right_bottom) / 255.0f;  
  24.    
  25.     float4 left = left_bottom + deltaLeft * (float)dimY;  
  26.     float4 right = right_bottom + deltaRight * (float)dimY;  
  27.     float4 delta = (right - left) / 255.0f;  
  28.     float4 result = left + delta * (float)dimX;  
  29.    
  30.     // clamp  
  31.     result = clamp(result, minValue, maxValue);  
  32.    
  33.     output[dimY][dimX] = result + (float4)(0.0f, 0.0f, 0.0f, 1.0f);  

***,我们讨论一下本文章的主题——变量的地址空间限定符

OpenCL有四种地址空间限定符——全局的(__global或global),本地的(__local或local),常量的(__constant或constant),私有的(__private或private)。

全局地址空间用于引用从全局存储空间池所分配的存储器对象。该存储器对象可以声明为指向一个标量的指针,指向一个向量的指针或用户自定义的结构的指针。这允许内核程序读或写该缓存的任意位置。这里要注意的是,__global(或global)所修饰的是指针变量所引用的地址。因此:

  1. __global long4 g;    // Error  
  2. __global image2d_t texture;    // OK. A 2D texture image  
  3.  
  4. void kernelMain(__global int *p    // OK  
  5.                              )  
  6. {  
  7.     __global float4 a;    // Error  

本地地址空间用于描述需要被分配在本地存储空间的变量,并且能被一个工作组的所有工作项共享。该限定符可以被用于函数实参或在函数内声明的声明的变量。而用于修饰函数实参时,变量必须是指针类型。

常量地址空间用于描述分配在全局存储空间的变量,并且它们在内核程序中是只读的。这些全局只读变量可以被所有工作组的所有工作项共享。
该限定符在可以用于修饰内核函数的指针变量参数,或是在内核函数中修饰指针变量,或是作为全局变量。在本例中,我们把__constant修饰全局变量。
这里还要注意的是,由于__constant变量不能被写,因此,作为全局变量时,它必须声明后立即用常量初始化。这里的常量是指在编译时能计算出数值结果的表达式。

私有地址空间的范围很广。所有函数参数、函数内定义的局部变量都是私有的。因此我们往往可以省略掉__private关键字。

这里要注意的是OpenCL支持const关键字。这个关键字只在编译时进行检查,它所修饰的变量不能被修改,而对运行时该变量分配在哪个存储空间无关。

***对这些关键字与实际性能的影像做一下简单的介绍。当前流行的GPU等HPC流处理器采用分层的存储架构。全局存储空间非常大(就相当于我们所说的显存,目前最少也有128MB,俺的Mac Mini就是这个大小),但是带宽很昂贵,因此数据传输也是最慢的。

而第二层是局部存储空间,或称为本地存储空间。局部存储空间只能被一个工作组的所有工作项共享,并且每个工作组都有自己独立的一个局部存储空间。而每个局部存储空间比较小,一般在128KB左右吧。但是其数据传输性能要比全局存储器要大很多。

私有存储空间是每个工作项私有的。也就是说每个工作项有自己独立的私有存储空间。这在GPU存储架构中实际上就是寄存器文件。寄存器文件比如一共 128KB,那么对所有工作项进行划分的话,那么每个工作项能分到的存储空间就非常小。但是寄存器的访问是最快的,读或写一次只需要1个周期。

小结:苹果开发语言OpenCL 变量地址限定符详解的内容介绍完了,希望本文对你有所帮助!

推荐一篇相关的文章:苹果开发语言OpenCL 多线程同步 附源码

责任编辑:zhaolei 来源: CocoaChina
相关推荐

2011-07-20 10:50:19

苹果 OpenCL 多线程

2011-06-20 13:54:41

Qt 动态 切换

2018-05-13 16:00:22

主播APP视频

2020-02-12 14:03:29

网页设计网页游戏设计

2023-05-26 16:34:31

HBase数据模型

2011-09-13 17:03:16

Eclipse And

2021-10-29 08:19:54

JMeterJava java sample

2021-11-30 11:04:36

C++函数语言

2010-02-03 15:40:11

C++地址运算符

2013-06-17 15:41:09

Windows PhoWP开发JSON生成C#类

2011-08-05 10:01:23

Xcode Interface

2014-06-06 09:13:28

SwiftSwift编程

2014-07-09 09:13:16

Web效果Web特效

2010-09-17 09:34:29

开发工具Windows Pho

2024-05-15 08:54:04

C++类型限定符代码

2011-04-12 15:03:26

C语言编程位操作

2010-11-09 09:51:52

汇编语言

2011-04-15 10:40:23

web开发框架

2010-10-25 09:54:09

Windows Pho

2013-12-06 10:43:52

Android 4.4特性
点赞
收藏

51CTO技术栈公众号