461 lines
12 KiB
C++
461 lines
12 KiB
C++
#include "DXWindow.h"
|
|
#include "IDrawable.h"
|
|
|
|
using namespace DirectX;
|
|
|
|
namespace eg3d {
|
|
|
|
DXWindow::DXWindow() : Window(true)
|
|
{
|
|
init();
|
|
initDrawObjects();
|
|
|
|
pCam = nullptr;
|
|
}
|
|
|
|
|
|
DXWindow::~DXWindow()
|
|
{
|
|
|
|
}
|
|
|
|
|
|
void DXWindow::init()
|
|
{
|
|
LOG("Initializing DXWindow!");
|
|
|
|
createDevice();
|
|
createSyncObjects();
|
|
queryDescriptorSizes();
|
|
createCommandObjects();
|
|
createSwapChain();
|
|
createDescriptorHeaps();
|
|
createRTVs();
|
|
createDSV();
|
|
setViewPort();
|
|
setScissorRectangle();
|
|
}
|
|
|
|
void DXWindow::createDevice()
|
|
{
|
|
LOG("Creating device!");
|
|
|
|
#if defined(DEBUG) | defined(_DEBUG)
|
|
LOG("Debug ON!");
|
|
|
|
if (FAILED(D3D12GetDebugInterface(IID_PPV_ARGS(mDebugController.GetAddressOf()))))
|
|
LOG("Failed to create debug interface!");
|
|
|
|
mDebugController->EnableDebugLayer();
|
|
#endif
|
|
|
|
//-------------------------------
|
|
|
|
HRESULT hardwareResult = D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(mDevice.GetAddressOf()));
|
|
|
|
if (FAILED(hardwareResult))
|
|
{
|
|
LOG("Could not create D3D12 Device!");
|
|
}
|
|
|
|
//-------------------------------
|
|
|
|
if (FAILED(CreateDXGIFactory1(IID_PPV_ARGS(mFactory.GetAddressOf()))))
|
|
LOG("Failed to create DXGI factory!");
|
|
|
|
}
|
|
|
|
void DXWindow::createSyncObjects()
|
|
{
|
|
if (FAILED(mDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(mFence.GetAddressOf()))))
|
|
LOG("Failed to create fence!");
|
|
}
|
|
|
|
void DXWindow::queryDescriptorSizes()
|
|
{
|
|
LOG("Querying descriptor sizes!");
|
|
|
|
mRTVDescSize = mDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
|
mDSVDescSize = mDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
|
|
mCBVSRVDescSize = mDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
|
}
|
|
|
|
void DXWindow::createCommandObjects()
|
|
{
|
|
LOG("Creating command objects!");
|
|
|
|
// command queue létrehozása
|
|
D3D12_COMMAND_QUEUE_DESC cqDesc = {};
|
|
cqDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
|
cqDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
|
|
|
if (FAILED(mDevice->CreateCommandQueue(&cqDesc, IID_PPV_ARGS(mCommandQueue.GetAddressOf()))))
|
|
LOG("Failed to create command queue!");
|
|
|
|
// command allocator létrehozása
|
|
if (FAILED(mDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(mCommandAllocator.GetAddressOf()))))
|
|
LOG("Failed to create command allocator!");
|
|
|
|
// command list létrehozása
|
|
if (FAILED(mDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, mCommandAllocator.Get(), nullptr,
|
|
IID_PPV_ARGS(mCommandList.GetAddressOf()))))
|
|
LOG("Failed to create command list!");
|
|
|
|
mCommandList->Close(); // command list lezárása
|
|
}
|
|
|
|
void DXWindow::createSwapChain()
|
|
{
|
|
LOG("Creating swap chain!");
|
|
|
|
SIZE size = getSize(); // ablak méretének lekérése
|
|
|
|
DXGI_SWAP_CHAIN_DESC swD = {};
|
|
|
|
swD.BufferDesc.Width = size.cx; // buffer méretének beállítása (px)
|
|
swD.BufferDesc.Height = size.cy;
|
|
swD.BufferDesc.RefreshRate = { 60, 1 }; // FPS
|
|
swD.BufferDesc.Format = cBackBufferFormat; // back buffer formátuma
|
|
swD.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
|
|
swD.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
|
|
|
|
swD.BufferCount = cSwapChainBufferCount;
|
|
swD.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
|
|
|
swD.OutputWindow = mHWND; // ablak fogantyúja
|
|
swD.Windowed = true;
|
|
swD.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
|
swD.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
|
|
|
|
swD.SampleDesc.Count = 1; // ~élsimítás
|
|
swD.SampleDesc.Quality = 0;
|
|
|
|
if (FAILED(mFactory->CreateSwapChain(mCommandQueue.Get(), &swD, mSwapChain.GetAddressOf())))
|
|
LOG("Failed to create swap chain!");
|
|
|
|
mCurrentBackBuffer = 0;
|
|
}
|
|
|
|
void DXWindow::createDescriptorHeaps()
|
|
{
|
|
LOG("Creating descriptor heaps!");
|
|
|
|
// ---------- RTV
|
|
D3D12_DESCRIPTOR_HEAP_DESC hD = {};
|
|
hD.NumDescriptors = cSwapChainBufferCount;
|
|
hD.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
|
|
hD.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
|
hD.NodeMask = 0;
|
|
|
|
if (FAILED(mDevice->CreateDescriptorHeap(&hD, IID_PPV_ARGS(mRtvDescriptorHeap.GetAddressOf()))))
|
|
LOG("Failed to create render target view descriptor heap!");
|
|
|
|
// ---------- DSV
|
|
hD.NumDescriptors = 1;
|
|
hD.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
|
|
|
|
if (FAILED(mDevice->CreateDescriptorHeap(&hD, IID_PPV_ARGS(mDsvDescriptorHeap.GetAddressOf()))))
|
|
LOG("Failed to create DSV descriptor heap!");
|
|
}
|
|
|
|
void DXWindow::createRTVs()
|
|
{
|
|
LOG("Creating RTV!");
|
|
|
|
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHeapHandle(mRtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
|
|
|
|
for (UINT i = 0; i < cSwapChainBufferCount; i++)
|
|
{
|
|
if (FAILED(mSwapChain->GetBuffer(i, IID_PPV_ARGS(&mSwapChainBuffer[i]))))
|
|
LOG("Failed to get buffer in createTRVs()!");
|
|
|
|
mDevice->CreateRenderTargetView(mSwapChainBuffer[i].Get(), nullptr, rtvHeapHandle);
|
|
|
|
rtvHeapHandle.Offset(1, mRTVDescSize);
|
|
}
|
|
}
|
|
|
|
void DXWindow::createDSV()
|
|
{
|
|
LOG("Creating DSV!");
|
|
|
|
SIZE size = getSize();
|
|
|
|
D3D12_RESOURCE_DESC dsD = {};
|
|
dsD.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
dsD.Alignment = 0;
|
|
dsD.Width = size.cx;
|
|
dsD.Height = size.cy;
|
|
dsD.DepthOrArraySize = 1;
|
|
dsD.MipLevels = 1;
|
|
dsD.Format = cDepthStencilFormat;
|
|
|
|
dsD.SampleDesc.Count = 1;
|
|
dsD.SampleDesc.Quality = 0;
|
|
|
|
dsD.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
dsD.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
|
|
|
|
D3D12_CLEAR_VALUE optClear;
|
|
optClear.Format = cDepthStencilFormat;
|
|
optClear.DepthStencil.Depth = 1.0f;
|
|
optClear.DepthStencil.Stencil = 0;
|
|
|
|
if (FAILED(mDevice->CreateCommittedResource(
|
|
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
|
|
D3D12_HEAP_FLAG_NONE,
|
|
&dsD,
|
|
D3D12_RESOURCE_STATE_DEPTH_WRITE,
|
|
&optClear,
|
|
IID_PPV_ARGS(mDepthStencilBuffer.GetAddressOf())
|
|
)))
|
|
LOG("Failed to create depth buffer committed resource!");
|
|
|
|
mDevice->CreateDepthStencilView(
|
|
mDepthStencilBuffer.Get(),
|
|
nullptr,
|
|
getDSVHandle());
|
|
}
|
|
|
|
void DXWindow::setViewPort()
|
|
{
|
|
LOG("Setting viewport!");
|
|
|
|
SIZE size = getSize();
|
|
|
|
mViewPort.TopLeftX = 0.0f;
|
|
mViewPort.TopLeftY = 0.0f;
|
|
mViewPort.Width = static_cast<float>(size.cx);
|
|
mViewPort.Height = static_cast<float>(size.cy);
|
|
mViewPort.MinDepth = 0.0f;
|
|
mViewPort.MaxDepth = 1.0f;
|
|
|
|
mCommandList->RSSetViewports(1, &mViewPort);
|
|
}
|
|
|
|
|
|
void DXWindow::setScissorRectangle()
|
|
{
|
|
LOG("Setting scissor rectangle!");
|
|
|
|
SIZE size = getSize();
|
|
|
|
mScissorRect = { 0, 0, size.cx, size.cy };
|
|
mCommandList->RSSetScissorRects(1, &mScissorRect);
|
|
}
|
|
|
|
|
|
D3D12_CPU_DESCRIPTOR_HANDLE DXWindow::getCurrentBackBufferRTVHandle() const {
|
|
return CD3DX12_CPU_DESCRIPTOR_HANDLE(
|
|
mRtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart(),
|
|
mCurrentBackBuffer,
|
|
mRTVDescSize);
|
|
}
|
|
|
|
D3D12_CPU_DESCRIPTOR_HANDLE DXWindow::getDSVHandle() const
|
|
{
|
|
return mDsvDescriptorHeap->GetCPUDescriptorHandleForHeapStart();
|
|
}
|
|
|
|
ID3D12Resource* DXWindow::getCurrentBackBuffer() const
|
|
{
|
|
return mSwapChainBuffer[mCurrentBackBuffer].Get();
|
|
}
|
|
|
|
void DXWindow::Draw(const DrawablePool &drawables)
|
|
{
|
|
updateConstantBuffers(); // konstansbufferek frissítése
|
|
|
|
// ----------------------
|
|
|
|
if (FAILED(mCommandAllocator->Reset()))
|
|
LOG("Couldn't reset command allocator!");
|
|
|
|
if (FAILED(mCommandList->Reset(mCommandAllocator.Get(), pso.Get())))
|
|
LOG("Couldn't reset command list!");
|
|
|
|
// --------
|
|
|
|
mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(getCurrentBackBuffer(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));
|
|
|
|
// ---
|
|
|
|
mCommandList->SetGraphicsRootSignature(rootSignature.Get());
|
|
mCommandList->RSSetViewports(1, &mViewPort);
|
|
mCommandList->RSSetScissorRects(1, &mScissorRect);
|
|
|
|
mCommandList->ClearRenderTargetView(getCurrentBackBufferRTVHandle(), DirectX::Colors::LightSteelBlue, 0, nullptr);
|
|
mCommandList->ClearDepthStencilView(getDSVHandle(), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);
|
|
|
|
mCommandList->OMSetRenderTargets(1, &getCurrentBackBufferRTVHandle(), true, &getDSVHandle());
|
|
|
|
// TODO konstansbuffer bekötése
|
|
mCommandList->SetGraphicsRootConstantBufferView(0, cbResource->GetGPUVirtualAddress());
|
|
|
|
////////// OBJEKTUMOK KIRAJZOLÁSA
|
|
|
|
for (unsigned i = 0; i < drawables.size(); i++)
|
|
{
|
|
drawables[i]->draw(mCommandList);
|
|
}
|
|
|
|
//////////
|
|
|
|
mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(getCurrentBackBuffer(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
|
|
|
|
// ---
|
|
|
|
if (FAILED(mCommandList->Close()))
|
|
LOG("Failed to close command list in Draw()!");
|
|
|
|
// ---
|
|
|
|
ID3D12CommandList * cmdLists[] = { mCommandList.Get() };
|
|
mCommandQueue->ExecuteCommandLists(_countof(cmdLists), cmdLists);
|
|
|
|
// ---
|
|
|
|
if (FAILED(mSwapChain->Present(0, 0)))
|
|
LOG("Failed to present current buffer!");
|
|
|
|
mCurrentBackBuffer = (mCurrentBackBuffer + 1) % cSwapChainBufferCount;
|
|
|
|
flushCommandQueue();
|
|
}
|
|
|
|
|
|
void DXWindow::flushCommandQueue()
|
|
{
|
|
mCurrentFence++;
|
|
|
|
if (FAILED(mCommandQueue->Signal(mFence.Get(), mCurrentFence)))
|
|
LOG("Couldn't signal command queue!");
|
|
|
|
if (mFence->GetCompletedValue() < mCurrentFence)
|
|
{
|
|
HANDLE eventHandle = CreateEventEx(nullptr, false, false, EVENT_ALL_ACCESS);
|
|
|
|
if (FAILED(mFence->SetEventOnCompletion(mCurrentFence, eventHandle)))
|
|
LOG("Couldn't set event to trigger on completion!");
|
|
|
|
WaitForSingleObject(eventHandle, INFINITE);
|
|
CloseHandle(eventHandle);
|
|
}
|
|
}
|
|
|
|
ComPtr<ID3D12Device> DXWindow::getDevice() const {
|
|
return mDevice;
|
|
}
|
|
|
|
// ------------------
|
|
|
|
|
|
void DXWindow::initDrawObjects()
|
|
{
|
|
setupInputLayout();
|
|
loadShaders();
|
|
createConstantBuffers();
|
|
createRootSignature();
|
|
createPSO();
|
|
}
|
|
|
|
void DXWindow::setupInputLayout()
|
|
{
|
|
inputElements = {
|
|
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
|
|
//{"COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}
|
|
// TODO további elemek létrehozása
|
|
};
|
|
}
|
|
|
|
void DXWindow::createConstantBuffers()
|
|
{
|
|
cbResource = createBuffer_UH(mDevice, calc256AlignedSize(sizeof(constantBuffer)));
|
|
}
|
|
|
|
void DXWindow::updateConstantBuffers()
|
|
{
|
|
DirectX::XMStoreFloat4x4(&constantBuffer.transformMatrix, XMMatrixTranspose(XMMatrixRotationX(-XM_PIDIV2)));
|
|
|
|
if (pCam != nullptr) {
|
|
constantBuffer.viewMatrix = pCam->getViewMatrix();
|
|
constantBuffer.projMatrix = pCam->getProjMatrix();
|
|
}
|
|
|
|
bufferMapCopy(cbResource, static_cast<void *>(&constantBuffer), sizeof(constantBuffer));
|
|
}
|
|
|
|
void DXWindow::createRootSignature()
|
|
{
|
|
// root paraméterek létrehozása
|
|
CD3DX12_ROOT_PARAMETER slotParams[1];
|
|
|
|
// TODO worldMatrix konstansbufferének hozzáadása
|
|
|
|
// konstansbuffer-TÍPUS beállítása
|
|
slotParams[0].InitAsConstantBufferView(0);
|
|
|
|
CD3DX12_ROOT_SIGNATURE_DESC rsD(1, &slotParams[0], 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
|
|
|
|
ComPtr<ID3DBlob> serializedRS = nullptr, errorBlob = nullptr;
|
|
if (FAILED(D3D12SerializeRootSignature(&rsD, D3D_ROOT_SIGNATURE_VERSION_1, serializedRS.GetAddressOf(), errorBlob.GetAddressOf())))
|
|
LOG("Error when serializing root signature: " + std::string((char *)errorBlob.Get()));
|
|
|
|
if (FAILED(mDevice->CreateRootSignature(0, serializedRS->GetBufferPointer(), serializedRS->GetBufferSize(), IID_PPV_ARGS(rootSignature.GetAddressOf()))))
|
|
LOG("Error creating root signature!");
|
|
}
|
|
|
|
void DXWindow::loadShaders()
|
|
{
|
|
vertexShader = loadBlob("shaders\\vs.cso");
|
|
pixelShader = loadBlob("shaders\\ps.cso");
|
|
}
|
|
|
|
void DXWindow::createPSO()
|
|
{
|
|
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoD = {};
|
|
|
|
psoD.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
|
|
//psoD.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
|
|
psoD.RasterizerState.FillMode = D3D12_FILL_MODE_WIREFRAME;
|
|
psoD.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
|
|
psoD.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
|
|
psoD.SampleMask = UINT_MAX;
|
|
psoD.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
|
psoD.NumRenderTargets = 1;
|
|
psoD.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
psoD.SampleDesc.Count = 1;
|
|
psoD.SampleDesc.Quality = 0;
|
|
psoD.DSVFormat = DXGI_FORMAT_D24_UNORM_S8_UINT;
|
|
|
|
// shaderprogamok beállítása
|
|
psoD.VS = { vertexShader->GetBufferPointer(), vertexShader->GetBufferSize() };
|
|
psoD.PS = { pixelShader->GetBufferPointer(), pixelShader->GetBufferSize() };
|
|
|
|
// input layout beállítása
|
|
psoD.InputLayout = { inputElements.data(), (UINT)inputElements.size() };
|
|
|
|
// root signature beállítása
|
|
psoD.pRootSignature = rootSignature.Get();
|
|
|
|
|
|
// PSO legyártása
|
|
HRESULT hardwareResult = mDevice->CreateGraphicsPipelineState(&psoD, IID_PPV_ARGS(pso.GetAddressOf()));
|
|
|
|
if (FAILED(hardwareResult))
|
|
{
|
|
LOG("Failed to create PSO!");
|
|
|
|
_com_error err(hardwareResult);
|
|
LOG(err.ErrorMessage());
|
|
}
|
|
}
|
|
|
|
void DXWindow::setCam(Cam *pCam) {
|
|
this->pCam = pCam;
|
|
}
|
|
|
|
|
|
|
|
}
|