Если вас не слишком заботит точность, то этот внутренний цикл должен дать вам вдвое большую вычислительную производительность по сравнению с более точным алгоритмом:
for (i=0; i<640; i+= 32)
{
uint8x16x2_t a, b;
uint8x16_t c, d;
/* load upper row, splitting even and odd pixels into a.val[0]
* and a.val[1] respectively. */
a = vld2q_u8(src1);
/* as above, but for lower row */
b = vld2q_u8(src2);
/* compute average of even and odd pixel pairs for upper row */
c = vrhaddq_u8(a.val[0], a.val[1]);
/* compute average of even and odd pixel pairs for lower row */
d = vrhaddq_u8(b.val[0], b.val[1]);
/* compute average of upper and lower rows, and store result */
vst1q_u8(dest, vrhaddq_u8(c, d));
src1+=32;
src2+=32;
dest+=16;
}
Он работает с использованием операции vhadd
, результат которой имеет тот же размер, что и ввод. Таким образом, вам не нужно смещать окончательную сумму обратно к 8-битной, а вся арифметика выполняется восьмибитной, что означает, что вы можете выполнять в два раза больше операций за инструкцию.
Однако он менее точен, потому что промежуточная сумма квантуется, а GCC 4.7 ужасно справляется с генерацией кода. GCC 4.8 работает нормально.
Однако вся операция имеет хорошие шансы быть привязанной к вводу-выводу. Цикл следует развернуть, чтобы максимизировать разделение между загрузками и арифметикой, а __builtin_prefetch()
(или PLD
) следует использовать для подъема входящих данных в кэш до того, как они потребуются.
person
sh1
schedule
07.08.2013