DirectX 12 原生三角形渲染
用命令列表和资源屏障绘制三角形
该博客上撰写的文章是出于教学目的而创建的。 另外,文章中的信息可能不正确,请谨慎。
DirectX 12中绘制三角形的整体流程与DX11类似,但资源状态和命令提交由开发人员直接管理。 创建设备后立即DrawInstanced它不是一个可以调用的结构。
需要的对象
Device
CommandQueue
SwapChain
DescriptorHeap(RTV)
CommandAllocator
GraphicsCommandList
Fence
VertexBuffer
RootSignature
PipelineState
顶点缓冲区
struct Vertex
{
DirectX::XMFLOAT3 Position;
DirectX::XMFLOAT4 Color;
};
const Vertex Vertices[] =
{
{ { 0.0f, 0.5f, 0.0f }, { 1, 0, 0, 1 } },
{ { 0.5f, -0.5f, 0.0f }, { 0, 1, 0, 1 } },
{ { -0.5f, -0.5f, 0.0f }, { 0, 0, 1, 1 } }
};
const UINT BufferSize = sizeof(Vertices);
CD3DX12_HEAP_PROPERTIES HeapProperties(D3D12_HEAP_TYPE_UPLOAD);
CD3DX12_RESOURCE_DESC BufferDescription =
CD3DX12_RESOURCE_DESC::Buffer(BufferSize);
Device->CreateCommittedResource(
&HeapProperties,
D3D12_HEAP_FLAG_NONE,
&BufferDescription,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&VertexBuffer)
);
void* MappedData = nullptr;
VertexBuffer->Map(0, nullptr, &MappedData);
std::memcpy(MappedData, Vertices, BufferSize);
VertexBuffer->Unmap(0, nullptr);
VertexBufferView.BufferLocation = VertexBuffer->GetGPUVirtualAddress();
VertexBufferView.SizeInBytes = BufferSize;
VertexBufferView.StrideInBytes = sizeof(Vertex);
该示例仅使用了上传堆。 实际上,将频繁读取的顶点数据复制到默认堆对于 GPU 访问性能是有利的。
在命令列表中记录绘图
CommandAllocator->Reset();
CommandList->Reset(CommandAllocator, PipelineState);
auto ToRenderTarget = CD3DX12_RESOURCE_BARRIER::Transition(
BackBuffers[FrameIndex],
D3D12_RESOURCE_STATE_PRESENT,
D3D12_RESOURCE_STATE_RENDER_TARGET
);
CommandList->ResourceBarrier(1, &ToRenderTarget);
CommandList->RSSetViewports(1, &Viewport);
CommandList->RSSetScissorRects(1, &ScissorRect);
CommandList->OMSetRenderTargets(1, &CurrentRTV, FALSE, nullptr);
const float ClearColor[] = { 0.08f, 0.08f, 0.12f, 1.0f };
CommandList->ClearRenderTargetView(CurrentRTV, ClearColor, 0, nullptr);
CommandList->SetGraphicsRootSignature(RootSignature);
CommandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
CommandList->IASetVertexBuffers(0, 1, &VertexBufferView);
CommandList->DrawInstanced(3, 1, 0, 0);
auto ToPresent = CD3DX12_RESOURCE_BARRIER::Transition(
BackBuffers[FrameIndex],
D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_PRESENT
);
CommandList->ResourceBarrier(1, &ToPresent);
CommandList->Close();
ID3D12CommandList* Lists[] = { CommandList };
CommandQueue->ExecuteCommandLists(1, Lists);
SwapChain->Present(1, 0);
BackBuffer 在 Present 状态和 RenderTarget 状态之间来回切换。 如果忽略此状态转换,调试层中将出现错误,或者屏幕将无法正确绘制。
DX12的三角代码较长,但结构清晰。 三个关键步骤是记录命令、将其提交到队列以及使用 Fence 检查 GPU 完成情况。