Мастера DELPHI, Delphi programming community Рейтинг@Mail.ru Титульная страница Поиск, карта сайта Написать письмо 
| Новости |
Новости сайта
Поиск |
Поиск по лучшим сайтам о Delphi
FAQ |
Огромная база часто задаваемых вопросов и, конечно же, ответы к ним ;)
Статьи |
Подборка статей на самые разные темы. Все о DELPHI
Книги |
Новинки книжного рынка
Новости VCL
Обзор свежих компонент со всего мира, по-русски!
|
| Форумы
Здесь вы можете задать свой вопрос и наверняка получите ответ
| ЧАТ |
Место для общения :)
Орешник |
Коллекция курьезных вопросов из форумов
KOL и MCK |
KOL и MCK - Компактные программы на Delphi
Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / rsdn.org

 
Чтобы не потерять эту дискуссию, сделайте закладку « предыдущая ветвь | форум | следующая ветвь »

BitBlt


dmk ©   (09.02.17 15:47

Подскажите пожалуйста, есть ли в WinApi возможность дождаться окончания вызова функции? Проблема в том, что в потоках рисуется буфер, который потом выводится на экран. Сразу после вызова BitBlt потоки успевают нарисовать в буфере обновленное содержимое, а отрисовка BitBlt еще не завершена. Получается наложение нового на старое. Можно конечно 2 буфера чередовать, но вдруг в WinApi что есть, чтобы дождаться окончания вывода?


NoUser ©   (09.02.17 17:02[1]

> дождаться окончания вывода?
У тебя два потока, - один 'рисует' в hdcSrc, второй вызывает BitBlt ?

Да, есть: EnterCriticalSection/LeaveCriticalSection.

Можно также, для большей утилизации многоядерности: TryEnterCriticalSection с дополнительным буфером ...


Игорь Шевченко ©   (09.02.17 19:27[2]

BitBlt не подразумевает асинхронное выполнение


dmk ©   (09.02.17 19:41[3]

>Да, есть: EnterCriticalSection/LeaveCriticalSection.
Так у меня через TThread.Synchronize процедура обновления. Т.е. там уже CriticalSection используется. Значит 2 буфера.

>BitBlt не подразумевает асинхронное выполнение
Так о том и пишу. Блок памяти в момент вывода досутпен для изменения :(


Игорь Шевченко ©   (09.02.17 21:39[4]

dmk ©   (09.02.17 19:41) [3]

Значит надо перед вызовом BitBlt заблокировать буфер функцией EnterCriticalSection, а после вызова разблокировать LeaveCriticalSection
А изменяющий код перед изменениями тоже должен вызвать EnterCriticalSection, а после изменения LeaveCriticalSection, вроде азы синхронизации.


NoUser ©   (10.02.17 00:36[5]


> Сразу после вызова BitBlt поток(и)! успевают нарисовать в буфере обновленное одержимое

у тебя больше одного дополнительного потока рисуют одну картинку?

Тогда Synchronize тебе не поможет - оно работает только между тем кто вызвал и основным потоком.


Pavia ©   (10.02.17 08:40[6]


> Получается наложение нового на старое. Можно конечно 2 буфера
> чередовать, но вдруг в WinApi что есть, чтобы дождаться
> окончания вывода?

Нету. Предполагается, что по выходу данные забраны на вывод.  

Но бага есть! Толи в самой винде, толи в драйверах. Скорее первое.


> Так у меня через TThread.Synchronize процедура обновления.

Это ничего не значит. Нужен код или схема.


> Игорь Шевченко ©   (09.02.17 21:39) [4]

Азы синхронизации говорят, что если надо заблокировать данные(буфер, блок данных), то надо использовать Mutex (исключительный доступ). Или замок к примеру Canvas.Lock.


Игорь Шевченко ©   (10.02.17 10:19[7]

Pavia ©   (10.02.17 08:40) [6]

Я поражаюсь твоему апломбу вкупе с твоим невежеством.


Pavia ©   (10.02.17 11:33[8]


> Я поражаюсь твоему апломбу вкупе с твоим невежеством.

Люблю правду и докапываюсь до истины. А самое главное я верю в то, что я говорю так как говорю правду. И вера моя основана на книгах, которые я прочитал и на экспериментах которые я поставил.
Все мы люди и можем ошибаться.

Так вот с BitBlt и синхронизацией я экспериментировал правда давненько и SDK в плоть до DDK прошерстил, а вот это было пару месяцев назад.

Что касается критической секции и мьютекса. Так это всего лишь указание на правильное использование слов с учётом их семантики. Есть такая вещь называется метафора и аналогия, и ими следует пользоваться вместо того что-бы грубо нарушать качество передачи смысла.  

А если тут найдётся умник который скажете, что Canvas.Lock основан на критических секциях. То уж извините это называется медвежьей услугой. Так как этот человек предлагает вам начать изобретать свой велосипед вместо того что-бы пользоваться готовым.

Вообще есть у меня в планах написать статью или брошюрку с описанием параллельности. Как что и зачем. Вот только шаблон книги надо подобрать.  Может посоветовать, что за рыбу взять?


dmk ©   (10.02.17 13:36[9]

>Предполагается, что по выходу данные забраны на вывод.

Вопрос решился простым циклом ожидания.
Вот такой цикл отрисовки.

procedure QThread.Execute;
var
 cP: TFloatPoint;
 Params: TDrawParams;

label
 StopDraw;

begin
 //Параметры по умолчанию
 Params := FillParams;

 //Центр вращения
 cP.X := cX;
 cP.Y := cY;

 //Порядковый номер потока
 NumberID := GetFreeID(ThreadID);

 //Заполняем параметры
 Params.cX := cX;
 Params.cY := cY;

 //Изменяем только угол
 Params.Angle := gAngle;

 //Отсечение всего региона
 if bClip then
   Params.R := lmR else
   Params.R := Rgn;

 //Цикл отрисовки
 while (gDrawCounter < gNumDrawCycles) do
 begin
   //Превышение индекса объектов
   //учитывается в программе отрисовки
   gDrawProc(Params);

   //Обновляет буфер самый шустрый поток
   if (ThreadID = gFirstID) then
   begin
     //Обновляем буфер
     //Synchronize(UpdateThreads); //<- Работает медленнее
     UpdateThreads; //<- Работает бытсрее
     //Прогресс
     gProgress := Round(gDrawCounter / (gNumDrawCycles - 1) * 100);
     //Кол-во циклов отрисовки
     Inc(gDrawCounter);
     //Следующий угол
     gAngle := RorAngle(gAngle, gAngleInc);
     //Сброс кол-ва отрисованных объектов
     gObjectIndex := 0;
   end;//if (gNumEntered)

   //Устанавливаем флаг завершения отрисовки
   FPaints[NumberID] := True;

   //Остальные потоки ждут здесь
   //пока первый поток не отрисует буфер
   //или все потоки не соберутся здесь
   while (not PaintsFinished) do
   begin
     //Проверка на превышение циклов отрисовки
     if (gDrawCounter >= gNumDrawCycles) then goto StopDraw;
   end;

   //Проверка на ESC
   if gESC then goto StopDraw;
 end;//while

StopDraw:

 //Устанавливаем флаг завершения отрисовки
 FPaints[NumberID] := True;

 //Ждем здесь пока остальные потоки не закончат отрисовку
 while (not PaintsFinished) do
 begin
 end;
end;


Вот такая процедура вывода

procedure UpdateThreads;
var
 dp: TDrawParams;

begin
 DrawProgress(gProgress, false);
 BitBlt(pDC, Rgn.X, Rgn.Y, Rgn.W, Rgn.H, sBmp.MemDC, Rgn.X, Rgn.Y, SrcCopy);

 //Счетчик обновлений
 Inc(gNumBufferUpdates);
end;


В таком виде работает нормально, но есть асинхронное поведение ядер.
Несмотря на InterlockedIncrement некоторые потоки успевают нарисовать быстрее.
Синхронность отсутствует вообще. Видимо из-за разницы в ГГц-ах.


NoUser ©   (10.02.17 13:36[10]

> SDK в плоть до DDK ))


> написать статью или брошюрку
ты не стесняйся, пиши все мысле-тезы сюды.

( 'Рыба': http://www.kurzenkov.com/Articles/multithreading1.html )


Игорь Шевченко ©   (10.02.17 13:54[11]

Pavia ©   (10.02.17 11:33) [8]


> И вера моя основана на книгах, которые я прочитал и на экспериментах
> которые я поставил.


Если бы среди прочитанных книг был учебник по грамматике русского языка - было бы еще лучше. А так - просто смешно.


Inovet ©   (10.02.17 17:06[12]

> [8] Pavia ©   (10.02.17 11:33)
> Вообще есть у меня в планах написать статью или брошюрку
> с описанием параллельности. Как что и зачем. Вот только
> шаблон книги надо подобрать.  Может посоветовать, что за
> рыбу взять?

Совет был дан кем-то из классиков: если можешь не писать - не пиши.


Eraser ©   (10.02.17 20:49[13]


> dmk ©   (09.02.17 15:47) 


> Сразу после вызова BitBlt потоки успевают нарисовать в буфере
> обновленное содержимое, а отрисовка BitBlt еще не завершена.
>

1. есть такое понятие, как двойная буферизация, погугли.

2. если нужна скорость - выкинь GDI и используй Direct2D http://docwiki.embarcadero.com/RADStudio/Seattle/en/Using_the_Direct2D_Canvas

3. Если вдруг надумал рисовать в потоках VCL оберткой над GDI, нужно везде использовать блокировки canvas, если интересно почему - см. FreeMemoryContexts из модуля Vcl.Graphics, там очень захватывающая история.


dmk ©   (10.02.17 23:19[14]

Eraser ©   (10.02.17 20:49) [13]

Да не. Цель наоборот избавиться от привязки к чужим технологиям. От ОС нужен только вывод, а так у меня библиотека сама многое рисует. Суть мультипоточности в моем случае сделать отрисовку быстрее и сохранить порядок наложения рисуемых объектов. Чтобы результат был одинаковый в одном потоке или нескольких.

Тут скриншот: http://hostingkartinok.com/show-image.php?id=347c22d0a4d969a5a9781c625d8f84b3
Тут exe: https://cloud.mail.ru/public/5mkt/mK1uRZZLT

Главное треугольник не трогать. Не допилен.


dmk ©   (10.02.17 23:20[15]

Под 32 бита наверно не пойдет.


Eraser ©   (11.02.17 02:16[16]


> dmk ©   (10.02.17 23:19) [14]

видимо речь про многопоточный 3D рендер, а не вывод.
мне кажется это весьма сложная тема, тут без серьезного углубления в теорию никак, с кондачка вряд ли выйдет.


dmk ©   (11.02.17 03:10[17]

Там и 3D и 2D. Типа своего директ икса.


Pavia ©   (11.02.17 10:12[18]


>  Суть мультипоточности в моем случае сделать отрисовку быстрее
> и сохранить порядок наложения рисуемых объектов. Чтобы результат
> был одинаковый в одном потоке или нескольких.

Что-бы сохранить порядок нужно либо Z-буфер либо разбивать экран на разные квадраты каждый квадрат обрабатывается своим потоком.
Либо как во всех движках на фрагменты. Все они помещаются в очередь и потоки по очереди берут из неё задание на рендеринг. Или по кадрам один кадр рисует один поток второй кадр второй поток.


han_malign ©   (20.04.17 15:12[19]


> Но бага есть! Толи в самой винде, толи в драйверах. Скорее первое.

- это не бага
https://msdn.microsoft.com/en-us/windows/hardware/drivers/display/asynchronous-rendering
GdiFlush()
https://msdn.microsoft.com/en-us/library/windows/desktop/dd144844(v=vs.85).aspx


MinGW   (20.04.17 20:46[20]

У вас DIB-секция - грубо говоря просто массив байт в памяти. Каким же образом GDI обязана "блокировать" доступ к ней? И зачем ей это?

Это вопрос не функций GDI, а синхронизации потоков.

Вы что, не имеете в своей многопоточной системе событий/сигналов типа "отрисовка кадра началась", "отрисовка кадра закончилась", "пора начать рисовать новый кадр"? Молотите как попало на максимуме процессора? Это как бы нехорошо.


dmk ©   (21.04.17 12:42[21]

>пора начать рисовать новый кадр
Суть потоков в том, что в совокупности они настолько быстрые, что после вызова BitBlt они начинают рисовать в буфере который еще выводится. Т.е. система не успевает дорисовать до конца буфер, а потоки уже успевают в нем нарисовать новое. Флага в системе что отрисовка окончена нет. В одном потоке нет проблем.


версия для печати

Написать ответ

Ваше имя (регистрация  E-mail 







Разрешается использование тегов форматирования текста:
<b>жирный</b> <i>наклонный</i> <u>подчеркнутый</u>,
а для выделения текста программ, используйте <code> ... </code>
и не забывайте закрывать теги! </b></i></u></code> :)


Наверх

  Рейтинг@Mail.ru     Титульная страница Поиск, карта сайта Написать письмо