This commit is contained in:
SunSerega 2019-10-12 02:22:00 +03:00
parent 74913a1c66
commit 1b4fed44e7
12 changed files with 1495 additions and 1080 deletions

View file

@ -0,0 +1,17 @@
uses OpenCLABC;
// Вывод типа и значения объекта
// "o?.GetType" это короткая форма "o=nil ? nil : o.GetType", то есть берём или тип объекта, или nil если сам объект nil
// _ObjectToString это функция, которую использует Writeln для форматирования значений
procedure OtpObject(o: object) :=
Writeln( $'{o?.GetType}[{_ObjectToString(o)}]' );
begin
var b0 := new Buffer(1);
OtpObject( Context.Default.SyncInvoke( b0.NewQueue as CommandQueue<Buffer> ) ); // Тип - буфер, потому что очередь создали из буфера
OtpObject( Context.Default.SyncInvoke( HFQ( ()->5 ) ) ); // Тип - Int32(integer), потому что это тип по-умолчанию для выражения "5"
OtpObject( Context.Default.SyncInvoke( HFQ( ()->'abc' ) ) ); // Тип - string, по той же причине
OtpObject( Context.Default.SyncInvoke( HPQ( ()->Writeln('Выполнилась HPQ') ) ) ); // Тип отсутствует, потому что HPQ возвращает nil
end.

View file

@ -0,0 +1,23 @@
uses OpenCLABC;
begin
var q1 := HFQ( ()->1 );
var q2 := HFQ( ()->2 );
// Выводит 2, то есть только результат последней очереди
// Так сделано из за вопросов производительности
Context.Default.SyncInvoke( q1+q2 ).Println;
// Однако всё же бывает так, что нужны результаты всех сложенных/умноженных очередей
// В таком случае надо использовать CombineSyncQueue и CombineAsyncQueue
// А точнее их перегрузку, первый параметр которой - функция преобразования
Context.Default.SyncInvoke(
CombineSyncQueue(
results->results.JoinIntoString, // функция преобразования. Если не указывать - CombineSyncQueue работает как обычное сложение (но быстрее если складывать >2 очередей)
q1, q2
)
).Println;
// Теперь выводит строку "1 2". Это то же самое что вернёт "Arr(1,2).JoinIntoString"
end.

View file

@ -0,0 +1,46 @@
uses OpenCLABC;
begin
var b := new Buffer( 3*sizeof(integer) );
var A := new integer[3];
// Код с очередями
var Q_BuffWrite :=
( b.NewQueue.AddWriteValue(1, 0*sizeof(integer) ) as CommandQueue<Buffer> ) *
( b.NewQueue.AddWriteValue(5, 1*sizeof(integer) ) as CommandQueue<Buffer> ) *
( b.NewQueue.AddWriteValue(7, 2*sizeof(integer) ) as CommandQueue<Buffer> )
;
var Q_BuffRead := b.NewQueue.AddReadArray(A) as CommandQueue<Buffer>;
var Q_Otp := HPQ(()->
begin
A.Println;
end);
Context.Default.SyncInvoke(
Q_BuffWrite +
Q_BuffRead +
Q_Otp
);
// Этот же код ещё раз, но без явных очередей
// Неявно - каждый метод .Write*** и .Read*** всё равно создаёт по очереди
// Такая запись короче, но выполняется медленнее
// Аналог Q_BuffWrite
System.Threading.Tasks.Parallel.Invoke(
()->b.WriteValue(1, 0*sizeof(integer) ),
()->b.WriteValue(5, 1*sizeof(integer) ),
()->b.WriteValue(7, 2*sizeof(integer) )
);
// Аналог Q_BuffRead
b.ReadArray(A);
// Аналог Q_Otp
A.Println;
end.

View file

@ -0,0 +1,10 @@
uses OpenCLABC;
begin
var q := HFQ(()->123);
Context.Default.SyncInvoke(
q.ThenConvert(i -> $'"{i}"' )
).Println;
end.

View file

@ -0,0 +1,26 @@
uses OpenCLABC;
begin
var q1 := HPQ(()->
begin
// lock надо чтоб при параллельном выполнении два потока не пытались использовать вывод одновременно. Иначе выйдет кашу
lock output do Writeln('Очередь 1 начала выполняться');
Sleep(500);
lock output do Writeln('Очередь 1 закончила выполняться');
end);
var q2 := HPQ(()->
begin
lock output do Writeln('Очередь 2 начала выполняться');
Sleep(500);
lock output do Writeln('Очередь 2 закончила выполняться');
end);
Writeln('Последовательное выполнение:');
Context.Default.SyncInvoke( q1 + q2 );
Writeln;
Writeln('Параллельное выполнение:');
Context.Default.SyncInvoke( q1 * q2 );
end.

View file

