08.26

신승빈·2022년 8월 26일
0

KGCA 수업

목록 보기
30/128

DirectX 개론

SDK

Software Development Kit

WDDM(Window Display Driver Model)

Windows Vista이후부터 사용
과거 CPU로 처리했던 Win API 대신 GPU를 통해 모든 Windows의 화면 출력

Reference : https://docs.microsoft.com/ko-kr/windows/win32/direct3darticles/graphics-apis-in-windows-vista#background
사견 : 이제는 2D를 위해 굳이 Win API를 배울 필요가 없을지도 모르겠음

DirectX의 흐름

DirectX 8 이전

T&L(Transform and Light)를 하드웨어에서 강제로 처리

DirectX 9

쉐이더 사용 가능

DirectX 10

T&L 없음
개발자가 점 하나를 찍기위해서라도 쉐이더를 사용해야 함

DirectX 11

쉐이더 5.0

DirectX 12

MultiThread Rendering 강화
다만 개발 난이도가 높아서 많이 사용하지 않음

Feature Level

그래픽 카드가 DirectX의 다양한 기능 중, 무엇을 지원하는지 알려줌

COM(Component Object Model)

DirectX의 기반
COM is a platform-independent, distributed, object-oriented system for creating binary software components that can interact.
COM objects can be created with a variety of programming languages.
IUnkown을 상속, 구현 필수

Reference : https://docs.microsoft.com/en-us/windows/win32/com/component-object-model--com--portal

DirectX 프로젝트 생성

속성


코드

#pragma comment(lib, "d3d11.lib")

DirectX Device 획득

예제

#include "Sample.h"
bool		Sample::Init()
{
    // 1)디바이스 생성
    HRESULT hr;
    D3D_FEATURE_LEVEL pFeatureLevel;
    UINT Flags=0;
    D3D_FEATURE_LEVEL pFeatureLevels[] =
    {        
        D3D_FEATURE_LEVEL_11_0, 
    };
    UINT FeatureLevels =1;
    hr = D3D11CreateDevice(
        nullptr, D3D_DRIVER_TYPE_HARDWARE,NULL,0, pFeatureLevels, 1, D3D11_SDK_VERSION,
        &m_pd3dDevice,// 디바이스 객체
        &pFeatureLevel,
        &m_pImmediateContext
    );
    if (FAILED(hr))
    {
        return false;
    }


    // 2)팩토리 생성
    hr = CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&m_pGIFactory);
    if (FAILED(hr)) return false;
    if (m_pd3dDevice == NULL) return E_FAIL;    

    // 3)스왑체인 생성
    // 후면(백)버퍼 생성  -> 전면버퍼
    DXGI_SWAP_CHAIN_DESC sd;
    ZeroMemory(&sd, sizeof(sd));
    sd.BufferCount = 1;
    sd.BufferDesc.Width = m_rtClient.right;
    sd.BufferDesc.Height = m_rtClient.bottom;
    sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;    
    sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    sd.OutputWindow = m_hWnd;
    sd.Windowed     = true;

    sd.BufferDesc.RefreshRate.Numerator = 60;
    sd.BufferDesc.RefreshRate.Denominator = 1;

    sd.SampleDesc.Count = 1;
    sd.SampleDesc.Quality = 0;
    
    sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
    hr = m_pGIFactory->CreateSwapChain(m_pd3dDevice,&sd,&m_pSwapChain);
    if (FAILED(hr))
    {
        return false;
    }

    // 4)랜더타켓뷰 생성
    ID3D11Texture2D* pBackBuffer = nullptr;
    m_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&pBackBuffer );
        m_pd3dDevice->CreateRenderTargetView(pBackBuffer , NULL, &m_pRTV);
    pBackBuffer->Release();

    // 5)뷰포트 설정
    D3D11_VIEWPORT vp;
    vp.Width = m_rtClient.right;
    vp.Height = m_rtClient.bottom;
    vp.TopLeftX = 0;
    vp.TopLeftY = 0;
    vp.MinDepth = 0.0f;
    vp.MaxDepth = 1.0f;
    // 굳이 설정하지 않아도 출력에는 문제 없음
    m_pImmediateContext->RSSetViewports(1, &vp);
    return true;
}
bool		Sample::Frame()
{
    return true;
}
bool		Sample::Render()
{
    static float fTimer = 0.0f;
    fTimer += 0.0001f;
    m_pImmediateContext->OMSetRenderTargets(1, &m_pRTV, NULL);
    float color[4] = {  cosf(fTimer)*0.5f+0.5f,
                        sinf(fTimer) * 0.5f + 0.5f,
                        cosf(fTimer*2) * 0.5f + 0.5f, 
                         1.0f };
    m_pImmediateContext->ClearRenderTargetView(m_pRTV, color);
    m_pSwapChain->Present(0, 0);
    return true;
}
bool		Sample::Release()
{
    if (m_pd3dDevice) m_pd3dDevice->Release();// 디바이스 객체        
    if (m_pImmediateContext)m_pImmediateContext->Release();
    if (m_pGIFactory)m_pGIFactory->Release();
    if (m_pSwapChain)m_pSwapChain->Release();
    if (m_pRTV) m_pRTV->Release();
    return true;
}

