#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(size.cx); mViewPort.Height = static_cast(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 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(&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 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; } }