^(코딩캣)^ = @"코딩"하는 고양이;
[단막 DirectX 9.0 활용] DirectX 9.0를 WM_PAINT 이벤트에 적용하기
단막 DirectX 9.0 활용 DirectX 9.0를 WM_PAINT 이벤트에 적용하기 WM_PAINT(MFC: OnPaint) 이벤트는 창의 내용을 그릴 때 호출되는 이벤트이다. 이 이벤트에 DirectX 9.0을 적용하여 보겠다. IDirect3DDevice9::TestCooperativeLevel 로스트 상태는, DirectX 객체와 실제 그래픽 어댑터 사이의 연결이 끊어진 상태를 뜻한다. DirectX 객체가 생성된 시점과 이 객체를 이용하여 실제로 그리는 시각 시점의 상대적으로 긴 시간이 있는 경우 이 사이에 여러가지 이유(예: 로그오프, 절전모드 등)로 객체와 장치간 연결이 끊어질 수 있는데 이는 IDirect3DDevice9::TestCooperativeLevel함수로 체크할 수 있다. 만..
API/DirectX
2019. 2. 26. 19:30

[단막 DirectX 9.0 활용] DirectX 9.0를 WM_PAINT 이벤트에 적용하기

API/DirectX
2019. 2. 26. 19:30

단막 DirectX 9.0 활용


 

DirectX 9.0를 WM_PAINT 이벤트에 적용하기


WM_PAINT(MFC: OnPaint) 이벤트는 창의 내용을 그릴 때 호출되는 이벤트이다. 이 이벤트에 DirectX 9.0을 적용하여 보겠다.

 

IDirect3DDevice9::TestCooperativeLevel


로스트 상태는, DirectX 객체와 실제 그래픽 어댑터 사이의 연결이 끊어진 상태를 뜻한다. DirectX 객체가 생성된 시점과 이 객체를 이용하여 실제로 그리는 시각 시점의 상대적으로 긴 시간이 있는 경우 이 사이에 여러가지 이유(예: 로그오프, 절전모드 등)로 객체와 장치간 연결이 끊어질 수 있는데 이는 IDirect3DDevice9::TestCooperativeLevel함수로 체크할 수 있다.

만일 DirectX와 장치간 연결이 정상이 아닐 경우 그 원인에 따라 D3DERR_DRIVERINTERNALERROR, D3DERR_DEVICELOST, D3DERR_DEVICENOTRESET 중 하나를 반환하는데, 이 때는 IDirect3DDevice9::CreateDevice에 사용되었던 D3DPRESENT_PARAMETERS 구조체를 다시 사용하여 IDirect3DDevice9::Reset 함수를 실행하여 장치와 객체의 연결을 리셋한다.

/* C++ Source */
IDirect3DDevice * pDirect3DDevice;
D3DPRESENT_PARAMETERS d3dPresentParameters;
HRESULT hResult;
// ...
hResult = pDirect3DDevice->TestCooperativeLevel();
switch (hResult)
{
case D3DERR_DRIVERINTERNALERROR:
    pDirect3DDevice->Reset(&d3dPresentParameters); // D3DPRESENT_PARAMETERS *
    // Reset 실패 시 각종 조치
    break;
case D3DERR_DEVICELOST:
    // Reset 실패 시 각종 조치
    pDirect3DDevice->Reset(&d3dPresentParameters); // D3DPRESENT_PARAMETERS *
    break;
case D3DERR_DEVICENOTRESET:
    // Reset 실패 시 각종 조치
    pDirect3DDevice->Reset(&d3dPresentParameters); // D3DPRESENT_PARAMETERS *
    break;
}

 

IDirect3DDevice9::Clear

장치의 로스트 상태 확인 및 조치를 완료하였다면 지정된 위치의 버퍼를 특정 색상으로 지운다.

/* C++ Source */
IDirect3DDevice * pDirect3DDevice;
D3DPRESENT_PARAMETERS d3dPresentParameters;
DWORD dwRects;
D3DRECT * pRects;

