From a32a863d831b44efc2f006920943b336c801fd79 Mon Sep 17 00:00:00 2001 From: Artem Kharytoniuk Date: Sun, 22 Oct 2017 20:08:54 +0200 Subject: [PATCH] DX12: first triangle. --- src/engine/renderer/shaders/shaders.hlsl | 31 ++++ src/engine/renderer/vk.cpp | 191 ++++++++++++++++++----- src/engine/renderer/vk.h | 7 + visual-studio/quake3.vcxproj | 4 +- 4 files changed, 192 insertions(+), 41 deletions(-) create mode 100644 src/engine/renderer/shaders/shaders.hlsl diff --git a/src/engine/renderer/shaders/shaders.hlsl b/src/engine/renderer/shaders/shaders.hlsl new file mode 100644 index 0000000..b00be4e --- /dev/null +++ b/src/engine/renderer/shaders/shaders.hlsl @@ -0,0 +1,31 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +struct PSInput +{ + float4 position : SV_POSITION; + float4 color : COLOR; +}; + +PSInput VSMain(float4 position : POSITION, float4 color : COLOR) +{ + PSInput result; + + result.position = position; + result.color = color; + + return result; +} + +float4 PSMain(PSInput input) : SV_TARGET +{ + return input.color; +} diff --git a/src/engine/renderer/vk.cpp b/src/engine/renderer/vk.cpp index 1d5d038..db0080e 100644 --- a/src/engine/renderer/vk.cpp +++ b/src/engine/renderer/vk.cpp @@ -797,6 +797,8 @@ static void deinit_vulkan_library() { VkPipeline create_pipeline(const Vk_Pipeline_Def&); +void wait_for_previous_frame(); + // Helper function for acquiring the first available hardware adapter that supports Direct3D 12. // If no such adapter can be found, *ppAdapter will be set to nullptr. void get_hardware_adapter(IDXGIFactory4* p_factory, IDXGIAdapter1** pp_adapter) { @@ -899,13 +901,108 @@ void dx_initialize() { DX_CHECK(vk.dx_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&vk.dx_command_allocator))); + // Create an empty root signature. + { + CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc; + rootSignatureDesc.Init(0, nullptr, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT); - DX_CHECK(vk.dx_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, vk.dx_command_allocator, nullptr, IID_PPV_ARGS(&vk.dx_command_list))); + ComPtr signature; + ComPtr error; + DX_CHECK(D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error)); + DX_CHECK(vk.dx_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&vk.dx_root_signature))); + } + + // Create the pipeline state, which includes compiling and loading shaders. + { + ComPtr vertexShader; + ComPtr pixelShader; + +#if defined(_DEBUG) + // Enable better shader debugging with the graphics debugging tools. + UINT compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; +#else + UINT compileFlags = 0; +#endif + + DX_CHECK(D3DCompileFromFile(L"../src/engine/renderer/shaders/shaders.hlsl", nullptr, nullptr, "VSMain", "vs_5_0", compileFlags, 0, &vertexShader, nullptr)); + DX_CHECK(D3DCompileFromFile(L"../src/engine/renderer/shaders/shaders.hlsl", nullptr, nullptr, "PSMain", "ps_5_0", compileFlags, 0, &pixelShader, nullptr)); + + // Define the vertex input layout. + D3D12_INPUT_ELEMENT_DESC inputElementDescs[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 } + }; + + // Describe and create the graphics pipeline state object (PSO). + D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; + psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) }; + psoDesc.pRootSignature = vk.dx_root_signature; + psoDesc.VS = CD3DX12_SHADER_BYTECODE(vertexShader.Get()); + psoDesc.PS = CD3DX12_SHADER_BYTECODE(pixelShader.Get()); + psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT); + psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT); + psoDesc.DepthStencilState.DepthEnable = FALSE; + psoDesc.DepthStencilState.StencilEnable = FALSE; + psoDesc.SampleMask = UINT_MAX; + psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + psoDesc.NumRenderTargets = 1; + psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; + psoDesc.SampleDesc.Count = 1; + DX_CHECK(vk.dx_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&vk.dx_pipeline_state))); + } + + DX_CHECK(vk.dx_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, vk.dx_command_allocator, vk.dx_pipeline_state, IID_PPV_ARGS(&vk.dx_command_list))); // Command lists are created in the recording state, but there is nothing // to record yet. The main loop expects it to be closed, so close it now. DX_CHECK(vk.dx_command_list->Close()); + // Create the vertex buffer. + { + struct Vertex + { + XMFLOAT3 position; + XMFLOAT4 color; + }; + + float aspect_ratio = float(glConfig.vidWidth) / float(glConfig.vidHeight); + + // Define the geometry for a triangle. + Vertex triangleVertices[] = + { + { { 0.0f, 0.25f * aspect_ratio, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f } }, + { { 0.25f, -0.25f * aspect_ratio, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f } }, + { { -0.25f, -0.25f * aspect_ratio, 0.0f }, { 0.0f, 0.0f, 1.0f, 1.0f } } + }; + + const UINT vertexBufferSize = sizeof(triangleVertices); + + // Note: using upload heaps to transfer static data like vert buffers is not + // recommended. Every time the GPU needs it, the upload heap will be marshalled + // over. Please read up on Default Heap usage. An upload heap is used here for + // code simplicity and because there are very few verts to actually transfer. + DX_CHECK(vk.dx_device->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), + D3D12_HEAP_FLAG_NONE, + &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, + IID_PPV_ARGS(&vk.dx_vertex_buffer))); + + // Copy the triangle data to the vertex buffer. + UINT8* pVertexDataBegin; + CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. + DX_CHECK(vk.dx_vertex_buffer->Map(0, &readRange, reinterpret_cast(&pVertexDataBegin))); + memcpy(pVertexDataBegin, triangleVertices, sizeof(triangleVertices)); + vk.dx_vertex_buffer->Unmap(0, nullptr); + + // Initialize the vertex buffer view. + vk.dx_vertex_buffer_view.BufferLocation = vk.dx_vertex_buffer->GetGPUVirtualAddress(); + vk.dx_vertex_buffer_view.StrideInBytes = sizeof(Vertex); + vk.dx_vertex_buffer_view.SizeInBytes = vertexBufferSize; + } + // Create synchronization objects. { DX_CHECK(vk.dx_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&vk.dx_fence))); @@ -917,18 +1014,50 @@ void dx_initialize() { { DX_CHECK(HRESULT_FROM_WIN32(GetLastError())); } + + // Wait for the command list to execute; we are reusing the same command + // list in our main loop but for now, we just want to wait for setup to + // complete before continuing. + wait_for_previous_frame(); + } +} + +void dx_shutdown() { + vk.dx_swapchain.Reset(); + + vk.dx_command_allocator->Release(); + vk.dx_command_allocator = nullptr; + + for (int i = 0; i < D3D_FRAME_COUNT; i++) { + vk.dx_render_targets[i]->Release(); } - // Create an empty root signature. - /* { - CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc; - rootSignatureDesc.Init(0, nullptr, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT); + vk.dx_rtv_heap->Release(); + vk.dx_rtv_heap = nullptr; - ComPtr signature; - ComPtr error; - DX_CHECK(D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error)); - DX_CHECK(vk.dx_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature))); - }*/ + vk.dx_root_signature->Release(); + vk.dx_root_signature = nullptr; + + vk.dx_command_queue->Release(); + vk.dx_command_queue = nullptr; + + vk.dx_command_list->Release(); + vk.dx_command_list = nullptr; + + vk.dx_pipeline_state->Release(); + vk.dx_pipeline_state = nullptr; + + vk.dx_fence->Release(); + vk.dx_fence = nullptr; + + ::CloseHandle(vk.dx_fence_event); + vk.dx_fence_event = NULL; + + vk.dx_vertex_buffer->Release(); + vk.dx_vertex_buffer = nullptr; + + vk.dx_device->Release(); + vk.dx_device = nullptr; } void vk_initialize() { @@ -1411,35 +1540,6 @@ void vk_initialize() { vk.active = true; } -void dx_shutdown() { - vk.dx_swapchain.Reset(); - - vk.dx_command_allocator->Release(); - vk.dx_command_allocator = nullptr; - - for (int i = 0; i < D3D_FRAME_COUNT; i++) { - vk.dx_render_targets[i]->Release(); - } - - vk.dx_rtv_heap->Release(); - vk.dx_rtv_heap = nullptr; - - vk.dx_command_queue->Release(); - vk.dx_command_queue = nullptr; - - vk.dx_command_list->Release(); - vk.dx_command_list = nullptr; - - vk.dx_fence->Release(); - vk.dx_fence = nullptr; - - ::CloseHandle(vk.dx_fence_event); - vk.dx_fence_event = NULL; - - vk.dx_device->Release(); - vk.dx_device = nullptr; -} - void vk_shutdown() { vkDestroyImage(vk.device, vk.depth_image, nullptr); vkFreeMemory(vk.device, vk.depth_image_memory, nullptr); @@ -2463,15 +2563,28 @@ void dx_begin_frame() { // re-recording. DX_CHECK(vk.dx_command_list->Reset(vk.dx_command_allocator, vk.dx_pipeline_state)); + // Set necessary state. + vk.dx_command_list->SetGraphicsRootSignature(vk.dx_root_signature); + + CD3DX12_VIEWPORT viewport(0.0f, 0.0f, static_cast(glConfig.vidWidth), static_cast(glConfig.vidHeight)); + vk.dx_command_list->RSSetViewports(1, &viewport); + + CD3DX12_RECT scissorRect(0, 0, static_cast(glConfig.vidWidth), static_cast(glConfig.vidHeight)); + vk.dx_command_list->RSSetScissorRects(1, &scissorRect); + // Indicate that the back buffer will be used as a render target. vk.dx_command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(vk.dx_render_targets[vk.dx_frame_index], D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET)); CD3DX12_CPU_DESCRIPTOR_HANDLE rtv_handle(vk.dx_rtv_heap->GetCPUDescriptorHandleForHeapStart(), vk.dx_frame_index, vk.dx_rtv_descriptor_size); + vk.dx_command_list->OMSetRenderTargets(1, &rtv_handle, FALSE, nullptr); // Record commands. const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f }; vk.dx_command_list->ClearRenderTargetView(rtv_handle, clearColor, 0, nullptr); + vk.dx_command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + vk.dx_command_list->IASetVertexBuffers(0, 1, &vk.dx_vertex_buffer_view); + vk.dx_command_list->DrawInstanced(3, 1, 0, 0); // Indicate that the back buffer will now be used to present. vk.dx_command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(vk.dx_render_targets[vk.dx_frame_index], diff --git a/src/engine/renderer/vk.h b/src/engine/renderer/vk.h index 8d867b1..3bb024b 100644 --- a/src/engine/renderer/vk.h +++ b/src/engine/renderer/vk.h @@ -13,9 +13,12 @@ #include "DXGI1_4.h" #include "wrl.h" #include "d3dx12.h" +#include "D3Dcompiler.h" +#include #include "../../engine/platform/win_local.h" using Microsoft::WRL::ComPtr; +using namespace DirectX; const int MAX_SWAPCHAIN_IMAGES = 8; const int MAX_VK_SAMPLERS = 32; @@ -138,6 +141,7 @@ struct Vk_Instance { ID3D12DescriptorHeap* dx_rtv_heap = nullptr; UINT dx_rtv_descriptor_size = 0; ID3D12Resource* dx_render_targets[D3D_FRAME_COUNT]; + ID3D12RootSignature* dx_root_signature = nullptr; ID3D12CommandAllocator* dx_command_allocator = nullptr; ID3D12GraphicsCommandList* dx_command_list = nullptr; ID3D12PipelineState* dx_pipeline_state = nullptr; @@ -147,6 +151,9 @@ struct Vk_Instance { UINT64 dx_fence_value = 0; HANDLE dx_fence_event = NULL; + ID3D12Resource* dx_vertex_buffer = nullptr; + D3D12_VERTEX_BUFFER_VIEW dx_vertex_buffer_view; + VkInstance instance = VK_NULL_HANDLE; VkPhysicalDevice physical_device = VK_NULL_HANDLE; VkSurfaceKHR surface = VK_NULL_HANDLE; diff --git a/visual-studio/quake3.vcxproj b/visual-studio/quake3.vcxproj index 7f3d389..02425f9 100644 --- a/visual-studio/quake3.vcxproj +++ b/visual-studio/quake3.vcxproj @@ -79,7 +79,7 @@ 0x0409 - winmm.lib;wsock32.lib;D3d12.lib;DXGI.lib;%(AdditionalDependencies) + winmm.lib;wsock32.lib;D3d12.lib;DXGI.lib;d3dcompiler.lib;%(AdditionalDependencies) true true Windows @@ -120,7 +120,7 @@ 0x0409 - winmm.lib;wsock32.lib;D3d12.lib;DXGI.lib;%(AdditionalDependencies) + winmm.lib;wsock32.lib;D3d12.lib;DXGI.lib;d3dcompiler.lib;%(AdditionalDependencies) true Windows 8388608