|
16番会議室「玉石混淆みんなで作るSample蔵」に寄せられたサンプル
"MMX を使ったビットマップの加算合成"
■説明
なんかここでは MMX を使ったサンプルが見あたらなかったので作ってみました。
24ビットカラーのビットマップの加算合成を MMX を使って高速化します。
まず、MMX の有無を検出する MMX ユニットです。このユニットの SupportedMMX 定数に
MMX の有無が格納されます。
そして加算合成を行う CopyBitmapAdd 関数です。MMX が使える環境では、MMX を
使用して高速化します。
procedure CopyBitmapAdd(Dest: TBitmap; dx, dy: Integer; Src: TBitmap);
■使い方
フォームに置いた TImage コンポーネント、Image1 上でマウスが動かされたら、
Image2 にあるビットマップを加算合成します。
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
CopyBitmapAdd(Image1.Picture.Bitmap, X, Y, Image2.Picture.Bitmap);
Image1.Refresh;
end;
■最後に
Delphi のインラインアセンブラでは、MMX が使えません(涙)
そこで自作ソフトの宣伝になって申し訳ないのですが、LIB 9 の 664 に
擬似的に MMX を使えるようにする MMXasm が登録されています。
■サンプルコード
unit MMX;
interface
const
SupportedMMX: Boolean = False;
implementation
procedure ReadCPUID;
const
CPUIDF_FPU = 1 shl 0; { Floating-point unit on-chip }
CPUIDF_VME = 1 shl 1; { Virtual Mode Extension }
CPUIDF_DE = 1 shl 2; { Debugging Extension }
CPUIDF_PSE = 1 shl 3; { Page Size Extension }
CPUIDF_TSC = 1 shl 4; { Time Stamp Counter }
CPUIDF_MSR = 1 shl 5; { Mode Spacific Registers }
CPUIDF_PAE = 1 shl 6; { Physical Address Extension }
CPUIDF_MCE = 1 shl 7; { Machine Check Exception }
CPUIDF_CX8 = 1 shl 8; { CMPXCHG8 Instruction Supported }
CPUIDF_APIC = 1 shl 9; { On-chip APIC Hardware Supported }
CPUIDF_MTRR = 1 shl 12; { Memory Type Range Registers }
CPUIDF_PGE = 1 shl 13; { Page Global Enable }
CPUIDF_MCA = 1 shl 14; { Machine Check Architecture }
CPUIDF_CMOV = 1 shl 15; { Conditional Move Instruction Supported }
CPUIDF_MMX = 1 shl 23; { Intel Architecture MMX Technology supported }
var
CPUIDFeatures: Integer;
begin
CPUIDFeatures := 0;
asm
push ebx
pushfd
pop eax
mov ecx,eax
xor eax,$200000
push eax
popfd
pushfd
pop eax
xor eax,ecx
jz @@exit
mov eax,0
db $0F,$A2 /// cpuid
cmp eax,1
jl @@exit
mov eax,1
db $0F,$A2 /// cpuid
mov CPUIDFeatures,edx
@@exit:
pop ebx
end;
if CPUIDFeatures and CPUIDF_MMX<>0 then
begin
{ MMX をサポートしている }
SupportedMMX := True;
end;
end;
initialization
ReadCPUID;
end.
-------------------------------------------------------------------
procedure CopyBitmapAdd(Dest: TBitmap; dx, dy: Integer; Src: TBitmap);
var
dx2, dy2, sx, sy, dWidth, dHeight: Integer;
x, y, val: Integer;
DestP, SrcP: PByte;
Count, Count2: Integer;
begin
if (Dest.PixelFormat<>pf24bit) or (Src.PixelFormat<>pf24bit) then
raise Exception.Create('24 ビットカラー以外には対応していません');
{ クリッピング }
dx2 := dx;
dy2 := dy;
sx := 0;
sy := 0;
dWidth := Src.Width;
dHeight := Src.Height;
if dx2<0 then
begin
Dec(dWidth, -dx2);
sx := -dx2;
dx2 := 0;
end;
if dy2<0 then
begin
Dec(dHeight, -dy2);
sy := -dy2;
dy2 := 0;
end;
if dx2+dWidth>Dest.Width then dWidth := Dest.Width-dx2;
if dy2+dHeight>Dest.Height then dHeight := Dest.Height-dy2;
if (dWidth<=0) or (dHeight<=0) then Exit;
{ 加算合成 }
for y:=0 to dHeight-1 do
begin
DestP := Dest.ScanLine[y+dy2]; Inc(DestP, dx2*3);
SrcP := Src.ScanLine[y+sy]; Inc(SrcP, sx*3);
Count := dWidth*3;
if SupportedMMX then
begin
{ MMX の時は、8バイト分をまとめて加算合成する }
Count2 := Count div 8;
if Count2>0 then
begin
asm
push edi
push esi
mov edi,DestP
mov esi,SrcP
mov ecx,Count2
@@Loop:
db $0F,$6F,$06 /// movq mm0,[esi]
db $0F,$6F,$0F /// movq mm1,[edi]
db $0F,$DC,$C1 /// paddusb mm0,mm1
db $0F,$7F,$07 /// movq [edi],mm0
add edi,8
add esi,8
dec ecx
jnz @@Loop
pop esi
pop edi
db $0F,$77 /// emms
end;
Inc(DestP, Count2*8);
Inc(SrcP, Count2*8);
Dec(Count, Count2*8);
end;
end;
{ 残りを加算合成する }
for x:=0 to Count-1 do
begin
val := DestP^+SrcP^;
if val>255 then val := 255;
DestP^ := val;
Inc(DestP);
Inc(SrcP);
end;
end;
end;
堀 浩行 hori@ingjapan.ne.jp
Original document by 堀 浩行 氏 ID:(BXI05470)
ここにあるドキュメントは NIFTY SERVEの Delphi Users' Forum の16番会議室「玉石混淆みんなで作るSample蔵」に投稿されたサンプルです。これらのサンプルはボーランド株式会社がサポートする公式のものではありません。また、必ずしも動作が検証されているものではありません。これらのサンプルを使用したことに起因するいかなる損害も投稿者、およびフォーラムスタッフはその責めを負いません。使用者のリスクの範疇でご使用下さい。
Copyright 1996-2002 Delphi Users' Forum
|