#include "DXWindow.h" #include "IDrawable.h" namespace eg3d { DXWindow::DXWindow() : Window(true) { init(); initDrawObjects(); } 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::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 ////////// OBJEKTUMOK KIRAJZOLÁSA drawObject(); // TODO drawables kirajzolása ////////// 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() { initVertices(); setupInputLayout(); createBuffers(); uploadBuffers(); loadShaders(); createConstantBuffers(); createRootSignature(); createPSO(); } void DXWindow::initVertices() { vertices = { { -0.5f, -0.5f, 0.1f }, { 0.5f, -0.5f, 0.1f }, { 0, 0.98f, 0.1f }, }; indices = { 0, 2, 1 }; } void DXWindow::setupInputLayout() { inputElements = { {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}, // TODO további elemek létrehozása }; } void DXWindow::createBuffers() { // --- vertex buffer létrehozása vertexBuffer = createBuffer_UH(mDevice, vertices.size() * sizeof(Vertex)); vertexBufferView.BufferLocation = vertexBuffer->GetGPUVirtualAddress(); vertexBufferView.StrideInBytes = sizeof(Vertex); vertexBufferView.SizeInBytes = vertices.size() * sizeof(Vertex); // --- index buffer létrehozása TODO átírás createBuffer_UH() használatával indexBuffer = createBuffer_UH(mDevice, indices.size() * sizeof(uint32_t)); indexBufferView.Format = DXGI_FORMAT_R32_UINT; indexBufferView.BufferLocation = indexBuffer->GetGPUVirtualAddress(); indexBufferView.SizeInBytes = indices.size() * sizeof(uint32_t); } void DXWindow::uploadBuffers() { // --- vertex buffer feltöltése bufferMapCopy(vertexBuffer, vertices.data(), vertices.size() * sizeof(Vertex)); // --- index buffer feltöltése bufferMapCopy(indexBuffer, indices.data(), indices.size() * sizeof(uint32_t)); } void DXWindow::createConstantBuffers() { // konstansbuffer létrehozása } void DXWindow::updateConstantBuffers() { // TODO konstansbuffer feltöltése } void DXWindow::createRootSignature() { // TODO root paraméterek megadása CD3DX12_ROOT_SIGNATURE_DESC rsD(0, nullptr, 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.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::drawObject() { mCommandList->IASetVertexBuffers(0, 1, &vertexBufferView); mCommandList->IASetIndexBuffer(&indexBufferView); mCommandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); mCommandList->DrawIndexedInstanced(indices.size(), 1, 0, 0, 0); } }