二つの画像をブレンドする(SIMD版)
effect.c
// // effect.c // // (c)Copyright Spacesoft corp., 2007 All rights reserved. // Hiro KITAYAMA // #include <windows.h>
//--------------------------------------------------------------------------- // // ブレンド // void effect( LPBYTE pAligned[], LONG width, LONG height ) { int loopCounter = (height*width)/4; LPBYTE pDest=pAligned[0]; LPBYTE pSrc0=pAligned[1]; LPBYTE pSrc1=pAligned[2];
_asm { xor ebx, ebx mov esi, pSrc0 /* esi = src0 */ mov edx, pSrc1 /* edx = src1 */ mov edi, pDest /* edi = dest */
mov ecx, loopCounter /* loop counter */
loopLbl: movdqa xmm1, [esi+ebx] pavgb xmm1, [edx+ebx]
movdqa [edi+ebx], xmm1 lea ebx, [ebx+16]
loop loopLbl } } |
pgm.c
// // pgm.c // // (c)Copyright Spacesoft corp., 2007 All rights reserved. // Hiro KITAYAMA // #include <stdio.h> #include <conio.h> // kbhit(), getch() #include <stdlib.h> // _splitpath() #include <windows.h>
#define SAFE_FREE( p ) if( p ) { free( p ) ; p=NULL ; } #define SZCLASSNAME "TEST"
// グローバル変数 PBITMAPINFOHEADER pDib[2] ; // tolal LPBYTE pBitmap[2] ; // data
void effect( LPBYTE pAligned[], LONG width, LONG height );
//--------------------------------------------------------------------------- // // ファイル名の取得 // BOOL getFname( char* inFname ) { OPENFILENAME fName ; char fileName[256] ; const char filefilter[] = "BMPファイル(*.bmp)\0*.bmp\0\0" ;
fileName[0] = '\0' ;
memset( &fName, 0, sizeof(OPENFILENAME) ) ; fName.lStructSize = sizeof(OPENFILENAME) ; fName.lpstrFilter = filefilter ; fName.nFilterIndex = 1 ; fName.lpstrFile = fileName ; fName.nMaxFile = sizeof(fileName) ; fName.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY ;
// 「ファイルを開く」ダイアログ if( GetOpenFileName( &fName ) == 0 ) return FALSE ;
strcpy( inFname, fileName ) ;
return TRUE ; }
//--------------------------------------------------------------------------- // // ビットッマプヘッダの読み込み // BOOL readHeader( FILE* fp, PBITMAPFILEHEADER bmHdr ) { // ビットッマプヘッダの読み込み if( fread( bmHdr, sizeof(BITMAPFILEHEADER), 1, fp ) != 1 ) { fprintf( stderr, "エラー:ファイル読み込み.\n" ) ; return FALSE ; }
// ビットッマプファイルかチェック if ( bmHdr -> bfType != 'M'*256+'B' ) { fprintf( stderr, "エラー:BMPフォーマットでは無い.\n" ); return FALSE ; } return TRUE ; }
//--------------------------------------------------------------------------- // // ビットッマプ本体の読み込み // BOOL readBody( FILE* fp, PBITMAPFILEHEADER bmHdr, PBITMAPINFOHEADER pDib ) { int bitmapSize ;
bitmapSize = bmHdr -> bfSize - sizeof(BITMAPFILEHEADER) ; // 画像の大きさ
// ビットッマプ本体の読み込み if( fread( pDib , bitmapSize, 1, fp ) != 1 ) { fprintf( stderr, "エラー:ファイル読み込み.\n" ) ; return FALSE ; } if( pDib -> biBitCount != 32 ) { fprintf( stderr, "エラー:32ビット ビットッマプではない.\n"); return FALSE ; } if( pDib -> biWidth % 4 ) { fprintf( stderr, "エラー:幅が4 バイトの整数倍でない.\n"); return FALSE ; } return TRUE ; }
//--------------------------------------------------------------------------- // // ビットッマファイルの読み込み // BOOL readBmpFile( PBITMAPINFOHEADER * pDib, PBITMAPFILEHEADER pBmHdr ) { char fName[_MAX_PATH] ; char dfFile[_MAX_PATH], dfName[_MAX_FNAME], dfExt[_MAX_EXT ] ; FILE* fp ; int bitmapSize ;
if( FALSE == getFname( fName ) ) return FALSE ;
// ビットマップファイルのオープン if( (fp = fopen( fName, "rb" )) == NULL ) { fprintf( stderr, "エラー:ファイルのオープンに失敗.\n" ) ; return FALSE ; }
// ファイル名の表示 _splitpath( fName, NULL, NULL, dfName, dfExt ) ; strcpy( dfFile, dfName ) ; strcat( dfFile, dfExt ) ; fprintf( stdout, "ファイル名 = [%s]\n", dfFile ) ;
// ヘッダの読み込み if( !readHeader( fp, pBmHdr ) ) { fclose( fp ) ; // ファイルクローズ return FALSE ; }
// ビットマップ本体のサイズ bitmapSize = pBmHdr->bfSize - sizeof(BITMAPFILEHEADER) ;
// メモリ確保 *pDib = (BITMAPINFOHEADER *)malloc( bitmapSize ) ;
// 本体読み込み if( !readBody( fp, pBmHdr, *pDib ) ) { SAFE_FREE( *pDib ) ; // メモリ解放 fclose( fp ) ; // ファイルクローズ return FALSE ; }
fclose( fp ) ; // ファイルクローズ
// 画像サイズの表示 fprintf( stdout, "ビットマップサイズ= %d x %d\n", (*pDib) -> biWidth, (*pDib) -> biHeight ) ;
return TRUE ; }
//--------------------------------------------------------------------------- // // window procedure // LRESULT CALLBACK WindProc( HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam ) { PAINTSTRUCT ps ;
switch( uMessage ) { case WM_PAINT: BeginPaint( hWnd, &ps ) ; SetDIBitsToDevice( ps.hdc, 0, 0, // copy BMP pDib[0] -> biWidth, pDib[0] -> biHeight, 0, 0, 0, pDib[0] -> biHeight, pBitmap[0], (BITMAPINFO*)pDib[0], DIB_RGB_COLORS ) ; EndPaint( hWnd, &ps ) ; break ;
case WM_DESTROY: PostQuitMessage( 0 ) ; break ;
default: return DefWindowProc( hWnd, uMessage, wParam, lParam ) ; } return 0 ; }
//--------------------------------------------------------------------------- // // create window // HWND createWindow( PBITMAPINFOHEADER pDib ) { HINSTANCE hInstanse ; WNDCLASSEX wcx ; HWND hWnd = NULL ; int ttlHeight, frameWidth, frameHeight ; int windowWidth, windowHeight ;
hInstanse = (HINSTANCE)GetWindowLong( NULL, GWL_HINSTANCE ) ;
memset( &wcx, 0, sizeof(WNDCLASSEX) ) ; wcx.cbSize = sizeof(WNDCLASSEX) ; wcx.lpfnWndProc = WindProc ; // ウィンドウプロシージャ wcx.hInstance = hInstanse ; wcx.hCursor = LoadCursor( NULL, IDC_ARROW ) ; wcx.lpszClassName = SZCLASSNAME ; // ウィンドウクラス名 if( !RegisterClassEx( &wcx ) ) // ウィンドウクラスの登録 return NULL ; // 失敗
ttlHeight = GetSystemMetrics( SM_CYCAPTION ) ; // ウィンドウタイトルの高さ frameWidth = GetSystemMetrics( SM_CXFIXEDFRAME ) ; // ウィンドウフレームの幅 frameHeight = GetSystemMetrics( SM_CYFIXEDFRAME ) ; // ウィンドウフレームの高さ
windowWidth = pDib -> biWidth + (frameWidth * 2), // ウィンドウの幅 windowHeight= pDib -> biHeight + ttlHeight + (frameHeight * 2) ; // ウィンドウの高さ
hWnd = CreateWindow( SZCLASSNAME, // ウィンドウクラス名 "表示ウィンドウ", // ウィンドウタイトル WS_OVERLAPPED | WS_SYSMENU | WS_VISIBLE,// ウィンドウスタイル CW_USEDEFAULT, CW_USEDEFAULT, // ウィンドウ位置 windowWidth,windowHeight, // ウィンドウサイズ HWND_DESKTOP, NULL, hInstanse, NULL ) ;
return hWnd ; }
//--------------------------------------------------------------------------- // // get counter // UINT64 getCurCounter(void) { UINT64 counter ; // 性能表示
_asm { rdtsc mov dword ptr [counter+0], eax mov dword ptr [counter+4], edx }
return counter; }
//--------------------------------------------------------------------------- // // main // int main( void ) { HWND hWnd ; MSG msg ; BITMAPFILEHEADER bmHdr[2] ; int loop, imgSize ; LPBYTE pAligned[3] ; // SIMD用バッファ UINT64 begin, finish, elapsed ; // 性能表示
if( !readBmpFile( &pDib[0], &bmHdr[0] ) ) { SAFE_FREE( pDib[0] ) ; // メモリ解放 return -1; }
if( !readBmpFile( &pDib[1], &bmHdr[1] ) ) { SAFE_FREE( pDib[1] ) ; // メモリ解放 return -1; } if( pDib[0] -> biWidth != pDib[1] -> biWidth || pDib[0] -> biHeight != pDib[1] -> biHeight ) { fprintf( stderr, "エラー:画像のサイズが異なります.\n" ) ; SAFE_FREE( pDib[1] ) ; // メモリ解放 SAFE_FREE( pDib[0] ) ; // メモリ解放 return -1; }
// ポインタをビットマップ本体位置へ移動 pBitmap[0] = (BYTE *)(pDib[0]) + bmHdr->bfOffBits - sizeof(BITMAPFILEHEADER) ; pBitmap[1] = (BYTE *)(pDib[1]) + bmHdr->bfOffBits - sizeof(BITMAPFILEHEADER) ;
imgSize=pDib[0]->biWidth * pDib[0]->biHeight * 4;
// alignされたメモリを確保 pAligned[0] = (LPBYTE)_aligned_malloc(imgSize*3, 16); // dest pAligned[1] = pAligned[0] + imgSize; // src0 pAligned[2] = pAligned[1] + imgSize; // src1
// alignされたエリアにコピー memcpy(pAligned[1], pBitmap[0], imgSize); // src0 memcpy(pAligned[2], pBitmap[1], imgSize); // src1
begin = getCurCounter();
//画像処理 for(loop=0;loop<100;loop++) //キャッシュなどの影響を排除するため100回実行 effect( pAligned, pDib[0] -> biWidth, pDib[0] -> biHeight ) ;
finish = getCurCounter(); elapsed = finish > begin ? finish - begin : begin - finish ; printf( "counter= %I64u\n", elapsed ) ;
// alignされたエリアからbitmapへコピー memcpy(pBitmap[0], pAligned[0], imgSize);
// ウィンドウ表示 hWnd = createWindow( pDib[0] ) ;
fprintf( stdout, "Enterキーを押せば終わります..." ) ;
// メッセージループ msg.message = WM_CREATE ; // dummy for while while( msg.message != WM_QUIT ) { if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) { TranslateMessage( &msg ) ; DispatchMessage( &msg ) ; }
// Enterキーを押されたらQuit if( kbhit() ) { PostMessage( hWnd, (UINT)WM_DESTROY, (UINT)0, (LONG)0 ) ; getch() ; } }
SAFE_FREE( pDib[0] ) ; // メモリ解放 SAFE_FREE( pDib[1] ) ; // メモリ解放 _aligned_free(pAligned[0]); // メモリ解放
return 0; } |