HRESULT hResult;
// ...
hResult = pDirect3DDevice->Clear
(
    0,                                // DWORD Count : pRects 배열의 원소 수
    NULL,                            // const D3DRECT * pRects
    D3DCLEAR_TARGET,                 //
    D3DCOLOR_XRGB(0x00, 0xFF, 0xFF), // D3DCOLOR Color : 리셋 후 버퍼의 색상
    0.0f,                            // float Z
    0                                // DWORD Stencil
);

if (FAILED(hResult))
{
    // Clear 실패 시 각종 조치
}

 

IDirect3DDevice9::BeginScene, IDirect3DDevice9::EndScene, IDirect3DDevice9::Present


그리기 단위인 '장면scene'을 시작하고, 끝내는 함수이고 IDirect3DDevice9::Present를 통해 버퍼 스왑을 한다.

/* C++ Source */
IDirect3DDevice * pDirect3DDevice;
D3DPRESENT_PARAMETERS d3dPresentParameters;
HRESULT hResult;
// ...
pDirect3DDevice->BeginScene();
if (FAILED(hResult))
{
    // BeginScene 실패 시 각종 조치
}

// 각종 그리기 연산

pDirect3DDevice->EndScene();
if (FAILED(hResult))
{
    // EndScene 실패 시 각종 조치
}

pDirect3DDevice->Present
(
    NULL, // const RECT * pSourceRect
    NULL, // const RECT * pDestRect
    NULL, // HWND hDestWindowOverride
    NULL  // const RGNDATA *pDirtyRegion
);

if (FAILED(hResult))
{
    // Present 실패 시 각종 조치
}

 

카테고리 “API/DirectX”
more...
썸네일 이미지
[단막 DirectX 9.0 활용] DirectX 9.0 객체의 생성과 해제
단막 DirectX 9.0 활용 DirectX 9.0 객체의 생성과 해제 DirectX 9.0을 시작하기 위해 객체의 생성을 하고 창을 닫을 때의 해제는 다음과 같이 한다. DirectX 객체는 COMComponent Object Model으로 제공되므로 C++ 언어를 사용한다. Direct3DCreate9, IDirect3D9::Release DirectX 9.0의 객체 생성은 Direct3DCreate9 함수를 실행한다. 성공하면 LPDIRECT3D9(struct IDirect3D9 *) 형식의 객체를 반환하고, 실패하면 NULL을 반환한다. /* C++ Source */ #pragma comment(lib, "d3d9.lib") // DirectX 9.0 라이브러리를 링크 #include // Wi..
API/DirectX
2019. 2. 12. 20:42

[단막 DirectX 9.0 활용] DirectX 9.0 객체의 생성과 해제

API/DirectX
2019. 2. 12. 20:42

단막 DirectX 9.0 활용


 

DirectX 9.0 객체의 생성과 해제


DirectX 9.0을 시작하기 위해 객체의 생성을 하고 창을 닫을 때의 해제는 다음과 같이 한다. DirectX 객체는 COMComponent Object Model으로 제공되므로 C++ 언어를 사용한다.

 

Direct3DCreate9, IDirect3D9::Release


DirectX 9.0의 객체 생성은 Direct3DCreate9 함수를 실행한다. 성공하면 LPDIRECT3D9(struct IDirect3D9 *) 형식의 객체를 반환하고, 실패하면 NULL을 반환한다.

/* C++ Source */
#pragma comment(lib, "d3d9.lib") // DirectX 9.0 라이브러리를 링크
#include <Windows.h> // Windows API에서 제공되는 기본 자료형들을 불러오기
#include <d3d9.h> // DirectX 9.0 API를 불러오기

LPDIRECT3D9 lpDirect3D = (LPDIRECT3D9)NULL; // DirectX 9.0 객체

/* 창을 생성하거나 그래픽을 리셋하는 단계에서 */

lpDirect3D = Direct3DCreate9(D3D_SDK_VERSION); // DirectX 9.0 버전으로 객체를 생성한다.
if (!lpDirect3D) 
{
    // 생성에 실패한 경우 실행 작업
}

/* 생성에 성공한 경우 실행 작업 */

 

