pascalabcnet/InstallerSamples/OpenGL и OpenCL/OpenCL/MatrMlt.pas

119 lines
5 KiB
ObjectPascal
Raw Permalink Normal View History

2019-05-18 10:24:07 +03:00
uses OpenCL;
uses System;
uses System.Runtime.InteropServices;
const
MatrW = 4; // можно поменять на любое положительное значение
VecByteSize = MatrW*8;
2019-05-18 10:24:07 +03:00
MatrL = MatrW*MatrW;
MatrByteSize = MatrL*8;
2020-02-26 07:34:25 +03:00
2019-05-18 10:24:07 +03:00
begin
2020-02-26 07:34:25 +03:00
Randomize(0); // чтоб при каждом выполнении были одинаковые результаты
2019-05-18 10:24:07 +03:00
var ec: ErrorCode;
// Инициализация
var platform: cl_platform_id;
2020-02-26 07:34:25 +03:00
cl.GetPlatformIDs(1, platform, IntPtr.Zero).RaiseIfError;
2019-05-18 10:24:07 +03:00
var device: cl_device_id;
2020-08-04 02:26:50 +03:00
cl.GetDeviceIDs(platform, DeviceType.DEVICE_TYPE_ALL, 1,device,IntPtr.Zero).RaiseIfError;
2019-07-18 03:47:28 +03:00
2020-02-26 07:34:25 +03:00
var context := cl.CreateContext(nil, 1,device, nil,IntPtr.Zero, ec);
2019-05-18 10:24:07 +03:00
ec.RaiseIfError;
2020-02-26 07:34:25 +03:00
var command_queue := cl.CreateCommandQueueWithProperties(context, device, nil, ec);
2019-05-18 10:24:07 +03:00
ec.RaiseIfError;
// Чтение и компиляция .cl файла
{$resource MatrMlt.cl}
2020-08-04 02:26:50 +03:00
var prog_str := System.IO.StreamReader.Create(
System.Reflection.Assembly.GetCallingAssembly.GetManifestResourceStream('MatrMlt.cl')
).ReadToEnd;
2019-05-18 10:24:07 +03:00
var prog := cl.CreateProgramWithSource(
context,
1,
new string[](prog_str),
2020-03-13 05:28:53 +03:00
nil,
2019-05-18 10:24:07 +03:00
ec
);
ec.RaiseIfError;
2020-02-26 07:34:25 +03:00
cl.BuildProgram(prog, 1,device, nil, nil,IntPtr.Zero).RaiseIfError;
2019-05-18 10:24:07 +03:00
var MatrMltMatrKernel := cl.CreateKernel(prog, 'MatrMltMatr', ec);
ec.RaiseIfError;
var MatrMltVecKernel := cl.CreateKernel(prog, 'MatrMltVec', ec);
ec.RaiseIfError;
// Подготовка параметров
2020-02-26 07:34:25 +03:00
Writeln('Матрица A:');
2019-05-18 10:24:07 +03:00
var A := MatrRandomReal(MatrW,MatrW,0,1).Println;
2020-02-26 07:34:25 +03:00
Writeln;
var A_buf := cl.CreateBuffer(context, MemFlags.MEM_READ_WRITE, new UIntPtr(MatrByteSize),IntPtr.Zero, ec);
2019-05-18 10:24:07 +03:00
ec.RaiseIfError;
2020-02-26 07:34:25 +03:00
cl.EnqueueWriteBuffer(command_queue, A_buf, Bool.BLOCKING, new UIntPtr(0),new UIntPtr(MatrByteSize), A[0,0], 0,nil,IntPtr.Zero).RaiseIfError;
2019-05-18 10:24:07 +03:00
2020-02-26 07:34:25 +03:00
Writeln('Матрица B:');
2019-05-18 10:24:07 +03:00
var B := MatrRandomReal(MatrW,MatrW,0,1).Println;
2020-02-26 07:34:25 +03:00
Writeln;
var B_buf := cl.CreateBuffer(context, MemFlags.MEM_READ_WRITE, new UIntPtr(MatrByteSize),IntPtr.Zero, ec);
2019-05-18 10:24:07 +03:00
ec.RaiseIfError;
2020-02-26 07:34:25 +03:00
cl.EnqueueWriteBuffer(command_queue, B_buf, Bool.BLOCKING, new UIntPtr(0),new UIntPtr(MatrByteSize), B[0,0], 0,nil,IntPtr.Zero).RaiseIfError;
2019-05-18 10:24:07 +03:00
2020-02-26 07:34:25 +03:00
Writeln('Вектор V1:');
var V1 := ArrRandomReal(MatrW);
V1.Println;
2020-02-26 07:34:25 +03:00
Writeln;
var V1_buf := cl.CreateBuffer(context, MemFlags.MEM_READ_WRITE, new UIntPtr(VecByteSize),IntPtr.Zero, ec);
2019-05-18 10:24:07 +03:00
ec.RaiseIfError;
2020-02-26 07:34:25 +03:00
cl.EnqueueWriteBuffer(command_queue, V1_buf, Bool.BLOCKING, new UIntPtr(0),new UIntPtr(VecByteSize), V1[0], 0,nil,IntPtr.Zero).RaiseIfError;
2019-05-18 10:24:07 +03:00
2020-02-26 07:34:25 +03:00
var C_buf := cl.CreateBuffer(context, MemFlags.MEM_READ_WRITE, new UIntPtr(MatrByteSize),IntPtr.Zero, ec);
2019-05-18 10:24:07 +03:00
ec.RaiseIfError;
2020-02-26 07:34:25 +03:00
var V2_buf := cl.CreateBuffer(context, MemFlags.MEM_READ_WRITE, new UIntPtr(VecByteSize),IntPtr.Zero, ec);
2019-05-18 10:24:07 +03:00
ec.RaiseIfError;
var MatrWParam := MatrW;
// Выполнение C := A*B
2020-02-26 07:34:25 +03:00
cl.SetKernelArg(MatrMltMatrKernel, 0, new UIntPtr(UIntPtr.Size), A_buf).RaiseIfError;
cl.SetKernelArg(MatrMltMatrKernel, 1, new UIntPtr(UIntPtr.Size), B_buf).RaiseIfError;
cl.SetKernelArg(MatrMltMatrKernel, 2, new UIntPtr(UIntPtr.Size), C_buf).RaiseIfError;
2020-08-04 02:26:50 +03:00
cl.SetKernelArg(MatrMltMatrKernel, 3, new UIntPtr(sizeof(integer)), @MatrWParam).RaiseIfError;
2019-05-18 10:24:07 +03:00
2020-02-26 07:34:25 +03:00
var k1_ev: cl_event;
cl.EnqueueNDRangeKernel(command_queue, MatrMltMatrKernel, 2, nil,new UIntPtr[](new UIntPtr(MatrW),new UIntPtr(MatrW)),nil, 0,nil,k1_ev).RaiseIfError;
2019-05-18 10:24:07 +03:00
// Выполнение V2 := C*V
2020-02-26 07:34:25 +03:00
cl.SetKernelArg(MatrMltVecKernel, 0, new UIntPtr(UIntPtr.Size), C_buf).RaiseIfError;
cl.SetKernelArg(MatrMltVecKernel, 1, new UIntPtr(UIntPtr.Size), V1_buf).RaiseIfError;
cl.SetKernelArg(MatrMltVecKernel, 2, new UIntPtr(UIntPtr.Size), V2_buf).RaiseIfError;
2020-08-04 02:26:50 +03:00
cl.SetKernelArg(MatrMltVecKernel, 3, new UIntPtr(sizeof(integer)), @MatrWParam).RaiseIfError;
2019-05-18 10:24:07 +03:00
2020-02-26 07:34:25 +03:00
var k2_ev: cl_event;
cl.EnqueueNDRangeKernel(command_queue, MatrMltVecKernel, 1, nil,new UIntPtr[](new UIntPtr(MatrW)),nil, 1,k1_ev,k2_ev).RaiseIfError;
2019-05-18 10:24:07 +03:00
// Чтение и вывод результата
2020-02-26 07:34:25 +03:00
// Внимание! В отличии от OpenCLABC - тут чтение "C_buf" не обязательно начнётся сразу после выполнения "k1_ev"
// Большинство реализаций OpenCL не поддерживают асинхронные очереди
// Чтоб получить асинхронное выполнение "cl.Enqueue*" команд - надо несколько вызовов "cl.CreateCommandQueueWithProperties"
cl.EnqueueReadBuffer(command_queue, C_buf, Bool.BLOCKING, new UIntPtr(0), new UIntPtr(MatrByteSize), A[0,0], 1,k1_ev,IntPtr.Zero).RaiseIfError;
Writeln('Матрица С = A*B:');
2019-05-18 10:24:07 +03:00
A.Println;
2020-02-26 07:34:25 +03:00
Writeln;
2019-05-18 10:24:07 +03:00
2020-08-04 02:26:50 +03:00
cl.EnqueueReadBuffer(command_queue, V2_buf, Bool.BLOCKING, new UIntPtr(0), new UIntPtr(VecByteSize), V1[0], 1,k2_ev,IntPtr.Zero).RaiseIfError;
2020-02-26 07:34:25 +03:00
Writeln('Вектор V2 = C*V1:');
V1.Println;
2019-05-18 10:24:07 +03:00
end.