**提示**：此条目的主题不是**OpenGL**。 

**OpenCL**（**Open** **C**omputing **L**anguage，开放计算语言）是一个为异构平台编写程序的框架，此异构平台可由CPU、GPU、DSP、FPGA或其他类型的处理器與硬體加速器所组成。OpenCL由一门用于编写kernels（在OpenCL设备上运行的函数）的语言（基于C99）和一组用于定义并控制平台的API组成。OpenCL提供了基于任务分割和数据分割的并行计算机制。

OpenCL类似于另外两个开放的工业标准OpenGL和OpenAL，这两个标准分别用于三维图形和计算机音频方面。OpenCL擴充了GPU圖形生成之外的能力。OpenCL由非盈利性技术组织Khronos Group掌管。

历史
--

OpenCL最初由苹果公司开发，拥有其商标权，并在与AMD，IBM，Intel和NVIDIA技术团队的合作之下初步完善。随后，苹果将这一草案提交至Khronos Group。

2008年6月16日，Khronos的通用计算工作小组成立。5个月后的2008年11月18日，该工作组完成了OpenCL 1.0规范的技术细节。该技术规范在由Khronos成员进行审查之后，于2008年12月8日公开发表。2010年6月14日，OpenCL 1.1发布。

範例
--

### 快速傅立葉變換

一個快速傅立葉變換的式子：

```
 // create a compute context with GPU device
 context = clCreateContextFromType(NULL, CL\_DEVICE\_TYPE\_GPU, NULL, NULL, NULL);

 // create a command queue
 queue = clCreateCommandQueue(context, NULL, 0, NULL);

 // allocate the buffer memory objects
 memobjs[0] = clCreateBuffer(context, CL\_MEM\_READ\_ONLY | CL\_MEM\_COPY\_HOST\_PTR, sizeof(float)\*2\*num\_entries, srcA, NULL);
 memobjs[1] = clCreateBuffer(context, CL\_MEM\_READ\_WRITE, sizeof(float)\*2\*num\_entries, NULL, NULL);

 // create the compute program
 program = clCreateProgramWithSource(context, 1, &fft1D\_1024\_kernel\_src, NULL, NULL);

 // build the compute program executable
 clBuildProgram(program, 0, NULL, NULL, NULL, NULL);

 // create the compute kernel
 kernel = clCreateKernel(program, "fft1D\_1024", NULL);

 // set the args values
 clSetKernelArg(kernel, 0, sizeof(cl\_mem),(void \*)&memobjs[0]);
 clSetKernelArg(kernel, 1, sizeof(cl\_mem),(void \*)&memobjs[1]);
 clSetKernelArg(kernel, 2, sizeof(float)\*(local\_work\_size[0]+1)\*16, NULL);
 clSetKernelArg(kernel, 3, sizeof(float)\*(local\_work\_size[0]+1)\*16, NULL);

 // create N-D range object with work-item dimensions and execute kernel
 global\_work\_size[0] = num\_entries;
 local\_work\_size[0] = 64;
 clEnqueueNDRangeKernel(queue, kernel, 1, NULL, global\_work\_size, local\_work\_size, 0, NULL, NULL);

```

真正的運算：（基於Fitting FFT onto the G80 Architecture（页面存档备份，存于））

