忍者ブログ

Memeplexes

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

C#でOpenCL入門 チュートリアルその4 コマンドキュー

 
今回はコマンドキューの生成と破棄を行います。
残念ながら前回に引き続き今回もサンプルプログラムは画面に何も出力しません。

コマンドキューとは、GPUに対する操作をカプセル化したオブジェクトです。
GPU内のバッファにデータを書き込んだり読み込んだり、データに対して計算を行ったり。
このような操作のほとんどすべてが非同期の関数です。
(今回は生成と破棄の2つしかしませんが)



コマンドキューの生成

コマンドキューの生成にはclCreateCommandQueue関数を使います。
この関数はコンテキストとデバイスから、コマンドキューを生成します。
参考

cl_command_queue clCreateCommandQueue(
    cl_context context,
    cl_device_id device,
    cl_command_queue_properties properties,
    cl_int *errcode_ret
)

contextはコマンドキューに結び付けられるコンテキスト。
deviceはコマンドキューに結び付けられるデバイス。
propertiesは生成するコマンドキューの属性のリストです。この値はビットフィールドで、以下の2つを組み合わせます。

コマンドキュープロパティ 解説
CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE コマンドキュー中のコマンド実行をout-of-order(並列実行)にします。そうでない場合はin-orderで、これはコマンド実行の順番を入れ替え無いモードです。
CL_QUEUE_PROFILING_ENABLE コマンドキュー内のcommandのプロファイリングを有効にします。詳細はclGetEventProfilingInfo関数を見てください。

errcode_retはこの関数のエラーコードです。NULLでも構いません。

エラーコードには以下の値があります。
名前 解説
CL_SUCCESS 0 関数は成功しました。
CL_INVALID_CONTEXT -34 contextが無効です。
CL_INVALID_DEVICE -33 deviceが無効です。あるいはdeviceがcontextに結び付けられていません。
CL_INVALID_VALUE -30 propertiesが無効です。
CL_INVALID_QUEUE_PROPERTIES -35 propertiesは有効ですが、デバイスにサポートされていません。
CL_OUT_OF_RESOURCES -5 デバイスがリソースを確保するのに失敗しました。
CL_OUT_OF_HOST_MEMORY -6 メモリが足りません。



コマンドキューの破棄

生成したコマンドキューは、使い終わったら最後に破棄しなければいけません。
破棄するにはclReleaseCommanndQueue関数を使います。
参考

例によってこれも正確には破棄する関数ではなく参照カウントを減らす関数です。
参照カウントが0になったときコマンドキューは破棄されます。
C#から使う場合は実質的に破棄する関数と同じですね。

cl_int clReleaseCommandQueue(
    cl_command_queue command_queue
)

command_queueは破棄するコマンドキューです。

名前 解説
CL_SUCCESS 0 関数は成功しました。
CL_INVALID_COMMAND_QUEUE -36 command_queueが無効です。
CL_OUT_OF_RESOURCES -5 デバイスがリソースを確保できませんでした。
CL_OUT_OF_HOST_MEMORY -6 メモリが足りません。


コマンドキューの生成と破棄

以上の2つの関数を使ったプログラムは次のようになります。

Program.cs
using System;
 
class Program
{
    static void Main()
    {
        IntPtr device = getDevices(getPlatforms()[0], DeviceType.Default)[0];
        Context context = new Context(device);
        CommandQueue commandQueue = new CommandQueue(context, device);
    }
 
    private static IntPtr[] getDevices(IntPtr platform, DeviceType deviceType)
    {
        int deviceCount;
        OpenCLFunctions.clGetDeviceIDs(platform, deviceType, 0, null, out deviceCount);
       
        IntPtr[] result = new IntPtr[deviceCount];
        OpenCLFunctions.clGetDeviceIDs(platform, deviceType, deviceCount, result, out deviceCount);
        return result;
    }
 
 
    private static IntPtr[] getPlatforms()
    {
        int platformCount;
        OpenCLFunctions.clGetPlatformIDs(0, null, out platformCount);
 
        IntPtr[] result = new IntPtr[platformCount];
        OpenCLFunctions.clGetPlatformIDs(platformCount, result, out platformCount);
        return result;
    }
}

OpenCLWrappers.cs
using System;

class Context
{
    public IntPtr InternalPointer { get; private set; }

    public Context(params IntPtr[] devices)
    {
        int error;
        InternalPointer = OpenCLFunctions.clCreateContext(
            null,
            devices.Length,
            devices,
            null,
            IntPtr.Zero,
            out error
            );
    }

    ~Context()
    {
        OpenCLFunctions.clReleaseContext(InternalPointer);
    }
}

class CommandQueue
{
    public IntPtr InternalPointer { get; private set; }

    public CommandQueue(Context context, IntPtr device)
    {
        int error;
        InternalPointer = OpenCLFunctions.clCreateCommandQueue(
            context.InternalPointer,
            device,
            0,
            out error
            );
    }

    ~CommandQueue()
    {
        OpenCLFunctions.clReleaseCommandQueue(InternalPointer);
    }
}


OpenCLFunctions.cs
using System;
using System.Runtime.InteropServices;

static class OpenCLFunctions
{
    [DllImport("OpenCL.dll")]
    public static extern int clGetPlatformIDs(int entryCount, IntPtr[] platforms, out int platformCount);

    [DllImport("OpenCL.dll")]
    public static extern int clGetDeviceIDs(
        IntPtr platform,
        DeviceType deviceType,
        int entryCount,
        IntPtr[] devices,
        out int deviceCount
        );

    [DllImport("OpenCL.dll")]
    public static extern IntPtr clCreateContext(
        IntPtr[] properties, 
        int deviceCount,
        IntPtr[] devices,
        NotifyCallback pfnNotify,
        IntPtr userData,
        out int errorCode
        );

    [DllImport("OpenCL.dll")]
    public static extern int clReleaseContext(IntPtr context);

    [DllImport("OpenCL.dll")]
    public static extern IntPtr clCreateCommandQueue(
        IntPtr context,
        IntPtr device,
        long properties,
        out int errorCodeReturn
        );

    [DllImport("OpenCL.dll")]
    public static extern int clReleaseCommandQueue(IntPtr commandQueue);
}

delegate void NotifyCallback(string errorInfo, IntPtr privateInfoSize, int cb, IntPtr userData);

enum DeviceType:long
{
    Default = (1 << 0),
    Cpu = (1 << 1),
    Gpu = (1 << 2),
    Accelerator = (1 << 3),
    All = 0xFFFFFFFF
}


このプログラムはコンテキストとデバイスから、コマンドキューを生成します。
ここでは単に生成するだけで何もしません。
画面には何も文字が出力されないでしょう。

今後、このコマンドキューによって、デバイスに命令します。
たとえばデバイスのバッファに値を書き込め、バッファから値を読み出せ、値を使って並列計算せよ、といった具合です。















拍手[1回]

PR