Модули для работы с OpenCL и OpenGL


#1

Отдельный репозиторий

Сейчас у паскаля есть только модуль OpenGL, и то, он ужасно кривой и в нём нет большинства функций, включая базовые (как те что для работы с текстурами).

Для начала я занялся OpenCL, раз для него вообще ничего нет.


Структура проекта:

Есть всего 4 модуля:

  • 2 базовых (OpenCL.pas и OpenGL.pas) - они только оборачивают неуправляемый код, не добавляя ничего своего.

  • 2 высокоуровневые обёртки (OpenCLABC.pas и OpenGLABC.pas) - они имеют много ограничений из за высокоуровневости, но позволяют сильно сократить код. По сути, они относятся к OpenCL.pas и OpenGL.pas, как WPFObjects к GraphWPF.


В данный момент OpenGL.pas, OpenCLABC.pas и OpenGLABC.pas недоделаны (последний - не начат).

Названия последних 2 я думаю поменять (только не знаю на что, есть идеи - предлагайте).

И так же другие претензии и идеи - излагайте в этой теме.


#2

OpenCLABC работает!
(если не считать вот этого всего ужаса)


Для сравнения, вот самый простой пример, на OpenCL:

uses OpenCL;
uses System;
uses System.Runtime.InteropServices;

//Описания всех подпрограмм найдёте в справке по OpenCL:
//www.khronos.org/registry/OpenCL/specs/2.2/html/OpenCL_API.html

begin
  var ec: ErrorCode;
  
  // Инициализация
  
  var platform: cl_platform_id;
  cl.GetPlatformIDs(1, @platform, nil).RaiseIfError;
  
  var device: cl_device_id;
  cl.GetDeviceIDs(platform, DeviceTypeFlags.Default, 1, @device, nil).RaiseIfError;
  
  var context := cl.CreateContext(nil, 1, @device, nil, nil, @ec);
  ec.RaiseIfError;
  
  var command_queue := cl.CreateCommandQueue(context, device, CommandQueuePropertyFlags.NONE, ec);
  ec.RaiseIfError;
  
  // Чтение и компиляция .cl файла
  
  {$resource SimpleAddition.cl} // эта строчка засовывает SimpleAddition.cl внутрь .exe, чтоб не надо было таскать его вместе с .exe
  var prog_str := System.IO.StreamReader.Create(GetResourceStream('SimpleAddition.cl')).ReadToEnd;
  var prog := cl.CreateProgramWithSource(
    context,
    1,
    new string[](prog_str),
    new UIntPtr[](new UIntPtr(prog_str.Length)),
    ec
  );
  ec.RaiseIfError;
  
  cl.BuildProgram(prog, 1, @device, nil, nil, nil).RaiseIfError;
  
  // Подготовка и запуск программы на GPU
  
  var kernel := cl.CreateKernel(prog, 'TEST', ec); // Обязательно то же имя что у карнела из .cl файла. И регистр важен!
  ec.RaiseIfError;
  
  var mem := Marshal.AllocHGlobal(40);
  Marshal.Copy(ArrFill(10,1),0,mem,10);
  var memobj := cl.CreateBuffer(context, MemoryFlags.READ_WRITE or MemoryFlags.USE_HOST_PTR, new UIntPtr(40), mem, ec); // USE_HOST_PTR значит что нужно скопировать память из mem в memobj
  ec.RaiseIfError;
  
  cl.SetKernelArg(kernel, 0, new UIntPtr(UIntPtr.Size), memobj).RaiseIfError;
  
  cl.EnqueueNDRangeKernel(command_queue, kernel, 1, nil,new UIntPtr[](new UIntPtr(10)),nil, 0,nil,nil).RaiseIfError;
  
  cl.Finish(command_queue).RaiseIfError;
  
  // Чтение и вывод результата
  
  cl.EnqueueReadBuffer(command_queue, memobj, 1, new UIntPtr(0), new UIntPtr(40), pointer(mem), 0,nil,nil).RaiseIfError;
  
  var res := new integer[10];
  Marshal.Copy(mem,res,0,10);
  res.Println;
  
end.

И он же, на OpenCLABC:

uses OpenCLABC;

//ToDo issue компилятора:
// - #1981

begin
  
  // Чтение и компиляция .cl файла
  
  {$resource SimpleAddition.cl} // эта строчка засовывает SimpleAddition.cl внутрь .exe, чтоб не надо было таскать его вместе с .exe
  var prog := new ProgramCode(Context.Default,
    System.IO.StreamReader.Create(GetResourceStream('SimpleAddition.cl')).ReadToEnd
  );
  
  // Подготовка параметров
  
  var A := new KernelArg(40);
  
  // Подготовка очередей выполнения
  
  var prog_Q :=
    prog['TEST'].NewQueue.Exec(10,
      
      A.NewQueue.WriteData(
        ArrFill(10,1)
      ) as CommandQueue<KernelArg>
      
    ) as CommandQueue<Kernel>;
  
  // Выполнение
  
  Context.Default.SyncInvoke(prog_Q);
  
  // Чтение и вывод результата
  
  A.GetArray&<array of integer>(10).Println;
  
