首页 > 其他分享 >DX12 HelloTriangle

DX12 HelloTriangle

时间:2023-02-06 23:33:59浏览次数:78  
标签:ThrowIfFailed 0.0 nullptr ComPtr DX12 HelloTriangle cpp D3D12

前言

此篇将展示如何利用DX12绘制一个静态的三角形

渲染流程与必备组件

Direct3D基本流程

shader

//cpu端
struct PSInput
{
	float4 position : SV_POSITION;
	float4 color : COLOR;
};

//GPU端
PSInput VSMain(float4 pos : POSITION, float4 color : COLOR)
{
	PSInput result;
	result.position = pos;
	result.color = color;

	return result;
}

float4 PSMain(PSInput input) : SV_TARGET	//This SV is used for pixel shader output color
{
	return input.color;
}

流程

初始化

LoadPipeline

启动调试层

//.cpp
UINT dxgiFactoryFlags = 0;

UINT dxgiFactoryFlags = 0;

/* Enables the debug layer */
//_DEBUG。Runtime selection when compiling
#if defined(_DEBUG)
ComPtr<ID3D12Debug> debugController;
ThrowIfFailed(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)));
debugController->EnableDebugLayer();
dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
#endif

创建设备

//.h
ComPtr<ID3D12Device> m_device;

//.cpp
/* create the device */
ComPtr<IDXGIFactory4> factory;
ThrowIfFailed(CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&factory)));

if (m_useWarpDevice)
{
    ComPtr<IDXGIAdapter> warpAdapter;
    ThrowIfFailed(factory->EnumWarpAdapter(IID_PPV_ARGS(&warpAdapter)));

    ThrowIfFailed(D3D12CreateDevice(
        warpAdapter.Get(),
        D3D_FEATURE_LEVEL_11_0,
        IID_PPV_ARGS(&m_device)
    ));
}
else
{
    ComPtr<IDXGIAdapter1> hardwareAdapter;
    GetHardwareAdapter(factory.Get(), &hardwareAdapter);

    ThrowIfFailed(D3D12CreateDevice(
        hardwareAdapter.Get(),
        D3D_FEATURE_LEVEL_11_0,
        IID_PPV_ARGS(&m_device)
    ));
}

创建命令队列

//.h
ComPtr<ID3D12CommandQueue> m_commandQueue;

//.cpp
/*Describe and create the command queue*/
D3D12_COMMAND_QUEUE_DESC queueDesc{};
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
queueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queueDesc.NodeMask = 0;

ThrowIfFailed(m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&m_commandQueue)));

创建交换链

//.h
ComPtr<IDXGISwapChain3> m_swapChain;
UINT m_frameIndex;

//.cpp
/*Describe and create the swap chain*/
/*Describe and create the swap chain*/
DXGI_SWAP_CHAIN_DESC1 swapChainDesc{};
swapChainDesc.Width = m_width;
swapChainDesc.Height = m_height;
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;	//unsigned-normalized-integer
swapChainDesc.Stereo = FALSE;	//Don't need the stereo
swapChainDesc.SampleDesc.Count = 1;		//multi-sampling descriptor
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;	//describes the surface usage and CPU access options for the back buffer
swapChainDesc.BufferCount = FrameCount;
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;	//make the back-buffer contents scale to fit the presentation target size
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;	//discard the contents of the back buffer
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;	//identifies the transparency behavior of the swap-chain back buffer

ComPtr<IDXGISwapChain1> swapChain;
ThrowIfFailed(factory->CreateSwapChainForHwnd(
    m_commandQueue.Get(),
    Win32Application::GetHwnd(),
    &swapChainDesc,
    nullptr,
    nullptr,
    &swapChain	//IDXGISwapChain1。So it needs to use IDXGISwapChain1 first
));

//ALT_ENTER switch fullscreen
ThrowIfFailed(factory->MakeWindowAssociation(Win32Application::GetHwnd(), DXGI_MWA_NO_ALT_ENTER));

ThrowIfFailed(swapChain.As(&m_swapChain));
m_frameIndex = m_swapChain->GetCurrentBackBufferIndex();


创建RTV描述符堆

//.h
ComPtr<ID3D12DescriptorHeap> m_rtvHeap;