@ -0,0 +1,24 @@
uses OpenCLABC;
begin
var b := new Buffer( 3*sizeof(integer) ); // Буфер достаточного размера чтоб содержать 3 значения типа integer.
// Создаём очередь
var q := b.NewQueue;
// Добавлять команды в полученную очередь можно вызывая соответствующие методы
q.AddWriteValue(1, 0*sizeof(integer) );
// Методы, добавляющие команду в очередь - возвращают очередь, для которой их вызвали (не копию а ссылку на оригинал)
// Поэтому можно добавлять по несколько команд в 1 строчке:
q.AddWriteValue(5, 1*sizeof(integer) ).AddWriteValue(7, 2*sizeof(integer) );
// Все команды в q будут выполнятся последовательно, что не всегда хорошо
// Если надо выполнять параллельно - создавайте несколько "b.NewQueue" и умножайте друг на друга
// В данной версии надо писать "as CommandQueue<...>" при использовании [Buffer/Kernel]CommandQueue вместо CommandQueue<...>, из за бага компилятора
Context.Default.SyncInvoke(q as CommandQueue<Buffer>);
// Вообще чтение тоже надо делать через очереди, но для простого примера - и неявные очереди подходят
b.GetArray1&<integer>(3).Println;
end.

View file

@ -0,0 +1,27 @@
uses OpenCLABC;
begin
var N := ReadInteger('Введите размер буфера:');
var b := new Buffer( N*sizeof(integer) );
var Q_RNG_val := HFQ(()->
begin
Result := Random(1,100);
end);
// .WriteValue принимает значение размерного типа
// Но вместо него - мы передали очередь (CommandQueue это класс, то есть точно не размерный тип)
// Так можно, потому что возвращаемое значение очереди Q_RNG_val - размерный тип (integer)
var Q_RNG_FillBuff := b.NewQueue.AddWriteValue(Q_RNG_val, 0) as CommandQueue<Buffer>;
for var i := 1 to N-1 do // 0 пропускаем, потому что его уже добавили выше
Q_RNG_FillBuff *= b.NewQueue.AddWriteValue(Q_RNG_val.Clone(), i*sizeof(integer) ) as CommandQueue<Buffer>;
// Вообще, это далеко не самый эффективный и красивый способ заполнить буфер
// В идеале - это надо делать карнелом
// То есть написать свой алгоритм Random на языке OpenCL-C (нет, это не сложно)
Context.Default.SyncInvoke(Q_RNG_FillBuff);
b.GetArray1&<integer>(N).Println;
end.

View file

@ -0,0 +1,11 @@
__kernel void TEST(__global int* message)
{
int gid = get_global_id(0);
message[gid] += gid;
}

View file

@ -0,0 +1,26 @@
uses OpenCLABC;
begin
// Когда код на языке OpenCL-C хранят в файле - обычно ему дают расширение .cl
// Но этот код можно хранить и в $resource или даже в '' в программме
var code_text := ReadAllText('0.cl');
// Создание объекта типа ProgramCode
// Перед текстом программы - можно так же указать контекст
// Если не указывать - используется Context.Default
var code := new ProgramCode(code_text);
var A := new Buffer( 10 * sizeof(integer) ); // будет хранить 10 чисел типа "integer"
// 'TEST' - имя подпрограммы-кёрнела из .cl файла. Регистр важен!
code['TEST'].Exec1(10, // используем 10 потоков
A.NewQueue.AddFillValue(1) // заполняем весь буфер единичками, прямо перед выполнением
as CommandQueue<Buffer> //ToDo нужно только из за issue компилятора #1981, иначе получаем странную ошибку. Когда исправят - можно будет убрать
);
A.GetArray1&<integer>(10).Println; // читаем одномерный массив с элементами "integer", длинной в 10
end.

View file

@ -166,7 +166,8 @@ begin
var sprog := InitProgram(vertex_shader, 0 {fragment_shader});
var uniform_rot_k := gl.GetUniformLocation(sprog, 'rot_k');
var uniform_rot_k := gl.GetUniformLocation(sprog, 'rot_k');
var attribute_position := gl.GetAttribLocation(sprog, 'position');
var attribute_color := gl.GetAttribLocation(sprog, 'color');

View file

@ -2093,7 +2093,7 @@ type
static function GetEventInfo(&event: cl_event; param_name: EventInfoType; param_value_size: UIntPtr; param_value: pointer; param_value_size_ret: ^UIntPtr): ErrorCode;
external 'opencl.dll' name 'clGetEventInfo';
static function SetEventCallback(&event: cl_event; command_exec_callback_type: ErrorCode; pfn_notify: Event_Callback; user_data: pointer): ErrorCode;
static function SetEventCallback(&event: cl_event; command_exec_callback_type: CommandExecutionStatus; pfn_notify: Event_Callback; user_data: pointer): ErrorCode;
external 'opencl.dll' name 'clSetEventCallback';
static function RetainEvent(&event: cl_event): ErrorCode;

File diff suppressed because it is too large Load diff