Быстрое копирование массивов с условием

krikus
Offline
Зарегистрирован: 22.07.2011

Доброго времени суток.
У меня вопрос по поводу копирования массивов.
Есть два массива:

Код C++
1
2
uint8_t mainbuf[320*240];
uint8_t cb[16*16];

Мне нужно скопировать массив cb в mainbuf на определенные координаты, с условием, что значение ячейки cb != 0xE3. Пока реализую так:

Код C++
1
2
3
4
5
6
7
void set(int x, int y) {
   for (unsigned char i=0; i<16; ++i) {
       for (unsigned char j=0; j<16; ++j) {
           if (cb[j*16+i]!=0xE3) mainbuf[(y+j)*320+(x+i)] = cb[j*16+i];
       }
   }
}

Эта операция происходит очень медленно, а таких операций проводится довольно много.
Как можно это оптимизировать? memcpy - ? - но там нельзя использовать условия.
Прошу вашей помощи.
Заранее спасибо 

step962
Offline
Зарегистрирован: 23.05.2011

krikus пишет:

Как можно это оптимизировать?

Ну, для начала следует вынести операции умножения из внутреннего цикла:

void set(int x, int y) {
  for (unsigned char j=0; j<16; ++j) {
    p=j*16;
    py=(y+j)*320;
    for (unsigned char i=0; i<16; ++i) {
      if (cb[p+i]!=0xE3) mainbuf[py+(x+i)] = cb[p+i];
    }
  }
}

Это уже даст приращение в скорости.

На втором шаге можно вообще от умножений избавиться - еще ощутимое ускорение.

Osseum
Offline
Зарегистрирован: 25.04.2013
void set(int x, int y) 
{
   int p=0;
   int py=y*320+x;
   for (unsigned char j=0; j<16; ++j)
   {
	    for (unsigned char i=0; i<16; ++i)
            {
	      if (cb[p]!=0xE3) mainbuf[py] = cb[p];
              p++;
              py++;
	     }
           py+=304; // 304=320-16
   }
}
//Если избавляться от умножений совсем, как сказал step962. В коде мог ошибиться.

 

krikus
Offline
Зарегистрирован: 22.07.2011

Спасибо, скорость действительно поднилась (немного). А что если распараллелить цикл, скорость возрастет?

__Alexander
Offline
Зарегистрирован: 24.10.2012

может легче при выводе массива 320х240 знать адрес вывода второго массива? Толку копировать, если массив это просто последовательно заполненый кусок памяти.

krikus
Offline
Зарегистрирован: 22.07.2011

Все не совсем так просто. У меня есть много массивов 16*16(с флагом PROGMEM) и один огромный массив 320*240. Мне нужно вывести на определенные координаты большого массива малый массив 16*16. 

А вообще, все это графическая система. Большой массив - видео-память. Малые массивы - спрайты(маленькие изображения).

Проблему почти решил. Сделал как писали step962 и Osseum. Также применил распараллелизацию цикла. Скорость заметно поднилась, но все же...

mixail844
Offline
Зарегистрирован: 30.04.2012

предлагаю сделать внешеий цикл while(cb[i]!=0xE3){...}

хотя полагаю у вас таких ячеек не особо много

__Alexander
Offline
Зарегистрирован: 24.10.2012

krikus пишет:

А вообще, все это графическая система. Большой массив - видео-память. Малые массивы - спрайты(маленькие изображения).

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

krikus
Offline
Зарегистрирован: 22.07.2011

Очень хорошая идея. Жаль, что в моем случае это невозможно. Я не могу управлять выводом большого массива, так как выводит его не ЦПУ контроллера, а DMA контроллер напрямую из ОЗУ и отправляет на порты.

__Alexander
Offline
Зарегистрирован: 24.10.2012

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

krikus
Offline
Зарегистрирован: 22.07.2011

Ну не знаю... Я работаю с Arduino Due и VGA выводом. Я использовал спец. библиотеку Vga, там все сделано на DMA(контроллер прямого доступа к памяти). Я пытался переключить адрес в регистре у DMA - ничего не заработало. Да и не особо я умею обращаться с DMA, однако весч это очень полезная.

PS: Если разберусь, попробую сделать переключение адреса.