DirectX 9.0 객체의 해제는 IDirect3D9::Release를 호출한다.

/* C++ Source */
#pragma comment(lib, "d3d9.lib") // DirectX 9.0 라이브러리를 링크
#include <Windows.h> // Windows API에서 제공되는 기본 자료형들을 불러오기
#include <d3d9.h> // DirectX 9.0 API를 불러오기

LPDIRECT3D9 lpDirect3D = (LPDIRECT3D9)NULL; // DirectX 9.0 객체

/* 창을 닫거나 그래픽을 종료하는 단계에서 */

lpDirect3D->Release(); // 객체 해제

/* 이후 작업 */

 

실제 코드에 적용


다음은 MFC에서 DirectX 객체를 생성하고 해제하는 예이다. CTestFrameCWndFrame에서 상속된 클래스이고 m_pDirect3D는 사전에 클래스 헤더에 선언된 멤버 변수이다.

/* MFC Source */
int CTestFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    HRESULT hResult = NULL;
    int ret = 0;
    
    TRACE(TEXT("[SUCCESS] CTestFrame::OnCreate called.\n"));
    
    ret = CFrameWnd::OnCreate(lpCreateStruct);
    if (ret != 0)
    {
        TRACE(TEXT("[FAILURE] CTestFrame::OnCreate.\n"));
        return ret;
    }
    
    this->m_pDirect3D = Direct3DCreate9(D3D_SDK_VERSION);
    if (this->m_pDirect3D == NULL)
    {
        TRACE(TEXT("[FAILURE] Direct3DCreate9.\n"));
        return ret;
    }
    
    return ret;
}

void CTestFrame::OnDestroy()
{
    TRACE(TEXT("[SUCCESS] CTestFrame::OnDestroy called.\n"));
    
    if (this->m_pDirect3D != NULL)
    {
        this->m_pDirect3D->Release();
    }
    
    CFrameWnd::OnDestroy();
}

 

MFC 프로그램의 실행 결과 (아직 빈 창)
OnCreate와 OnDestroy이 실행된 흔적

 

어댑터 종류 열거하기


DirectX를 사용하기 위해 컴퓨터에서 지원 가능한 그래픽 어댑터의 종류를 모두 가져오려면 CreateDXGIFactory 함수로 생성된 IDXGIFactory형 객체를 사용한다.

 

CreateDXGIFactory


/* C++ Source */
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "dxgi.lib")

#include <d3d9.h>
#include <dxgi.h>

IDXGIFactory * pDXGIFactory = NULL;
IDXGIAdapter * pDXGIAdapter = NULL;
SIZE_T nDXGIAdapter = 0;

/* 창을 생성하거나 그래픽을 리셋하는 단계에서 */
hResult = CreateDXGIFactory
(
    __uuidof(IDXGIFactory),                  // REFIID riid
    reinterpret_cast<void **>(&pDXGIFactory) // void ** ppFactory
);

// 해당 인덱스 번호에 해당하는 어댑터가 없다면 DXGI_ERROR_NOT_FOUND를 반환하기 시작한다.
// 0번 어댑터부터 검색을 시작한다.
nDXGIAdapter = 0;
while (pDXGIFactory->EnumAdapter(nDXGIAdapter, &pDXGIAdapter) != DXGI_ERROR_NOT_FOUND)
{
nDXGIAdapter++; // 다음 번호의 어댑터를 확인한다.

}

 

실제 코드에 적용


그래픽 어댑터의 종류를 열거하는 위 코드를 응용하여 디버그 문자열로 그래픽 어댑터의 이름을 출력해보겠다.

