◎スプライトルーチン(その1)


        ピクセルフォーマットは16bpp(I1R5G5B5)とします。
        スプライトパターンのIビットが0の場合のみフレームバッファへ転送します。


        /* C言語風表記(1ピクセル処理) */
        /* vram = フレームバッファへのポインタ */
        /* sprite = スプライトパターンへのポインタ */
        *vram = (*sprite & 0x8000) ? *vram : *sprite;


        ; NASM(8ピクセル処理)
        ;UV大文字表記は他のパイプに移動できない命令です
        ;edi = フレームバッファのアドレス
        ;ebx = スプライトパターンのアドレス
        movq    mm1,[ebx]       ;U1 mm1 = *sprite
        pxor    mm2,mm2         ;v1 mm2 = 0
        movq    mm4,[ebx+8]     ;U2
        pxor    mm5,mm5         ;v2
        movq    mm0,[edi]       ;U3 mm0 = *vram
        pcmpgtw mm2,mm1         ;v3 mm2 = (0 > *sprite) ? 0xffff : 0
        movq    mm3,[edi+8]     ;U4
        pcmpgtw mm5,mm4         ;v4
        psubw   mm0,mm1         ;u5 mm0 = *vram - *sprite
        psubw   mm3,mm4         ;v5
        pand    mm0,mm2         ;u6 mm0 = (0 > *sprite) ? *vram - *sprite : 0
        pand    mm3,mm5         ;v6
        lea     edi,[edi+16]    ;u7 パイプが空いたので入れてみる
        paddw   mm0,mm1         ;v7 mm0 = (0 > *sprite) ? *vram : *sprite
        lea     ebx,[ebx+16]    ;u8 パイプが空いたので入れてみる
        paddw   mm3,mm4         ;v8
        movq    [edi-16],mm0    ;U9<-8 メモリストアは1クロック前に準備される
                                ;v9 MMX命令のみ挿入可能
        movq    [edi-8],mm3     ;U10<-9 


        有効なペアリングのために4ピクセルのデーターを2組処理しています。


        とりあえずキャッシュが全てヒットした場合を考えます。


        MMX Pentium(P55C)では、
        8ピクセル当たり10クロックで処理します。
        パターンをQWORDにアラインするのは当然にしても、
        転送先のアドレスは表示位置によって変わってしまうので、
        8ピクセル当たり22クロック程度と考えるのが妥当です。
        これらの値は実際に測定し確認しました。


        実際の実行速度はメモリのキャッシュ状況に大きく依存しますので、
        パターンの描画順序、メモリ配置等を十分に考慮する必要があります。






◎スプライトルーチン(その2)


        ピクセルフォーマットは、双方とも15bpp(R5G5B5)とします。
        パターンの全ビットが0の場合転送しません。


        /* C言語風表記(1ピクセル処理) */
        /* vram = フレームバッファへのポインタ */
        /* sprite = スプライトパターンへのポインタ */
        *vram = (*sprite == 0) ? *vram : *sprite;


        ; NASM(8ピクセル処理)
        ;UV大文字表記は他のパイプに移動できない命令です
        ;edi = フレームバッファのアドレス
        ;ebx = スプライトパターンのアドレス
        movq    mm1,[ebx]       ;U1 mm1 = *sprite
        pxor    mm2,mm2         ;v1 mm2 = 0
        movq    mm4,[ebx+8]     ;U2
        pxor    mm5,mm5         ;v2
        movq    mm0,[edi]       ;U3 mm0 = *vram
        pcmpeqw mm2,mm1         ;v3 mm2 = (0 == *sprite) ? 0xffff : 0
        movq    mm3,[edi+8]     ;U4
        pcmpeqw mm5,mm4         ;v4
        psubw   mm0,mm1         ;u5 mm0 = *vram - *sprite
        psubw   mm3,mm4         ;v5
        pand    mm0,mm2         ;u6 mm0 = (0 == *sprite) ? *vram - *sprite : 0
        pand    mm3,mm5         ;v6
        lea     edi,[edi+16]    ;u7 パイプが空いたので入れてみる
        paddw   mm0,mm1         ;v7 mm0 = (0 == *sprite) ? *vram : *sprite
        lea     ebx,[ebx+16]    ;u8 パイプが空いたので入れてみる
        paddw   mm3,mm4         ;v8
        movq    [edi-16],mm0    ;U9<-8
                                ;v9 MMX命令のみ挿入可能
        movq    [edi-8],mm3     ;U10<-9


        速度はスプライトルーチン(その1)と一緒です。




◎32bppスプライトルーチン


        ピクセルフォーマットは32bpp(I8R8G8B8)とします。
        スプライトパターンの全ビットが0の場合転送しません。


        /* C言語風表記(1ピクセル処理) */
        /* vram = フレームバッファへのポインタ */
        /* sprite = スプライトパターンへのポインタ */
        *vram = (*sprite == 0) ? *vram : *sprite;


        ; NASM整数命令版(1ピクセル処理)
        ;UV大文字表記は他のパイプに移動できない命令です
        ;edi = フレームバッファのアドレス
        ;ebx = スプライトパターンのアドレス
        mov     eax,[edi]       ;u1
        mov     esi,[ebx]       ;v1
        mov     edx,esi         ;u2
        add     esi,-1          ;v2
        sbb     esi,esi         ;U3
        sub     edx,eax         ;v3
        add     edi,4           ;u4
        and     edx,esi         ;v4
        add     ebx,4           ;u5
        add     eax,edx         ;v5
        mov     [edi-4],eax     ;u6


        Pentium や MMX Pentium(P55C)では、
        1ピクセル当たり6クロックで処理します。
        パターンをDWORDにアラインするのは当然にしても、
        転送先のアドレスは表示位置によって変わってしまうので、
        1ピクセル当たり12クロック程度と考えるのが妥当です。
        これらの値は実際に測定し確認しました。