忍者ブログ

Memeplexes

プログラミング、3DCGとその他いろいろについて

C#でOpenCL入門 (Cloo版) カーネル

カーネル

こちらも合わせてお読みください。

今回は「カーネル」について解説します。
カーネルというとよく意味が取れない方もいらっしゃるかも知れません。
OpenCLでカーネルというと、GPUで動かす関数のことです。

前回登場した「プログラム」との違いを言うと、カーネルは関数であるのに対し、プログラムはカーネルの塊である、といったところでしょうか。

今回することを3つにまとめるとこうなります:

  1. プログラムからカーネル生成
  2. カーネルに引数のセット
  3. カーネルの実行


使うメソッド

今回はすることは3つあります。
それらを行うメソッドを一つ一つ紹介します。

カーネルの生成

まずはカーネルの生成を行うメソッドから。
ComputeProgram.CreateKenerlメソッドです。

public ComputeKernel CreateKernel(string kernelName);

kernelNameは関数名です。

カーネルに引数をセット

次はカーネルに引数をセットするメソッドです。
ComputeKernel.SetMemoryArgumentメソッドです。

public void SetMemoryArgument(int index, ComputeMemory memObj);

indexは引数の位置です。例えば最初の引数なら0です。

カーネルの実行

最後はカーネルの実行を行うComputeCommandQueue.ExecuteTaskメソッドを紹介します。

public void ExecuteTask(ComputeKernel kernel, ICollection<ComputeEventBase> events);

kernelは実行するカーネルです。
eventsにはとりあえずnullを入れましょう。

サンプルコード

Program.cs

using Cloo;
using System.Linq;

class Program
{
    static void Main()
    {
        ComputePlatform platform = ComputePlatform.Platforms[0];
        ComputeDevice[] devices = platform
            .Devices
            .Where(d => d.Type == ComputeDeviceTypes.Gpu)
            .ToArray();
        ComputeContext context = new ComputeContext(
            devices,
            new ComputeContextPropertyList(platform),
            null, 
            System.IntPtr.Zero
            );
        ComputeProgram program = new ComputeProgram(
            context,
            System.IO.File.ReadAllText("myKernelProgram.cl")
            );
        program.Build(devices, null, null, System.IntPtr.Zero);
        ComputeKernel kernel = program.CreateKernel("myKernelFunction");
        const int bufferNumberCount = 3;
        ComputeBuffer<float> buffer = new ComputeBuffer<float>(
            context,
            ComputeMemoryFlags.ReadWrite,
            bufferNumberCount);
        kernel.SetMemoryArgument(0, buffer);

        ComputeCommandQueue commandQueue = new ComputeCommandQueue(
            context, 
            devices[0],
            ComputeCommandQueueFlags.None
            );
        commandQueue.ExecuteTask(kernel, null);
        float[] dataFromGpu = new float[bufferNumberCount];
        commandQueue.ReadFromBuffer(buffer, ref dataFromGpu, true, null);

        foreach (var number in dataFromGpu)
        {
            System.Console.WriteLine(number);
        }

        commandQueue.Dispose();
        buffer.Dispose();
        kernel.Dispose();
        program.Dispose();
        context.Dispose();
    }
}

myKernelProgram.cl

__kernel void myKernelFunction(__global float* numbers)
{
    numbers[0] = 3;
    numbers[1] = 4;
    numbers[2] = 5;
}

このプログラムは実行すると次のような結果になります:

3
4
5

拍手[1回]

PR