/* MFC Source */
int CTestFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    HRESULT hResult = NULL;
    int ret = 0;
    
    TRACE(TEXT("[SUCCESS] CTestFrame::OnCreate called.\n"));
    
    ret = CFrameWnd::OnCreate(lpCreateStruct);
    if (ret != 0)
    {
        TRACE(TEXT("[FAILURE] OnCreate::OnCreate.\n"));
        return ret;
    }
    
    // DirectX 객체를 생성
    this->m_pDirect3D = Direct3DCreate9(D3D_SDK_VERSION);
    if (this->m_pDirect3D == NULL)
    {
        TRACE(TEXT("[FAILURE] Direct3DCreate9.\n"));
        return ret;
    }
    
    // 어댑터를 열거할 수 있는 IDXGIFactory 객체 생성
    IDXGIFactory * pDXGIFactory = NULL;
    hResult = CreateDXGIFactory
    (
        __uuidof(IDXGIFactory),                  // REFIID riid
        reinterpret_cast<void **>(&pDXGIFactory) // void ** ppFactory
    );
    if (FAILED(hResult))
    {
        TRACE(TEXT("[FAILURE] CreateDXGIFactory.\n"));
        return ret;
    }
    
    // 열거된 어댑터를 하나씩 배열에 보관
    CArray<IDXGIAdapter *> dxgiAdapters;
    IDXGIAdapter * pDXGIAdapter = NULL;
    UINT i = 0;
    while (TRUE)
    {
        hResult = pDXGIFactory->EnumAdapters
        (
            i++,          // UINT Adapter
            &pDXGIAdapter // IDXGIAdapter ** ppAdapter
        );
        
        if (hResult == DXGI_ERROR_NOT_FOUND) break;
        
        dxgiAdapters.Add(pDXGIAdapter);
        pDXGIAdapter = NULL;
    }
    
    // 배열에 보관된 어댑터의 이름을 디버그 문자열로 출력
    for (INT_PTR i = 0; i < dxgiAdapters.GetCount(); i++)
    {
        DXGI_ADAPTER_DESC dxgiAdapterDesc;
        TCHAR szBuffer[256];
        
        dxgiAdapters[i]->GetDesc(&dxgiAdapterDesc);
        TRACE(TEXT("[%2d] DXGI_ADAPTER_DESC.Description = %s\n"), i, dxgiAdapterDesc.Description);
    }
    
    // 사용이 끝난 어댑터 객체와 Factory 객체 해제
    for (INT_PTR i = 0; i < dxgiAdapters.GetCount(); i++)
    {
        dxgiAdapters[i]->Release();
    }
    dxgiAdapters.RemoveAll();
    pDXGIFactory->Release();
    
    return ret;
}

 

본 컴퓨터에 장착된 그래픽 어댑터의 종류가 열거되는 것을 확인할 수 있다. 다만 [장치 관리자]에는 없는 Microsoft Basic Render Driver가 마지막에 있을 수도 있다.

컴퓨터에 장착된 그래픽 어댑터의 종류가 열거되는 결과

 

그래픽 어댑터의 색상 포맷의 지원 여부 확인


ARGB, RGB, HSV 등등의 색상 포맷을 사용하고자 할 때 그래픽 어댑터가 이를 지원하는지 여부를 확인한다. 여기서 XRGB는 RGB와 같은 것을 의미한다.

 

IDirect3D9::EnumAdapterModes


 

/* C++ Source */
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "dxgi.lib")

#include <d3d9.h>
#include <dxgi.h>

LPDIRECT3D9 lpDirect3D = (LPDIRECT3D9)NULL; // DirectX 9.0 객체
UINT uAdapterMode = 0;

/* 창 또는 그래픽을 리셋하는 단계에서 */

uAdapterMode = lpDirect3D->GetAdapterModeCount
(
    D3DADAPTER_DEFAULT, // UINT Adapter : 시스템 기본 어댑터를 사용하겠다
    D3DFMT_X8R8G8B8     // D3DFORMAT Format : 픽셀당 32비트 색상 포맷을 쓴다. 단, 실제 사용되는 비트는 R, G, B 24비트이다. 
);

 

실제 코드에 적용


그래픽 어댑터에서 해당 색상 포맷으로 몇 개의 모드를 지원하는지를 확인해 보겠다.