GAME_RUN(P2_CreateWidnow2, 1024, 768)

Device 객체 획득

HRESULT WINAPI D3D11CreateDevice(
    _In_opt_ IDXGIAdapter* pAdapter,	// 생성할 장치를 나타내는 display adapter - GPU, NULL시 기본 어댑터 - 현재 사용중인 GPU
    D3D_DRIVER_TYPE DriverType,			// 드라이버 타입. 하드웨어 가속 시 HARDWARE. 그 외 여러 옵션 존재.
    HMODULE Software,					// 소프트웨어 구동기. 하드웨어 구동 시 NULL 지정
    UINT Flags,							// 디버그 모드 등 플래그
    _In_reads_opt_( FeatureLevels ) CONST D3D_FEATURE_LEVEL* pFeatureLevels,	// 프로그램에서 지원하고자 하는 DX 수준. NULL시 최고 기능 수준. 지정 시 지정된 값 중 최고 수준
    UINT FeatureLevels,					// pFeatureLevels의 원소 개수. NULL시 0
    UINT SDKVersion,					// 사용하는 SDK 버전
    _COM_Outptr_opt_ ID3D11Device** ppDevice,	// 생성된 장치 반환
    _Out_opt_ D3D_FEATURE_LEVEL* pFeatureLevel,	// pFeatureLevels 배열 중 처음으로 지원가능 기능 또는 NULL시 최고 수준 반환
    _COM_Outptr_opt_ ID3D11DeviceContext** ppImmediateContext	// 생성된 DeviceContext반환
    );

DXGI 팩토리 생성

HRESULT WINAPI CreateDXGIFactory(
	REFIID riid,
    _COM_Outptr_ void **ppFactory
    );

SwapChain 생성

typedef struct DXGI_SWAP_CHAIN_DESC
    {
    DXGI_MODE_DESC BufferDesc;		// 후면 버퍼 속성
    DXGI_SAMPLE_DESC SampleDesc;	// 다중표본화를 위해 추출할 표본의 개수. 픽셀 당 다수의 표본 추출을 통해 품질 증가
    DXGI_USAGE BufferUsage;			// 버퍼의 용도
    UINT BufferCount;				// 후면 버퍼의 개수
    HWND OutputWindow;
    BOOL Windowed;					// 창모드
    DXGI_SWAP_EFFECT SwapEffect;	// 교환 시 효과. DISCARD 설정 시 알아서 지정
    UINT Flags;
    } 	DXGI_SWAP_CHAIN_DESC;
        
virtual HRESULT STDMETHODCALLTYPE CreateSwapChain( 
    /* [annotation][in] */ 
    _In_  IUnknown *pDevice,					// ID3D11Device를 가리키는 포인터
    /* [annotation][in] */
    _In_  DXGI_SWAP_CHAIN_DESC *pDesc,
    /* [annotation][out] */ 
    _COM_Outptr_  IDXGISwapChain **ppSwapChain	// 생성된 교환 사슬 인터페이스 반환
    ) = 0;

