« 人は、なんても酒にする。そばビール登場? | トップページ | マイクロソフト太っ腹? »

2006年4月20日 (木)

ブレンドの速い処理は?

実行時間を計測すると
変な事が分かるようになるかも知れない…。

例えば良くある画像のブレンド処理。
二枚の画像をブレンドして出力する場合
このような処理になると思う…。

面倒なので他の処理も一気に書いたりする…。

#include <windows.h>
#include <stdio.h>
/*------------------------------------*/
#define SIZE_X 800
#define SIZE_Y 600
#define IMAGE_SIZE (SIZE_X*SIZE_Y*3)
/*------------------------------------*/
unsigned char output_pixel[IMAGE_SIZE];
unsigned char source_pixel[IMAGE_SIZE];
unsigned char object_pixel[IMAGE_SIZE];
/*--------------------------------------
ごく普通にそのまんまプログラムにおこすと
多分こんなプログラム。
--------------------------------------*/
void blend_a(unsigned char*output,unsigned char*source,unsigned char*object,int size_x,int size_y,int blend)
{
    int i,source_blend;

    source_blend=0x100-blend;
    for(i=size_x*size_y;i>0;i--)
    {
        output[0]    =(source[0]*source_blend+object[0]*blend)/0x100;
        output[1]    =(source[1]*source_blend+object[1]*blend)/0x100;
        output[2]    =(source[2]*source_blend+object[2]*blend)/0x100;
        source    +=3;
        object    +=3;
        output    +=3;
    }
}
/*--------------------------------------
割り算をシフトに換えて高速化
--------------------------------------*/
void blend_b(unsigned char*output,unsigned char*source,unsigned char*object,int size_x,int size_y,int blend)
{
    int i,source_blend;

    source_blend=0x100-blend;
    for(i=size_x*size_y;i>0;i--)
    {
        output[0]    =(source[0]*source_blend+object[0]*blend)>>8;
        output[1]    =(source[1]*source_blend+object[1]*blend)>>8;
        output[2]    =(source[2]*source_blend+object[2]*blend)>>8;
        source    +=3;
        object    +=3;
        output    +=3;
    }
}
/*--------------------------------------
演算部分をテーブル化して高速化
--------------------------------------*/
unsigned char blend_table[0x101][0x100];
void blend_c(unsigned char*output,unsigned char*source,unsigned char*object,int size_x,int size_y,int blend)
{
    int i;
    unsigned char*source_blend,*object_blend;

    source_blend=blend_table[0x100-blend];
    object_blend=blend_table[blend];
    for(i=size_x*size_y;i>0;i--)
    {
        output[0]    =source_blend[source[0]]+object_blend[object[0]];
        output[1]    =source_blend[source[1]]+object_blend[object[1]];
        output[2]    =source_blend[source[2]]+object_blend[object[2]];
        source    +=3;
        object    +=3;
        output    +=3;
    }
}
/*--------------------------------------
3バイト単位を1バイト単位で処理した時の
実行速度の比較
--------------------------------------*/
void blend_d(unsigned char*output,unsigned char*source,unsigned char*object,int size_x,int size_y,int blend)
{
    int i;
    unsigned char*source_blend,*object_blend;

    source_blend=blend_table[0x100-blend];
    object_blend=blend_table[blend];
    for(i=size_x*size_y*3;i>0;i--)
    {
        *output    =source_blend[*source]+object_blend[*object];
        source++;
        object++;
        output++;
    }
}
/*------------------------------------*/
void main(void)
{
    DWORD t[5];
    int i, j;

    /* 別に初期化しなくても良いんだけど… */
    for(i=0;i<=0x100;i++)
    for(j=0;j<0x100;j++)
        blend_table[i][j]=(i*j)>>8;
    for(i=0;i<IMAGE_SIZE;i++)
        source_pixel[i]=object_pixel[IMAGE_SIZE-1-i]=i;

    t[0]=GetTickCount();
    for(i=0x100;i>=0;i--)
        blend_a(output_pixel,source_pixel,object_pixel,SIZE_X,SIZE_Y,i);
    t[1]=GetTickCount();
    for(i=0x100;i>=0;i--)
        blend_b(output_pixel,source_pixel,object_pixel,SIZE_X,SIZE_Y,i);
    t[2]=GetTickCount();
    for(i=0x100;i>=0;i--)
        blend_c(output_pixel,source_pixel,object_pixel,SIZE_X,SIZE_Y,i);
    t[3]=GetTickCount();
    for(i=0x100;i>=0;i--)
        blend_d(output_pixel,source_pixel,object_pixel,SIZE_X,SIZE_Y,i);
    t[4]=GetTickCount();

    printf("blend_a = %d (%f)\n",t[1]-t[0],(double)(t[1]-t[0])/0x101);
    printf("blend_b = %d (%f)\n",t[2]-t[1],(double)(t[2]-t[1])/0x101);
    printf("blend_c = %d (%f)\n",t[3]-t[2],(double)(t[3]-t[2])/0x101);
    printf("blend_d = %d (%f)\n",t[4]-t[3],(double)(t[4]-t[3])/0x101);
}

※「Release」で結果を確認してね。
「Debug」だと正しい結果が得られないので…。

※ちなみにテストPCのスペックは…
CPUPⅢ500MHz/メモリ287MB
なので結果は、その辺を考慮してね…。
たぶん最近のPCでやると全然違うはず…。

結果…

blend_a = 9255 (36.011673)
blend_b = 7386 (28.739300)
blend_c = 6921 (26.929961)
blend_d = 8334 (32.428016)

「blend_a-blend_b」から
割り算は、シフトにすると劇的に速くなる!
事が分かる。

「blend_b-blend_c」から
テーブル化でさらに高速化!
シフト程でないのが歯痒い…。
もっと差が出て欲しいが…。
ちなみにメモリーアクセスが異様に
高速化された最近のPCならもっと
良い数値が出ると思われる…。

「blend_c-blend_d」から
「for」ループは、重い…。
出来る限りループしない方が速い。

等が分かる…。

時間が有れば、色々計測すると
スピードアップの勘所を
養えるかも知れないし…
養えないかも知れない…。


|

« 人は、なんても酒にする。そばビール登場? | トップページ | マイクロソフト太っ腹? »

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/108365/9675319

この記事へのトラックバック一覧です: ブレンドの速い処理は?:

« 人は、なんても酒にする。そばビール登場? | トップページ | マイクロソフト太っ腹? »