赞
踩
本文已同步至公众号,方便交流:
第三章 库函数
这一章,我们就写一写CM中提供了哪些库函数,来帮助我们实现内核的编程。
第一节 属性限定符
Cm设置有函数的限定符,便于这些函数能够被编译器编译成GPU可以运行的文件。在前面的博客中,《深度学习完全攻略。(连载二:GPU加速技术指南)》主要阐述了client端的编程,但是client端的编程是不适用这些限定符的。那么cm中都有哪些限定符呢。
(1)_GENX_MAIN_
此限定符主要用于限定一个GenX的核函数,而且这个核函数不能被其他函数调用
(2)_GENX_
此限定符用于限定一个用户定义的核函数,这个核函数可以被其他核函数调用。
第二节 用户定义核函数
用户定义的核函数的参数,可以是基本类型,也可以是vector/matrix,或者 SurfaceIndex/SamplerIndex/VmeIndex,或者vector_ref 和matrix_ref。但是输出类型不能是vector_ref/matrix_ref。
举个例子:
#include <cm/cm.h>
_GENX_ matrix<float, 2, 2> M; // global data declaration
_GENX_ matrix<float, 4, 4> plusone(matrix<float, 4, 4> m)
{
return m+1.0f;
}
_GENX_ float foo(matrix<float, 4, 4> m) // user defined GenX function
{
matrix<float, 4, 4> newm = plusone(m);
return cm_sum<float>(newm);
}
_GENX_ void bar_value(vector<float, 16> v, float f) // user defined GenX function
// using pass-by-value for "v"
{
matrix<float, 4, 4> m1;
m1 = v + f;
float s = foo(m1);
M = m1.select<2, 2, 2, 2>(0, 0) * s;
}
_GENX_ void bar_ref(vector<float, 16> v, float f, // user defined GenX function
matrix_ref<float, 2, 2> m) // using pass-by-reference for "m"
{
matrix<float, 4, 4> m1;
m1 = v + f;
float s = foo(m1);
m = m1.select<2, 2, 2, 2>(0, 0) * s;
}
_GENX_MAIN_ void kernel(SurfaceIndex inbuf, SurfaceIndex outbuf, // GenX kernel function
int x_pos, int y_pos)
{
matrix<float, 4, 4> m;
vector<float, 16> v;
read(inbuf, x_pos, y_pos, m);
v = m;
bar_value(v, 0.5f);
write(outbuf, x_pos, y_pos, M);
bar_ref(v, 1.0f, M);
write(outbuf, x_pos, y_pos + 2, M);
}
第三节 内置函数
Cm提供了一些内置的数学运算函数,便于直接调用。就像c语言中<math.h>函数库。这里大致列举一些。如果使用的话,还请查询手册。这些函数主要是以模板的形式存在。
(1)cm_abs<T>:求绝对值
参数1: matrix(_ref), vector(_ref) or scalar type
参数2: flags (default is 0; use SAT for saturation)
返回值: vector or scalar
(2)cm_add<T>:求和
参数1: matrix(_ref), vector(_ref) or scalar
参数2: matrix(_ref), vector(_ref) or scalar
参数3: flags (default is 0; use SAT for saturation)
返回值: vector or scalar
(3)cm_mul<T>:乘法
参数1: matrix(_ref), vector(_ref) or scalar
参数2: matrix(_ref), vector(_ref) or scalar
参数3: flags (default is 0; use SAT for saturation)
返回值: vector or scalar
限制:如果输入是int类型,输出不能位float类型,如果其中一个输入时int,则另外一个不能时float,如果其中一个输入时int或者uint类型,则SAT不能时1.
其他就不多说了。
第四节 数据接口
这一节主要介绍两个很重要的函数,read和write。Read和write的作用就是从内存中读数据和写数据。
(1)Media Block Read/Write
主要有两个函数,主要用于读和写整个surface:
void read (SurfaceIndex IND, int X, int Y, matrix_ref<TYPE, M, N> m);
IND:surface index(请参考我的另外一个系列的博客,连载二)
X:左上角x的坐标,以字节为单位,
Y:左上角y的坐标,实际上就是rows
M:是目标矩阵
void write(SurfaceIndex IND, int X, int Y, const matrix m);
IND:surface index(请参考我的另外一个系列的博客,连载二)
X:左上角x的坐标,以字节为单位,
Y:左上角y的坐标,实际上就是rows
M:是目标矩阵
(2)Media Block Read/Write for Planar Surface
这个函数主要用于读或写单个通道的数据
void read_plane(SurfaceIndex IND, CmSurfacePlaneIndex plane_index, int X, int Y, matrix_ref m);
IND:surface index
plane_index:the index to the plane.
X:左上角坐标
Y:左上角坐标就是rows
M:目标数据
void write_plane(SurfaceIndex IND, int plane_index, int X, int Y, const matrix m);
IND:surface index
plane_index:the index to the plane.
X:左上角坐标
Y:左上角坐标就是rows
M:目标数据
(3)OWord Block Read/Write
这两个函数主要是针对vector来定义的:
void read(SurfaceIndex IND, int offset, vector_ref v);
IND:surface index,
Offset:开始的坐标
V:目标数据
void write(SurfaceIndex IND, int offset, const vector v);
IND:surface index,
Offset:开始的坐标
V:目标数据
第五节 Sampler Interface
这里只介绍一个函数,是对surface进行采样。如下:
void sample16(matrix_ref<T, N, 16> m, ChannelMaskType channelMask, SurfaceIndex surfIndex, SamplerIndex sampIndex, vector<float, 16> u, vector<float, 16> v = 0, vector<float, 16> r = 0);
M:保存返回的结果。 N表示最小的返回的channel的个数。
channelMask:表是对哪些channel做采样。
surfIndex:surface index.
sampIndex:采样状态表的index
U:归一化的x坐标 the normalized x coordinates of the texels to be sampled.
V: (optional, default = 0) :归一化的y坐标
R: (optional, default = 0):归一化的z坐标,对于3D而言。
第六节 Media Walker Interface
这个是非常关键的一个参数。当输入的图像很大时,我们当然希望让GPU中的每个执行单元去分别计算每个块,那么怎么设置呢?这就是这一节的主要内容。
unsigned short get_thread_origin_x();
unsigned short get_thread_origin_y();
这两个函数就是返回所有需要GPU运行内核的初始坐标。比如说:一个图像按照16*16这样划分块。在不考虑块重叠的情况下,那么确定每个内核操作图像的起始坐标就是:
(get_thread_origin_x()*16, get_thread_origin_y()*16)
系统会自动帮你返回当前这个内核在图像某个块的起始位置,然后乘以块的长度即可,实际上就是stride。
这一章主要是作为一个引子,cm内核里面还有很多东西,本文就不一一列举了。
我相信很多同学已经发现了,既然client端和server端的代码都有了,那么这两者是怎么联系起来的呢,又是如何运行起来的呢?这些将在下一篇博客中介绍。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。