//.cpp
// Describe and create a render target view (RTV) descriptor heap
D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {};
rtvHeapDesc.NumDescriptors = FrameCount;
rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
ThrowIfFailed(m_device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&m_rtvHeap)));

创建帧资源

//.h
ComPtr<ID3D12Resource> m_renderTargets[FrameCount];
static const UINT FrameCount = 2;

//.cpp
m_rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);

CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart());

// Create a RTV for each frame
for (UINT n = 0; n < FrameCount; n++)
{
    ThrowIfFailed(m_swapChain->GetBuffer(n, IID_PPV_ARGS(&m_renderTargets[n])));
    m_device->CreateRenderTargetView(m_renderTargets[n].Get(), nullptr, rtvHandle);
    rtvHandle.Offset(1, m_rtvDescriptorSize);
}

创建命令分配器

//.h
ComPtr<ID3D12CommandAllocator> m_commandAllocator;

//.cpp
/*create command allocator*/
ThrowIfFailed(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocator)));

LoadAssets

创建空的根签名

//.h
ComPtr<ID3D12RootSignature> m_rootSignature;

//.cpp
CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc;
rootSignatureDesc.Init(0, nullptr, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
ComPtr<ID3DBlob> signature;
ComPtr<ID3DBlob> error;
ThrowIfFailed(D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error));
ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature)));

创建顶点输入布局

//.cpp
/*create and load the vertex buffer*/
//Define the geometry for a triangle.
Vertex triangleVertices[] =
{
    {{0.0f, 0.25f * m_aspectRatio, 0.0f}, {1.0f, 0.0f, 0.0f, 1.0f}},
    {{0.25f, -0.25f * m_aspectRatio, 0.0f},{0.0f, 1.0f, 0.0f, 1.0f}},
    {{-0.25f, -0.25f * m_aspectRatio, 0.0f},{0.0f, 0.0f, 1.0f, 1.0f}}
};

创建管线对象描述符并创建管线对象

//.h
ComPtr<ID3D12PipelineState> m_pipelineState;

//.cpp
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

ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "VSMain", "vs_5_0", compileFlags, 0, &vertexShader, nullptr));
ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "PSMain", "ps_5_0", compileFlags, 0, &pixelShader, nullptr));

// Describe and create the graphics pipeline state object (PSO).
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) };
psoDesc.pRootSignature = m_rootSignature.Get();
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;
ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineState)));

创建命令列表

//.h
ComPtr<ID3D12GraphicsCommandList> m_commandList;

//.cpp
/*create the command list*/
ThrowIfFailed(m_device->CreateCommandList(
    0,
    D3D12_COMMAND_LIST_TYPE_DIRECT,
    m_commandAllocator.Get(),
    m_pipelineState.Get(),
    IID_PPV_ARGS(&m_commandList)
));

关闭命令列表

/*close the command list*/
ThrowIfFailed(m_commandList->Close());

创建并加载顶点缓冲区

//.h
ComPtr<ID3D12Resource> m_vertexBuffer;

//.cpp
/*create and load the vertex buffer*/
//Define the geometry for a triangle.
Vertex triangleVertices[] =
{
    {{0.0f, 0.25f * m_aspectRatio, 0.0f}, {1.0f, 0.0f, 0.0f, 1.0f}},
    {{0.25f, -0.25f * m_aspectRatio, 0.0f},{0.0f, 1.0f, 0.0f, 1.0f}},
    {{-0.25f, -0.25f * m_aspectRatio, 0.0f},{0.0f, 0.0f, 1.0f, 1.0f}}
};

const UINT vertexBufferSize = sizeof(triangleVertices);

//Creates a resource and an heap.the resource is mapped to the heap
ThrowIfFailed(m_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(&m_vertexBuffer)
));

//Copy the triangle data to the vertex buffer
UINT8* pVertexDataBegin;
CD3DX12_RANGE readRange(0, 0);	//Describes a memory range
ThrowIfFailed(m_vertexBuffer->Map(
    0, 
    &readRange, 
    reinterpret_cast<void**>(&pVertexDataBegin)		////pVertexDataBegin指向m_vertexBuffer
));
memcpy(pVertexDataBegin, triangleVertices, sizeof(triangleVertices));
m_vertexBuffer->Unmap(0, nullptr);	//null pointer indicates the entire subresource might have been modified by the CPU

