HRESULT EnumDisplayModes( DWORD dwFlags

Download Report

Transcript HRESULT EnumDisplayModes( DWORD dwFlags

Direct3D를 위한
DirectDraw의 설정
Direct Draw의 기능
기초 표면

화면에서 보는 것을 표현하는 메모리에 해당하는 기초
표현
이미지를 저장하는 표면

보이는 출력 영역으로 전송될수 있는 이미지를 저장하는
화면 밖 표면.
하드웨어 오버레이

기초 표면의 내용을 건드리지 않고 “앞에” 나타나는 2D
이미지의 출력을 허용하는 하드웨어 오버레이 지원
깊이버퍼

3D 영상 구현시의 깊이 정보를 저장
2
Direct Draw의 기능
하드웨어 블리터

한 위치에서 다른 곳으로 2D 데이터를 복사하는 과정을
위해 사용.
플리핑 지원 표면

렌더링 뷰와 보이는 메인 출력 표면 사이에 전환에 사용.
클리핑

윈도우나 전체 화면 프로그램을 위한 클리핑
3
CD3DAppication Class(확장)
class CD3DApplication
{
CD3DFramework7* m_pFramework;
BOOL
m_bActive;
BOOL
m_bReady;
BOOL
m_bFrameMoving;
BOOL
m_bSingleStep;
HRESULT
Initialize3DEnvironment();
virtual HRESULT Render3DEnvironment();
VOID
Cleanup3DEnvironment();
VOID
DisplayFrameworkError( HRESULT, DWORD );
public:
HRESULT Change3DEnvironment();
protected:
HWND
m_hWnd;
D3DEnum_DeviceInfo*
m_pDeviceInfo;
4
LPDIRECTDRAW7
LPDIRECTDRAWSURFACE7
// For stereo modes
LPDIRECTDRAWSURFACE7
DDSURFACEDESC2
m_pDD;
m_pddsRenderTarget;
m_pddsRenderTargetLeft;
m_ddsdRenderTarget;
TCHAR*
m_strWindowTitle;
BOOL
m_bAppUseStereo;
BOOL
m_bShowStats;
HRESULT
(*m_fnConfirmDevice)(DDCAPS*, D3DDEVICEDESC7*);
// Overridable functions for the 3D scene created by the app
virtual HRESULT OneTimeSceneInit()
{ return S_OK; }
virtual HRESULT InitDeviceObjects()
{ return S_OK; }
virtual HRESULT DeleteDeviceObjects()
{ return S_OK; }
virtual HRESULT Render()
{ return S_OK; }
virtual HRESULT FrameMove( FLOAT )
{ return S_OK; }
virtual HRESULT RestoreSurfaces()
{ return S_OK; }
virtual HRESULT FinalCleanup()
{ return S_OK; }
5
// Overridable power management (APM) functions
virtual LRESULT OnQuerySuspend( DWORD dwFlags );
virtual LRESULT OnResumeSuspend( DWORD dwData );
// Miscellaneous functions
VOID
ShowStats();
VOID OutputText( DWORD x, DWORD y, TCHAR* str );
public:
// Functions to create, run, pause, and clean up the application
virtual HRESULT Create( HINSTANCE, TCHAR* );
virtual INT
Run();
virtual LRESULT MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam,
LPARAM lParam );
virtual VOID
Pause( BOOL bPause );
// Accessor functions
CD3DFramework7 *
GetFramework()
{ return m_pFramework; };
HWND
Get_hWnd()
{ return m_hWnd; };
BOOL
GetbActive()
{ return m_bActive; };
BOOL
GetbReady()
{ return m_bReady; };
6
VOID
SetbReady(BOOL val)
{ m_bReady = val; };
VOID
SetbActive(BOOL val)
{ m_bActive = val; };
VOID
SetbFrameMoving(BOOL val) { m_bFrameMoving = val; };
BOOL
GetbFrameMoving()
{ return m_bFrameMoving; };
DWORD
GetBaseTime()
{ return m_dwBaseTime; };
DWORD
GetStopTime()
{ return m_dwStopTime; };
VOID
SetBaseTime(DWORD val) { m_dwBaseTime = val; };
VOID
SetStopTime(DWORD val)
{ m_dwStopTime = val; };
VOID
DeleteFramework()
{ SAFE_DELETE( m_pFramework ); };
BOOL
GetSingleStep()
{ return m_bSingleStep; };
VOID
SetSingleStep(BOOL val)
{ m_bSingleStep = val; };
// Class constructor
CD3DApplication();
};
7
DirectDraw 설정
Direct3D 장치의 정보를 기반으로 설정
1. Direct3D 장치의 정보를 저장하는 구초제 생성
2. 시스템에 설치된 유효한 DirectDraw 장치를 나열
3. 각각의 DirectDraw 장치에 대해서 다음의 과정 수행
3.1 DirectDraw 오브젝트 생성
3.2 출력 모드를 나열
3.3 Direct3D 장치를 나열
4. 출력 장치와 Driect3D 장치를 선택
5. DirectDraw의 초기화
협조 단계를 설정하고, 프론트, 백 버퍼를 생성하고, 클리퍼를 부착
8
나열되는 장치를 가지는 구조체 생성
장치 정보를 저장하는 구조체 생성.


Direct3D, DirectDraw 의 장치 정보, DirectDraw 의 모드 정보를 가진
다.
D3DEnumDeviceInfo : d3denum.h에 정의
struct D3DEnum_DeviceInfo
{
// D3D Device info
TCHAR
strDesc[40];
GUID*
pDeviceGUID;
D3DDEVICEDESC7 ddDeviceDesc;
BOOL
bHardware;
// DDraw Driver info
GUID*
pDriverGUID;
DDCAPS
ddDriverCaps;
DDCAPS
ddHELCaps;
// DDraw Mode Info
DDSURFACEDESC2 ddsdFullscreenMode;
BOOL
bWindowed;
BOOL
bStereo;
// For internal use (apps should not need to use these)
GUID
guidDevice;
GUID
guidDriver;
DDSURFACEDESC2* pddsdModes;
DWORD
dwNumModes;
DWORD
dwCurrentMode;
BOOL
bDesktopCompatible;
BOOL
bStereoCompatible;
9
};
DirectDraw 장치 나열하기(1)
DirectDrawEnumerateEX


리스트의 각 요소에 대해 콜백 함수를 실행하여 특별한
요소를 나열하는데 사용.
Direct3D Framework에서 나열 동작은 d3denum.cpp의 함
수인 D3Denum_EnumerateDevices 에서 시작.
10
DirectDraw 장치 나열하기(2)
HRESULT D3DEnum_EnumerateDevices( HRESULT (*AppConfirmFn)(DDCAPS*,
D3DDEVICEDESC7*) )
{
// Store the device enumeration callback function
g_fnAppConfirmFn = AppConfirmFn;
// Enumerate drivers, devices, and modes
DirectDrawEnumerateEx( DriverEnumCallback, NULL,
DDENUM_ATTACHEDSECONDARYDEVICES |
DDENUM_DETACHEDSECONDARYDEVICES |
DDENUM_NONDISPLAYDEVICES );
if( 0 == g_dwNumDevicesEnumerated )
{
DEBUG_MSG( _T("No devices and/or modes were enumerated!") );
return D3DENUMERR_ENUMERATIONFAILED;
}
11
DirectDraw 장치 나열하기(2)
if( 0 == g_dwNumDevices )
{
DEBUG_MSG( _T("No enumerated devices were accepted!") );
DEBUG_MSG( _T("Try enabling the D3D Reference Rasterizer.") );
return D3DENUMERR_SUGGESTREFRAST;
}
return S_OK;
}
12
DirectDraw 장치 나열하기(3)
DirectDrawEnumerateEX의 파라미터

첫번째 포인터
 응용프로그램의 함수 포인터로 대상 시스템에 설치된 각 DirectDraw 지
원 HAL 의 설명을 이용해서 호출될 콜백 함수의 어드레스
 본 예제에서는 DriverEnumCall 루틴으로 설정.(형식은 다음과 같아야 한
다.)
DDEnumCallBackEx(GUID FAR *lpGUID, LPSTR lpDirverSescription,
LPSTR lpDriverName, LPVOID lpContext, MHONITOR hm)

두번째 포인터
 나열 콜백 함수가 호출될 때마다 전달되는 어플리케이션 정의 컨텍스트
의 어드레스

세번째 포인터
 dwFlags
13
DriverEnumCallback 함수 (1)
static BOOL WINAPI DriverEnumCallback( GUID* pGUID, TCHAR* strDesc,
TCHAR* strName, VOID*, HMONITOR )
{
D3DEnum_DeviceInfo d3dDeviceInfo;
LPDIRECTDRAW7
pDD;
LPDIRECT3D7
HRESULT
pD3D;
hr;
// Step 1 : Use the GUID to create the DirectDraw object
hr = DirectDrawCreateEx( pGUID, (VOID**)&pDD, IID_IDirectDraw7, NULL );
if( FAILED(hr) )
{
DEBUG_MSG( _T("Can't create DDraw during enumeration!") );
return D3DENUMRET_OK;
}
14
DriverEnumCallback 함수 (2)
// Step 2: Create a D3D object, to enumerate the d3d devices
hr = pDD->QueryInterface( IID_IDirect3D7, (VOID**)&pD3D );
if( FAILED(hr) )
{
pDD->Release();
DEBUG_MSG( _T("Can't query IDirect3D7 during enumeration!") );
return D3DENUMRET_OK;
}
// Step 3 :Copy data to a device info structure
ZeroMemory( &d3dDeviceInfo, sizeof(d3dDeviceInfo) );
lstrcpyn( d3dDeviceInfo.strDesc, strDesc, 39 );
d3dDeviceInfo.ddDriverCaps.dwSize = sizeof(DDCAPS);
d3dDeviceInfo.ddHELCaps.dwSize = sizeof(DDCAPS);
pDD->GetCaps( &d3dDeviceInfo.ddDriverCaps, &d3dDeviceInfo.ddHELCaps );
15
DriverEnumCallback 함수 (3)
if( pGUID )
{
d3dDeviceInfo.guidDriver = (*pGUID);
d3dDeviceInfo.pDriverGUID = &d3dDeviceInfo.guidDriver;
}
strcpy(D3Ddevicename, d3dDeviceInfo.strDesc);
// 장치가 데스크탑 윈도우로 렌더될 수 있는지 기록한다.
if( d3dDeviceInfo.ddDriverCaps.dwCaps2 &
DDCAPS2_CANRENDERWINDOWED )
if( NULL == d3dDeviceInfo.pDriverGUID )
d3dDeviceInfo.bDesktopCompatible = TRUE;
// Step 4 : Enumerate the fullscreen display modes.
pDD->EnumDisplayModes( 0, NULL, &d3dDeviceInfo, ModeEnumCallback );
16
DriverEnumCallback 함수 (4)
// Sort list of display modes
qsort( d3dDeviceInfo.pddsdModes, d3dDeviceInfo.dwNumModes,
sizeof(DDSURFACEDESC2),
SortModesCallback );
// Now, enumerate all the 3D devices
pD3D->EnumDevices( DeviceEnumCallback, &d3dDeviceInfo );
// Clean up and return
SAFE_DELETE( d3dDeviceInfo.pddsdModes );
pD3D->Release();
pDD->Release();
return DDENUMRET_OK;
}
17
DirectDrawCreateEx
DirectDraw 장치를 생성
새로운 IDirectDraw7 인터페이스를 반환
HRESULT WINAPI DirectDrawCreateEx(GUID FAR *lpGUID,
LPDIRECTDRAW FAR *lplpDD, REFIID iid, IUnknown Far *pUnkOuter);




lpGUID : DirectDraw 장치를 위한 GUID 어드레스
lplpDD : IDriectDraw7 인터페이스 포인터를 저장하는 변수의 어드레
스
iid : IID_DirectDraw7로 설정.
pUnknown : NULL로 설정.
18
GetCaps
객체에서 지원하는 기능을 질의
하드웨어 기능과 에뮬레이션 특징을 정의하는 기능 비트를
반환.
DirectDraw기능 위주의 특징 저장.
HRESULT GetCaps( LPDDCAPS lpDDDriverCaps, LPDDCAPS lpDDHELCaps);

lpDDDriverCaps : 하드웨어 기능을 저장하는 구조체의 주소

lpDDHELCaps : HEL 기능을 저장하는 구조체의 주소
19
유효출력 모드 나열
현재 설치된 모니터가 지원하는 출력모드를 결정
출력 모드 : 픽셀 해상도, 픽셀 수, 갱신율
SetDisplayMode를 지원여부 결정.
HRESULT EnumDisplayModes( DWORD dwFlags, LPDDSURFACES2 lpDDSurfaceDest2,
LPVOID lpContext, LPDDENUMMODESCALLBACK2
lpEnumModesCallBack);
dwFlags
lpDDSurfaceDesc2
lpContext
lpEnumModesCallback
20
ModeEnumCallback 함수
static HRESULT WINAPI ModeEnumCallback( DDSURFACEDESC2* pddsd,
VOID* pParentInfo )
{
D3DEnum_DeviceInfo* pDevice = (D3DEnum_DeviceInfo*)pParentInfo;
// Reallocate storage for the modes
DDSURFACEDESC2* pddsdNewModes
= new DDSURFACEDESC2 [pDevice->dwNumModes+1];
memcpy(
pddsdNewModes, pDevice->pddsdModes,
pDevice->dwNumModes * sizeof(DDSURFACEDESC2) );
delete pDevice->pddsdModes;
pDevice->pddsdModes = pddsdNewModes;
pDevice->pddsdModes[pDevice->dwNumModes++] = (*pddsd);
return DDENUMRET_OK;
}
21
Direct3D 장치 나열
DriveEnumCallback의 마지막 단계
IDriect3D7::EnumDevice 호출
HRESULT EnumDevice ( LPD3DENUMDEVICESCALLBACK7 lpEnumDevicesCallback,
LPVOID lpUserArg );
lpEnumDevicesCallback
lpUserArg
22
DeviceEnumCallback
static HRESULT WINAPI DeviceEnumCallback( TCHAR* strDesc, TCHAR* strName,
D3DDEVICEDESC7* pDesc, VOID* pParentInfo )
{
// 나열된 장치의 수를 관리.
g_dwNumDevicesEnumerated++;
D3DEnum_DeviceInfo* pDriverInfo = (D3DEnum_DeviceInfo*)pParentInfo;
D3DEnum_DeviceInfo* pDeviceInfo = &g_pDeviceList[g_dwNumDevices];
ZeroMemory( pDeviceInfo, sizeof(D3DEnum_DeviceInfo) );
// HAL, HEL 장치 설명을 선택.
pDeviceInfo->bHardware = pDesc->dwDevCaps &
D3DDEVCAPS_HWRASTERIZATION;
memcpy( &pDeviceInfo->ddDeviceDesc, pDesc, sizeof(D3DDEVICEDESC7) );
// 이번에 추가되는 장치 정보를 설정.
pDeviceInfo->bDesktopCompatible = pDriverInfo->bDesktopCompatible;
pDeviceInfo->ddDriverCaps
= pDriverInfo->ddDriverCaps;
pDeviceInfo->ddHELCaps
= pDriverInfo->ddHELCaps;
23
DeviceEnumCallback
pDeviceInfo->guidDevice
= pDesc->deviceGUID;
pDeviceInfo->pDeviceGUID = &pDeviceInfo->guidDevice;
pDeviceInfo->pddsdModes = new DDSURFACEDESC2[pDriverInfo>dwNumModes ];
// 추가되는 장치를 위한 GUID와 설명을 복사
if( pDriverInfo->pDriverGUID )
{
pDeviceInfo->guidDriver = pDriverInfo->guidDriver;
pDeviceInfo->pDriverGUID = &pDeviceInfo->guidDriver;
lstrcpyn( pDeviceInfo->strDesc, pDriverInfo->strDesc, 39 );
}
else
{
pDeviceInfo->pDriverGUID = NULL;
lstrcpyn( pDeviceInfo->strDesc, strName, 39 );
}
24
// 중복 제거 : 오직 추가 DirectDraw 드라이버를 위한 하드웨어 장치만을 나열한
다.
if( NULL != pDeviceInfo->pDriverGUID && FALSE == pDeviceInfo->bHardware )
return D3DENUMRET_OK;
// 어플리케이션이 이 장치를 받아들이거나 거부하게 해준다.
if( g_fnAppConfirmFn )
if( FAILED( g_fnAppConfirmFn( &pDeviceInfo->ddDriverCaps,
&pDeviceInfo->ddDeviceDesc ) ) )
return D3DENUMRET_OK;
// 장치를 위한 지원 모드의 목록을 구성
for( DWORD i=0; i<pDriverInfo->dwNumModes; i++ )
{
DDSURFACEDESC2 ddsdMode = pDriverInfo->pddsdModes[i];
DWORD dwRenderDepths = pDeviceInfo->ddDeviceDesc.
dwDeviceRenderBitDepth;
DWORD dwDepth
= ddsdMode.ddpfPixelFormat.dwRGBBitCount;
25
// 장치와 호환되는 모드를 받아들인다.
if( ( ( dwDepth == 32 ) && ( dwRenderDepths & DDBD_32 ) ) ||
( ( dwDepth == 24 ) && ( dwRenderDepths & DDBD_24 ) ) ||
( ( dwDepth == 16 ) && ( dwRenderDepths & DDBD_16 ) ) )
{ // 호화 모드를 장치 지원 모드의 목록에 복사
pDeviceInfo->pddsdModes[pDeviceInfo->dwNumModes++] = ddsdMode;
// 장치의 스테레오 모드 기록
if( ddsdMode.ddsCaps.dwCaps2 &
DDSCAPS2_STEREOSURFACELEFT )
pDeviceInfo->bStereoCompatible = TRUE;
}
}
// 장치가 지원 모드를 가지지 않는다면 제거.
if( 0 == pDeviceInfo->dwNumModes )
return D3DENUMRET_OK;
26
// 기본적인 전체 화면 모드를 위한 640x480x16 모드를 찾는다.
for( i=0; i<pDeviceInfo->dwNumModes; i++ )
{
if( ( pDeviceInfo->pddsdModes[i].dwWidth == 640 ) &&
( pDeviceInfo->pddsdModes[i].dwHeight == 480 ) &&
( pDeviceInfo->pddsdModes[i].ddpfPixelFormat.dwRGBBitCount == 16 ) )
{
pDeviceInfo->ddsdFullscreenMode = pDeviceInfo->pddsdModes[i];
pDeviceInfo->dwCurrentMode
= i;
}
}
// 장치가 초기에 윈도우 모드인지 선택.
pDeviceInfo->bWindowed = pDeviceInfo->bDesktopCompatible;
// 장치를 받아들이고 반환.
g_dwNumDevices++;
return D3DENUMRET_OK;
}
27
Confirm Device
멤버변수 : m_fnConfirmDevice로 설정.

상속받은 클래스에서 다음과 같이 설정
m_fnConfirmDevice = ConfirmDevice



클래스 D3DApplication은 확인 함수를 가리킬 수 있는 멤
버 변수 m_fnConfirmDevice를 정의하므로 따라서 이를
상속받은 클래스에서도 이 멤버변수를 상속.
따라서 상속받은 클래스에서 장치 확인 함수를 제공하고
나서 클래스의 멤버 변수에 함수의 주소를 설정할 수 있
다.
특별한 기능이 필요치 않다면 NULL로 설정.
28
Direct3D 장치 선택
마지막으로 Direct3D 장치를 결정

Driect3D Framework에서 나열 코드를 사용중이라면
D3DEnum_SelectDefaultDevice를 호출
HRESULT D3DEnum_SelectDefaultDevice( D3DEnum_DeviceInfo** ppDevice,
DWORD dwFlags )
{ // 인수를 확인
if( NULL == ppDevice )
return E_INVALIDARG;
// 나열 장치 목록에 대한 액세스를 구함.
D3DEnum_DeviceInfo* pDeviceList;
DWORD
dwNumDevices;
D3DEnum_GetDevices( &pDeviceList, &dwNumDevices );
// 윈도우 지원의 소프트웨어, 하드에서, 하드웨어 T&L 장치를 찾는다.
D3DEnum_DeviceInfo* pRefRastDevice = NULL;
D3DEnum_DeviceInfo* pSoftwareDevice = NULL;
D3DEnum_DeviceInfo* pHardwareDevice = NULL;
D3DEnum_DeviceInfo* pHardwareTnLDevice = NULL;
29
for( DWORD i=0; i<dwNumDevices; i++ )
{
if( pDeviceList[i].bDesktopCompatible )
{
if( pDeviceList[i].bHardware )
{
if( (*pDeviceList[i].pDeviceGUID) == IID_IDirect3DTnLHalDevice )
pHardwareTnLDevice = &pDeviceList[i];
else
pHardwareDevice = &pDeviceList[i];
}
else
{
if( (*pDeviceList[i].pDeviceGUID) == IID_IDirect3DRefDevice )
pRefRastDevice = &pDeviceList[i];
else
pSoftwareDevice = &pDeviceList[i];
}
}
}
30
// Prefer a hardware TnL device first, then a non-TnL hardware device, and
// finally, a software device.
if( 0 == ( dwFlags & D3DENUM_SOFTWAREONLY ) && pHardwareTnLDevice )
(*ppDevice) = pHardwareTnLDevice;
else if( 0 == ( dwFlags & D3DENUM_SOFTWAREONLY ) && pHardwareDevice )
(*ppDevice) = pHardwareDevice;
else if( pSoftwareDevice )
(*ppDevice) = pSoftwareDevice;
else if( pRefRastDevice )
(*ppDevice) = pRefRastDevice;
else
return D3DENUMERR_NOCOMPATIBLEDEVICES;
// 새로이 선택된 장치를 윈도우 상태로 지정.
(*ppDevice)->bWindowed = TRUE;
return S_OK;
}
31
CD3DFramework7 기반의 DirectDraw초기화
CD3DFramework7 지원 기능



메인윈도우 핸들
프론트와 백 버퍼
다양한 상태 정보
CD3DApplication::Initialize3DEnvironment
CD3DFramework7::Initialize
CD3DFramework7::CreateEnvironment
CD3DFramework7::CreateDirectDraw
32
CD3DFramework7
class CD3DFramework7
{
// Internal variables for the framework class
HWND
m_hWnd;
// The window object
BOOL
m_bIsFullscreen;
// Fullscreen vs. windowed
BOOL
m_bIsStereo;
// Stereo view mode
DWORD
m_dwRenderWidth; // Dimensions of target
// render target
DWORD
m_dwRenderHeight;
RECT
m_rcScreenRect; // Screen rect for window
LPDIRECTDRAW7
m_pDD;
// The DirectDraw object
// The primary surface
LPDIRECTDRAWSURFACE7 m_pddsFrontBuffer;
// The backbuffer surface
LPDIRECTDRAWSURFACE7 m_pddsBackBuffer;
// For stereo modes
LPDIRECTDRAWSURFACE7 m_pddsBackBufferLeft;
DWORD
m_dwDeviceMemType;
DDPIXELFORMAT
m_ddpfBackBufferPixelFormat;
33
CD3DFramework7
// Internal functions for the framework class
HRESULT CreateFullscreenBuffers( DDSURFACEDESC2* );
HRESULT CreateWindowedBuffers();
HRESULT CreateDirectDraw(
GUID*, DWORD );
HRESULT CreateEnvironment( GUID*, GUID*, DDSURFACEDESC2*,
DWORD );
public:
// Access functions for DirectX objects
LPDIRECTDRAW7
GetDirectDraw()
{ return m_pDD; }
LPDIRECTDRAWSURFACE7 GetFrontBuffer()
{ return m_pddsFrontBuffer; }
LPDIRECTDRAWSURFACE7 GetBackBuffer()
{ return m_pddsBackBuffer; }
LPDIRECTDRAWSURFACE7 GetRenderSurface()
{ return m_pddsBackBuffer; }
LPDIRECTDRAWSURFACE7 GetRenderSurfaceLeft()
{ return m_pddsBackBufferLeft; }
34
DWORD
GetRenderWidth()
{ return m_dwRenderWidth; }
DWORD
GetRenderHeight()
{ return m_dwRenderHeight; }
// Functions to aid rendering
HRESULT RestoreSurfaces();
HRESULT ShowFrame();
HRESULT FlipToGDISurface( BOOL bDrawFrame = FALSE );
// Functions for managing screen and viewport bounds
BOOL IsFullscreen()
{ return m_bIsFullscreen; }
BOOL IsStereo()
{ return m_bIsStereo; }
VOID Move( INT x, INT y );
// Creates the Framework
HRESULT Initialize(
HWND hWnd, GUID* pDriverGUID, GUID*
pDeviceGUID,
DDSURFACEDESC2* pddsd,
DWORD dwFlags );
HRESULT DestroyObjects();
CD3DFramework7();
~CD3DFramework7();
};
35
CD3DApplication::Initialize3DEnvironment
작업



Framework를 초기화
전체 화면이나 윈도우 모드를 설정.
초기화 과정에서 발생할 수 있는 에러를 처리.
HRESULT CD3DApplication::Initialize3DEnvironment()
{
HRESULT hr;
DWORD dwFrameworkFlags = 0L;
dwFrameworkFlags |= ( !m_pDeviceInfo->bWindowed ? D3DFW_FULLSCREEN : 0L );
// Direct3D framework를 초기화
if( SUCCEEDED( hr = m_pFramework->Initialize( m_hWnd,
m_pDeviceInfo->pDriverGUID, m_pDeviceInfo->pDeviceGUID,
&m_pDeviceInfo->ddsdFullscreenMode, dwFrameworkFlags ) ) )
{
m_pDD
=
m_pFramework->GetDirectDraw();
m_pddsRenderTarget = m_pFramework->GetRenderSurface();
36
m_pddsRenderTargetLeft = m_pFramework->GetRenderSurfaceLeft();
m_ddsdRenderTarget.dwSize = sizeof(m_ddsdRenderTarget);
m_pddsRenderTarget->GetSurfaceDesc( &m_ddsdRenderTarget );
if( SUCCEEDED( hr = InitDeviceObjects() ) )
return S_OK;
else
{
DeleteDeviceObjects();
m_pFramework->DestroyObjects();
}
}
// 하드웨어 장치 대상이었다면 , 다시 소프트웨어 래스터라이저에 다시 시도
if( m_pDeviceInfo->bHardware )
{
DisplayFrameworkError( hr, MSGWARN_SWITCHEDTOSOFTWARE );
D3DEnum_SelectDefaultDevice( &m_pDeviceInfo, D3DENUM_SOFTWAREONLY );
return Initialize3DEnvironment();
}
return hr;
}
37
CD3DFramework7::Initialize
HRESULT CD3DFramework7::Initialize( HWND hWnd, GUID* pDriverGUID,
GUID* pDeviceGUID, DDSURFACEDESC2* pMode, DWORD dwFlags )
{
HRESULT hr;
if( ( NULL==hWnd ) || ( NULL==pDeviceGUID ) ||
( NULL==pMode && (dwFlags&D3DFW_FULLSCREEN) ) )
return E_INVALIDARG;
// 윈도우/전체 화면 모드의 상태를 설정.
m_hWnd
= hWnd;
m_bIsStereo = FALSE;
m_bIsFullscreen = ( dwFlags & D3DFW_FULLSCREEN ) ? TRUE : FALSE;
// 표면, 장치, 뷰포트 등의 D3D 렌더링 환경을 생성.
if( FAILED( hr = CreateEnvironment( pDriverGUID, pDeviceGUID, pMode, dwFlags ) ) )
{
DestroyObjects();
return hr;
}
return S_OK;
}
38
CD3DFramework7::CreateEnvironment
HRESULT CD3DFramework7::CreateEnvironment( GUID* pDriverGUID, GUID* pDeviceGUID,
DDSURFACEDESC2* pMode, DWORD dwFlags )
{
HRESULT hr;
// 하드웨어 장치의 유무에 따른 메모리를 선택.
if( IsEqualIID( *pDeviceGUID, IID_IDirect3DHALDevice) )
m_dwDeviceMemType = DDSCAPS_VIDEOMEMORY;
else if( IsEqualIID( *pDeviceGUID, IID_IDirect3DTnLHalDevice) )
m_dwDeviceMemType = DDSCAPS_VIDEOMEMORY;
else
m_dwDeviceMemType = DDSCAPS_SYSTEMMEMORY;
// DDraw 객체를 생성.
hr = CreateDirectDraw( pDriverGUID, dwFlags );
if( FAILED( hr ) )
return hr;
// 프론트, 백 버퍼를 생성 후 이에 클리퍼를 연결.
if( dwFlags & D3DFW_FULLSCREEN )
hr = CreateFullscreenBuffers( pMode );
else
hr = CreateWindowedBuffers();
if( FAILED( hr ) )
return hr;
return S_OK;
39
}
CD3DFramework7::CreateDirectDraw
HRESULT CD3DFramework7::CreateDirectDraw( GUID* pDriverGUID, DWORD dwFlags )
{
// DirectDraw interface 생성
if( FAILED( DirectDrawCreateEx( pDriverGUID, (VOID**)&m_pDD,I_IDirectDraw7,
NULL ) ) )
{
DEBUG_MSG( _T("Could not create DirectDraw") );
return D3DFWERR_NODIRECTDRAW;
}
// Windows cooperative level를 설정
DWORD dwCoopFlags = DDSCL_NORMAL;
if( m_bIsFullscreen )
dwCoopFlags = DDSCL_ALLOWREBOOT|DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN;
// 기본적으로 Direct3D가 부동 소수 계산을 최적화하도록 플래그가 생성.
if( 0L == ( dwFlags & D3DFW_NO_FPUSETUP ) )
dwCoopFlags |= DDSCL_FPUSETUP;
40
CD3DFramework7::CreateDirectDraw
if( FAILED( m_pDD->SetCooperativeLevel( m_hWnd, dwCoopFlags ) ) )
{
DEBUG_MSG( _T("Couldn't set coop level") );
return D3DFWERR_COULDNTSETCOOPLEVEL;
}
// 출력 장치가 팔레트를 사용하는지 확인한다.
// Direct3D Framework는 팔레트 시스템을 지원하지 않는다.
DDSURFACEDESC2 ddsd;
ddsd.dwSize = sizeof(ddsd);
m_pDD->GetDisplayMode( &ddsd );
if( ddsd.ddpfPixelFormat.dwRGBBitCount <= 8 )
return D3DFWERR_INVALIDMODE;
return S_OK;
}
41
Cooperative level 설정
DirectDraw, DirectSound, DirectInput를 위해 사용.
다른 어플리케이션과 작업하는 방법 지정.
IDirectDraw7::SetCooperativeLevel을 사용.
표준모드

기초 표면의 팔레트 변경이나 페이지 플리핑의 수행을
허용하지 않도록 설정 -> 문제 발생여지 있음.
HRESULT SetCooperativeLevel (HWND hWnd, DWORD dwFlags);
42
표면 생성
기초 출력 표면, 텍스처에 이용
HRESULT CreateSurface (LPDDSURFACEDESC2 lpDDSurfaceDestc2,
LPDIRECTDRAWSURFACE7 FAR * lplpDDSurface, IUnkown
Far *pUnkOuter);
•
lpDDSurfaceDesc2
•
lplpDDSurface
•
pUnkOuter
생성 대상

단일 표면, 복잡한 표면-플리핑 체인, 3차원 표면
43
프론트, 백 버퍼, 클리퍼
프론트 버프


모니터에 보이는 표면
각 DirectDraw 객체는 오직 하나의 기초 표면을 소유.
 DDSCAPS_PRIMARYSURFACE 플래그로 구분되는
 기초 표면은 현재 출력 모드와 일치하도록 크리과 픽셀 형식이
지정되므로 직접 선언이 불필요.
전체 화면 버퍼


프론트와 백 버퍼만 소유
클리퍼 객체가 불필요
윈도우 모드 화면 버퍼

클리퍼 객체 필요
44
CreateFullScreenBuffers
HRESULT CD3DFramework7::CreateFullscreenBuffers( DDSURFACEDESC2* pddsd )
{
HRESULT hr;
// 단계 1: 전체 화면 모드의 크기를 구하고, 이를 사각형으로 저장.
SetRect( &m_rcScreenRect, 0, 0, pddsd->dwWidth, pddsd->dwHeight );
m_dwRenderWidth = m_rcScreenRect.right - m_rcScreenRect.left;
m_dwRenderHeight = m_rcScreenRect.bottom - m_rcScreenRect.top;
// 단계 2: 출력 모드를 요청된 크기로 설정하고, ModeX를 사용하지 않도록 설정.
DWORD dwModeFlags = 0;
if( (320==m_dwRenderWidth) && (200==m_dwRenderHeight) &&
(8==pddsd->ddpfPixelFormat.dwRGBBitCount) )
dwModeFlags |= DDSDM_STANDARDVGAMODE;
45
if( FAILED( m_pDD->SetDisplayMode( m_dwRenderWidth, m_dwRenderHeight,
pddsd->ddpfPixelFormat.dwRGBBitCount,
pddsd->dwRefreshRate, dwModeFlags ) ) )
{
DEBUG_MSG( _T("Can't set display mode") );
return D3DFWERR_BADDISPLAYMODE;
}
// 단계 3 : 기초 표면과 백 버퍼를 설정.
DDSURFACEDESC2 ddsd;
ZeroMemory( &ddsd, sizeof(ddsd) );
ddsd.dwSize
= sizeof(ddsd);
ddsd.dwFlags
= DDSD_CAPS|DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
DDSCAPS_3DDEVICE |
DDSCAPS_FLIP | DDSCAPS_COMPLEX;
ddsd.dwBackBufferCount = 1;
46
if( m_bIsStereo ) // 스레테오 출력을 지원
{
ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
ddsd.ddsCaps.dwCaps2 |= DDSCAPS2_STEREOSURFACELEFT;
}
// 단계 4 : 기초표면을 생성.
if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer,
NULL ) ) )
{
DEBUG_MSG( _T("Error: Can't create primary surface") );
if( hr != DDERR_OUTOFVIDEOMEMORY )
return D3DFWERR_NOPRIMARY;
DEBUG_MSG( _T("Error: Out of video memory") );
return DDERR_OUTOFVIDEOMEMORY;
}
// 단계 5 : 기초 포면과 함께 생성된 백버퍼의 주소를 구한다.
DDSCAPS2 ddscaps = { DDSCAPS_BACKBUFFER, 0, 0, 0 };
47
if( FAILED( hr = m_pddsFrontBuffer->GetAttachedSurface( &ddscaps,
&m_pddsBackBuffer ) ) )
{
DEBUG_ERR( hr, _T("Error: Can't get the backbuffer") );
return D3DFWERR_NOBACKBUFFER;
}
// 윈도우 모드와의 일관성을 위해 백 버퍼 카운트를 증가
m_pddsBackBuffer->AddRef();
// 단계 6: 스테레오 출력을 지원
if( m_bIsStereo )
{
// Get the left back buffer, which was created along with the primary.
DDSCAPS2 ddscaps = { 0, DDSCAPS2_STEREOSURFACELEFT, 0, 0 };
if( FAILED( hr = m_pddsBackBuffer->GetAttachedSurface( &ddscaps,
&m_pddsBackBufferLeft ) ) )
{
DEBUG_ERR( hr, _T("Error: Can't get the left back buffer") );
return D3DFWERR_NOBACKBUFFER;
}
48
m_pddsBackBufferLeft->AddRef();
}
FILE *fplog = fopen("rrlogfile.txt","a");
ZeroMemory(&m_ddpfBackBufferPixelFormat, sizeof(DDPIXELFORMAT));
m_ddpfBackBufferPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
hr = m_pddsBackBuffer->GetPixelFormat(&m_ddpfBackBufferPixelFormat);
if(hr == DD_OK)
{
fprintf( fplog, "Backbuffer Pixelformat RGB bits = : ");
fprintf( fplog, "%d\n",m_ddpfBackBufferPixelFormat.dwRGBBitCount);
fprintf( fplog, "Backbuffer Pixelformat RGB masks = : ");
fprintf( fplog, "%d %d %d\n\n",
m_ddpfBackBufferPixelFormat.dwRBitMask,
m_ddpfBackBufferPixelFormat.dwGBitMask,
m_ddpfBackBufferPixelFormat.dwBBitMask);
}
49
else
fprintf( fplog, "Check on backbuffer pixel format FAILED ");
hr = m_pddsBackBuffer->GetSurfaceDesc( &ddsd );
fclose(fplog);
return S_OK;
}
50
CreateWindowedBuffers
HRESULT CD3DFramework7::CreateWindowedBuffers()
{
HRESULT hr;
// 단계 1 : 뷰포트와 화면 경계의 크기를 계산
GetClientRect( m_hWnd, &m_rcScreenRect );
ClientToScreen( m_hWnd, (POINT*)&m_rcScreenRect.left );
ClientToScreen( m_hWnd, (POINT*)&m_rcScreenRect.right );
m_dwRenderWidth = m_rcScreenRect.right - m_rcScreenRect.left;
m_dwRenderHeight = m_rcScreenRect.bottom - m_rcScreenRect.top;
// 단계 2: 기초 표면의 정보 설정.
DDSURFACEDESC2 ddsd;
ZeroMemory( &ddsd, sizeof(ddsd) );
ddsd.dwSize
ddsd.dwFlags
= sizeof(ddsd);
= DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
51
if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) )
{ // 단계 3 : 기초 표면을 생성.
DEBUG_MSG( _T("Error: Can't create primary surface") );
if( hr != DDERR_OUTOFVIDEOMEMORY )
return D3DFWERR_NOPRIMARY;
DEBUG_MSG( _T("Error: Out of video memory") );
return DDERR_OUTOFVIDEOMEMORY;
}
// 단계 4 : 클리퍼 객체 생성
LPDIRECTDRAWCLIPPER pcClipper;
if( FAILED( hr = m_pDD->CreateClipper( 0, &pcClipper, NULL ) ) )
{
DEBUG_MSG( _T("Error: Couldn't create clipper") );
return D3DFWERR_NOCLIPPER;
}
52
// 단계 5 : 클리퍼 객체와 윈도우를 연결
pcClipper->SetHWnd( 0, m_hWnd );
m_pddsFrontBuffer->SetClipper( pcClipper );
SAFE_RELEASE( pcClipper );
// 단계 6 : 백 버퍼를 생성.
ddsd.dwFlags
= DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
ddsd.dwWidth
= m_dwRenderWidth;
ddsd.dwHeight
= m_dwRenderHeight;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsBackBuffer, NULL ) ) )
{
DEBUG_ERR( hr, _T("Error: Couldn't create the backbuffer") );
if( hr != DDERR_OUTOFVIDEOMEMORY )
return D3DFWERR_NOBACKBUFFER;
DEBUG_MSG( _T("Error: Out of video memory") );
return DDERR_OUTOFVIDEOMEMORY;
}
53
ZeroMemory(&m_ddpfBackBufferPixelFormat, sizeof(DDPIXELFORMAT));
m_ddpfBackBufferPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
hr = m_pddsBackBuffer->GetPixelFormat(&m_ddpfBackBufferPixelFormat);
hr = m_pddsBackBuffer->GetSurfaceDesc( &ddsd );
return S_OK;
}
54
표면 플리핑
그래픽 출력의 성능 개선
다수의 버퍼를 사용하여 티어링(Tearing) 제거
Complex Surface




