grafika-latest-working/DXWindow.cpp

482 lines
13 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::Black, 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},
{"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, 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();
XMFLOAT3 camPos = pCam->getViewParams().position;
constantBuffer.camPosition = { camPos.x, camPos.y, camPos.z, 0.0 };
// megvilágítás iránya
//XMVECTOR lightDir = XMVectorSet(1.0, 1.0, 1.0, 0.0);
XMFLOAT3 viewDir = pCam->getViewDirection();
XMVECTOR lightDir;
lightDir = XMLoadFloat3(&viewDir);
lightDir = -XMVector4Normalize(lightDir);
//lightDir = XMVector4Transform(lightDir, XMMatrixRotationY(lightAngle));
lightDir = XMVector4Transform(lightDir, XMMatrixRotationY(0));
XMStoreFloat4(&constantBuffer.lightDir, lightDir);
// fény iránya
lightAngle += 0.01f;
if (lightAngle > XM_2PI) {
lightAngle -= XM_2PI;
}
}
bufferMapCopy(cbResource, static_cast<void *>(&constantBuffer), sizeof(constantBuffer));
}
void DXWindow::createRootSignature()
{
// root paraméterek létrehozása
CD3DX12_ROOT_PARAMETER slotParams[2];
// TODO worldMatrix konstansbufferének hozzáadása
// konstansbuffer-TÍPUS beállítása
slotParams[0].InitAsConstantBufferView(0);
slotParams[1].InitAsConstantBufferView(1);
CD3DX12_ROOT_SIGNATURE_DESC rsD(2, &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;
}
}