创建顶点缓冲区视图

//.h
D3D12_VERTEX_BUFFER_VIEW m_vertexBufferView;

//.cpp
/*create the vertex buffer view*/
m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress();
m_vertexBufferView.SizeInBytes = vertexBufferSize;
m_vertexBufferView.StrideInBytes = sizeof(Vertex);

创建围栏

//.h
ComPtr<ID3D12Fence> m_fence;
UINT64 m_fenceValue;

//.cpp
ThrowIfFailed(m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence)));
m_fenceValue = 1;

创建事件句柄

//.h
HANDLE m_fenceEvent;

//.cpp
// Create an event handle to use for frame synchronization.
m_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
if (m_fenceEvent == nullptr)
{
    ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError()));
}

等待GPU完成

//.cpp
WaitForPreviousFrame();

渲染

向命令列表加入命令

重置命令列表分配器

//.cpp
ThrowIfFailed(m_commandAllocator->Reset());

重置命令列表

//.cpp
//reset the command list
ThrowIfFailed(m_commandList->Reset(m_commandAllocator.Get(), m_pipelineState.Get()));

设置图像根签名

//.cpp
m_commandList->SetGraphicsRootSignature(m_rootSignature.Get());

设置视图和裁剪矩阵

//.h
CD3DX12_VIEWPORT m_viewport;
CD3DX12_RECT m_scissorRect;

//.cpp
m_commandList->RSSetViewports(1, &m_viewport);
m_commandList->RSSetScissorRects(1, &m_scissorRect);

设置资源屏障,将后台缓冲区用作渲染目标

//.cpp
// Indicate that the back buffer will be used as a render target.
m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));

CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), m_frameIndex, m_rtvDescriptorSize);
m_commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr);

向命令列表添加命令

//.cpp
// Record commands.
const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
m_commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);
m_commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_commandList->IASetVertexBuffers(0, 1, &m_vertexBufferView);
m_commandList->DrawInstanced(3, 1, 0, 0);

指出当命令列表的命令被执行后后台缓冲区被用于呈现

//.cpp
// Indicate that the back buffer will now be used to present.
m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));

关闭命令列表

ThrowIfFailed(m_commandList->Close());

执行命令列表

//.cpp
// Execute the command list
ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);

呈现帧画面

//.cpp
// Present the frame
ThrowIfFailed(m_swapChain->Present(1, 0));

等待GPU完成

//.cpp
WaitForPreviousFrame();

销毁

等待GPU完成

WaitForPreviousFrame();
const UINT64 fence = m_fenceValue;
ThrowIfFailed(m_commandQueue->Signal(m_fence.Get(), fence));
m_fenceValue++;

// Wait until the previous frame is finished.
if (m_fence->GetCompletedValue() < fence)
{
    ThrowIfFailed(m_fence->SetEventOnCompletion(fence, m_fenceEvent));
    WaitForSingleObject(m_fenceEvent, INFINITE);
}

m_frameIndex = m_swapChain->GetCurrentBackBufferIndex();

关闭事件句柄

//.cpp
CloseHandle(m_fenceEvent);

报错

  1. hlsl报错(X3501)image-20230204180009882

    ​ 这是因为hlsl没有写主函数

    ​ 解决方案:

    右键".hlsl"文件->属性->配置属性->常规->项类型。选择"不参与生产"

  2. 左值报错(C2102)image-20230204180621647

    ​ 解决方案:

    右键项目->属性->配置属性->c/c++->语言->"符合模式"改为否

reference

microsoft/DirectX-Graphics-Samples: This repo contains the DirectX Graphics samples that demonstrate how to build graphics intensive applications on Windows. (github.com)

标签:ThrowIfFailed,0.0,nullptr,ComPtr,DX12,HelloTriangle,cpp,D3D12
From: https://www.cnblogs.com/chenglixue/p/17097031.html

相关文章

  • DX12 Hello World系列 基础篇(上)
    前言DX12对于初学者来说难度是偏大的,龙书确实写的不错,但笔者认为还是不够清晰,因此本篇将带你了解DX12最为基本的流程,希望能带你快速入门DX12本篇为上册,下册将讲解渲染管......