/* MFC Source */
int CTestFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    HRESULT hResult = NULL;
    int ret = 0;
    
    TRACE(TEXT("[SUCCESS] CTestFrame::OnCreate called.\n"));
    
    ret = CFrameWnd::OnCreate(lpCreateStruct);
    if (ret != 0)
    {
        TRACE(TEXT("[FAILURE] OnCreate::OnCreate.\n"));
        return ret;
    }
    
    this->m_pDirect3D = Direct3DCreate9(D3D_SDK_VERSION);
    if (this->m_pDirect3D == NULL)
    {
        TRACE(TEXT("[FAILURE] Direct3DCreate9.\n"));
        return ret;
    }
    
    IDXGIFactory * pDXGIFactory = NULL;
    hResult = CreateDXGIFactory
    (
        __uuidof(IDXGIFactory),                 // REFIID riid
        reinterpret_cast<void **>(&pDXGIFactory) // void ** ppFactory
    );
    if (FAILED(hResult))
    {
        TRACE(TEXT("[FAILURE] CreateDXGIFactory.\n"));
        return ret;
    }
    
    UINT uAdapterMode = this->m_pDirect3D->GetAdapterModeCount
    (
        D3DADAPTER_DEFAULT, // UINT Adapter
        D3DFMT_X8R8G8B8     // D3DFORMAT Format
    );
    TRACE(TEXT("[SUCCESS] GetAdapterModeCount = %u\n"), uAdapterMode);
    
    return ret;
}

 

본 컴퓨터의 경우 RGB(X8R8G8B8) 색상 포맷으로 43가지의 어댑터 모드를 지원한다.

 

IDirect3D9::EnumAdapterModes


IDirect3D9::EnumAdapterModes 함수는 그래픽 어댑터가 지원 가능한 모드를 상세히 열거하는 함수이다. 지원 모드는 D3DDISPLAYMODE 구조체를 통해 반환된다.

/* C++ Source */
UINT uAdapterMode = this->m_pDirect3D->GetAdapterModeCount
(
    D3DADAPTER_DEFAULT, // UINT Adapter
    D3DFMT_X8R8G8B8     // D3DFORMAT Format
);

for (UINT i = 0; i < uAdapterMode; i++)
{
    D3DDISPLAYMODE d3dDisplayMode;
    hResult = this->m_pDirect3D->EnumAdapterModes
    (
        D3DADAPTER_DEFAULT, // UINT Adapter
        D3DFMT_X8R8G8B8,    // D3DFORMAT Format
        i,                  // UINT Mode : 어댑터에 대해 얻고자 하는 모드의 번호
        &d3dDisplayMode     // D3DDISPLAYMODE * pMode : 반환 정보
    );
}

 

실제 코드에 적용


기본 어댑터(D3DADAPTER_DEFAULT)의 RGB 컬러(D3DFMT_X8R8G8B8)로 몇 가지의 어댑터 모드가 지원 가능한지 조회해 보겠다. 실행 결과는 컴퓨터마다 상이하다.

/* MFC Source */
int CTestFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    HRESULT hResult = NULL;
    int ret = 0;
    
    TRACE(TEXT("[SUCCESS] CTestFrame::OnCreate called.\n"));
    
    ret = CFrameWnd::OnCreate(lpCreateStruct);
    if (ret != 0)
    {
        TRACE(TEXT("[FAILURE] OnCreate::OnCreate.\n"));
        return ret;
    }
    
    this->m_pDirect3D = Direct3DCreate9(D3D_SDK_VERSION);
    if (this->m_pDirect3D == NULL)
    {
        TRACE(TEXT("[FAILURE] Direct3DCreate9.\n"));
        return ret;
    }
    
    IDXGIFactory * pDXGIFactory = NULL;
    hResult = CreateDXGIFactory
    (
        __uuidof(IDXGIFactory),                  // REFIID riid
        reinterpret_cast(&pDXGIFactory) // void ** ppFactory
    );
    if (FAILED(hResult))
    {
        TRACE(TEXT("[FAILURE] CreateDXGIFactory.\n"));
        return ret;
    }
    
    UINT uAdapterMode = this->m_pDirect3D->GetAdapterModeCount
    (
        D3DADAPTER_DEFAULT, // UINT Adapter
        D3DFMT_X8R8G8B8     // D3DFORMAT Format
    );
    TRACE(TEXT("[SUCCESS] GetAdapterModeCount = %u\n"), uAdapterMode);
    
    for (UINT i = 0; i < uAdapterMode; i++)
    {
        D3DDISPLAYMODE d3dDisplayMode;
        hResult = this->m_pDirect3D->EnumAdapterModes
        (
            D3DADAPTER_DEFAULT, // UINT Adapter
            D3DFMT_X8R8G8B8,    // D3DFORMAT Format
            i,                  // UINT Mode : 어댑터에 대해 얻고자 하는 모드의 번호
            &d3dDisplayMode     // D3DDISPLAYMODE * pMode : 반환 정보
        );
        if (SUCCEEDED(hResult))
        {
            TRACE(TEXT("[%2u] EnumAdapterModes\n"), i);
            TRACE(TEXT("     D3DDISPLAYMODE.Format = %x\n"), d3dDisplayMode.Format);
            TRACE(TEXT("     D3DDISPLAYMODE.RefreshRate = %u\n"), d3dDisplayMode.RefreshRate);
            TRACE(TEXT("     D3DDISPLAYMODE.Width = %u\n"), d3dDisplayMode.Width);
            TRACE(TEXT("     D3DDISPLAYMODE.Height = %u\n"), d3dDisplayMode.Height);
        }
    }
    
    return ret;
}

 

