BREW の高速転送

昔、RGB565 から RGB565 へ高速に転送するルーチンを書きました。
ふと思い出したので貼り付けておきます。

// dst: RGB565
// src: RGB565
// 透過色指定による透過転送
void Blt_RGB565_RGB565_Colorkey(
    word* dst,
    int dx,
    int dy,
    int dp,
    word* src,
    int sx,
    int sy,
    int sp,
    int w,
    int h,
    word key)
{
    dst = (word*)((byte*)dst + dx * sizeof(word) + dy * dp );
    src = (word*)((byte*)src + sx * sizeof(word) + sy * sp );

#ifdef WIN32
    for (int y = 0; y < h; y++)
    {
        for (int x = 0; x < w; x++)
        {
            if (src[x] != key)
            {
                dst[x] = src[x];
            }
        }
        dst = (word*)((byte*)dst + dp);
        src = (word*)((byte*)src + sp);
    }
#else
    uint32 jend = (uint32)((byte*)src + h * sp);

    uint32 ddp = dp - w * sizeof(word);
    uint32 dsp = sp - w * sizeof(word);

    uint32 al = (4 - ((uint32)src & 0x3)) & 0x3;
    if ((uint32)w * sizeof(word) < al) al = w * sizeof(word);

    uint32 iend8d = ((w - al) & 7) * sizeof(word);

    uint32 key2 = key << 16;

    uint32 mask = 0xffff;

    uint32 iend,iend8;
    uint32 alend;

    __asm
    {
        B       jcomp
    jloop:
        ADD     iend, src, w, LSL #1
        SUB     iend8, iend, iend8d

        ADD     alend, src, al
        B       alcomp
    alloop:
        LDRH    r0, [src], #2
        CMP     r0, key
        STRNEH  r0, [dst, #0]

        ADD     dst, dst, #2
    alcomp:
        CMP     src, alend
        BLT     alloop

        B       icomp8
    iloop8:
        LDMIA   src!, {r1-r4}

        EORS    r0, key2, r1, LSL #16
        STRNEH  r1, [dst, #0]

        AND     r0, mask, r1, LSR #16
        CMP     r0, key
        STRNEH  r0, [dst, #2]

        EORS    r0, key2, r2, LSL #16
        STRNEH  r2, [dst, #4]

        AND     r0, mask, r2, LSR #16
        CMP     r0, key
        STRNEH  r0, [dst, #6]

        EORS    r0, key2, r3, LSL #16
        STRNEH  r3, [dst, #8]

        AND     r0, mask, r3, LSR #16
        CMP     r0, key
        STRNEH  r0, [dst, #10]

        EORS    r0, key2, r4, LSL #16
        STRNEH  r4, [dst, #12]

        AND     r0, mask, r4, LSR #16
        CMP     r0, key
        STRNEH  r0, [dst, #14]

        ADD     dst, dst, #16
    icomp8:
        CMP     src, iend8
        BLT     iloop8

        B       icomp
    iloop:
        LDRH    r0, [src], #2
        CMP     r0, key
        STRNEH  r0, [dst, #0]

        ADD     dst, dst, #2
    icomp:
        CMP     src, iend
        BLT     iloop

        ADD     dst, dst, ddp
        ADD     src, src, dsp
    jcomp:
        CMP     src, jend
        BLT     jloop
    };
#endif
}

基本的に1ラインの転送において、


1.src のポインタを 4 バイトでアライン
2.16 バイト(8 ピクセル)ほど一気にロードして転送するのを、16 バイト同時にロードできなくなるまで繰り返す
3.残りのバイトを転送


という動作を行っています。
前回のパレット転送と同じですね。


8ループ展開内での転送は ARM の命令やマスクをうまく使って高速化しようとした痕跡がありますね。
この辺の最適化は、
id:melpon:20051130
id:melpon:20051201
id:melpon:20051202
ここら辺で頑張ってたみたいです。