end.

Вроде, примеров должно быть достаточно, чтоб понять как работать с OpenCLABC. Если это не так - спрашивайте, не стесняйтесь. Если надо - я добавлю примеров/комментариев.


Из особо интересных фич:

  Context.Default.SyncInvoke(
    
    Calc_C_Q +
    (
      Otp_C_Q *
      (
        Calc_V2_Q +
        Otp_V2_Q
      )
    )
    
  );

(из примера умножения матриц)

Эту фичу я стыбзил из Graph3D.
Сложение очередей - даёт последовательное выполнение. А умножение - паралельное.

После того как посчиталась матрица C - можно сразу и выводить её, и считать вектор V2, поэтому там умножение.


Сейчас, в OpenCLABC реализовано только базовые возможности, я хочу так же добавить тонну сахара, чтоб уж точно горько небыло. У кого есть идеи - пишите!


#3

У меня просьба. Поместите примеры в папку OpenCL. Уберите вот это задвоение [CL,GL].


#4

То есть как? Сделать в корне папку OpenCL и в неё засунуть папки OpenCL и OpenCLABC? Или как?
И - потом так же с OpenGL?

P.S. так и сделал в общем…


#5

Добавил большинство сахара который планировал с самого начала. Теперь, тот пример выше стал ещё короче и проще:

uses OpenCLABC;

//ToDo issue компилятора:
// - #1981

begin
  
  // Чтение и компиляция .cl файла
  
  {$resource SimpleAddition.cl} // эта строчка засовывает SimpleAddition.cl внутрь .exe, чтоб не надо было таскать его вместе с .exe
  var prog := new ProgramCode(Context.Default,
    System.IO.StreamReader.Create(GetResourceStream('SimpleAddition.cl')).ReadToEnd
  );
  
  // Подготовка параметров
  
  var A := new KernelArg(40);
  
  // Выполнение
  
  prog['TEST'].Exec(10,
    
    A.NewQueue.WriteData(
      ArrFill(10,1)
    ) as CommandQueue<KernelArg>
    
  );
  
  // Чтение и вывод результата
  
  A.GetArray&<array of integer>(10).Println;
  
end.

То есть, теперь для простых, синхронных действий - не надо создавать очереди (хотя их всё равно создаст внутри, ибо сам OpenCL синхронно не работает).


#6

Прошу переработать модуль OpenGLABC - он дестабилизирует инсталлят. Возможность описывать ограничения вида T: Array будет закрыта, поскольку она отсутствует в C# и трудно или очень трудно реализуется корректно.


#7

Несмотря на то, что основное обсуждение (скорее срач) уже прошло на гитхабе и нисколько не пошатнуло мнение разработчиков, мне всё же хочется вставить свои 5 копеек.

Ручаться за то, что разрешение System.Array за собой не может повлечь никаких серьёзных последствий я не буду. Но эта конструкция была 15 лет разрешена и проблем не возникало (хотя мало кто серьёзно это всё тестировал). За исключением конкретно этой issue. И у меня вопрос: В чём смысл запрещать?

Разумеется, мы все знаем то, что язык ориентируется на промышленные языки, включая и С#. Здесь я полностью согласен с мнением SunSerega — в C# полно бессмысленных запретов, скорее всего имеющих шаблонные отговорки вроде “поскольку это сложно реализовать и мало где это используется, то и делать мы этого не будем”. Я, столкнувшись с рядом проблем C# отказался переписывать на него свой проект на PascalABC.NET. Так вот, к чему я это. Равняться на C# во всём — затея неплохая, но с оговоркой — Ничто не идеально. Независимо от статуса. Сколько бы разработчиков не трудилось в Microsoft.

Это, знаете, похоже на одну реальную ситуацию в мире. Ведь в России все хотят жить как в Европе, Японии или США. И мы пытаемся копировать всё с них. Ведь они-то уж наверняка знают, как нормально построить экономику, не зря же у этих государств такие высокие показатели ВВП, они точно знают что и как правильно делать. И никто не задумывается о том, какие бредовые вещи они делают. К примеру, возьмём отказ от ядерной энергетики в Японии. Похоронить будущее своего государства, когда самой дешёвой и чистой электроэнергией является атом, а уголь, газ и нефть стремительно кончаются. Из килограмма урана можно получить энергии столько же, сколько из 100 тонн высокосортного угля или 50 тонн нефти. И без влияния на окружающую среду. А они решили, как п(р)одвинутая Европа, перейти на псевдочистые (производства фотоэлементов и аккумуляторов весьма грязны) источники электроэнергии, такие как ветер и солнце. И почти никого не заботит огромная финансовая невыгодность всей этой бредятины. Платить в сотню раз больше за электричество? Сдувать каждый день пыль с солнечных панелей? Молиться ветру? Кто-нибудь хочет, чтобы также было и в России? Лично я — нет.