```
 // This kernel computes FFT of length 1024. The 1024 length FFT is decomposed into
 // calls to a radix 16 function, another radix 16 function and then a radix 4 function

 \_\_kernel void fft1D\_1024(\_\_global float2 \*in, \_\_global float2 \*out,
 \_\_local float \*sMemx, \_\_local float \*sMemy){
 int tid = get\_local\_id(0);
 int blockIdx = get\_group\_id(0) \* 1024 + tid;
 float2 data[16];

 // starting index of data to/from global memory
 in = in + blockIdx; out = out + blockIdx;

 globalLoads(data, in, 64); // coalesced global reads
 fftRadix16Pass(data); // in-place radix-16 pass
 twiddleFactorMul(data, tid, 1024, 0);

 // local shuffle using local memory
 localShuffle(data, sMemx, sMemy, tid, (((tid & 15)\* 65) +(tid >> 4)));
 fftRadix16Pass(data); // in-place radix-16 pass
 twiddleFactorMul(data, tid, 64, 4); // twiddle factor multiplication

 localShuffle(data, sMemx, sMemy, tid, (((tid >> 4)\* 64) +(tid & 15)));

 // four radix-4 function calls
 fftRadix4Pass(data); // radix-4 function number 1
 fftRadix4Pass(data + 4); // radix-4 function number 2
 fftRadix4Pass(data + 8); // radix-4 function number 3
 fftRadix4Pass(data + 12); // radix-4 function number 4

 // coalesced global writes
 globalStores(data, out, 64);
 }

```

Apple的網站上可以發現傅立葉變換的例子

### 平行合併排序法

使用 Python 3.x 搭配 PyOpenCL 與 NumPy

```
import io
import random
import numpy as np
import pyopencl as cl

def dump\_step(data, chunk\_size):
 """顯示排序過程"""
    msg = io.StringIO('')
    div = io.StringIO('')
    for idx, item in enumerate(data):
        if idx % chunk\_size == 0:
            if idx > 0:
                msg.write(' ||')
                div.write(' ')
            div.write(' --')
        else:
            msg.write(' ')
            div.write('------')
        msg.write(' {:2d}'.format(item))

    out = msg.getvalue()
    if chunk\_size == 1: print(' ' + '-' \* (len(out) - 1))
    print(out)
    print(div.getvalue())
    msg.close()
    div.close()

def cl\_merge\_sort\_sbs(data\_in):
 """平行合併排序"""
    # OpenCL kernel 函數程式碼
    CL\_CODE = '''
 kernel void merge(int chunk\_size, int size, global long\* data, global long\* buff) {
 // 取得分組編號
 const int gid = get\_global\_id(0);

 // 根據分組編號計算責任範圍
 const int offset = gid \* chunk\_size;
 const int real\_size = min(offset + chunk\_size, size) - offset;
 global long\* data\_part = data + offset;
 global long\* buff\_part = buff + offset;

 // 設定合併前的初始狀態
 int r\_beg = chunk\_size >> 1;
 int b\_ptr = 0;
 int l\_ptr = 0;
 int r\_ptr = r\_beg;

 // 進行合併
 while (b\_ptr < real\_size) {
 if (r\_ptr >= real\_size) {
 // 若右側沒有資料，取左側資料堆入緩衝區
 buff\_part[b\_ptr] = data\_part[l\_ptr++];
 } else if (l\_ptr == r\_beg) {
 // 若左側沒有資料，取右側資料堆入緩衝區
 buff\_part[b\_ptr] = data\_part[r\_ptr++];
 } else {
 // 若兩側都有資料，取較小資料堆入緩衝區
 if (data\_part[l\_ptr] < data\_part[r\_ptr]) {
 buff\_part[b\_ptr] = data\_part[l\_ptr++];
 } else {
 buff\_part[b\_ptr] = data\_part[r\_ptr++];
 }
 }
 b\_ptr++;
 }
 }
 '''

    # 配置計算資源，編譯 OpenCL 程式
    ctx = cl.Context(dev\_type=cl.device\_type.GPU)
    prg = cl.Program(ctx, CL\_CODE).build()
    queue = cl.CommandQueue(ctx)
    mf = cl.mem\_flags

    # 資料轉換成 numpy 形式以利轉換為 OpenCL Buffer
    data\_np = np.int64(data\_in)
    buff\_np = np.empty\_like(data\_np)

    # 建立緩衝區，並且複製數值到緩衝區
    data = cl.Buffer(ctx, mf.READ\_WRITE | mf.COPY\_HOST\_PTR, hostbuf=data\_np)
    buff = cl.Buffer(ctx, mf.READ\_WRITE | mf.COPY\_HOST\_PTR, hostbuf=buff\_np)

    # 設定合併前初始狀態
    data\_len = np.int32(len(data\_np))
    chunk\_size = np.int32(1)

    dump\_step(data\_np, chunk\_size)
    while chunk\_size < data\_len:
        # 更新分組大小，每一回合變兩倍
        chunk\_size <<= 1
        # 換算平行作業組數 
        group\_size = ((data\_len - 1) // chunk\_size) + 1
        # 進行分組合併作業
        prg.merge(queue, (group\_size,), (1,), chunk\_size, data\_len, data, buff)
        # 將合併結果作為下一回合的原始資料
        temp = data
        data = buff
        buff = temp
        # 顯示此回合狀態
        cl.enqueue\_copy(queue, data\_np, data)
        dump\_step(data\_np, chunk\_size)

    queue.finish()
    data.release()
    buff.release()

def main():
    n = random.randint(5, 16)
    data = []
    for i in range(n):
        data.append(random.randint(1, 99))
    cl\_merge\_sort\_sbs(data)

if \_\_name\_\_ == '\_\_main\_\_':
    main()

```