RGB 모드로 지원 가능한 43개의 어댑터 모드에 대해 프레임 속도와 해상도가 열거되고 있다.

 

어댑터 장치의 성능 확인하기


장치의 성능 중에서 특히 자주하게 확인할 것은 하드웨어로 버텍스 처리가 가능한지 여부이다. 하드웨어에서 버텍스 프로세싱이 가능하면 그대로 이용하고, 그렇지 않을 경우 소프트웨어(CPU)로 버텍스를 연산해야 한다. 이 경우 체감 속도가 다소 느릴 수 있다.

 

IDirect3D9::GetDeviceCaps


IDirect3D9::GetDeviceCaps 함수가 반환하는 구조체인 D3DCAPS9DevCaps 멤버를 통해 확인이 가능하며 D3DDEVCAPS_HWTRANSFORMANDLIGHT 비트의 설정 여부로 하드웨어의 버텍스 처리 성능을 판단할 수 있다.

/* C++ Source */
D3DCAPS9 d3dCaps;
ZeroMemory(&d3dCaps, sizeof(D3DCAPS9));
hResult = this->m_pDirect3D->GetDeviceCaps
(
    D3DADAPTER_DEFAULT, // UINT Adapter
    D3DDEVTYPE_HAL,     // D3DDEVTYPE DeviceType
    &d3dCaps            // D3DCAPS9 * pCaps
);
if (FAILED(hResult))
{
    // 장치 정보 얻기에 실패시 조치
}
if ((d3dCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0)
{
    // 하드웨어로 버텍스 처리가 가능하다.
}
else
{
    // 소프트웨어로 버텍스 처리가 가능하다. (속도 느림)
}

 

실제 코드에 적용


실제 코드에 적용하여 보겠다.

/* MFC Source */
int CTestFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    HRESULT hResult = NULL;
    int ret = 0;
    
    TRACE(TEXT("[SUCCESS] CTestFrame::OnCreate called.\n"));
    
    ret = CFrameWnd::OnCreate(lpCreateStruct);
    if (ret != 0)
    {
        TRACE(TEXT("[FAILURE] OnCreate::OnCreate.\n"));
        return ret;
    }
    
    this->m_pDirect3D = Direct3DCreate9(D3D_SDK_VERSION);
    if (this->m_pDirect3D == NULL)
    {
        TRACE(TEXT("[FAILURE] Direct3DCreate9.\n"));
        return ret;
    }
    
    D3DCAPS9 d3dCaps;
    ZeroMemory(&d3dCaps, sizeof(D3DCAPS9));
    hResult = this->m_pDirect3D->GetDeviceCaps
    (
        D3DADAPTER_DEFAULT, // UINT Adapter
        D3DDEVTYPE_HAL,     // D3DDEVTYPE DeviceType
        &d3dCaps            // D3DCAPS9 * pCaps
    );
    if (FAILED(hResult))
    {
        TRACE(TEXT("[FAILURE] IDirect3D9::GetDeviceCaps = %u"), hResult);
        return ret;
    }
    if ((d3dCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0)
    {
        TRACE(TEXT("[DEVCAPS] D3DCAPS9.DevCaps has D3DDEVCAPS_HWTRANSFORMANDLIGHT\n"));
    }
    else
    {
        TRACE(TEXT("[DEVCAPS] D3DCAPS9.DevCaps not D3DDEVCAPS_HWTRANSFORMANDLIGHT\n"));
    }
    
    return ret;
}
실행 결과 하드웨어 버텍스 처리가 가능하면 위와 같이 출력될 것이다.

 

IDirect3DDevice9 객체 생성


그래픽 어댑터를 호출할 수 있는 장치 인터페이스인 IDirect3DDevice9 객체를 생성한다. 앞서 확인한 각종 하드웨어 사항과 본인이 선정한 색상 포맷, 기타 필요한 사항들을 조합하여 하나의 컨텍스트를 만든 다음 이를 IDirect3D9::CreateDevice함수에 D3DPRESENT_PARAMETERS 구조체로 전달한다.

IDirect3D9::CreateDevice


IDirect3D9::CreateDevice의 사용 방법은 다음과 같다.

/* C++ Source */
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "dxgi.lib")

