#include "RESrcLoader.h"
RESrcLoader::RESrcLoader(HWND hWnd, ComPtr<ID3D12Device> inDevice, ComPtr<ID3D12GraphicsCommandList> inCommandList, ComPtr<ID3D12CommandQueue> inCommandQueue, DXGI_FORMAT inBackBufferFormat, DXGI_FORMAT inDepthStencilFormat, int inMSAAQuality, bool inMSAA4X)
{
mHasAnimation = false;
mMeshCount = 0;
RE_hWnd = hWnd;
md3dDevice = inDevice;
mCommandList = inCommandList;
mCommandQueue = inCommandQueue;
m4xMsaaState = inMSAA4X; // 4X MSAA enabled
m4xMsaaQuality = inMSAAQuality; // quality level of 4X MSAA
mBackBufferFormat = inBackBufferFormat;
mDepthStencilFormat = inDepthStencilFormat;
}
void RESrcLoader::BuildDescriptorHeaps()
{
D3D12_DESCRIPTOR_HEAP_DESC cbvHeapDesc;
cbvHeapDesc.NumDescriptors = 1;
cbvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
cbvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
cbvHeapDesc.NodeMask = 0;
ThrowIfFailed(md3dDevice->CreateDescriptorHeap(&cbvHeapDesc, IID_PPV_ARGS(&mCbvHeap)));
D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {};
srvHeapDesc.NumDescriptors = 1;
srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
ThrowIfFailed(md3dDevice->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&mSrvHeap)));
}
void RESrcLoader::BuildConstantBuffers()
{
mCB = make_unique<UploadBuffer<RE_CB>>(md3dDevice.Get(), 1, true);
UINT objCBByteSize = Common::CalcConstantBufferByteSize(sizeof(RE_CB));
D3D12_GPU_VIRTUAL_ADDRESS cbAddress = mCB->Resource()->GetGPUVirtualAddress();
D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc;
cbvDesc.BufferLocation = 0;
cbvDesc.SizeInBytes = Common::CalcConstantBufferByteSize(sizeof(RE_CB));
md3dDevice->CreateConstantBufferView(
&cbvDesc,
mCbvHeap->GetCPUDescriptorHandleForHeapStart());
}
void RESrcLoader::BuildRootSignature()
{
// Shader programs typically require resources as input (constant buffers,
// textures, samplers). The root signature defines the resources the shader
// programs expect. If we think of the shader programs as a function, and
// the input resources as function parameters, then the root signature can be
// thought of as defining the function signature.
// Root parameter can be a table, root descriptor or root constants.
CD3DX12_ROOT_PARAMETER slotRootParameter[2];
// Create a single descriptor table of CBVs.
CD3DX12_DESCRIPTOR_RANGE cbvTable;
cbvTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0);
CD3DX12_DESCRIPTOR_RANGE srvTable;
srvTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC);
slotRootParameter[0].InitAsDescriptorTable(1, &cbvTable);
slotRootParameter[1].InitAsDescriptorTable(1, &srvTable, D3D12_SHADER_VISIBILITY_PIXEL);
D3D12_STATIC_SAMPLER_DESC sampler = {};
sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
sampler.MipLODBias = 0;
sampler.MaxAnisotropy = 0;
sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
sampler.MinLOD = 0.0f;
sampler.MaxLOD = D3D12_FLOAT32_MAX;
sampler.ShaderRegister = 0;
sampler.RegisterSpace = 0;
sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
// A root signature is an array of root parameters.
CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(2, slotRootParameter, 1, &sampler,
D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
// create a root signature with a single slot which points to a descriptor range consisting of a single constant buffer
ComPtr<ID3DBlob> serializedRootSig = nullptr;
ComPtr<ID3DBlob> errorBlob = nullptr;
HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());
if (errorBlob != nullptr)
{
::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
}
ThrowIfFailed(hr);
ThrowIfFailed(md3dDevice->CreateRootSignature(
0,
serializedRootSig->GetBufferPointer(),
serializedRootSig->GetBufferSize(),
IID_PPV_ARGS(&mRootSignature)));
}
void RESrcLoader::BuildShadersAndInputLayout()
{
mvsByteCode = Common::CompileShader(L"Shaders\\REMain.hlsl", nullptr, "VSMAIN", "vs_5_0");
mpsByteCode = Common::CompileShader(L"Shaders\\REMain.hlsl", nullptr, "PSMAIN", "ps_5_0");
mhsByteCode = Common::CompileShader(L"Shaders\\REMain.hlsl", nullptr, "HSMAIN", "hs_5_0");
mdsByteCode = Common::CompileShader(L"Shaders\\REMain.hlsl", nullptr, "DSMAIN", "ds_5_0");
mInputLayout = { {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
{"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 20, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}/*,
{"BONEINDICES", 0, DXGI_FORMAT_R32G32B32A32_UINT, 0, 32, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
{"WEIGHTS", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 48, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}*/ };
}
void RESrcLoader::BuildPSO()
{
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc;
ZeroMemory(&psoDesc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
psoDesc.InputLayout = { mInputLayout.data(), (UINT)mInputLayout.size() };
psoDesc.pRootSignature = mRootSignature.Get();
psoDesc.VS =
{
reinterpret_cast<BYTE*>(mvsByteCode->GetBufferPointer()),
mvsByteCode->GetBufferSize()
};
psoDesc.HS =
{
reinterpret_cast<BYTE*>(mhsByteCode->GetBufferPointer()),
mhsByteCode->GetBufferSize()
};
psoDesc.DS =
{
reinterpret_cast<BYTE*>(mdsByteCode->GetBufferPointer()),
mdsByteCode->GetBufferSize()
};
psoDesc.PS =
{
reinterpret_cast<BYTE*>(mpsByteCode->GetBufferPointer()),
mpsByteCode->GetBufferSize()
};
D3D12_RASTERIZER_DESC rastdesc = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
rastdesc.CullMode = D3D12_CULL_MODE_NONE;
psoDesc.RasterizerState = rastdesc;
psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
psoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
psoDesc.SampleMask = UINT_MAX;
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH;
psoDesc.NumRenderTargets = 1;
psoDesc.RTVFormats[0] = mBackBufferFormat;
psoDesc.SampleDesc.Count = m4xMsaaState ? 4 : 1;
psoDesc.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
psoDesc.DSVFormat = mDepthStencilFormat;
ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&mPSO)));
}
void RESrcLoader::Draw(Camera *ActiveCamera)
{
RE_CB cb;
for (UINT i = 0; i < 96; ++i)
XMStoreFloat4x4(&cb.Bones[i], XMMatrixIdentity());
cb.LightDirection = XMFLOAT3(0, 1, 0);
cb.TessellationFactor = 1.0f;
XMStoreFloat4x4(&cb.mView, XMMatrixTranspose(ActiveCamera->mView));
XMStoreFloat4x4(&cb.mProjection, XMMatrixTranspose(ActiveCamera->mProjection));
XMStoreFloat4x4(&cb.mWorld, XMMatrixTranspose(XMMatrixTranslation(0,0,-10)));
cb.mHasAnimation = 0;
mCB->CopyData(0, cb);
// Set necessary state.
mCommandList->SetGraphicsRootSignature(mRootSignature.Get());
{
ID3D12DescriptorHeap* ppHeaps[] = { mCbvHeap.Get() };
mCommandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps);
mCommandList->SetGraphicsRootDescriptorTable(0, mCbvHeap->GetGPUDescriptorHandleForHeapStart());
}
{
ID3D12DescriptorHeap* ppHeaps[] = { mSrvHeap.Get() };
mCommandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps);
mCommandList->SetGraphicsRootDescriptorTable(1, mSrvHeap->GetGPUDescriptorHandleForHeapStart());
}
for (auto md : Model)
{
md.DrawMesh(mCommandList);
}
}
struct Mesh_Data
{
string mMeshName;
string mMeshTextureName;
int mVertexCount;
vector<RE_VERTEX> mMeshGeometry;
ComPtr<ID3D12Resource> Mesh_Vertex_Buffer_GPU;
ComPtr<ID3D12Resource> Mesh_Vertex_Buffer_Uploader;
UINT VertexByteStride;
UINT VertexBufferByteSize;
Mesh_Data()
{
Mesh_Vertex_Buffer_GPU = nullptr;
VertexByteStride = 0;
VertexBufferByteSize = 0;
}
void CreateMeshVertexBuffer(ComPtr<ID3D12Device> inDevice, ComPtr<ID3D12GraphicsCommandList> inCommandList)
{
const UINT vbByteSize = (UINT)mMeshGeometry.size() * sizeof(RE_VERTEX);
Mesh_Vertex_Buffer_GPU = Common::CreateDefaultBuffer(inDevice.Get(),
inCommandList.Get(), mMeshGeometry.data(), vbByteSize, Mesh_Vertex_Buffer_Uploader);
VertexByteStride = sizeof(RE_VERTEX);
VertexBufferByteSize = vbByteSize;
}
D3D12_VERTEX_BUFFER_VIEW VertexBufferView()const
{
D3D12_VERTEX_BUFFER_VIEW vbv;
vbv.BufferLocation = Mesh_Vertex_Buffer_GPU->GetGPUVirtualAddress();
vbv.StrideInBytes = VertexByteStride;
vbv.SizeInBytes = VertexBufferByteSize;
return vbv;
}
void DrawMesh(ComPtr<ID3D12GraphicsCommandList> inCommandList)
{
inCommandList->IASetVertexBuffers(0, 1, &VertexBufferView());
inCommandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST);
inCommandList->DrawInstanced((UINT)mMeshGeometry.size(), 1, 0, 0);
}
};
void Core::Render()
{
if (mREnder)
{
__int64 PrevCount, CurrCount;
QueryPerformanceCounter((LARGE_INTEGER*)&PrevCount);
cam->Update(XM_PI / 3, (float)1024 / (float)768, 0.1f, 100.0f);
// Reuse the memory associated with command recording.
// We can only reset when the associated command lists have finished execution on the GPU.
ThrowIfFailed(mDirectCmdListAlloc->Reset());
// A command list can be reset after it has been added to the command queue via ExecuteCommandList.
// Reusing the command list reuses memory.
ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), m3DObj->mPSO.Get()));
// Indicate a state transition on the resource usage.
mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));
// Set necessary state.
//mCommandList->SetGraphicsRootSignature(m3DObj->mRootSignature.Get());
/*
{
ID3D12DescriptorHeap* ppHeaps[] = { m3DObj->mCbvHeap.Get() };
mCommandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps);
mCommandList->SetGraphicsRootDescriptorTable(0, m3DObj->mCbvHeap->GetGPUDescriptorHandleForHeapStart());
}
{
ID3D12DescriptorHeap* ppHeaps[] = { m3DObj->mSrvHeap.Get() };
mCommandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps);
mCommandList->SetGraphicsRootDescriptorTable(1, m3DObj->mSrvHeap->GetGPUDescriptorHandleForHeapStart());
}
*/
// Set the viewport and scissor rect. This needs to be reset whenever the command list is reset.
mCommandList->RSSetViewports(1, &mScreenViewport);
mCommandList->RSSetScissorRects(1, &mScissorRect);
// Clear the back buffer and depth buffer.
mCommandList->ClearRenderTargetView(CurrentBackBufferView(), Colors::LightSteelBlue, 0, nullptr);
mCommandList->ClearDepthStencilView(DepthStencilView(), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);
// Specify the buffers we are going to render to.
mCommandList->OMSetRenderTargets(1, &CurrentBackBufferView(), true, &DepthStencilView());
m3DObj->Draw(cam);
// Indicate a state transition on the resource usage.
mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
// Done recording commands.
ThrowIfFailed(mCommandList->Close());
// Add the command list to the queue for execution.
ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
// swap the back and front buffers
ThrowIfFailed(mSwapChain->Present(0, 0));
mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;
// Wait until frame commands are complete. This waiting is inefficient and is
// done for simplicity. Later we will show how to organize our rendering code
// so we do not have to wait per frame.
FlushCommandQueue();
FrameCount++;
if (ttmp >= 1.0)
{
FPS = (FrameCount / ttmp);
ttmp = 0;
FrameCount = 0;
}
QueryPerformanceCounter((LARGE_INTEGER*)&CurrCount);
tDelta = (double)(CurrCount - PrevCount) * SecondsPerCount;
if (tDelta < 0)
tDelta = 0;
tElapsed += tDelta;
ttmp += tDelta;
char str[256];
sprintf_s(str, "FPS %.2f (Frame Time %.3f)", FPS, tDelta);
SetWindowTextA(tmphWnd, str);
}
}
void Core::InitDirect3D(HWND hWnd, int Width, int Height)
{
tmphWnd = hWnd;
#if defined(DEBUG) || defined(_DEBUG)
// Enable the D3D12 debug layer.
{
ComPtr<ID3D12Debug> debugController;
ThrowIfFailed(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)));
debugController->EnableDebugLayer();
}
#endif
ThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(&mdxgiFactory)));
// Try to create hardware device.
ThrowIfFailed(D3D12CreateDevice(
nullptr, // default adapter
D3D_FEATURE_LEVEL_12_0,
IID_PPV_ARGS(&md3dDevice)));
ThrowIfFailed(md3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE,
IID_PPV_ARGS(&mFence)));
mRtvDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
mDsvDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
mCbvSrvUavDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
// Check 4X MSAA quality support for our back buffer format.
// All Direct3D 11 capable devices support 4X MSAA for all render
// target formats, so we only need to check quality support.
D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msQualityLevels;
msQualityLevels.Format = mBackBufferFormat;
msQualityLevels.SampleCount = 4;
msQualityLevels.Flags = D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE;
msQualityLevels.NumQualityLevels = 0;
ThrowIfFailed(md3dDevice->CheckFeatureSupport(
D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,
&msQualityLevels,
sizeof(msQualityLevels)));
m4xMsaaQuality = msQualityLevels.NumQualityLevels;
assert(m4xMsaaQuality > 0 && "Unexpected MSAA quality level.");
#ifdef _DEBUG
LogAdapters();
#endif
CreateCommandObjects();
CreateSwapChain(hWnd, Width, Height);
CreateRtvAndDsvDescriptorHeaps();
cam = new Camera(XMVectorSet(0, 0, -20, 0.0f), XMVectorSet(0, 0, -10, 0.0f));
ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), nullptr));
m3DObj = new RESrcLoader(hWnd, md3dDevice, mCommandList, mCommandQueue, mBackBufferFormat, mDepthStencilFormat, m4xMsaaQuality, m4xMsaaState);
m3DObj->LoadFromRE3DM("ball.RE3DM");
m3DObj->InitializeResource();
// Execute the initialization commands.
ThrowIfFailed(mCommandList->Close());
ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
// Wait until initialization is complete.
FlushCommandQueue();
mREnder = true;
}