2009-09-03 21:01:11 +02:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using OpenTK.Compute.CL10;
|
|
|
|
|
|
|
|
|
|
namespace Examples
|
|
|
|
|
{
|
|
|
|
|
using cl_context = IntPtr;
|
|
|
|
|
using cl_device_id = IntPtr;
|
|
|
|
|
using cl_command_queue = IntPtr;
|
|
|
|
|
using cl_program = IntPtr;
|
|
|
|
|
using cl_kernel = IntPtr;
|
|
|
|
|
using cl_mem = IntPtr;
|
|
|
|
|
|
|
|
|
|
[Example("Vector Addition", ExampleCategory.OpenCL, "1.0")]
|
2009-10-19 19:45:50 +02:00
|
|
|
|
class VectorAdd
|
2009-09-03 21:01:11 +02:00
|
|
|
|
{
|
|
|
|
|
public static void Main()
|
|
|
|
|
{
|
2009-10-28 15:54:20 +01:00
|
|
|
|
const int cnBlockSize = 4;
|
2009-09-03 21:01:11 +02:00
|
|
|
|
const int cnBlocks = 3;
|
|
|
|
|
IntPtr cnDimension = new IntPtr(cnBlocks * cnBlockSize);
|
|
|
|
|
string sProgramSource = @"
|
|
|
|
|
__kernel void
|
|
|
|
|
vectorAdd(__global const float * a,
|
|
|
|
|
__global const float * b,
|
|
|
|
|
__global float * c)
|
|
|
|
|
{
|
|
|
|
|
// Vector element index
|
|
|
|
|
int nIndex = get_global_id(0);
|
|
|
|
|
c[nIndex] = a[nIndex] + b[nIndex];
|
|
|
|
|
}
|
|
|
|
|
";
|
|
|
|
|
|
|
|
|
|
ErrorCode error;
|
|
|
|
|
|
|
|
|
|
// create OpenCL device & context
|
|
|
|
|
cl_context hContext;
|
|
|
|
|
unsafe { hContext = CL.CreateContextFromType((ContextProperties*)null, DeviceTypeFlags.DeviceTypeDefault, IntPtr.Zero, IntPtr.Zero, &error); }
|
|
|
|
|
|
|
|
|
|
// query all devices available to the context
|
|
|
|
|
IntPtr nContextDescriptorSize;
|
|
|
|
|
CL.GetContextInfo(hContext, ContextInfo.ContextDevices, IntPtr.Zero, IntPtr.Zero, out nContextDescriptorSize);
|
|
|
|
|
cl_device_id[] aDevices = new cl_device_id[nContextDescriptorSize.ToInt32()];
|
|
|
|
|
unsafe
|
|
|
|
|
{
|
|
|
|
|
fixed (cl_device_id* ptr = aDevices)
|
|
|
|
|
{
|
|
|
|
|
IntPtr ret;
|
|
|
|
|
CL.GetContextInfo(hContext, ContextInfo.ContextDevices, nContextDescriptorSize, new IntPtr(ptr), out ret);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// create a command queue for first device the context reported
|
|
|
|
|
cl_command_queue hCmdQueue = CL.CreateCommandQueue(hContext, aDevices[0], (CommandQueueFlags)0, out error);
|
|
|
|
|
// create & compile program
|
|
|
|
|
cl_program hProgram;
|
|
|
|
|
unsafe { hProgram = CL.CreateProgramWithSource(hContext, 1, new string[] { sProgramSource }, null, &error); }
|
|
|
|
|
CL.BuildProgram(hProgram, 0, (IntPtr[])null, null, IntPtr.Zero, IntPtr.Zero);
|
|
|
|
|
|
|
|
|
|
// create kernel
|
|
|
|
|
cl_kernel hKernel = CL.CreateKernel(hProgram, "vectorAdd", out error);
|
|
|
|
|
// allocate host vectors
|
|
|
|
|
float[] A = new float[cnDimension.ToInt32()];
|
|
|
|
|
float[] B = new float[cnDimension.ToInt32()];
|
|
|
|
|
float[] C = new float[cnDimension.ToInt32()];
|
|
|
|
|
// initialize host memory
|
2009-10-28 15:54:20 +01:00
|
|
|
|
Random rand = new Random();
|
|
|
|
|
for (int i = 0; i < A.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
A[i] = rand.Next() % 256;
|
|
|
|
|
B[i] = rand.Next() % 256;
|
|
|
|
|
}
|
2009-09-03 21:01:11 +02:00
|
|
|
|
|
|
|
|
|
// allocate device memory
|
|
|
|
|
unsafe
|
|
|
|
|
{
|
|
|
|
|
fixed (float* pA = A)
|
|
|
|
|
fixed (float* pB = B)
|
|
|
|
|
fixed (float* pC = C)
|
|
|
|
|
{
|
|
|
|
|
cl_mem hDeviceMemA, hDeviceMemB, hDeviceMemC;
|
|
|
|
|
hDeviceMemA = CL.CreateBuffer(hContext,
|
|
|
|
|
MemFlags.MemReadOnly | MemFlags.MemCopyHostPtr,
|
|
|
|
|
new IntPtr(cnDimension.ToInt32() * sizeof(float)),
|
|
|
|
|
new IntPtr(pA),
|
|
|
|
|
out error);
|
|
|
|
|
hDeviceMemB = CL.CreateBuffer(hContext,
|
|
|
|
|
MemFlags.MemReadOnly | MemFlags.MemCopyHostPtr,
|
|
|
|
|
new IntPtr(cnDimension.ToInt32() * sizeof(float)),
|
|
|
|
|
new IntPtr(pA),
|
|
|
|
|
out error);
|
|
|
|
|
hDeviceMemC = CL.CreateBuffer(hContext,
|
|
|
|
|
MemFlags.MemWriteOnly,
|
|
|
|
|
new IntPtr(cnDimension.ToInt32() * sizeof(float)),
|
|
|
|
|
IntPtr.Zero,
|
|
|
|
|
out error);
|
|
|
|
|
|
|
|
|
|
// setup parameter values
|
|
|
|
|
CL.SetKernelArg(hKernel, 0, new IntPtr(sizeof(cl_mem)), new IntPtr(&hDeviceMemA));
|
|
|
|
|
CL.SetKernelArg(hKernel, 1, new IntPtr(sizeof(cl_mem)), new IntPtr(&hDeviceMemB));
|
|
|
|
|
CL.SetKernelArg(hKernel, 2, new IntPtr(sizeof(cl_mem)), new IntPtr(&hDeviceMemC));
|
|
|
|
|
|
2009-10-19 19:45:50 +02:00
|
|
|
|
// write data from host to device
|
|
|
|
|
CL.EnqueueWriteBuffer(hCmdQueue, hDeviceMemA, true, IntPtr.Zero,
|
|
|
|
|
new IntPtr(cnDimension.ToInt32() * sizeof(float)),
|
|
|
|
|
new IntPtr(pA), 0, null, (IntPtr[])null);
|
|
|
|
|
CL.EnqueueWriteBuffer(hCmdQueue, hDeviceMemB, true, IntPtr.Zero,
|
|
|
|
|
new IntPtr(cnDimension.ToInt32() * sizeof(float)),
|
|
|
|
|
new IntPtr(pB), 0, null, (IntPtr[])null);
|
|
|
|
|
|
2009-09-03 21:01:11 +02:00
|
|
|
|
// execute kernel
|
2009-10-28 15:54:20 +01:00
|
|
|
|
error = (ErrorCode)CL.EnqueueNDRangeKernel(hCmdQueue, hKernel, 1, null, &cnDimension, null, 0, null, null);
|
|
|
|
|
if (error != ErrorCode.Success)
|
|
|
|
|
throw new Exception(error.ToString());
|
|
|
|
|
|
2009-09-03 21:01:11 +02:00
|
|
|
|
// copy results from device back to host
|
2009-10-28 15:54:20 +01:00
|
|
|
|
IntPtr event_handle = IntPtr.Zero;
|
|
|
|
|
error = (ErrorCode)CL.EnqueueReadBuffer(hCmdQueue, hDeviceMemC, true, IntPtr.Zero,
|
2009-10-19 19:45:50 +02:00
|
|
|
|
new IntPtr(cnDimension.ToInt32() * sizeof(float)),
|
|
|
|
|
new IntPtr(pC), 0, null, (IntPtr[])null);
|
2009-10-28 15:54:20 +01:00
|
|
|
|
if (error != ErrorCode.Success)
|
|
|
|
|
throw new Exception(error.ToString());
|
|
|
|
|
|
|
|
|
|
CL.Finish(hCmdQueue);
|
2009-09-03 21:01:11 +02:00
|
|
|
|
|
|
|
|
|
CL.ReleaseMemObject(hDeviceMemA);
|
|
|
|
|
CL.ReleaseMemObject(hDeviceMemB);
|
|
|
|
|
CL.ReleaseMemObject(hDeviceMemC);
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-10-19 19:45:50 +02:00
|
|
|
|
|
|
|
|
|
for (int i = 0; i < A.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
System.Diagnostics.Trace.WriteLine(String.Format("{0} + {1} = {2}", A[i], B[i], C[i]));
|
|
|
|
|
}
|
2009-09-03 21:01:11 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|