Перейти к содержанию
    

Как наибыстрейше вывести на экран точку?

Господа, я с месяц назад создавал тут тему, с вопросом по 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);
		}
	}
}

Скажите, как можно сделать вывод точки рациональнее и изящнее?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 минуты назад, Salamander сказал:

Скажите, как можно сделать вывод точки рациональнее и изящнее?

Рисовать не точками, а графическими примитивами. Или использовать другие соответствующие функции API.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 minutes ago, jcxz said:

Рисовать не точками, а графическими примитивами. Или использовать другие соответствующие функции API.

Так я и нарисовал графическим примитивом - прямоугольником. Вы посмотрите,  сколько там вычислений и операций. Понятно, что оно грузит процессор.

полюбуйтесь https://cloud.mail.ru/public/DGUX/TZoRw7stw

А вот как работает на том же STM32F746 у автора библиотеки   

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 минуты назад, Salamander сказал:

Так я и нарисовал графическим примитивом - прямоугольником.

Прямоугольник 1x1 - это и есть точка.

"Рисовать графическимми примитивами" - это значит рисовать 3D-поверхность не самостоятельно точками, а использовать соответствующие функции имеющегося API (что там есть - рисование треугольника в 3-мерных координатах (и из треугольников набирать поверхность) или сразу рисование поверхности описанной N точками).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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-вызовах. Если это возможно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

15 minutes ago, Salamander said:

Вот основной файл библиотеки

https://github.com/FabioRM/dsp3D/blob/master/src/dsp3D.c

по идее, код в нем не нуждается в редакции

Видно что код явно излишний для STM-ов с векторным ускорителем. Там клипинг и матричные повороты и другие афинные преобразования делаются аппаратно.
Этот Fabio Angeletti явно не дурак, и оставил за собой вероятно добрый кусок оптимизированного кода. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Вот есть товарищ, который запустил библиотеку недурака Фабио 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 минут назад, Salamander сказал:

Но вот беда, мой keil не знает , что такое __no_init . Как с этим быть?

Этот аттрибут всего лишь заставляет поместить массив в секцию ОЗУ, которая при запуске программы не будет инициализирована значениями по-умолчанию. Можете смело опустить пока. А потом почитать документацию на ваш компилятор и подобрать что-то подходящее. От этого будет зависить скорость запуска ПО, но вряд ли это сейчас для вас критично.

Изменено пользователем MrBearManul

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 минуты назад, Salamander сказал:

Но вот беда, мой keil не знает , что такое __no_init . Как с этим быть?

Для тестов можно и без __no_init. Это влияет сейчас, по сути, только на скорость передачи управления в main().

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Цитата

для двойной буферизации.

Исходя из названия, вангую что dsp3D_LL_writeToDepthBuffer - не "для двойной буферизации", а для задания некоей глубины чего-то на текущей картинке.

 

Цитата

Но вот беда, мой keil не знает , что такое __no_init . Как с этим быть?

Удалить.

__no_init - означает, что переменную не нужно инициализировать. В данном конкретном случае - это просто для оптимизации (убирания ненужного заполнения 0-ми очевидно большого массива при старте ПО).

Если не знаете замены ему в Keil - просто удалите, будет просто медленнее стартовать ПО.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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 выкинуть.

нет.... проверка границ ни при чем, все равно медленно...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да - чё-то я слишком поверхностно глянул на dsp3D_LL_drawPoint(). А там идут не проверки на min/max, а видимо накопление min/max координат выводимых точек.

Если заранее знаете в какой размер окна выводите - то и эти проверки можно (нужно) выкинуть. Или если всё равно будете целиком видеобуфер на экран копировать.

Тогда можно вообще dsp3D_LL_drawPoint() определить как макрос - будет быстрее (если либа в исходниках).

 

5 минут назад, Salamander сказал:

нет.... проверка границ ни при чем, все равно медленно...

Причём! Посмотрите на результирующий листинг. И удалите её нафиг.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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;
}

это нафиг? Если да, то медленно

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

7 минут назад, Salamander сказал:

То есть, тупо, атомарно пишу в память. Скорость не увеличилась ни на грамм.

Этого не может быть. Чтобы при замене огромной функции TFT_FillRectangle() на одну запись в память не было никакого ускорения - не может такого быть. Значит у вас проблема в чём-то другом.

И зачем там ещё умножение на 3?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...