使用 OpenCL.Net 进行 C# GPU 并行编程

初探 C# GPU 通用计算技术 中,我使用 Accelerator 编写了一个简单的 GPU 计算程序。也简单看了一些 Brahma 的代码,从它的 SVN 最新代码看,Brahma 要转移到使用 OpenCL.Net 作为底层了,于是也去网上搜索了一下,发现了 OpenCL.Net 和另一个相关的项目 OpenCLTemplate

 

看了一些它的代码,颇像 DirectCompute 的风格,其 GPU 程序是标准 C 代码,所以编写和阅读也容易一些,而 Host 程序是 C# 的,把 GPU 代码字符串传给编译器进行编译,然后就可以在 C# 对它进行调用,并且取回结果了。

 

安装了 ati-stream-sdk-v2.1-vista-win7-64,折腾了一下它的例子程序 FirstOpenCLProgram,运行时会抛出一个 InvalidContext 的异常,到它的论坛去问,版主建议我安装 ati 最新 driver 先,虽然觉得本本刚买没几天,应该驱动比较新,还是去安装了最新的驱动,果然不再报异常了。只是如果直接引用 OpenCLTemplate 下的 OpenCL.NET.dll 和 OpenCLTemplate.dll 的话,在初始化的时候会报空指针;而引用 FirstOpenCLProgram 下的这两个 dll 的话,则初始化时会闪现好几个控制台窗口,但是后续都是正常的。

 

既然正常了,就还是以上次那个程序,来看看 OpenCL 的方式,会不会有更大的速度提升。

 

使用 OpenCL 的程序代码如下:

 

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
private const int GridSize = 1024 ;
private readonly float [] _map;

private const string Code = @"
__kernel void Test(__global float* v1)
{
int i = get_global_id(0);
float p = v1[i];
v1[i] = p * p * p / 4 + 194;
}
" ;
private readonly CLCalc.Program.Kernel _test;
private readonly CLCalc.Program.Variable _vmap;
private readonly CLCalc.Program.Variable[] _args;
private readonly int [] _workers;

public Form1()
{
InitializeComponent();

_map
= new float [GridSize * GridSize];
for ( int y = 0 ; y < GridSize; y ++ )
{
for ( int x = 0 ; x < GridSize; x ++ )
{
_map[x
* GridSize + y] = x * y;
}
}

CLCalc.InitCL();
CLCalc.Program.Compile(
new [] { Code });
_test
= new CLCalc.Program.Kernel( " Test " );
_vmap
= new CLCalc.Program.Variable(_map);
_args
= new [] { _vmap };
_workers
= new [] { GridSize * GridSize };

Render();
}

private void Start_Click( object sender, EventArgs e)
{
var stopwatch
= new Stopwatch();
stopwatch.Start();

_test.Execute(_args, _workers);
_vmap.ReadFromDeviceTo(_map);

var time
= stopwatch.ElapsedMilliseconds;
this .Text = time.ToString();
Render();
}

private void Render()
{
var workingBitmap
= new Bitmap(pictureBox1.Width, pictureBox1.Height);

for ( int y = 0 ; y < pictureBox1.Height; y ++ )
{
for ( int x = 0 ; x < pictureBox1.Width; x ++ )
{
workingBitmap.SetPixel(x, y, Color.FromArgb(
- 0x1000000 | ( int )_map[x * 2 * GridSize + y * 2 ]));
}
}
pictureBox1.Image
= workingBitmap;
}

 

 

运行程序,点击 4 次按钮,显示图形和前两个程序相同,说明程序运算正常,4 次时间为:8、8、7、8。比使用 Accelerator 的程序速度也快了 5 倍以上。

 

因为是标准 C 程序,所以我们的自由度很大,我也在 OpenCL 下实现了一下 Life 游戏,C# 部分的代码就不贴了,GPU 代码如下:

 

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
#define width 512
#define length 262144

int GetValue(__global int * v, int index)
{
if (index < 0 || index >= length)
{
return 0 ;
}
return v[index] == 0 ? 0 : 1 ;
};

__kernel
void Test(__global int * v)
{
int i = get_global_id( 0 );
int topLeft = GetValue(v, i - width - 1 );
int top = GetValue(v, i - width);
int topRight = GetValue(v, i - width + 1 );
int left = GetValue(v, i - 1 );
int current = GetValue(v, i);
int right = GetValue(v, i + 1 );
int bottomLeft = GetValue(v, i + width - 1 );
int bottom = GetValue(v, i + width);
int bottomRight = GetValue(v, i + width + 1 );
int liveNeighbors = topLeft + top + topRight + left + right + bottomLeft + bottom + bottomRight;
if (current > 0 )
{
v[i]
= ((liveNeighbors < 2 ) || (liveNeighbors > 3 )) ? 0 : 255 ;
}
else
{
v[i]
= (liveNeighbors == 3 ) ? 255 : 0 ;
}
};

 

 

很长时间不用 C,有很多像函数声明顺序等规则都忘了,好的一点是 OpenCL.Net 中还提供了 OpenCLCodeChecker,用来进行代码检测,同时也在侧边栏里提供了语言帮助,只是它的检测稍嫌弱智,代码稍微复杂,提示的错误位置很奇怪,有时候告知编译出错,Log 里面却没有任何错误信息。不过总体来说,帮助还是很大就是了。

 

这个 Life 程序,有一个小 Bug,在于没有判断超出右边界的代码,所以如果左边有生物,右边虽然原来没有生物,也会无中生有 :)

 

总的来说,用 OpenCL.Net 编程,感觉还是很愉快的。

转载于:https://www.cnblogs.com/lephone/archive/2010/05/24/csharp_gpgpu_with_opencl.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值