в самое начало


demo.design
3D programming FAQ



ОПТИМИЗАЦИЯ
6.3. Использование инструкций MMX

Если вкратце (а по-другому и не выйдет) с помощью MMX можно довольно неплохо разогнать некоторые медленные операции - например, сделать RGB-освещение. Или текстурирование с билинейной фильтрацией. Здесь я только продемонстрирую эти два примера; всяческие дальнейшие применения - на откуп читателю.

Пример внутреннего цикла с освещением через инструкции MMX:

    mov   eax,u             ; 24:8 fixedpoint
    mov   ebx,v             ; 24:8 fixedpoint
    mov   ecx,length
    xor   edx,edx
    mov   esi,texture
    mov   edi,outputbuffer
    movq  mm1,light         ; RGB-освещенность, qword
                            ; (4 штуки 0:9 fixedpoint)
    movq  mm2,delta_light   ; изменение освещенности
inner:
    mov        dl,ah           ; dl = (u >> 8)
    add        eax,du          ; u += du
    mov        dh,bh           ; dh = (v >> 8)
    add        ebx,dv          ; v += dv
    movd       mm0,[esi+4*edx] ; грузим пиксел
    punpcklbw  mm0,mm0         ; распаковываем пиксел
    psrlw      mm0,1           ; для того, чтобы были
                               ; беззнаковые числа
    pmulhw     mm0,mm1         ; умножаем RGB на RGB-освещенность
    add        edi,4
    dec        ecx
    packuswb   mm0,mm0         ; пакуем пиксел обратно
    paddw      mm1,mm2         ; light += delta_light
    movd       [edi-4],mm0
    jnz        inner

Этот цикл дает после некоторой дальнейшей оптимизации 7 тактов на пиксел - зато с текстурированием и полноценным RGB-освещением. Собственно освещение занимает лишь 2 такта. Не очень плохо.

Пример внутреннего цикла с билинейной фильтрацией через инструкции MMX:

    mov   eax,u        ; 24:8 fixedpoint
    mov   ebx,v        ; 24:8 fixedpoint
    mov   ebp,length
    xor   ecx,ecx
    xor   edx,edx
    mov   esi,texture
    mov   edi,outputbuffer
inner:
    mov        dl,ah           ; dl = (u >> 8)
    add        eax,du          ; u += du
    mov        dh,bh           ; dh = (v >> 8)
    add        ebx,dv          ; v += dv
    mov        cl,al           ; ecx = (u & 0xFF) = fu - дробная
                               ; часть u
    movd       mm0,[esi+4*edx] ; грузим пикселы
    movd       mm1,[esi+4*edx+4]
    movd       mm2,[esi+4*edx+4*256]
    movd       mm3,[esi+4*edx+4*257]
    punpcklbw  mm0,mm0         ; распаковываем пикселы
    punpcklbw  mm1,mm1
    punpcklbw  mm2,mm2
    punpcklbw  mm3,mm3
    psrlw      mm0,1           ; для того, чтобы были беззнаковые
    psrlw      mm1,1           ; числа и pmulhw (знаковое
    psrlw      mm2,1           ; умножение) работало нормально
    psrlw      mm3,1
    psubw      mm1,mm0         ; mm1 = tex[v+1][u]-tex[v][u]
    psubw      mm3,mm2         ; mm3 = tex[v+1][u+1]-tex[v][u+1]
    pmulhw     mm1,tab[8*ecx]  ; mm1 *= fu
    pmulhw     mm3,tab[8*ecx]  ; mm3 *= fu
    add        esi,4
    add        edi,4
    psllw      mm1,7           ; корректируем результат умножения
    psllw      mm3,7
    paddsw     mm0,mm1         ; mm0 = tex[v][u] + mm1
    paddsw     mm2,mm3         ; mm2 = tex[v][u+1] + mm3
    mov        cl,bl           ; ecx = (v & 0xFF) = fv - дробная
                               ; часть v
    psubw      mm2,mm0         ; mm2 -= mm0
    pmulhw     mm2,tab[8*ecx]  ; mm2 *= fv
    psrlw      mm0,7           ; корректируем результат умножения
    paddsw     mm0,mm2         ; mm0 += mm2 - отфильтрованное
                               ; значение
    packuswb   mm0,mm0         ; пакуем пиксел
    movd       [edi-4],mm0     ; записываем его
    dec        ebp
    jnz        inner

Отдельного упоминания и разъяснение требует табличка tab. Это просто табличка дробных частей в готовом для MMX-умножения виде:

tab label      qword
    dw         0,0,0,0
    dw         1,1,1,1
    dw         2,2,2,2
    ; ...
    dw         255,255,255,255

То есть в данном примере tab[8*ecx] = [cl, cl, cl, cl] - как раз готовая для использования в MMX-инструкциях дробная часть.

Здесь получается уже довольно приличное количество тактов на пиксел, порядка двадцати. Но несмотря на это, вышеприведенный цикл уронил fps на моей любимой тестовой сцене всего лишь в 1.5 раза по сравнению с обычным текстурированием. Тоже не очень плохо. В общем, успехов в использовании. Только не забывайте включать поддержку не-MMX режима для тех, у кого MMX нет, и, соответственно, детектор наличия MMX-инструкций.



 в самое начало


demo.design
3D programming FAQ