Salamander 0 Posted January 10 · Report post Господа, я с месяц назад создавал тут тему, с вопросом по 3d библиотеке https://github.com/FabioRM/dsp3D под STM32 Дошел до отрисовки в режиме Wireframe, с режимом Flat забуксовал и забросил малость. Сейчас разобрался и обнаружил что у меня отрисовка идет очень медленно. Это вопрос не к самой библиотеке - в ней есть функция void dsp3D_LL_drawPoint(uint32_t x, uint32_t y, color32_t color) { if(x < minX) minX = x; if(x > maxX) maxX = x; if(y < minY) minY = y; if(y > maxY) maxY = y; // YOUR IMPLEMENTATION } Где нужно прописать свой код вывода точки. Я вывожу прямоугольник с размерами 1х1 oid TFT_FillRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint32_t color) { #define swap(a,b) {int16_t t=a;a=b;b=t;} if(x1>x2) swap(x1,x2); if(y1>y2) swap(y1,y2); uint32_t addr=0; addr = hltdc.LayerCfg[0].FBStartAdress + 3*(y1*hltdc.LayerCfg[0].ImageWidth+x1); hdma2d.Init.Mode = DMA2D_R2M; hdma2d.Init.OutputOffset = hltdc.LayerCfg[0].ImageWidth - (x2-x1); if(HAL_DMA2D_Init(&hdma2d) == HAL_OK) { if(HAL_DMA2D_Start(&hdma2d, color, addr, x2-x1, y2-y1) == HAL_OK) { HAL_DMA2D_PollForTransfer(&hdma2d, 10); } } } Скажите, как можно сделать вывод точки рациональнее и изящнее? Quote Ответить с цитированием Share this post Link to post Share on other sites
jcxz 0 Posted January 10 · Report post 3 минуты назад, Salamander сказал: Скажите, как можно сделать вывод точки рациональнее и изящнее? Рисовать не точками, а графическими примитивами. Или использовать другие соответствующие функции API. Quote Ответить с цитированием Share this post Link to post Share on other sites
Salamander 0 Posted January 10 · Report post 3 minutes ago, jcxz said: Рисовать не точками, а графическими примитивами. Или использовать другие соответствующие функции API. Так я и нарисовал графическим примитивом - прямоугольником. Вы посмотрите, сколько там вычислений и операций. Понятно, что оно грузит процессор. полюбуйтесь https://cloud.mail.ru/public/DGUX/TZoRw7stw А вот как работает на том же STM32F746 у автора библиотеки Quote Ответить с цитированием Share this post Link to post Share on other sites
jcxz 0 Posted January 10 · Report post 4 минуты назад, Salamander сказал: Так я и нарисовал графическим примитивом - прямоугольником. Прямоугольник 1x1 - это и есть точка. "Рисовать графическимми примитивами" - это значит рисовать 3D-поверхность не самостоятельно точками, а использовать соответствующие функции имеющегося API (что там есть - рисование треугольника в 3-мерных координатах (и из треугольников набирать поверхность) или сразу рисование поверхности описанной N точками). Quote Ответить с цитированием Share this post Link to post Share on other sites
Salamander 0 Posted January 10 · Report post 3 minutes ago, jcxz said: функции имеющегося API Какого API? 3d библиотеки? Так она платформонезависима, в ней чистый сишный код, который сам все делает и в фундамент программы нужно только заложить функцию вывода точки, потому как библиотека не знает, на каком железе это будет запускаться. функция dsp3D_LL_drawPoint вызывается в самом конце расчета, когда цвет точки уже ясен, осталось ее только вывести. Это как в FatFS - весь код независим, нужно только прописать функции записи и чтения секторов. Вот основной файл библиотеки https://github.com/FabioRM/dsp3D/blob/master/src/dsp3D.c по идее, код в нем не нуждается в редакции прописать низкоуровневые йункции нужно только здесь https://github.com/FabioRM/dsp3D/blob/master/LowLevelTemplate/dsp3D_LL_template.c Quote Ответить с цитированием Share this post Link to post Share on other sites
jcxz 0 Posted January 10 · Report post 14 минут назад, Salamander сказал: нужно только заложить функцию вывода точки, потому как библиотека не знает, на каком железе это будет запускаться. Тогда - выделить в ОЗУ видеобуфер под весь кадр и выводить точки туда. А после формирования всего кадра только копировать их в видео-ОЗУ. Типа такого: __no_init color32_t videoBuf[RESOLUTION_X * RESOLUTION_Y]; void dsp3D_LL_drawPoint(uint32_t x, uint32_t y, color32_t color) { if(x < minX) minX = x; if(x > maxX) maxX = x; if(y < minY) minY = y; if(y > maxY) maxY = y; videoBuf[y * RESOLUTION_X + x] = color; } PS: Да и проверки на min/max - тоже лучше выкинуть для скорости, а ограничения делать для координат в API-вызовах. Если это возможно. Quote Ответить с цитированием Share this post Link to post Share on other sites
AlexandrY 0 Posted January 10 · Report post 15 minutes ago, Salamander said: Вот основной файл библиотеки https://github.com/FabioRM/dsp3D/blob/master/src/dsp3D.c по идее, код в нем не нуждается в редакции Видно что код явно излишний для STM-ов с векторным ускорителем. Там клипинг и матричные повороты и другие афинные преобразования делаются аппаратно. Этот Fabio Angeletti явно не дурак, и оставил за собой вероятно добрый кусок оптимизированного кода. Quote Ответить с цитированием Share this post Link to post Share on other sites
Salamander 0 Posted January 10 · Report post 1 minute ago, jcxz said: Тогда - выделить в ОЗУ видеобуфер под весь кадр и выводить точки туда. А после формирования всего кадра только копировать их в видео-ОЗУ. Типа такого: Хорошая идея. Мне кажется, она согласуется с тем фактом, что в библиотеке есть еще функции void dsp3D_LL_switchScreen(void) { // YOUR IMPLEMENTATION } void dsp3D_LL_writeToDepthBuffer(uint32_t pos, float32_t value) { // YOUR IMPLEMENTATION } для двойной буферизации. Но вот беда, мой keil не знает , что такое __no_init . Как с этим быть? 1 minute ago, AlexandrY said: Видно что код явно излишний для STM-ов с векторным ускорителем. Там клипинг и матричные повороты и другие афинные преобразования делаются аппаратно. Этот Fabio Angeletti явно не дурак, и оставил за собой вероятно добрый кусок оптимизированного кода. За собой он оставил только то, что в функциях, в названиях которых есть LL Вот есть товарищ, который запустил библиотеку недурака Фабио Quote Ответить с цитированием Share this post Link to post Share on other sites
MrBearManul 0 Posted January 10 (edited) · Report post 5 минут назад, Salamander сказал: Но вот беда, мой keil не знает , что такое __no_init . Как с этим быть? Этот аттрибут всего лишь заставляет поместить массив в секцию ОЗУ, которая при запуске программы не будет инициализирована значениями по-умолчанию. Можете смело опустить пока. А потом почитать документацию на ваш компилятор и подобрать что-то подходящее. От этого будет зависить скорость запуска ПО, но вряд ли это сейчас для вас критично. Edited January 10 by MrBearManul Quote Ответить с цитированием Share this post Link to post Share on other sites
Arlleex 0 Posted January 10 · Report post 3 минуты назад, Salamander сказал: Но вот беда, мой keil не знает , что такое __no_init . Как с этим быть? Для тестов можно и без __no_init. Это влияет сейчас, по сути, только на скорость передачи управления в main(). Quote Ответить с цитированием Share this post Link to post Share on other sites
jcxz 0 Posted January 10 · Report post Цитата для двойной буферизации. Исходя из названия, вангую что dsp3D_LL_writeToDepthBuffer - не "для двойной буферизации", а для задания некоей глубины чего-то на текущей картинке. Цитата Но вот беда, мой keil не знает , что такое __no_init . Как с этим быть? Удалить. __no_init - означает, что переменную не нужно инициализировать. В данном конкретном случае - это просто для оптимизации (убирания ненужного заполнения 0-ми очевидно большого массива при старте ПО). Если не знаете замены ему в Keil - просто удалите, будет просто медленнее стартовать ПО. Quote Ответить с цитированием Share this post Link to post Share on other sites
Salamander 0 Posted January 10 · Report post 25 minutes ago, jcxz said: Типа такого: Я вместо организации буфера сделал такой вариант void dsp3D_LL_drawPoint(uint32_t x, uint32_t y, color32_t color) { if(x < minX) minX = x; if(x > maxX) maxX = x; if(y < minY) minY = y; if(y > maxY) maxY = y; // YOUR IMPLEMENTATION *(__IO uint32_t*)(0xD0000000 + 3*(y * SCREEN_WIDTH + x))=color; } То есть, тупо, атомарно пишу в память. Скорость не увеличилась ни на грамм. Значит тормозит само API? Сейчас попробую проверку minX,minY выкинуть. нет.... проверка границ ни при чем, все равно медленно... Quote Ответить с цитированием Share this post Link to post Share on other sites
jcxz 0 Posted January 10 · Report post Да - чё-то я слишком поверхностно глянул на dsp3D_LL_drawPoint(). А там идут не проверки на min/max, а видимо накопление min/max координат выводимых точек. Если заранее знаете в какой размер окна выводите - то и эти проверки можно (нужно) выкинуть. Или если всё равно будете целиком видеобуфер на экран копировать. Тогда можно вообще dsp3D_LL_drawPoint() определить как макрос - будет быстрее (если либа в исходниках). 5 минут назад, Salamander сказал: нет.... проверка границ ни при чем, все равно медленно... Причём! Посмотрите на результирующий листинг. И удалите её нафиг. Quote Ответить с цитированием Share this post Link to post Share on other sites
Salamander 0 Posted January 10 · Report post 3 minutes ago, jcxz said: ричём! Посмотрите на результирующий листинг. И удалите её нафиг. Вот так void dsp3D_LL_drawPoint(uint32_t x, uint32_t y, color32_t color) { /* if(x < minX) minX = x; if(x > maxX) maxX = x; if(y < minY) minY = y; if(y > maxY) maxY = y; */ // YOUR IMPLEMENTATION //TFT_FillRectangle(x,y,x+1,y+1,color); //videoBuf[y * SCREEN_WIDTH + x] = color; *(__IO uint32_t*)(0xD0000000 + 3*(y * SCREEN_WIDTH + x))=color; } это нафиг? Если да, то медленно Quote Ответить с цитированием Share this post Link to post Share on other sites
jcxz 0 Posted January 10 · Report post 7 минут назад, Salamander сказал: То есть, тупо, атомарно пишу в память. Скорость не увеличилась ни на грамм. Этого не может быть. Чтобы при замене огромной функции TFT_FillRectangle() на одну запись в память не было никакого ускорения - не может такого быть. Значит у вас проблема в чём-то другом. И зачем там ещё умножение на 3? Quote Ответить с цитированием Share this post Link to post Share on other sites