| demo.design 3D programming FAQ | download | links | author

ОПТИМИЗАЦИЯ
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 | previous | content | next