Header
#pragma once
class CGameFramework
{
private:
HINSTANCE m_hInstance;
HWND m_hWnd;
int m_nWndClientWidth;
int m_nWndClientHeight;
IDXGIFactory4* m_pdxgiFactory;
IDXGISwapChain3* m_pdxgiSwapChain;
ID3D12Device* m_pd3dDevice;
bool m_bMsaa4xEnable = { false };
UINT m_nMsaa4xQualityLevels = { 0 };
static const UINT m_nSwapChainBuffers = { 2 };
UINT m_nSwapChainBufferIndex;
ID3D12Resource* m_ppd3dRenderTargetBuffers[m_nSwapChainBuffers];
ID3D12DescriptorHeap* m_pd3dRtvDescriptorHeap;
UINT m_nRtvDescriptorIncrementSize;
// 렌더타겟, 서술자힙 포인터. 렌더 타겟 서술자 크기
ID3D12Resource* m_pd3dDepthStencilBuffer;
ID3D12DescriptorHeap* m_pd3dDsvDescriptorHeap;
UINT m_nDsvDescriptorIncrementSize;
// 깊이 스텐실 버퍼, 서술자 힙 포인터. 깊이 스텐실 서술자 크기
ID3D12CommandQueue* m_pd3dCommandQueue;
ID3D12CommandAllocator* m_pd3dCommandAllocator;
ID3D12GraphicsCommandList* m_pd3dCommandList;
//명령 큐, 명령 할당자, 명령 리스트 포인터
ID3D12PipelineState* m_pd3dPipelineState;
// 그래픽 파이프라인 상태 객체 포인터
ID3D12Fence* m_pd3dFence;
UINT64 m_nFenceValue;
HANDLE m_hFenceEvent;
// 펜스 포인터, 펜스 값, 이벤트 핸들
D3D12_VIEWPORT m_d3dViewport;
D3D12_RECT m_d3dScissorRect;
//뷰포트와 시저 사각형
public:
CGameFramework();
~CGameFramework();
bool OnCreate(HINSTANCE hInstance, HWND hMainWnd);
void OnDestroy();
void CreateSwapChain();
void CreateRtvAndDsvDescriptorHeaps();
void CreateDirect3DDevice();
void CreateCommandQueueAndList();
//스왑 체인, 디바이스, 서술자 힙, 명령 큐/할당자/리스트 생성 함수
void CreateRenderTargetViews();
void CreateDepthStencilView();
//렌더 타겟 뷰와 깊이 스텐실 뷰 생성 함수
void BuildObjects();
void ReleaseObjects();
//렌더링할 메쉬와 게임 객체를 생성하고 소멸하는 함수
void ProcessInput();
void AnimateObjects();
void FrameAdvance();
// 사용자 입력, 애니메이션, 렌더링 함수
void WaitForGpuComplete();
// CPU와 GPU 동기화 함수
void OnProcessingMouseMessage(HWND hWnd, UINT nMessageID, WPARAM wParam, LPARAM lParam);
void OnProcessingKeyboardMessage(HWND hWnd, UINT nMessageID, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK OnProcessingWindowMessage(HWND hWnd, UINT nMessageID, WPARAM wParam, LPARAM lParam);
//윈도우의 메세지 처리 함수
};
CPP
CGameFramework::CGameFramework(){
m_pdxgiFactory = nullptr;
m_pdxgiSwapChain = nullptr;
m_pd3dDevice = nullptr;
m_pd3dCommandAllocator = nullptr;
m_pd3dCommandQueue = nullptr;
m_pd3dPipelineState = nullptr;
m_pd3dCommandList = nullptr;
for (int i = 0; i < m_nSwapChainBuffers; ++i)
m_ppd3dRenderTargetBuffers[i] = nullptr;
m_pd3dRtvDescriptorHeap = nullptr;
m_nRtvDescriptorIncrementSize = 0;
m_pd3dDepthStencilBuffer = nullptr;
m_pd3dDsvDescriptorHeap = nullptr;
m_nDsvDescriptorIncrementSize = 0;
m_nSwapChainBufferIndex = 0;
m_hFenceEvent = nullptr;
m_pd3dFence = nullptr;
m_nFenceValue = 0;
m_nWndClientWidth = FRAME_BUFFER_WIDTH;
m_nWndClientHeight = FRAME_BUFFER_HEIGHT;
}
CGameFramework::~CGameFramework() {
}
bool CGameFramework::OnCreate(HINSTANCE hInstance, HWND hMainWnd){
m_hInstance = hInstance;
m_hWnd = hMainWnd;
CreateDirect3DDevice();
CreateCommandQueueAndList();
CreateSwapChain();
CreateRtvAndDsvDescriptorHeaps();
CreateRenderTargetViews();
CreateDepthStencilView();
BuildObjects();
return true;
}
void CGameFramework::OnDestroy(){
WaitForGpuComplete();
ReleaseObjects();
::CloseHandle(m_hFenceEvent);
for (int i = 0; i < m_nSwapChainBuffers; ++i)
if (m_ppd3dRenderTargetBuffers[i])
m_ppd3dRenderTargetBuffers[i]->Release();
if (m_pd3dRtvDescriptorHeap) m_pd3dRtvDescriptorHeap->Release();
if (m_pd3dDepthStencilBuffer) m_pd3dDepthStencilBuffer->Release();
if (m_pd3dDsvDescriptorHeap) m_pd3dDsvDescriptorHeap->Release();
if (m_pd3dCommandAllocator) m_pd3dCommandAllocator->Release();
if (m_pd3dCommandQueue) m_pd3dCommandQueue->Release();
if (m_pd3dPipelineState) m_pd3dPipelineState->Release();
if (m_pd3dCommandList) m_pd3dCommandList->Release();
if (m_pd3dFence) m_pd3dFence->Release();
m_pdxgiSwapChain->SetFullscreenState(false, nullptr);
if (m_pdxgiSwapChain) m_pdxgiSwapChain->Release();
if (m_pd3dDevice) m_pd3dDevice->Release();
if (m_pdxgiFactory) m_pdxgiFactory->Release();
#if defined(__DEBUG)
IDXGIDebug1* pdxgiDebug = nullptr;
DXGIGetDebugInterface1(0, __uuidof(IDXGIDebug1), (void**)&pdxgiDebug);
HRESULT hResult = pdxgiDebug->ReportLiveObjects(DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_DETAIL);
pdxgiDebug->Release();
#endif
}
void CGameFramework::CreateSwapChain(){
RECT rcClient;
::GetClientRect(m_hWnd, &rcClient);
m_nWndClientWidth = rcClient.right - rcClient.left;
m_nWndClientHeight = rcClient.bottom - rcClient.top;
DXGI_SWAP_CHAIN_DESC1 dxgiSwapChainDesc;
::ZeroMemory(&dxgiSwapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC1));
dxgiSwapChainDesc.Width = m_nWndClientWidth;
dxgiSwapChainDesc.Height = m_nWndClientHeight;
dxgiSwapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
dxgiSwapChainDesc.SampleDesc.Count = (m_bMsaa4xEnable) ? 4 : 1;
dxgiSwapChainDesc.SampleDesc.Quality = (m_bMsaa4xEnable) ? (m_nMsaa4xQualityLevels - 1) : 0;
dxgiSwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
dxgiSwapChainDesc.BufferCount = m_nSwapChainBuffers;
dxgiSwapChainDesc.Scaling = DXGI_SCALING_NONE;
dxgiSwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
dxgiSwapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
dxgiSwapChainDesc.Flags = 0;
DXGI_SWAP_CHAIN_FULLSCREEN_DESC dxgiSwapChainFullScreenDesc;
::ZeroMemory(&dxgiSwapChainFullScreenDesc, sizeof(DXGI_SWAP_CHAIN_FULLSCREEN_DESC));
dxgiSwapChainFullScreenDesc.RefreshRate.Numerator = 60;
dxgiSwapChainFullScreenDesc.RefreshRate.Denominator = 1;
dxgiSwapChainFullScreenDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
dxgiSwapChainFullScreenDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
dxgiSwapChainFullScreenDesc.Windowed = true;
m_pdxgiFactory->CreateSwapChainForHwnd(m_pd3dCommandQueue, m_hWnd, &dxgiSwapChainDesc,
&dxgiSwapChainFullScreenDesc, nullptr, (IDXGISwapChain1**)&m_pdxgiSwapChain);
m_pdxgiFactory->MakeWindowAssociation(m_hWnd, DXGI_MWA_NO_ALT_ENTER);
m_nSwapChainBufferIndex = m_pdxgiSwapChain->GetCurrentBackBufferIndex();
}
void CGameFramework::CreateDirect3DDevice(){
HRESULT hResult;
UINT nDXGIFactoryFlags = 0;
#if defined(__DEBUG)
ID3D12Debug* pd3dDebugController = nullptr;
hResult = D3D12GetDebugInterface(__uuidof(iD3D12Debug), (void**)&pd3dDebugController);
if (pd3dDebugController) {
pd3dDebugController->EnableDebugLayer();
pd3dDebugController->Release();
}
nDXGIFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
#endif
hResult = ::CreateDXGIFactory2(nDXGIFactoryFlags, __uuidof(IDXGIFactory4), (void**)
&m_pdxgiFactory);
IDXGIAdapter1* pd3dAdapter = nullptr;
for (UINT i = 0; DXGI_ERROR_NOT_FOUND != m_pdxgiFactory->EnumAdapters1(i, &pd3dAdapter); ++i) {
DXGI_ADAPTER_DESC1 dxgiAdapterDesc;
pd3dAdapter->GetDesc1(&dxgiAdapterDesc);
if (dxgiAdapterDesc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) continue;
if(SUCCEEDED(D3D12CreateDevice(pd3dAdapter, D3D_FEATURE_LEVEL_12_0, __uuidof(ID3D12Device),
(void**)&m_pd3dDevice))) break;
}
if (!pd3dAdapter) {
m_pdxgiFactory->EnumWarpAdapter(__uuidof(IDXGIFactory4), (void**)&pd3dAdapter);
D3D12CreateDevice(pd3dAdapter, D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device),
(void**)&m_pd3dDevice);
}
D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS d3dMsaaQualityLevels;
d3dMsaaQualityLevels.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
d3dMsaaQualityLevels.SampleCount = 4;
d3dMsaaQualityLevels.Flags = D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE;
d3dMsaaQualityLevels.NumQualityLevels = 0;
m_pd3dDevice->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,
&d3dMsaaQualityLevels, sizeof(D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS));
m_nMsaa4xQualityLevels = d3dMsaaQualityLevels.NumQualityLevels;
m_bMsaa4xEnable = (m_nMsaa4xQualityLevels > 1) ? true : false;
hResult = m_pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_pd3dFence));
m_nFenceValue = 0;
m_hFenceEvent = ::CreateEvent(nullptr, false, false, nullptr);
m_d3dViewport.TopLeftX = 0;
m_d3dViewport.TopLeftY = 0;
m_d3dViewport.Width = static_cast<float>(m_nWndClientWidth);
m_d3dViewport.Height = static_cast<float>(m_nWndClientHeight);
m_d3dViewport.MinDepth = 0.0f;
m_d3dViewport.MaxDepth = 1.0f;
m_d3dScissorRect = { 0, 0, m_nWndClientWidth, m_nWndClientHeight };
if (pd3dAdapter) pd3dAdapter->Release();
}
void CGameFramework::CreateCommandQueueAndList(){
D3D12_COMMAND_QUEUE_DESC d3dCommandQueueDesc;
::ZeroMemory(&d3dCommandQueueDesc, sizeof(D3D12_COMMAND_QUEUE_DESC));
d3dCommandQueueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
d3dCommandQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
HRESULT hResult = m_pd3dDevice->CreateCommandQueue(&d3dCommandQueueDesc,
IID_PPV_ARGS(&m_pd3dCommandQueue));
hResult = m_pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT,
IID_PPV_ARGS(&m_pd3dCommandAllocator));
hResult = m_pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT,
m_pd3dCommandAllocator, nullptr, __uuidof(ID3D12GraphicsCommandList), (void**)
&m_pd3dCommandList);
hResult = m_pd3dCommandList->Close();
}
void CGameFramework::CreateRtvAndDsvDescriptorHeaps(){
D3D12_DESCRIPTOR_HEAP_DESC d3dDescriptorHeapDesc;
::ZeroMemory(&d3dDescriptorHeapDesc, sizeof(D3D12_DESCRIPTOR_HEAP_DESC));
d3dDescriptorHeapDesc.NumDescriptors = m_nSwapChainBuffers;
d3dDescriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
d3dDescriptorHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
d3dDescriptorHeapDesc.NodeMask = 0;
HRESULT hResult = m_pd3dDevice->CreateDescriptorHeap(&d3dDescriptorHeapDesc,
IID_PPV_ARGS(&m_pd3dRtvDescriptorHeap));
m_nRtvDescriptorIncrementSize = m_pd3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
d3dDescriptorHeapDesc.NumDescriptors = 1;
d3dDescriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
hResult = m_pd3dDevice->CreateDescriptorHeap(&d3dDescriptorHeapDesc,
IID_PPV_ARGS(&m_pd3dDsvDescriptorHeap));
m_nDsvDescriptorIncrementSize = m_pd3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
}
void CGameFramework::CreateRenderTargetViews() {
D3D12_CPU_DESCRIPTOR_HANDLE d3dRtvCPUDescriptorHandle =
m_pd3dRtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart();
for (UINT i = 0; i < m_nSwapChainBuffers; ++i) {
m_pdxgiSwapChain->GetBuffer(i, IID_PPV_ARGS(&m_ppd3dRenderTargetBuffers[i]));
m_pd3dDevice->CreateRenderTargetView(m_ppd3dRenderTargetBuffers[i], nullptr,
d3dRtvCPUDescriptorHandle);
d3dRtvCPUDescriptorHandle.ptr += m_nRtvDescriptorIncrementSize;
}
}
void CGameFramework::CreateDepthStencilView(){
D3D12_RESOURCE_DESC d3dResourceDesc;
d3dResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
d3dResourceDesc.Alignment = 0;
d3dResourceDesc.Width = m_nWndClientWidth;
d3dResourceDesc.Height = m_nWndClientHeight;
d3dResourceDesc.DepthOrArraySize = 1;
d3dResourceDesc.MipLevels = 1;
d3dResourceDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
d3dResourceDesc.SampleDesc.Count = (m_bMsaa4xEnable) ? 4 : 1;
d3dResourceDesc.SampleDesc.Quality = (m_bMsaa4xEnable) ? (m_nMsaa4xQualityLevels - 1) : 0;
d3dResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
d3dResourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
D3D12_HEAP_PROPERTIES d3dHeapProperties;
::ZeroMemory(&d3dHeapProperties, sizeof(D3D12_HEAP_PROPERTIES));
d3dHeapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
d3dHeapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
d3dHeapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
d3dHeapProperties.CreationNodeMask = 1;
d3dHeapProperties.VisibleNodeMask = 1;
D3D12_CLEAR_VALUE d3dClearValue;
d3dClearValue.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
d3dClearValue.DepthStencil.Depth = 1.0f;
d3dClearValue.DepthStencil.Stencil = 0;
m_pd3dDevice->CreateCommittedResource(&d3dHeapProperties, D3D12_HEAP_FLAG_NONE,
&d3dResourceDesc, D3D12_RESOURCE_STATE_DEPTH_WRITE, &d3dClearValue,
IID_PPV_ARGS(&m_pd3dDepthStencilBuffer));
D3D12_CPU_DESCRIPTOR_HANDLE d3dDsvCpuDescriptorHandle =
m_pd3dDsvDescriptorHeap->GetCPUDescriptorHandleForHeapStart();
m_pd3dDevice->CreateDepthStencilView(m_pd3dDepthStencilBuffer, nullptr, d3dDsvCpuDescriptorHandle);
}
void CGameFramework::BuildObjects(){
}
void CGameFramework::ReleaseObjects(){
}
void CGameFramework::OnProcessingMouseMessage(HWND hWnd, UINT nMessageID, WPARAM wParam, LPARAM lParam){
switch (nMessageID) {
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
break;
case WM_LBUTTONUP:
case WM_RBUTTONUP:
break;
case WM_MOUSEMOVE:
break;
default:
break;
}
}
void CGameFramework::OnProcessingKeyboardMessage(HWND hWnd, UINT nMessageID, WPARAM wParam, LPARAM lParam){
switch (nMessageID) {
case WM_KEYUP:
switch (wParam) {
case VK_ESCAPE:
::PostQuitMessage(0);
break;
case VK_RETURN:
break;
case VK_F8:
break;
case VK_F9:
break;
default:
break;
}
break;
default:
break;
}
}
LRESULT CGameFramework::OnProcessingWindowMessage(HWND hWnd, UINT nMessageID, WPARAM wParam, LPARAM lParam){
switch (nMessageID) {
case WM_SIZE: {
m_nWndClientWidth = LOWORD(lParam);
m_nWndClientHeight = HIWORD(lParam);
break;
}
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_LBUTTONUP:
case WM_RBUTTONUP:
case WM_MOUSEMOVE:
OnProcessingMouseMessage(hWnd, nMessageID, wParam, lParam);
break;
case WM_KEYDOWN:
case WM_KEYUP:
OnProcessingKeyboardMessage(hWnd, nMessageID, wParam, lParam);
break;
}
return 0;
}
void CGameFramework::ProcessInput(){
}
void CGameFramework::AnimateObjects(){
}
void CGameFramework::WaitForGpuComplete(){
++m_nFenceValue;
const UINT64 nFence = m_nFenceValue;
HRESULT hResult = m_pd3dCommandQueue->Signal(m_pd3dFence, nFence);
if (m_pd3dFence->GetCompletedValue() < nFence) {
hResult = m_pd3dFence->SetEventOnCompletion(nFence, m_hFenceEvent);
::WaitForSingleObject(m_hFenceEvent, INFINITE);
}
}
void CGameFramework::FrameAdvance(){
ProcessInput();
AnimateObjects();
HRESULT hResult = m_pd3dCommandAllocator->Reset();
hResult = m_pd3dCommandList->Reset(m_pd3dCommandAllocator, nullptr);
D3D12_RESOURCE_BARRIER d3dResourceBarrier;
::ZeroMemory(&d3dResourceBarrier, sizeof(D3D12_RESOURCE_BARRIER));
d3dResourceBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
d3dResourceBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
d3dResourceBarrier.Transition.pResource =
m_ppd3dRenderTargetBuffers[m_nSwapChainBufferIndex];
d3dResourceBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
d3dResourceBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
d3dResourceBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
m_pd3dCommandList->ResourceBarrier(1, &d3dResourceBarrier);
m_pd3dCommandList->RSSetViewports(1, &m_d3dViewport);
m_pd3dCommandList->RSSetScissorRects(1, &m_d3dScissorRect);
D3D12_CPU_DESCRIPTOR_HANDLE d3dRtvCPUDescriptorHandle =
m_pd3dRtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart();
d3dRtvCPUDescriptorHandle.ptr += (m_nSwapChainBufferIndex * m_nRtvDescriptorIncrementSize);
float pfClearColor[4] = { 0.0f, 0.125f, 0.3f, 1.0f };
m_pd3dCommandList->ClearRenderTargetView(d3dRtvCPUDescriptorHandle,
pfClearColor, 0, nullptr);
D3D12_CPU_DESCRIPTOR_HANDLE d3dDsvCPUDescriptorHandle =
m_pd3dDsvDescriptorHeap->GetCPUDescriptorHandleForHeapStart();
m_pd3dCommandList->ClearDepthStencilView(d3dDsvCPUDescriptorHandle,
D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);
m_pd3dCommandList->OMSetRenderTargets(1, &d3dRtvCPUDescriptorHandle, true, &d3dDsvCPUDescriptorHandle);
//렌더링코드는 여기에
d3dResourceBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
d3dResourceBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
d3dResourceBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
m_pd3dCommandList->ResourceBarrier(1, &d3dResourceBarrier);
hResult = m_pd3dCommandList->Close();
ID3D12CommandList* ppd3dCommandLists[] = { m_pd3dCommandList };
m_pd3dCommandQueue->ExecuteCommandLists(1, ppd3dCommandLists);
WaitForGpuComplete();
DXGI_PRESENT_PARAMETERS dxgiPresentParameters;
dxgiPresentParameters.DirtyRectsCount = 0;
dxgiPresentParameters.pDirtyRects = nullptr;
dxgiPresentParameters.pScrollRect = nullptr;
dxgiPresentParameters.pScrollOffset = nullptr;
m_pdxgiSwapChain->Present1(1, 0, &dxgiPresentParameters);
//스왑체인 프리젠트 , 현재 후면버퍼가 전면버퍼로 이동하고, 렌더 타겟 인덱스가 바뀔것
m_nSwapChainBufferIndex = m_pdxgiSwapChain->GetCurrentBackBufferIndex();
}
'Graphics > DirectX' 카테고리의 다른 글
( D3DX12 / DirectX12 ) 2. DirectX12의 그리기 연산 (2) | 2020.09.08 |
---|---|
추상 클래스와 정적 다형성 ( abstract class, static polymorphism ? ) (0) | 2019.10.09 |