DX12: first triangle.

This commit is contained in:
Artem Kharytoniuk 2017-10-22 20:08:54 +02:00
parent 9b01830559
commit a32a863d83
4 changed files with 192 additions and 41 deletions

View File

@ -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;
}

View File

@ -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<ID3DBlob> signature;
ComPtr<ID3DBlob> 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<ID3DBlob> vertexShader;
ComPtr<ID3DBlob> 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<void**>(&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<ID3DBlob> signature;
ComPtr<ID3DBlob> 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<float>(glConfig.vidWidth), static_cast<float>(glConfig.vidHeight));
vk.dx_command_list->RSSetViewports(1, &viewport);
CD3DX12_RECT scissorRect(0, 0, static_cast<LONG>(glConfig.vidWidth), static_cast<LONG>(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],

View File

@ -13,9 +13,12 @@
#include "DXGI1_4.h"
#include "wrl.h"
#include "d3dx12.h"
#include "D3Dcompiler.h"
#include <DirectXMath.h>
#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;

View File

@ -79,7 +79,7 @@
<Culture>0x0409</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>winmm.lib;wsock32.lib;D3d12.lib;DXGI.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>winmm.lib;wsock32.lib;D3d12.lib;DXGI.lib;d3dcompiler.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SuppressStartupBanner>true</SuppressStartupBanner>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
@ -120,7 +120,7 @@
<Culture>0x0409</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>winmm.lib;wsock32.lib;D3d12.lib;DXGI.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>winmm.lib;wsock32.lib;D3d12.lib;DXGI.lib;d3dcompiler.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SuppressStartupBanner>true</SuppressStartupBanner>
<SubSystem>Windows</SubSystem>
<StackReserveSize>8388608</StackReserveSize>