Блокировка холста - PullRequest
       28

Блокировка холста

0 голосов
/ 08 июня 2018

У меня есть форма моего приложения, которая может иметь до 1000 визуальных компонентов, в которой я рисую каждый из них один раз, используя Canvas растрового изображения, и сохраняю это растровое изображение каждого компонента (вид двойной буферизации), потому что каждая операциязанимает 20 мс.

Я использую потоки для рисования растровых изображений и отправки уведомлений с этим растровым изображением в MainThread, чтобы обновить визуальные компоненты, пользовательский интерфейс.

Теоретически, это должно было быиметь жидкую форму отверстия с отображением компонентов, поскольку их растровые изображения были окрашены в потоках, но на практике это не было жидким.Я решил взглянуть на TCanvas delphi и заметил что-то ошеломляющее:

class var // <<<<<<<<<<<<<<<<<<<<<<<<<<<< class var
  FLock: TObject;

function TCanvas.BeginScene(AClipRects: PClipRects = nil; AContextHandle: THandle = 0): Boolean;
begin
  Lock;
  ...
end;

procedure TCanvas.EndScene;
begin
  ...
  Unlock;
end;

class procedure TCanvas.Lock;
begin
  TMonitor.Enter(FLock);
end;

class procedure TCanvas.Unlock;
begin
  TMonitor.Exit(FLock);
end;

Это определенно не кажется правильным.Почему embarcadero делает невозможным одновременную работу с TCanvas в разных потоках?Бесполезно создавать 10 потоков для создания растровых рисунков, поскольку все будет обрабатываться по одному за раз ...

  1. Почему это существует?
  2. Есть ли обходной путь?Что может произойти, если я сделаю свою версию FMX.Graphics только с локальными мониторами для каждого TCanvas?
  3. Есть ли какая-либо сторонняя библиотека с собственным TCanvas?

Я знаю, что многиепосоветует мне использовать нативные классы, JCanvas в android и CGContextRef в iOS, но я хотел найти решение с TCanvas, потому что его работа заключается в том, чтобы быть оболочкой для функций рисования всех платформ и быть простым в использовании.

============= @EDIT =============

Я изменил блокировку и разблокировку TCanvas в FMX. Графикаблок для использования локальных вместо глобальных мониторов, а также BeginScene и EndScene TContext3D в блоке FMX.Types3D.Я очень обеспокоен этим изменением, но, очевидно, приложение работает нормально, самая большая работа была перекомпилировать весь FMX.

1 Ответ

0 голосов
/ 09 июня 2018

Tbitmap не является многопоточным.Это было сделано как многопоточность в Delphi Tokyo, но с очень плохим дизайном (их все еще много, когда вы используете Tbitmap в фоновом потоке, например, Tbitmap по-прежнему использует уведомления об обмене сообщениями, которые вообще не являются многопоточными и, следовательно, могут привести к случайному исключению).То, что было сделано неплохо в Токио, - это сделать многопоточный контекст OpenGL (под android / ios), и это работает довольно хорошо (но не TTexture, которая по-прежнему связана с Messaging, но вы можете легко обновить исходный код ttexture, чтобы исправитьэто (Вы можете посмотреть исходный код Alcinoe , чтобы узнать, как это сделать).

Единственный обходной путь для достижения того, чего вы хотите достичь:

  1. Не используйте TBitmap, но используйте вместо этого Texture (потому что openGL полностью многопоточный без какой-либо блокировки)
  2. Создание текстуры в фоновом потоке с помощью встроенной функции ОС (JCanvas в android и CGContextRef в iOS)
  3. Avoidиспользовать так много элементов управления, но вместо этого нарисуйте все текстуры, которые готовы и видимы из основного потока (например, в событии onpaint) в нужном месте

Да, я знаю, что это боль!

...