OpenCL

OpenCL（Open Computing Language，中譯：開放計算語言），是一個為異構平臺編寫程序的框架，此異構平臺可由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發佈。2011年11月15日，OpenCL 1.2發佈。2013年11月18日，OpenCL 2.0發佈。2015年11月16日，OpenCL 2.1發佈。2017年5月16日，OpenCL 2.2發佈。

**路線圖**
在2017年5月發行OpenCL 2.2之時，Khronos Group宣佈OpenCL將盡可能的匯合於Vulkan，以確使OpenCL軟件在這兩種API上靈活部署。這已經由Adobe的Premiere Rush展示出來，它使用clspv開源編譯器，編譯了大量OpenCL C內核代碼，使其在部署於Android的Vulkan運行時系統上運行。
OpenCL擁有獨立於Vulkan的前瞻性路線圖，即曾意圖在2020年發行的“OpenCL Next”，它可以集成於擴展諸如Vulkan/OpenCL互操作、Scratch-Pad內存管理、擴展子組、SPIR-V 1.4攝入和SPIR-V擴展調試信息；OpenCL還在考慮類似Vulkan的裝載器和分層以及“靈活配置”，以便在多種加速類型上靈活部署。

**OpenCL 3.0**
在2020年8月30日，發行了最終的OpenCL 3.0規範。OpenCL 1.2功能已經成為強制性基準，而所有OpenCL 2.x和OpenCL 3.0特徵變為可選項。這個規範保留了“OpenCL C”語言，並廢棄了版本2.1介入的“OpenCL C++”內核語言，將其替代為“C++ for OpenCL”語言，它基於了Clang/LLVM編譯器，實現了C++17的子集和SPIR-V中間代碼。C++ for OpenCL版本1.0的官方文檔在2020年12月發表，它後向兼容於OpenCL C 2.0。
在IWOCL 21上發佈的OpenCL 3.0.7，提出了C++ for OpenCL的新版本和一些Khronos openCL擴展。在2021年12月，發行了C++ for OpenCL版本2021，它完全兼容於OpenCL 3.0標準。NVIDIA密切協作於Khronos OpenCL工作組，通過信號量和內存共享改進了Vulkan互操作。小更新3.0.14版本，具有缺陷修正和針對多設備的一個新擴展。

**範例**

**快速傅立葉變換**
一個快速傅立葉變換的式子：
// 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
memobjs0 = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(float)*2*num_entries, srcA, NULL);
memobjs1 = 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 *)&memobjs0);
clSetKernelArg(kernel, 1, sizeof(cl_mem),(void *)&memobjs1);
clSetKernelArg(kernel, 2, sizeof(float)*(local_work_size0+1)*16, NULL);
clSetKernelArg(kernel, 3, sizeof(float)*(local_work_size0+1)*16, NULL);
// create N-D range object with work-item dimensions and execute kernel
global_work_size0 = num_entries;
local_work_size0 = 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 data16;
// 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) {
// 若右側沒有資料，取左側資料堆入緩衝區
buff_partb_ptr = data_partl_ptr++;
} else if (l_ptr == r_beg) {
// 若左側沒有資料，取右側資料堆入緩衝區
buff_partb_ptr = data_partr_ptr++;
} else {
// 若兩側都有資料，取較小資料堆入緩衝區
if (data_partl_ptr 
執行結果：
--------------------------------------------------------------------------------------
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
--------------------------------------------------------------------------------------

**參見**
 GPGPU- CUDA- DirectCompute- C++ AMP

**參考文獻**

**外部連結**
  支援OpenCL的產品date=20180629130825 -  開源GPU社區