お知らせ

電子会議

ライブラリ

パレット

Delphi FAQ検索

Delphi FAQ一覧

サンプル蔵





FDelphi FAQ
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