RenderTargetView 생성

virtual HRESULT STDMETHODCALLTYPE CreateRenderTargetView( 
    /* [annotation] */ 
    _In_  ID3D11Resource *pResource,						// 후면 버퍼
    /* [annotation] */ 
    _In_opt_  const D3D11_RENDER_TARGET_VIEW_DESC *pDesc,
    /* [annotation] */ 
    _COM_Outptr_opt_  ID3D11RenderTargetView **ppRTView		// 생성된 렌더 대상 뷰 반환
    ) = 0;

ViewPort 설정

virtual void STDMETHODCALLTYPE RSSetViewports( 
    /* [annotation] */ 
    _In_range_(0, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE)  UINT NumViewports,		// 뷰포트의 개수
    /* [annotation] */ 
    _In_reads_opt_(NumViewports)  const D3D11_VIEWPORT *pViewports	// 뷰포트 배열
    ) = 0;

주요 용어

RenderTarget

Resource의 종류를 의미
예를 들어 Multi Render Target기법의 경우 다양한 Render Target에 원하는 작업만을 수행하여 저장할 수 있음

Reference : https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=amoeba74&logNo=120059193066

다만 일반적으로 Device가 그릴 영역을 의미
BackBuffer는 특별한 Render Target의 종류를 의미
그렇기 때문에 RenderTargetView 생성이라 하면 Display에 Draw할 BackBuffer를 설정하는 것을 의미

Reference : https://docs.microsoft.com/en-us/windows/win32/learnwin32/render-targets--devices--and-resources

ViewPort

Draw하고자 하는 렌더타겟의 출력하고자하는 영역 설정

Reference : https://en.wikipedia.org/wiki/Viewport
Reference : https://docs.microsoft.com/en-us/windows/uwp/graphics-concepts/viewports-and-clipping

ex) 1p-2p 화면 나눠쓰기

Tearing, Flickering과 Double Buffering

이미지의 출력이 이루어질 Buffer를 1개만 사용할 시 Buffer에 작성과 출력이 동시에 진행되면서 깔끔하지 못한 이미지가 출력될 수 있음

Flickering

작성이 진행중인 Buffer의 이미지가 출력되어 잔상이 남거나 깜박이는 현상

Tearing

Buffer의 작성이 완료되었더라도 화면출력과 작성간의 순서가 맞지 않으면 이전 이미지의 일부가 남을 수 있음

Reference : https://ko.wikipedia.org/wiki/%EC%8A%A4%ED%81%AC%EB%A6%B0_%ED%85%8C%EC%96%B4%EB%A7%81

Double Buffering

이를 막기 위해 출력을 담당하는 Primary Buffer와 작성을 담당하는 Back Buffer를 사용하여 이미지의 작성이 완벽히 완료된 후 출력 수행

Reference : https://movefast.tistory.com/6

Flipping과 Blitting

RenderTarget에 그려진 이미지를 Display에 출력하는 방식
Flipping 방식이 불필요한 복사가 적어서 일반적으로 더 빠름

Flipping

작성된 이미지를 바로 DWM에 전송

Blitting

작성된 이미지를 DWM의 Buffer에 복사
DWM은 복사된 이미지를 출력

Reference : https://docs.microsoft.com/en-us/windows/win32/direct3ddxgi/dxgi-flip-model#comparing-the-dxgi-flip-model-and-the-bitblt-model

Device와 DeviceContext

Device

다른 인터페이스(하드웨어를 제어하는 Object)를 생성 시 사용

DeviceContext

생성된 인터페이스를 제어 시 사용

m_pImmediateContext->RSSetViewports(1, &vp);
m_pImmediateContext->OMSetRenderTargets(1, &m_pRTV, NULL);
m_pImmediateContext->ClearRenderTargetView(m_pRTV, color);

DXGI

GI(Graphic Infrastructure)

하드웨어 조회, 앨리어싱 수준 설정 등 가장 최하단에 위치한 인터페이스
D3D와 분리되어 있기 때문에 D2D에서도 사용 가능

profile
이상을 길잡이 삼아 로망을 추구합니다.

0개의 댓글