DirectDraw 플리핑 표면
IDirectDraw7::CreateSurface 메소드을 호출함으로써 생성.
IDirectDraw7::Flip
DDSCAPS_FLIP
55
ShowFrame
HRESULT CD3DFramework7::ShowFrame()
{
if( NULL == m_pddsFrontBuffer )
return D3DFWERR_NOTINITIALIZED;
if( m_bIsFullscreen )
{
// We are in fullscreen mode, so perform a flip.
if( m_bIsStereo )
return m_pddsFrontBuffer->Flip( NULL, DDFLIP_WAIT | DDFLIP_STEREO );
else
return m_pddsFrontBuffer->Flip( NULL, DDFLIP_WAIT );
}
else
{
// We are in windowed mode, so perform a blit.
return m_pddsFrontBuffer->Blt( &m_rcScreenRect, m_pddsBackBuffer,
NULL, DDBLT_WAIT, NULL );
}
}
56
Simple Exam : DDex
57
Simple Exam : DDex
// Project 생성
// ddutil.h, ddutil.cpp 를 프로젝트에 첨가
// CDDexView Class에 변수 선언 추가
class CDisplay;
class CSurface;
class CDDexView : public CView
{
….
CDisplay*
m_pDisplay
;
CSurface*
m_pLogoSurface ;
CSurface*
m_pTextSurface ;
….
public:
void DoDirectDraw();
}
58
Simple Exam : DDex
CDDexView::CDDexView()
{
// TODO: add construction code here
m_pDisplay = NULL;
m_pLogoSurface = NULL ;
m_pTextSurface = NULL ;
}
void CDDexView::DoDirectDraw()
{
//
CClientDC dc(this);
static float y=0;
if (m_pDisplay == NULL)
return;
y+=0.01f;
HRESULT hr;
// Fill the back buffer with black, ignoring errors until the flip
m_pDisplay->Clear( 0 );
59
Simple Exam : DDex
// Blt the help text on the backbuffer, ignoring errors until the flip
m_pDisplay->Blt( 10, 10, m_pTextSurface, NULL );
// Blt all the sprites onto the back buffer using color keying,
// ignoring errors until the last blt. Note that all of these sprites
// use the same DirectDraw surface.
m_pDisplay->Blt( 0, y, m_pLogoSurface, NULL );
// We are in windowed mode so perform a blt from the backbuffer
// to the primary, returning any errors like DDERR_SURFACELOST
if( FAILED( hr = m_pDisplay->Present() ) )
return ;
return ;
}
60
Simple Exam : DDex
void CDDexView::OnSetDirectx()
{
LPDIRECTDRAWPALETTE pDDPal = NULL;
HRESULT
int
hr;
iSprite;
RECT
rect;
HWND
hWnd = this->m_hWnd ;
GetClientRect(&rect);
m_pDisplay = new CDisplay();
if( FAILED( hr = m_pDisplay->CreateWindowedDisplay( hWnd, rect.right , rect.bottom ) ) )
{
MessageBox( TEXT("Failed initializing DirectDraw."),
TEXT("DirectDraw Sample"), MB_ICONERROR | MB_OK );
return ;
}
61
Simple Exam : DDex
// Create and set the palette when in palettized color
if( FAILED( hr = m_pDisplay->CreatePaletteFromBitmap( &pDDPal,
MAKEINTRESOURCE( IDB_DIRECTX ) ) ) )
return ;
m_pDisplay->SetPalette( pDDPal );
SAFE_RELEASE( pDDPal );
// Create a surface, and draw a bitmap resource on it.
if( FAILED( hr = m_pDisplay->CreateSurfaceFromBitmap( &m_pLogoSurface,
MAKEINTRESOURCE( IDB_DIRECTX ),
SPRITE_DIAMETER, SPRITE_DIAMETER ) ) )
return ;
// Create a surface, and draw text to it.
if( FAILED( hr = m_pDisplay->CreateSurfaceFromText( &m_pTextSurface, NULL,
HELPTEXT,
RGB(0,0,0), RGB(255, 255, 0) ) ) )
return ;
}
62