Jump to content

    
Salamander

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

Recommended Posts

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

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

Share this post


Link to post
Share on other sites
3 минуты назад, Salamander сказал:

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

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

Share this post


Link to post
Share on other sites
3 minutes ago, jcxz said:

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

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

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

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

 

Share this post


Link to post
Share on other sites
4 минуты назад, Salamander сказал:

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

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

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

Share this post


Link to post
Share on other sites
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

 

Share this post


Link to post
Share on other sites
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-вызовах. Если это возможно.

Share this post


Link to post
Share on other sites
15 minutes ago, Salamander said:

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

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

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

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

Share this post


Link to post
Share on other sites
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

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

 

Share this post


Link to post
Share on other sites
5 минут назад, Salamander сказал:

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

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

Edited by MrBearManul

Share this post


Link to post
Share on other sites
3 минуты назад, Salamander сказал:

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

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

Share this post


Link to post
Share on other sites
Цитата

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

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

 

Цитата

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

Удалить.

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

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

 

Share this post


Link to post
Share on other sites
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 выкинуть.

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

Share this post


Link to post
Share on other sites

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

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

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

 

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

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

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

Share this post


Link to post
Share on other sites
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;
}

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

Share this post


Link to post
Share on other sites
7 минут назад, Salamander сказал:

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

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

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

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.