Конференция "Начинающим" » Потоки
 
  • dmk © (30.01.18 12:14) [20]
    >А как, я извиняюсь, другие рендеры работают, тоже со скоростью памяти мучаются ?
    Именно так. В 3Ds max софтверные драйвера медленнее моих функций в несколько раз.
  • dmk © (30.01.18 12:32) [21]
    А вообще софтвер особо не в почете, когда есть видюхи.
    Железный рендер быстрее в любом случае. Мне просто хотелось иметь свой софтверный
    вариант. Оказалось процессоры под это не особо заточены.
  • dmk © (30.01.18 14:55) [22]
    >В 3Ds max софтверные драйвера медленнее моих функций в несколько раз.
    У меня на 1 ядре ~500к полигонов с освещением по ламберту выдает 13-15 fps.
    В 3ds max на 10 ядрах - 9-10 fps. У меня на 10 ядрах ~45-50 fps. Мелочь, а приятно :)

    Вот скрин:
    https://cdn1.radikalno.ru/uploads/2018/1/30/56bf85bf6fd189af421f397e711fc325-full.jpg
  • dmk © (30.01.18 14:58) [23]
  • dmk © (30.01.18 15:08) [24]
    >разные чудеса бывают если использовать глобальные(внешние) переменные внутри
    >потоков. даже если это необходимо, но криво продумано/сделано.

    Подскажите как правильно? Во всех примерах, которые я нашел
    используются глобальные переменные с 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, что очень хотелось бы.
  • Eraser © (30.01.18 16:44) [25]

    > 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% даст только логирование, в этом случае.
  • dmk © (30.01.18 20:18) [26]
    >не то чтобы я не доверяю
    В 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 испарилось где то посередине, хотя выхода там нигде нет.
  • Eraser © (30.01.18 23:41) [27]

    > dmk ©   (30.01.18 20:18) [26]



    > Надо параллелить лучше.


    в общем, исходя из всех твоих вопросов по многопоточному рендерингу, ларчик открывается просто. тебе надо подтянуть знания по работе с потоками. и в целом по системе, и в частности, по VCL. т.е. знания по графике у тебя приличные, а знания по созданию многопоточных приложений нужно подтянуть, там за вечер можно во всем разобраться, в отличие от создания графических движков )

    http://rouse.drkb.ru/books.php#rihter там в самом низу. Рихтер.
    Есть раздел про объекты синхронизации и т.д.
    Интуитивно догадываюсь, что тебя в итоге спасет что-то вроде смеси семафоров и waitformultipleobjects.
  • sniknik © (31.01.18 10:13) [28]
    > Моя версия многопоточности
    у тебя ее похоже и нет... и не нужна, судя по оговоркам о циклах потоков, ожидании завершения для начала работы другого.
    у тебя есть куча лишнего, путающего тебя же, кода делающего то же что вызов процедур в простом цикле... в общем есть кривая и запутанная обработка линейной логики.
    выкинь все лишнее связанное с потоками, упрости и все ускорится, пусть не намного (цикл или цепочка последовательных потоков равны, если +- секунды считать). ну или логику продумай под много поточность. сначала нужно конечно понять потоки, а не спрашивать "как правильно", правильно под разные случаи по разному.
  • Игорь Шевченко © (31.01.18 10:32) [29]

    > Delphi видимо плохо отлажена


    Очевидно же
  • dmk © (31.01.18 16:10) [30]
    >Очевидно же
    Для 64 битов при передаче более 3-х параметров компилятор иногда помещает
    4-й и более параметр в RSP+OFFSET вместо регистров или RBP+OFFSET. Что приводит к AV.
    Я же его не заставляю этого делать. А у меня вообще .NOFRAME стоит.
    Align16 не работает ни при каких обстоятельствах. Еще некоторые директивы не работают.
    Глюки есть. Это чтобы не слыть пустозвоном. В EDN все вопросы подняты, но стоят без ответов.
  • dmk © (31.01.18 16:17) [31]
    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;
  • dmk © (31.01.18 16:36) [32]
    В данном случае мне удалось заставить потоки делать все шаги последовательно.
    Этот участок даже не нужен. Я его пока для отладки оставил.
    repeat until (gAllClear and gAllTransformed and gAllPainted);

    Вот что получается (видео 12 Мб):
    https://yadi.sk/i/-rurTadp3RxJMD
    Полоски в некоторых местах и иногда пробивает «нечто».
    На самом деле это не дочищенный Buffer.
  • sniknik © (31.01.18 18:43) [33]
    > Ну почему же нет. Вот мой цикл Execute.
    вот поэтому -
    > В данном случае мне удалось заставить потоки делать все шаги последовательно.
    потоки работают параллельно, независимо, на разных процессорах (если их несколько), если же они работают(/их заставляют) последовательно то это просто одно поточный цикл for реализованный сложным косвенным методом.
  • dmk © (31.01.18 20:49) [34]
    >последовательно то это просто одно поточный цикл for
    Ну да, только многопоточный (усиленный). Этого и добиваюсь.
  • dmk © (03.02.18 07:04) [35]
    В общем сделал. Вот тут видос: https://yadi.sk/i/JOWjny6z3S3tP8
    Распараллеливание записано c 7:40 до 9:25. Перед этим все на одном ядре работает.
    Ускорение от 4,5 до 8 раз. Все упирается в скорость памяти к сожалению.
    Даже одно ядро забивает почти всю пропускную способность памяти.
    Но в целом 1 млн полигонов ~35 fps. Норм для софтрендера.
 
Конференция "Начинающим" » Потоки
Есть новые Нет новых   [118622   +8][b:0][p:0.001]