#include <d3d9.h>
#include <dxgi.h>

LPDIRECT3D9 lpDirect3D9 = NULL;
LPDIRECT3DDEVICE9 lpDirect3DDevice9 = NULL;
HRESULT hResult;

/* 그래픽을 리셋하는 부분에서 */

hResult = lpDirect3D9->CreateDevice
(
    D3DADAPTER_DEFAULT, // UINT Adapter
    D3DDEVTYPE_HAL,     // D3DDEVTYPE DeviceType
    &d3dCaps            // D3DCAPS9 * pCaps
);

 

실제 코드에 적용


본 함수를 시험하기 전에 새 멤버변수를 클래스의 헤더에 선언하였다.

static const DWORD CTestFrame::GRAPHIC_WIDTH = 800;
윈도우의 폭이면서 그래픽 버퍼의 폭이다. 앞서 그래픽 어댑터에서 지원 가능한 것으로 확인된 800 픽셀을 상수로 지정한 것이다.
static const DWORD CTestFrame::GRAPHIC_HEIGHT = 600;
윈도우의 높이면서 그래픽 버퍼의 높이이다. 앞서 그래픽 어댑터에서 지원 가능한 것으로 확인된 600 픽셀을 상수로 지정한 것이다.
IDirect3DDevice * m_pDirect3DDevice = NULL
새로 생성될 장치 객체이다.

 

