-
>А как, я извиняюсь, другие рендеры работают, тоже со скоростью памяти мучаются ? Именно так. В 3Ds max софтверные драйвера медленнее моих функций в несколько раз.
-
А вообще софтвер особо не в почете, когда есть видюхи. Железный рендер быстрее в любом случае. Мне просто хотелось иметь свой софтверный вариант. Оказалось процессоры под это не особо заточены.
-
-
-
>разные чудеса бывают если использовать глобальные(внешние) переменные внутри >потоков. даже если это необходимо, но криво продумано/сделано.
Подскажите как правильно? Во всех примерах, которые я нашел используются глобальные переменные с InterlockedIncrement. Как мне их заставить рисовать последовательно? Создавать на каждое действие свой класс потоков и вызывать из основного цикла? Типа так? 1. Resume ClearBufferThreads 2. Очистка буферов (Класс потоков - ClearBufferThreads) 3. Suspend ClearBufferThreads 4. Resume ModifyObjectsThreads 5. Трансформация объектов (Класс потоков - ModifyObjectsThreads) 6. Suspend ModifyObjectsThreads 7. Resume RenderObjectsThreads 8. Рендер объектов (Класс потоков - RenderObjectsThreads) 9. Suspend RenderObjectsThreads 10. Вывод просчитанного в основном VCL-потоке.
В нынешнем варианте потоки очень много простаивают в циклах. Серьезная потеря производительности. Если запустить просчет без ожидания потоков, то скорость отрисовки возрастает до ~350 fps, что очень хотелось бы.
-
> dmk © (30.01.18 14:55) [22] > >В 3Ds max софтверные драйвера медленнее моих функций в > несколько раз. > У меня на 1 ядре ~500к полигонов с освещением по ламберту > выдает 13-15 fps. > В 3ds max на 10 ядрах - 9-10 fps. У меня на 10 ядрах ~45- > 50 fps. Мелочь, а приятно :)
не то чтобы я не доверяю, но картинки только от твоего рендера, откуда взяты данные 3ds max - не ясно, также, ну и самое главное, при сравнении fps нужно сравнивать и качество картинки ) ну и небольшое отступление - модная нынче на форуме рубрика "минутка рекламы облаков". сколько можно выкладывать фотки на всякий помойках да еще и в невменяемом качестве? https://disk.yandex.ru/https://www.dropbox.com/и т.д. там не обязательно даже устанавливать что-то, за глаза хватит и веб-версии для хостинга картинок. мне не совсем понятно, какой все таки этап ты хочешь распараллелить? вот статья для чайников https://habrahabr.ru/post/158983/ ткни пальцем, что именно ты пытаешься обрабатывать в потоках? > Но он каким то волшебным образом вылетел из процедуры и > «тусит» в другом цикле.
это ты как понял, через отладчик? так это, скорее всего, глюк отладчика, такой эффект бывает, при отладке многопоточного кода. 100% даст только логирование, в этом случае.
-
>не то чтобы я не доверяю В 3ds max работаю по основной профессии. Не то чтобы круто, но лицензия стоит. Вот видос моего редактора. Делаю в свободное время. https://yadi.sk/i/QagOQ1em3RvfjsПока делаю рендер. В основном VCL-потоке маленькие модели крутятся шустро, а мне надо сделать поддержку многопоточности для крупных моделей. В самом начале видоса - гоблин. 500к. Средняя модель. Моя версия многопоточности видимо не очень хороша, т.к. медленно. 50-55 fps всего. Надо параллелить лучше. Рендер у меня софтверный - свой. Свои примитивы, свои шейдеры и т.п. Свой mini-API. OpenGL пока не подключен, ибо пойдет потом навесом. Unity мне не надо. У меня стоит. Вот я и думаю, а как лучше реализовать многопоточность, чтобы в цикле соблюдалась последовательность рендеринга? У меня 5 этапов: 1. Очистка буферов 2. Трансформация 3. Рендеринг объектов 4. Постобработка. 5. Вывод на экран >это ты как понял, через отладчик? Ага. Вот это и напрягает. Delphi видимо плохо отлажена. У меня XE6 Prof. Хотя при запуске все 19 потокв вошли в процедуру, а вышли из нее только 15. 4 испарилось где то посередине, хотя выхода там нигде нет.
-
> dmk © (30.01.18 20:18) [26]
> Надо параллелить лучше.
в общем, исходя из всех твоих вопросов по многопоточному рендерингу, ларчик открывается просто. тебе надо подтянуть знания по работе с потоками. и в целом по системе, и в частности, по VCL. т.е. знания по графике у тебя приличные, а знания по созданию многопоточных приложений нужно подтянуть, там за вечер можно во всем разобраться, в отличие от создания графических движков ) http://rouse.drkb.ru/books.php#rihter там в самом низу. Рихтер. Есть раздел про объекты синхронизации и т.д. Интуитивно догадываюсь, что тебя в итоге спасет что-то вроде смеси семафоров и waitformultipleobjects.
-
> Моя версия многопоточности у тебя ее похоже и нет... и не нужна, судя по оговоркам о циклах потоков, ожидании завершения для начала работы другого. у тебя есть куча лишнего, путающего тебя же, кода делающего то же что вызов процедур в простом цикле... в общем есть кривая и запутанная обработка линейной логики. выкинь все лишнее связанное с потоками, упрости и все ускорится, пусть не намного (цикл или цепочка последовательных потоков равны, если +- секунды считать). ну или логику продумай под много поточность. сначала нужно конечно понять потоки, а не спрашивать "как правильно", правильно под разные случаи по разному.
-
> Delphi видимо плохо отлажена
Очевидно же
-
>Очевидно же Для 64 битов при передаче более 3-х параметров компилятор иногда помещает 4-й и более параметр в RSP+OFFSET вместо регистров или RBP+OFFSET. Что приводит к AV. Я же его не заставляю этого делать. А у меня вообще .NOFRAME стоит. Align16 не работает ни при каких обстоятельствах. Еще некоторые директивы не работают. Глюки есть. Это чтобы не слыть пустозвоном. В EDN все вопросы подняты, но стоят без ответов.
-
sniknik © (31.01.18 10:13) [28] >у тебя ее похоже и нет...
Ну почему же нет. Вот мой цикл Execute. Из вызываемых процедур в цикле только одну приведу, т.к. другие очень большие. Работает, но асинхронная передача данных приводит к визуальным глюкам. А так довольно шустро все распараллеливает. В данном случае вместо 35 fps в одном потоке - ~175-177 fps.
procedure RenderThread.ClearBufferLines; var zA, pA: QWord;
begin if (not gAllClear) then begin gLineIndex := InterlockedIncrement(gLineIndex) - 1; if (gLineIndex < RenderTarget^.BitmapRegion.H) then begin zA := RenderTarget^.ZAddress32(0, gLineIndex); pA := RenderTarget^.PAddress32(0, gLineIndex);
StoreQWords(zA, TargetLen, ZQ); StoreQWords(pA, TargetLen, 0);
gNumClearLines := InterlockedIncrement(gNumClearLines); end; end;
gAllClear := (gNumClearLines >= RenderTarget^.BitmapRegion.H); end;
procedure RenderThread.Execute; begin //Цикл отрисовки while (gDrawCounter <= gNumDrawCycles) do begin repeat ClearBufferLines; until gAllClear;
//Трансформация repeat TransformObjects(ZStars); until gAllTransformed;
//Отрисовка repeat DrawObjects(ZStars); until gAllPainted;
//Ждем конца отрисовки всеми потоками repeat until (gAllClear and gAllTransformed and gAllPainted);
//Флаг завершения обновления gUpdatingFinished := False;
//Обновляет буфер один поток if (FNumberID = 0) then begin //Загрузка процессора if (gDrawCounter mod 10) = 0 then gUsage := GetCPUUsage(gCPUTimes);
//Обновляем буфер Synchronize(TestForm.UpdateThreads); //TestForm.UpdateThreads;
//Флаг завершения обновления gUpdatingFinished := True; end;//if (gNumEntered)
//Ждем конца обновления repeat until gUpdatingFinished;
//Проверка на ESC if gESC then Break; end;//while end;
-
В данном случае мне удалось заставить потоки делать все шаги последовательно. Этот участок даже не нужен. Я его пока для отладки оставил. repeat until (gAllClear and gAllTransformed and gAllPainted); Вот что получается (видео 12 Мб): https://yadi.sk/i/-rurTadp3RxJMDПолоски в некоторых местах и иногда пробивает «нечто». На самом деле это не дочищенный Buffer.
-
> Ну почему же нет. Вот мой цикл Execute. вот поэтому - > В данном случае мне удалось заставить потоки делать все шаги последовательно. потоки работают параллельно, независимо, на разных процессорах (если их несколько), если же они работают(/их заставляют) последовательно то это просто одно поточный цикл for реализованный сложным косвенным методом.
-
>последовательно то это просто одно поточный цикл for Ну да, только многопоточный (усиленный). Этого и добиваюсь.
-
В общем сделал. Вот тут видос: https://yadi.sk/i/JOWjny6z3S3tP8Распараллеливание записано c 7:40 до 9:25. Перед этим все на одном ядре работает. Ускорение от 4,5 до 8 раз. Все упирается в скорость памяти к сожалению. Даже одно ядро забивает почти всю пропускную способность памяти. Но в целом 1 млн полигонов ~35 fps. Норм для софтрендера.
|