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

оптимизировать цикл

есть контроллер кортекс, подключенный к нему через FPGA дисплей

вывожу картинку старого формата XBM на экран монитора

DMAнет  и выводить нужно попиксельно

экран долго рисует, что ожидаемо

 

/**
 * Вывести файл XBM (ширина должна делиться на 8!!!)
 */
void bitmap_draw_xbm(const char* bmp, int width, int height)
{
    u32 k = 0;
    u8 m = 0, pix;

    for (int y = 0; y < height; y++) {
	for (int x = 0; x < width; x++) {
	    pix = bmp[k];
	    pix = (pix >> m) & 1;
	    display_put_pixel(x, DISPLAY_HEIGTH - y, pix == 0? 0xFFFF: 0);            

	    m++;
	    if (m == 8) {
		k++;
		m = 0;
	    }
	}
    }
}

            
        
    
    

формат XBM такой, если кто не знает:

#define x_width 512
#define x_height 512
static char x_bits[] = {
0x28, 0x8a, 0xe2, 0x3f, 0xfe, 0xf3,

каждый бит в байте и сдвигать

выводя попиксельно

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


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

Восемь раз подряд один и тот же адрес памяти читать "pix = bmp[k];" в цикле по x не накладно?

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


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

это я уже убрал и сделал так:

    for (int y = 0; y < height; y++) {
    for (int x = 0; x < width; x += 8, k++) {
        pix = *(bmp + k);

            p0 = pix & 1;
            p1 = pix & 2;            
            p2 = pix & 4;
            p3 = pix & 8;            

            p4 = pix & 16;
            p5 = pix & 32;            
            p6 = pix & 64;
            p7 = pix & 128;            
            
        display_put_pixel(x, DISPLAY_HEIGTH - y, p0 == 0? 0xFFFF: 0);            
        display_put_pixel(x + 1, DISPLAY_HEIGTH - y, p1 == 0? 0xFFFF: 0);            
        display_put_pixel(x + 2, DISPLAY_HEIGTH - y, p2 == 0? 0xFFFF: 0);            
        display_put_pixel(x + 3, DISPLAY_HEIGTH - y, p3 == 0? 0xFFFF: 0);            

        display_put_pixel(x + 4, DISPLAY_HEIGTH - y, p4 == 0? 0xFFFF: 0);            
        display_put_pixel(x + 5, DISPLAY_HEIGTH - y, p5 == 0? 0xFFFF: 0);            
        display_put_pixel(x + 6, DISPLAY_HEIGTH - y, p6 == 0? 0xFFFF: 0);            
        display_put_pixel(x + 7, DISPLAY_HEIGTH - y, p7 == 0? 0xFFFF: 0);            
    }
    }

но все равно скорость не достаточная

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


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

30 minutes ago, inventor said:

это я уже убрал и сделал так:


    for (int y = 0; y < height; y++) {
    for (int x = 0; x < width; x += 8, k++) {
        pix = *(bmp + k);

            p0 = pix & 1;
            p1 = pix & 2;            
            p2 = pix & 4;
            p3 = pix & 8;            

            p4 = pix & 16;
            p5 = pix & 32;            
            p6 = pix & 64;
            p7 = pix & 128;            
            
        display_put_pixel(x, DISPLAY_HEIGTH - y, p0 == 0? 0xFFFF: 0);            
        display_put_pixel(x + 1, DISPLAY_HEIGTH - y, p1 == 0? 0xFFFF: 0);            
        display_put_pixel(x + 2, DISPLAY_HEIGTH - y, p2 == 0? 0xFFFF: 0);            
        display_put_pixel(x + 3, DISPLAY_HEIGTH - y, p3 == 0? 0xFFFF: 0);            

        display_put_pixel(x + 4, DISPLAY_HEIGTH - y, p4 == 0? 0xFFFF: 0);            
        display_put_pixel(x + 5, DISPLAY_HEIGTH - y, p5 == 0? 0xFFFF: 0);            
        display_put_pixel(x + 6, DISPLAY_HEIGTH - y, p6 == 0? 0xFFFF: 0);            
        display_put_pixel(x + 7, DISPLAY_HEIGTH - y, p7 == 0? 0xFFFF: 0);            
    }
    }

но все равно скорость не достаточная

основное время тратится скорее всего вот тут

display_put_pixel

можно посмотреть как это реализовано и как то оптимизировать. например выводить не по 1 точке а сразу 8

 

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


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

Just now, Zeal0t said:

можно посмотреть как это реализовано и как то оптимизировать. например выводить не по 1 точке а сразу 8

 

это просто запись в память

    (*((volatile u32 *) (addr))) = col;

вероятно сама плис долго выводит

решили сделать 2 адресных пространства

1-е попиксельное рисование в цветах

2-е вывожу двойное слово где каждый бит- ч/б пиксель

так будет быстрее работать

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


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

2 часа назад, inventor сказал:

экран долго рисует, что ожидаемо

А что такое display_put_pixel() - предлагаете телепатам угадать? Очередная угадайка....

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


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

Восемь раз display_put_pixel вызывается и каждый раз аргумент вычисляется (DISPLAY_HEIGTH - y): есть гарантия что не 8 раз одно и то же? Из цикла по x - долой...

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


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

22 minutes ago, inventor said:

   (*((volatile u32 *) (addr))) = col;

Зачем volatile?
 

pix = *bmp++;

*outpix++ = (pix & 1) ? 0xFFFF : 0;
*outpix++ = (pix & 2) ? 0xFFFF : 0;
*outpix++ = (pix & 4) ? 0xFFFF : 0;
*outpix++ = (pix & 8) ? 0xFFFF : 0;
*outpix++ = (pix & 16) ? 0xFFFF : 0;
*outpix++ = (pix & 32) ? 0xFFFF : 0;
*outpix++ = (pix & 64) ? 0xFFFF : 0;
*outpix++ = (pix & 128) ? 0xFFFF : 0;

 

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


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

2 часа назад, amaora сказал:

Зачем volatile?

А зачем такая куча условных выражений? Ведь каждое - это ветвление, а значит особенные тормоза.

Цитата

 


pix = *bmp++;

*outpix++ = (pix & 1) ? 0xFFFF : 0;
*outpix++ = (pix & 2) ? 0xFFFF : 0;
*outpix++ = (pix & 4) ? 0xFFFF : 0;
*outpix++ = (pix & 8) ? 0xFFFF : 0;
*outpix++ = (pix & 16) ? 0xFFFF : 0;
*outpix++ = (pix & 32) ? 0xFFFF : 0;
*outpix++ = (pix & 64) ? 0xFFFF : 0;
*outpix++ = (pix & 128) ? 0xFFFF : 0;

 

ТС как будто сделал целью сделать как можно более тормозной код. Только такое объяснение нахожу этой куче лишних переменных и ветвлений...  :russian_ru:

Да и у ТСа вроде при бите==0 должно получаться 0xFFFF, а у Вас - наоборот.

Если у ТСа внутри этого секретного макроса display_put_pixel() (и макроса ли?) действительно именно такие записи в память, то всё делается много лаконичнее и быстрее:

int i = ~*bmp++;
*outpix++ = i << 31 >> 31 & 0xFFFF;
*outpix++ = i << 30 >> 31 & 0xFFFF;
*outpix++ = i << 29 >> 31 & 0xFFFF;
...  

При полной оптимизации это должно дать всего по 3 ассемблерных команды на каждый бит.

А вообще низкоуровневая оптимизация делается низкоуровневыми средствами - ассемблером. Так можно сделать ещё оптимальнее.

 

PS: А дальше надо смотреть - а зачем 32-битные записи, если старшие 16 бит содержимого памяти всегда ==0? Может хватит 16-битных записей? И, если внешняя шина к FPGA у ТСа 16-разрядная, то это может дать существенный прирост скорости.

Вобщем - при таком уровне информации, когда ТС 90% данных утаил трудно что-то насоветовать разумное...  :unknw:

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


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

Самый быстрый способ могу предложить только такой:

	SBFX   R1,R0,#0,#1
	STRH   R1,[R2,#0]   
	SBFX   R1,R0,#1,#1
	STRH   R1,[R2,#2]
	....
	SBFX   R1,R0,#7,#1
	STRH   R1,[R2,#14]
	

По два такта на пиксель.

Это вполне и при помощи GCC inline asm делается, так что можно обойтись без отдельного модуля на ассемблере.

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

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


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

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

А зачем такая куча условных выражений? Ведь каждое - это ветвление, а значит особенные тормоза.

Я дополню. Если процессорный конвейер равен 6-ти, то каждое ветвление, т.е. вызов или возврат - это 6 тактов ожидания. В этом плане проще сделать 6 команд последовательно, чем одно ветвление. Ну и тут надо смотреть, есть ли команды не "перехода по условию", а "пропуска команды по условию"... Потому как пропуск команды - это только один такт, а не 6...

А вот дальше надо смотреть, как именно производится запись в экранную память. Если запись возможно только на обратном ходе луча, то можно посчитать, сколько циклов записи туда влезет. И возможно, что быстрее будет подсинхронизироваться с этим процессом - на прямом ходе луча вычислять, а на обратном быстро, быстро писать в экранную память...

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


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

13 минут назад, Rst7 сказал:

Самый быстрый способ могу предложить только такой:

По два такта на пиксель.

Это так можно только если действительно можно не записывать старшие 16 бит. Я выше уже писал об этом.

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


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

29 minutes ago, jcxz said:

Это так можно только если действительно можно не записывать старшие 16 бит. Я выше уже писал об этом.

Я так думаю, что если сдуру там и сделано 32 бита только, то можно писать не 0 и 0xFFFF, а 0 и 0xFFFFFFFF почти наверняка.

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


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

13 hours ago, jcxz said:

А что такое display_put_pixel() - предлагаете телепатам угадать? Очередная угадайка....

/**
 * Вывод пикселя на экран с координатами x, y и с заданым цветом
 */
IDEF void display_put_pixel(u16 x, u16 y, u16 col)
{
    volatile u32 addr;


    if (x < DISPLAY_WIDTH && y < DISPLAY_HEIGTH) {

    /* расчитаем координаты точки */
    addr = DISPLAY_START_ADDR + (((DISPLAY_HEIGTH - y - 1) * DISPLAY_WIDTH + x) << 2);

    /* Выведем точку */
    *((u32 *) (addr)) = col;
//      printf("%d, %d; ", x, y);
    }
}

IDEF это static inline

13 hours ago, Obam said:

Восемь раз display_put_pixel вызывается и каждый раз аргумент вычисляется (DISPLAY_HEIGTH - y): есть гарантия что не 8 раз одно и то же? Из цикла по x - долой...

убрал 

        u16 h = DISPLAY_HEIGTH - y;    

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


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

2 часа назад, inventor сказал:

    if (x < DISPLAY_WIDTH && y < DISPLAY_HEIGTH) {

    /* расчитаем координаты точки */
    addr = DISPLAY_START_ADDR + (((DISPLAY_HEIGTH - y - 1) * DISPLAY_WIDTH + x) << 2);

    /* Выведем точку */
    *((u32 *) (addr)) = col;
//      printf("%d, %d; ", x, y);
    }

 

Да уж... Вы действительно сделали всё, чтобы затормозить работу как можно сильнее...  :hang1:

13 часов назад, Rst7 сказал:

Я так думаю, что если сдуру там и сделано 32 бита только, то можно писать не 0 и 0xFFFF, а 0 и 0xFFFFFFFF почти наверняка.

Глядя на код ТС-а, там можно ожидать чего угодно.  :russian_ru:

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


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

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

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

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

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

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

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

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

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

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