/* MFC Source */
int CTestFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    HRESULT hResult = NULL;
    int ret = 0;
    
    TRACE(TEXT("[SUCCESS] CTestFrame::OnCreate called.\n"));
    
    ret = CFrameWnd::OnCreate(lpCreateStruct);
    if (ret != 0)
    {
        TRACE(TEXT("[FAILURE] OnCreate::OnCreate.\n"));
        return ret;
    }
    
    this->m_pDirect3D = Direct3DCreate9(D3D_SDK_VERSION);
    if (this->m_pDirect3D == NULL)
    {
        TRACE(TEXT("[FAILURE] Direct3DCreate9.\n"));
        return ret;
    }
    
    // 윈도우 크기를 조정한다.
    RECT rect;
    this->GetWindowRect(&rect);
    this->SetWindowPos(NULL, rect.left, rect.top, CTestFrame::GRAPHIC_WIDTH, CTestFrame::GRAPHIC_HEIGHT, SWP_NOMOVE | SWP_NOZORDER | SWP_SHOWWINDOW);
    
    D3DCAPS9 d3dCaps;
    D3DPRESENT_PARAMETERS d3dPresentParameters;
    ZeroMemory(&d3dCaps, sizeof(D3DCAPS9));
    ZeroMemory(&d3dPresentParameters, sizeof(D3DPRESENT_PARAMETERS));
    hResult = this->m_pDirect3D->GetDeviceCaps
    (
        D3DADAPTER_DEFAULT, // UINT Adapter
        D3DDEVTYPE_HAL,     // D3DDEVTYPE DeviceType
        &d3dCaps            // D3DCAPS9 * pCaps
    );
    if (FAILED(hResult))
    {
        TRACE(TEXT("[FAILURE] IDirect3D9::GetDeviceCaps = %u"), hResult);
        return ret;
    }
    if ((d3dCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0)
    {
        TRACE(TEXT("[DEVCAPS] D3DCAPS9.DevCaps has D3DDEVCAPS_HWTRANSFORMANDLIGHT\n"));
        
        // 그래픽 어댑터가 하드웨어 버텍스 처리를 지원하는 경우
        ZeroMemory(&d3dPresentParameters, sizeof(D3DPRESENT_PARAMETERS));
        d3dPresentParameters.BackBufferWidth = CTestFrame::GRAPHIC_WIDTH;
        d3dPresentParameters.BackBufferHeight = CTestFrame::GRAPHIC_HEIGHT;
        d3dPresentParameters.BackBufferFormat = D3DFMT_X8R8G8B8;
        d3dPresentParameters.BackBufferCount = 1;
        d3dPresentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
        d3dPresentParameters.hDeviceWindow = this->m_hWnd; // 윈도우 핸들
        d3dPresentParameters.Windowed = TRUE;  // 어플리케이션을 창 모드로 연다.
        d3dPresentParameters.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
        
        hResult = m_pDirect3D->CreateDevice
        (
            D3DADAPTER_DEFAULT,
            D3DDEVTYPE_HAL,
            this->m_hWnd,
            D3DCREATE_HARDWARE_VERTEXPROCESSING, // 하드웨어 버텍스 처리
            &d3dPresentParameters,
            &this->m_pDirect3DDevice
        );
        if (FAILED(hResult))
        {
            TRACE(TEXT("[FAILURE] IDirect3D9::CreateDevice = %x\n"), hResult);
            return ret;
        }
        TRACE(TEXT("[SUCCESS] IDirect3D9::CreateDevice\n"));
    }
    else
    {
        TRACE(TEXT("[DEVCAPS] D3DCAPS9.DevCaps not D3DDEVCAPS_HWTRANSFORMANDLIGHT\n"));
        
        // 그래픽 어댑터가 하드웨어 버텍스 처리를 지원하지 않는 경우
        ZeroMemory(&d3dPresentParameters, sizeof(D3DPRESENT_PARAMETERS));
        d3dPresentParameters.BackBufferWidth = CTestFrame::GRAPHIC_WIDTH;
        d3dPresentParameters.BackBufferHeight = CTestFrame::GRAPHIC_HEIGHT;
        d3dPresentParameters.BackBufferFormat = D3DFMT_X8R8G8B8;
        d3dPresentParameters.BackBufferCount = 1;
        d3dPresentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
        d3dPresentParameters.hDeviceWindow = this->m_hWnd; // 윈도우 핸들
        d3dPresentParameters.Windowed = TRUE; // 어플리케이션을 창 모드로 연다.
        d3dPresentParameters.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
        
        // 장치 객체를 생성한다.
        hResult = m_pDirect3D->CreateDevice
        (
            D3DADAPTER_DEFAULT,
            D3DDEVTYPE_HAL,
            this->m_hWnd,
            D3DCREATE_SOFTWARE_VERTEXPROCESSING, // 소프트웨어로 버텍스 연산한다. (느림)
            &d3dPresentParameters,
            &this->m_pDirect3DDevice
        );
        if (FAILED(hResult))
        {
            TRACE(TEXT("[FAILURE] IDirect3D9::CreateDevice = %x\n"), hResult);
            return ret;
        }
        TRACE(TEXT("[SUCCESS] IDirect3D9::CreateDevice\n"));
    }
    
    return ret;>>
}
크기가 조정된 DirectX 윈도우
장치 객체 생성에 성공한 흔적

 

카테고리 “API/DirectX”
more...

“API/DirectX” (2건)