執行結果：

```
 --------------------------------------------------------------------------------------
 85 || 41 || 64 || 40 || 90 || 29 || 38 || 41 || 64 || 17 || 20 || 41 || 16 || 65 || 83
 --    --    --    --    --    --    --    --    --    --    --    --    --    --    --
 41    85 || 40    64 || 29    90 || 38    41 || 17    64 || 20    41 || 16    65 || 83
 --------    --------    --------    --------    --------    --------    --------    --
 40    41    64    85 || 29    38    41    90 || 17    20    41    64 || 16    65    83
 --------------------    --------------------    --------------------    --------------
 29    38    40    41    41    64    85    90 || 16    17    20    41    64    65    83
 --------------------------------------------    --------------------------------------
 16    17    20    29    38    40    41    41    41    64    64    65    83    85    90
 --------------------------------------------------------------------------------------

```

參考文獻
----

1. ↑   (新闻稿). Khronos Group. 2008-06-16  [2008-06-18]. （原始内容存档于2008-06-20）.
2. ↑ . MacWorld. 2008-11-20  [2009-06-12]. （原始内容存档于2009-02-18）.
3. ↑   (新闻稿). Khronos Group. 2008-12-08  [2009-06-12]. （原始内容存档于2010-07-13）.
4. ↑   (新闻稿). Khronos Group. 2010-06-14  [2010-10-13]. （原始内容存档于2010-09-23）.
5. ↑   (PDF). SIGGRAPH2008. 2008-08-14  [2008-08-14]. （原始内容 (PDF)存档于2012-03-19）.
6. ↑   (PDF). Vasily Volkov and Brian Kazian, UC Berkeley CS258 project report. May 2008  [2008-11-14]. （原始内容存档 (PDF)于2012-03-19）.
7. ↑  .
. Apple. 16 Nov 2009  [2009-12-07]. （原始内容存档于2009-11-30）.

外部連結
----

* 支援OpenCL的產品（页面存档备份，存于）
* 开源GPU社区（简体中文）

参见
--

* 信息技术主题

* GPGPU
* CUDA
* DirectCompute
* C++ AMP
* 比特币的挖礦


|  |  |  |  |  |  |  |  |
| --- | --- | --- | --- | --- | --- | --- | --- |
| 

| * 
* 论
* 编
科納斯組織制定標準 |
| --- |
|  |
| 活跃 | 
* OpenCL
	+ SYCL
* OpenGL
	+ OpenGL ES
		- WebGL
	+ OpenGL SC
	+ EGL（英语：）
* OpenVX
* OpenVG
* OpenXR
* SPIR（英语：）
* Vulkan
* glTF

 |
|  |
| 不活跃 | 
* COLLADA（英语：）
* OpenKCam
* OpenKODE（英语：）
* OpenMAX
* OpenML
* OpenSL ES（英语：）
* OpenWF（英语：）
* StreamInput
* WebCL（英语：）

 |

 |