Очень отвлечённый пример. Но, возможно, также может выйти и с запретом Array в where. Налицо просто плохая реализация фичи в C#. И да, если вам уж настолько не хватает времени заняться починкой данной issue, то этим может заняться @Sun_Serega. В конце концов, сейчас ему эта фича и нужна.


#8

Я уже как раз искал причину того бага. Лишний box добавляется в вызове на строке 4946 в NetGenerator.cs:

value.obj.visit(this); // obj это IExpressionNode

Eсли его убрать - box пропадает. Но, разумеется, не всё так просто, в месте с ним - пропадает и ldloca.s, то есть загрузка адреса переменной, что уже убирать нельзя. А значит - надо смотреть внутрь этого вызова, и поставить какое то условие перед .Emit(OpCodes.Box, ...)

Но - это виртуальный вызов, ещё и из другой библиотеки… Поэтому нужна отладка. Тупая пересборка всего компилятора + метод тыка - тут уже не прокатят.

Если вам на столько не хватает времени - я готов взять всё связанное с where на себя. Но для этого - я уже много раз просил, посвятите меня в использования отладчика в вашем проекте! Или скажите как вы сами ищите баги.


#9

Когда возникают проблемы, связанные с кем-то написанной сторонней библиотекой - это неприятность, касающаяся того или иного количества пользователей этой библиотеки. И разработчики могут позволить себе в той или иной степени дистанцироваться от такой проблемы. Но когда сторонние разработчики забираются в код ядра проекта, это может преподнести неприятный сюрприз всем пользователям. Причем, во внешне вроде бы не имеющем отношение к внесенным изменениям месте. Сейчас за баги отвечает руководитель проекта, хорошо знающий свою команду и уверенный в ней. Сможет ли он настолько быть уверенным в сторонних разработчиках, допуская их в “святую святых”?


#10

Не сторонней. Компилятор состоит из нескольких библиотек, и вот на той строчке 1 из библиотек вызывает метод интерфейса, который объявлен в другой, а реализуется вообще в третьей библиотеке.

Разработчики всегда могут быть уверены в автоматических тестах, без проведения которых я не залью пулл.


#11

Копировать Запад не нужно,ибо это и есть мировой срач. Но и делать свой срач тоже не нужно. Срач срачем не выбивают. Русские долго запрягают, поэтому не нужно суеты. Спокойствие, только спокойствие. Если не помогает, балуйтесь плюшками (мягкий вариант).


#12

Тем временем, спустя 101 костыль - я кое как запустил отладку. И - вот оно. Вот это тот самый лишний box:

Это точно он, ибо в той подпрограмме больше нет box-ов, и я удостоверился что точка останова попадется только 1 раз:

Сейчас разберусь надо ли там условие или он вообще лишний…


#13

#14

@Admin, пожалуйста, перенесите всё, начиная с этого сообщения - сюда, т.к. это оффтоп.


#15

Кстати, в итоге оказалось что where T: Array было вообще не при чём. Этот код вообще падал:

type
  t0 = abstract class
    function f0: integer; abstract;
  end;
  t1 = class(t0)
    i: integer;
    function f0: integer; override := i;
    constructor(i: integer) := self.i := i;
  end;

function f1<T>: T;
where T: t0;
begin
  
  Result := T(t0(
    new t1(10)
  ));
  
  Result.f0.Println;
  
end;

begin
  
  f1&<t1>;
  
//  readln;
end.

Проблема была та же, и в моём пуле она тоже исправилась.


#16

Да, код падает. Найдёте минимальный падающий код?


#17
  1. Это и есть минимальный падающий.
  2. Я уже исправил это тут:

Я же говорю, это и есть на самом деле минимальный код к той issue в которой вы решили убрать where T: Array. И where T: Array к этой проблеме вообще не имеет никакого отношения.

И, ещё раз, если оно отмоталось куда то:
Я готов взятся за все issue связанные с where (а может и некоторые другие), если это поможет разгрузить вас так чтоб вы не делали запретов от нехватки времени на исправление.

Поэтому пожалуйста, не запрещайте where T: Array. Оно действительно полезно, а если оно что то сломает - я сам исправлю.


#18

А, да, увидел pull request. Мы посоветуемся с ibond.

Если дело было не в ограничении where T: Array, то запрещать нечего.

Два дня поиска информации в Интернете - откуда такое ограничение в C# - к успеху меня не привели. Не вижу в нем ничего сильно криминального.


#19

#20

Видимо, надо заменить модуль OpenGL в комплекте Паскаля