2012-04-12 4 views
3

Мне нужна подсказка, как реализовать эту функцию Delphi с помощью сборки SSE2 (32 бит). Другие оптимизации также приветствуются. Может быть, можно сказать, какие инструкции можно использовать, поэтому у меня есть отправная точка для дальнейшего чтения.Как оптимизировать эту функцию Delphi с помощью SSE2?

Actual:

const Precision = 10000; 

// This function adds all Pixels into one. The pixels are weighted before adding. 
// A weight can range from 0 to "Precision". "Size" is typically 10 to 50. 

function TFilter.Combine(Pixels: PByte; Weights: PCardinal; const Size: Cardinal): Cardinal; 
var 
    i, R, G, B, A: Cardinal; 
begin 
    B := Pixels^ * Weights^; Inc(Pixels); 
    G := Pixels^ * Weights^; Inc(Pixels); 
    R := Pixels^ * Weights^; Inc(Pixels); 
    A := Pixels^ * Weights^; Inc(Pixels); 
    Inc(Weights); // goto next weight 
    for i := 1 to Size - 1 do 
    begin 
    Inc(B, Pixels^ * Weights^); Inc(Pixels); 
    Inc(G, Pixels^ * Weights^); Inc(Pixels); 
    Inc(R, Pixels^ * Weights^); Inc(Pixels); 
    Inc(A, Pixels^ * Weights^); Inc(Pixels); 
    Inc(Weights); // goto next weight 
    end; 
    B := B div Precision; 
    G := G div Precision; 
    R := R div Precision; 
    A := A div Precision; 

    Result := A shl 24 or R shl 16 or G shl 8 or B; 
end; 

Ожидаемый:

function TFilter.Combine(Pixels: PByte; Weights: PCardinal; const Size: Cardinal): Cardinal; 
asm 
    // Insert fast SSE2-Code here ;-) 
end; 
+5

I Посмотрите на GR32 и посмотрите, есть ли у вас рутина, в которой вы нуждаетесь. Если нет, то у него есть много оптимизированных SSE2, которые вы могли бы использовать в качестве учебного ресурса. –

+0

Сколько пикселей это объединить сразу? Я спрашиваю, потому что, если число достаточно мало, вы не увидите заметного ускорения из-за всех накладных расходов. Кроме того, значения веса должны быть 32 бита? Будут ли 16 бит содержать их? –

+0

Весовые значения не обязательно должны быть 32 бита, так как они варьируются только до точности 10000 (подходит в 16 бит). –

ответ

10

Довольно простая реализация. Я изменил ваш прототип функции - регулярную функцию (против метода объекта).

Этот код работает около 3х раз быстрее, чем байт-на-байт функции (1500 мс для 1000000 итераций на массиве 256-элементного, примерно 0,7 Гб/сек на моем старом Athlon XP 2.2 ГГц)

function Combine(Pixels: PByte; Weights: PInteger; const Size: Cardinal): Integer; 
//x86, register calling convention - three parameters in EAX, EDX, ECX 
const 
    Precision: Single = 1.0; 
asm 
    pxor XMM6, XMM6 //zero const 
    pxor XMM4, XMM4 // zero accum 

@@cycle: 
    movd XMM1, [eax] //load color data 
    movss XMM3, [edx] //load weight 

    punpcklbw XMM1, XMM6 //bytes to words 
    shufps XMM3, XMM3, 0 // 4 x weight 
    punpcklwd XMM1, XMM6 //words to ints 
    cvtdq2ps XMM2, XMM3 //ints to singles 
    cvtdq2ps XMM0, XMM1 //ints to singles 

    mulps XMM0, XMM2 //data * weight 
    addps XMM4, XMM0 //accum = accum + data * weight 

    add eax, 4  // inc pointers 
    add edx, 4 
    loop @@cycle 

    movss XMM5, Precision 
    shufps XMM5, XMM5, 0 // 4 x precision constant 

    divps XMM4, XMM5 //accum/precision 

    cvtps2dq XMM2, XMM4 //rounding singles to ints 
    packssdw XMM2, XMM2 //ints to ShortInts 
    packuswb XMM2, XMM2 //ShortInts to bytes 

    movd eax, XMM2 //result 
end; 
+0

Ничего себе, я не ожидал полной версии! ;-) И да, это работает как шарм. Ускорение на моей машине (Core i7-920): примерно в 4 раза быстрее! –

+0

Некоторые вопросы: Почему вы используете вычисления с плавающей запятой? Разве нет возможности делать это только с целыми числами? Я думаю, это будет еще быстрее. И если нет, я мог бы хранить весы в качестве синглов, поэтому никаких конверсий не требовалось бы. –

+0

О плавающей запятой - я не вижу команду SSE2 для умножения 4 упакованных целых чисел. Может быть, я пропустил это. И да, можно хранить весовые коэффициенты как синглы (я сомневаюсь в значительном ускорении) – MBo