Not
Åtkomst till denna sida kräver auktorisation. Du kan prova att logga in eller byta katalog.
Åtkomst till denna sida kräver auktorisation. Du kan prova att byta katalog.
Not
Se DirectX-Graphics-Samples lagringsplats för DirectX 12-grafikexempel som visar hur du skapar grafikintensiva program för Windows 10.
Det här avsnittet beskriver anropsflödet för att skapa en grundläggande Direct3D 12-komponent.
Kodflöde för en enkel app
Den yttersta loopen i ett D3D 12-program följer en mycket standardgrafikprocess:
Tips
Funktioner som är nya för Direct3D 12 följs av en anteckning.
Initialisera
Initieringen omfattar att först konfigurera globala variabler och klasser, och en initierad funktion måste förbereda pipelinen och tillgångarna.
- Initiera pipelinen.
Aktivera felsökningsskiktet.
Skapa enheten.
Skapa kommandokön.
Skapa swapkedjan.
Skapa en RTV-beskrivning (Render Target View).
Not
En deskriptorhög kan betraktas som en matris med deskriptorer. Där varje beskrivning helt beskriver ett objekt till GPU:n.
Skapa ramresurser (en återgivningsmålvy för varje ram).
Skapa en kommandoallokerare.
Not
En kommandoallokerare hanterar den underliggande lagringen för kommandolistor och paket.
- Initiera tillgångarna.
Skapa en tom rotsignatur.
Not
En grafik rotsignatur definierar vilka resurser som är bundna till grafikpipelinen.
Kompilera skuggningsfärgerna.
Skapa vinkelingångslayouten.
Skapa en beskrivning av tillståndsobjektet för - och pipeline, och skapa därefter objektet.
Obs
Ett pipelinetillståndsobjekt upprätthåller tillståndet för alla nuvarande shaders samt vissa objekt för fasta funktionstillstånd (till exempel indatasammansättare, tesselator, rasteriserare och utdatasammanslagning).
Skapa kommandolistan.
Stäng kommandolistan.
Skapa och ladda vertixbuffertarna.
Skapa vertexbuffertvyerna.
Skapa ett staket.
Notis
Ett staket används för att synkronisera processorn med GPU:n (se Synkronisering av flera motorer).
Skapa en händelsehanterare.
Vänta tills GPU:n har slutfört sin uppgift.
Not
Kolla på staketet!
Se klass D3D12HelloTriangle, OnInit, LoadPipeline och LoadAssets.
Uppdatera
Uppdatera allt som ska ändras sedan den senaste ramen.
- Ändra konstanten, brytpunkten, indexbuffertarna och allt annat efter behov.
Se OnUpdate.
Rendera
Rita den nya världen.
- Fyll i kommandolistan.
Återställ allokeraren för kommandolistan.
Not
Återanvänd det minne som är associerat med kommandoallokeraren.
Återställ kommandolistan.
Ange grafikens rotsignatur.
Notera
Anger vilken rotsignatur för grafik som ska användas för den aktuella kommandolistan.
Ange viewport och saxrektanglar.
Ställ in en resursbarriär som anger att backbufferten ska användas som återgivningsmål.
Notera
Resursbarriärer används för att hantera resursövergångar.
Registrera kommandon i kommandolistan.
Ange att bakgrundsbuffer ska användas för att presentera när kommandolistan har körts.
Obs.
Ett annat anrop för att sätta en resursbarriär.
Stäng kommandolistan för ytterligare inspelning.
- Kör kommandolistan.
- Presentera ramen.
- Vänta tills GPU:n är klar.
Not
Fortsätt att uppdatera och kontrollera stängslet.
Se OnRender.
Förstöra
Stäng appen ordentligt.
Vänta på att GPU:n ska bli klar.
Notera
Sista kontrollen på staketet.
Stäng händelsehandtaget.
Hänvisa till OnDestroy.
Kodexempel för en enkel app
Följande expanderar kodflödet ovan för att inkludera den kod som krävs för ett grundläggande exempel.
klass D3D12HelloTriangle
Definiera först klassen i en rubrikfil, inklusive en vyport, saxrektangel och hörnbuffert med hjälp av strukturerna:
#include "DXSample.h"
using namespace DirectX;
using namespace Microsoft::WRL;
class D3D12HelloTriangle : public DXSample
{
public:
D3D12HelloTriangle(UINT width, UINT height, std::wstring name);
virtual void OnInit();
virtual void OnUpdate();
virtual void OnRender();
virtual void OnDestroy();
private:
static const UINT FrameCount = 2;
struct Vertex
{
XMFLOAT3 position;
XMFLOAT4 color;
};
// Pipeline objects.
D3D12_VIEWPORT m_viewport;
D3D12_RECT m_scissorRect;
ComPtr<IDXGISwapChain3> m_swapChain;
ComPtr<ID3D12Device> m_device;
ComPtr<ID3D12Resource> m_renderTargets[FrameCount];
ComPtr<ID3D12CommandAllocator> m_commandAllocator;
ComPtr<ID3D12CommandQueue> m_commandQueue;
ComPtr<ID3D12RootSignature> m_rootSignature;
ComPtr<ID3D12DescriptorHeap> m_rtvHeap;
ComPtr<ID3D12PipelineState> m_pipelineState;
ComPtr<ID3D12GraphicsCommandList> m_commandList;
UINT m_rtvDescriptorSize;
// App resources.
ComPtr<ID3D12Resource> m_vertexBuffer;
D3D12_VERTEX_BUFFER_VIEW m_vertexBufferView;
// Synchronization objects.
UINT m_frameIndex;
HANDLE m_fenceEvent;
ComPtr<ID3D12Fence> m_fence;
UINT64 m_fenceValue;
void LoadPipeline();
void LoadAssets();
void PopulateCommandList();
void WaitForPreviousFrame();
};
OnInit()
I huvudkällan för projekten börjar du initiera objekten:
void D3D12HelloTriangle::OnInit()
{
LoadPipeline();
LoadAssets();
}
LoadPipeline()
Följande kod skapar grunderna för en grafikpipeline. Processen att skapa enheter och växlingskedjor liknar Direct3D 11.
- Aktivera felsökningsskiktet med anrop till:
D3D12GetDebugInterface
ID3D12Debug::EnableDebugLayer
- Skapa enheten:
CreateDXGIFactory1
D3D12CreateDevice
- Fyll i en beskrivning av kommandokön och skapa sedan kommandokön:
D3D12_COMMAND_QUEUE_DESC
ID3D12Enhet::CreateCommandQueue
- Fyll i en swapchain-beskrivning och skapa sedan växlingskedjan:
DXGI_SWAP_CHAIN_DESC
IDXGIFactory::CreateSwapChain
IDXGISwapChain3::GetCurrentBackBufferIndex
- Fyll i en beskrivning av en samling. skapa sedan en deskriptorhög
D3D12_DESCRIPTOR_HEAP_DESC
ID3D12Enhet::CreateDescriptorHeap
ID3D12Enhet::GetDescriptorHandleIncrementSize
- Skapa återgivningsmålvyn:
CD3DX12_CPU_DESCRIPTOR_HANDLE
GetCPUDescriptorHandleForHeapStart
IDXGISwapChain::GetBuffer
ID3D12Device::CreateRenderTargetView
- Skapa kommandoallokeraren: ID3D12Device::CreateCommandAllocator.
I senare steg hämtas kommandolistor från kommandoallokeraren och skickas till kommandokön.
Läs in beroenden för återgivningspipelinen (observera att det är helt valfritt att skapa en WARP-enhet för programvara).
void D3D12HelloTriangle::LoadPipeline()
{
#if defined(_DEBUG)
// Enable the D3D12 debug layer.
{
ComPtr<ID3D12Debug> debugController;
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController))))
{
debugController->EnableDebugLayer();
}
}
#endif
ComPtr<IDXGIFactory4> factory;
ThrowIfFailed(CreateDXGIFactory1(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)
));
}
// Describe and create the command queue.
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
ThrowIfFailed(m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&m_commandQueue)));
// Describe and create the swap chain.
DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
swapChainDesc.BufferCount = FrameCount;
swapChainDesc.BufferDesc.Width = m_width;
swapChainDesc.BufferDesc.Height = m_height;
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
swapChainDesc.OutputWindow = Win32Application::GetHwnd();
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.Windowed = TRUE;
ComPtr<IDXGISwapChain> swapChain;
ThrowIfFailed(factory->CreateSwapChain(
m_commandQueue.Get(), // Swap chain needs the queue so that it can force a flush on it.
&swapChainDesc,
&swapChain
));
ThrowIfFailed(swapChain.As(&m_swapChain));
// This sample does not support fullscreen transitions.
ThrowIfFailed(factory->MakeWindowAssociation(Win32Application::GetHwnd(), DXGI_MWA_NO_ALT_ENTER));
m_frameIndex = m_swapChain->GetCurrentBackBufferIndex();
// Create descriptor heaps.
{
// 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)));
m_rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
}
// Create frame resources.
{
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);
}
}
ThrowIfFailed(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocator)));
}
LoadAssets()
Att läsa in och förbereda tillgångar är en lång process. Många av dessa steg liknar D3D 11, även om vissa är nya för D3D 12.
I Direct3D 12 kopplas det nödvändiga pipeline-tillståndet till en kommandolista via ett pipeline-tillståndsobjekt (PSO). Det här exemplet visar hur du skapar en PSO. Du kan lagra PSO som en medlemsvariabel och återanvända den så många gånger som behövs.
En deskriptorheap definierar vyerna och hur man kommer åt resurser (till exempel en rendermålvy).
Med kommandolistallokeraren och PSO kan du skapa den faktiska kommandolistan, som kommer att köras vid ett senare tillfälle.
Följande API:er och processer anropas i följd.
- Skapa en tom rotsignatur med hjälp av den tillgängliga hjälpstrukturen:
CD3DX12_ROOT_SIGNATURE_DESC
D3D12SerializeRootSignature
ID3D12Enhet::CreateRootSignature
- Läs in och kompilera skuggningsfilerna: D3DCompileFromFile.
- Skapa hörnindatalayouten: D3D12_INPUT_ELEMENT_DESC.
- Fyll i en beskrivning av pipelinetillståndet med hjälpstrukturerna som är tillgängliga och skapa sedan statusen för grafikpipelinen:
D3D12_GRAPHICS_PIPELINE_STATE_DESC
CD3DX12_RASTERIZER_DESC
CD3DX12_BLEND_DESC
ID3D12Enhet::CreateGraphicsPipelineState
- Skapa och stäng sedan en kommandolista:
ID3D12Device::CreateCommandList
ID3D12GraphicsCommandList::Close
- Skapa hörnbufferten: ID3D12Enhet::CreateCommittedResource.
- Kopiera hörndata till hörnbufferten:
ID3D12Resource::Map
ID3D12Resource::Unmap
- Initiera hörnbuffertvyn: GetGPUVirtualAddress.
- Skapa och initiera stängslet: ID3D12Enhet::CreateFence.
- Skapa en händelsehanterare för användning med ramsynkronisering.
- Vänta tills GPU:n är färdig med sin uppgift.
void D3D12HelloTriangle::LoadAssets()
{
// 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);
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)));
}
// 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
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));
// 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 = m_rootSignature.Get();
psoDesc.VS = { reinterpret_cast<UINT8*>(vertexShader->GetBufferPointer()), vertexShader->GetBufferSize() };
psoDesc.PS = { reinterpret_cast<UINT8*>(pixelShader->GetBufferPointer()), pixelShader->GetBufferSize() };
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)));
}
// 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)));
// 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.
ThrowIfFailed(m_commandList->Close());
// Create 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);
// 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.
CD3DX12_HEAP_PROPERTIES heapProps(D3D12_HEAP_TYPE_UPLOAD);
auto desc = CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize);
ThrowIfFailed(m_device->CreateCommittedResource(
&heapProps,
D3D12_HEAP_FLAG_NONE,
&desc,
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); // We do not intend to read from this resource on the CPU.
ThrowIfFailed(m_vertexBuffer->Map(0, &readRange, reinterpret_cast<void**>(&pVertexDataBegin)));
memcpy(pVertexDataBegin, triangleVertices, sizeof(triangleVertices));
m_vertexBuffer->Unmap(0, nullptr);
// Initialize the vertex buffer view.
m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress();
m_vertexBufferView.StrideInBytes = sizeof(Vertex);
m_vertexBufferView.SizeInBytes = vertexBufferSize;
}
// Create synchronization objects and wait until assets have been uploaded to the GPU.
{
ThrowIfFailed(m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence)));
m_fenceValue = 1;
// 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()));
}
// 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.
WaitForPreviousFrame();
}
}
OnUpdate()
För ett enkelt exempel uppdateras ingenting.
void D3D12HelloTriangle::OnUpdate()
{
}
OnRender()
Under konfigurationen användes medlemsvariabeln m_commandList för att registrera och köra alla konfigurationskommandon. Nu kan du återanvända medlemmen i huvudåtergivningsloopen.
Rendering innebär ett anrop för att fylla i kommandolistan, sedan kan kommandolistan köras och nästa buffert i växlingskedjan visas:
- Fyll i kommandolistan.
- Kör kommandolistan: ID3D12CommandQueue::ExecuteCommandLists.
- IDXGISwapChain1::Present1 ramen.
- Vänta på att GPU:n ska bli klar.
void D3D12HelloTriangle::OnRender()
{
// Record all the commands we need to render the scene into the command list.
PopulateCommandList();
// Execute the command list.
ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
// Present the frame.
ThrowIfFailed(m_swapChain->Present(1, 0));
WaitForPreviousFrame();
}
PopulateCommandList()
Du måste återställa kommandolisteallokeraren och själva kommandolistan innan du kan återanvända dem. I mer komplexa scenarier kan det vara bra att återställa allokeraren var några bildrutor. Minnet är associerat med allokeraren som inte kan släppas omedelbart efter att en kommandolista har körts. Det här exemplet visar hur du återställer allokeraren efter varje bildruta.
Återanvänd nu kommandolistan för den aktuella ramen. Koppla om vyporten till kommandolistan (vilket måste göras när en kommandolista återställs, och innan kommandolistan körs), indikera att resursen kommer att användas som ett återgivningsmål, spela in kommandon och indikera sedan att återgivningsmålet ska användas för presentation när kommandolistan är färdig att köra.
När du fyller i kommandolistor anropas följande metoder och processer i tur och ordning:
- Återställ kommandoallokeraren och kommandolistan:
ID3D12CommandAllocator::Återställ
ID3D12GraphicsCommandList::Återställ
- Ange rotsignaturen, viewporten och beskärningsrektanglarna:
ID3D12GraphicsCommandList::SetGraphicsRootSignature
ID3D12GraphicsCommandList::RSSetViewports
ID3D12GraphicsCommandList::RSSetScissorRects
- Ange att backbuffer ska användas som renderingstarget.
ID3D12GraphicsCommandList::ResourceBarrier
ID3D12DescriptorHeap::GetCPUDescriptorHandleForHeapStart
ID3D12GraphicsCommandList::OMSetRenderTargets
- Registrera kommandona:
ID3D12GraphicsCommandList::ClearRenderTargetView
ID3D12GraphicsCommandList::IASetPrimitiveTopology
ID3D12GraphicsCommandList::IASetVertexBuffers
ID3D12GraphicsCommandList::DrawInstanced
- Ange att bakbufferten nu ska användas för att presentera: ID3D12GraphicsCommandList::ResourceBarrier.
- Stäng kommandolistan: ID3D12GraphicsCommandList::Close.
void D3D12HelloTriangle::PopulateCommandList()
{
// Command list allocators can only be reset when the associated
// command lists have finished execution on the GPU; apps should use
// fences to determine GPU execution progress.
ThrowIfFailed(m_commandAllocator->Reset());
// However, when ExecuteCommandList() is called on a particular command
// list, that command list can then be reset at any time and must be before
// re-recording.
ThrowIfFailed(m_commandList->Reset(m_commandAllocator.Get(), m_pipelineState.Get()));
// Set necessary state.
m_commandList->SetGraphicsRootSignature(m_rootSignature.Get());
m_commandList->RSSetViewports(1, &m_viewport);
m_commandList->RSSetScissorRects(1, &m_scissorRect);
// Indicate that the back buffer will be used as a render target.
auto barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
m_commandList->ResourceBarrier(1, &barrier);
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), m_frameIndex, m_rtvDescriptorSize);
m_commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr);
// 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);
// Indicate that the back buffer will now be used to present.
barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
m_commandList->ResourceBarrier(1, &barrier);
ThrowIfFailed(m_commandList->Close());
}
WaitForPreviousFrame()
Följande kod visar en alltför förenklad användning av staket.
Not
Att vänta på att en bildruta ska slutföras är för ineffektivt för de flesta appar.
Följande API:er och processer anropas i ordning:
- ID3D12CommandQueue::Signal
- ID3D12Fence::GetCompletedValue
- ID3D12Fence::SetEventOnCompletion
- Vänta på händelsen.
- Uppdatera ramindexet: IDXGISwapChain3::GetCurrentBackBufferIndex.
void D3D12HelloTriangle::WaitForPreviousFrame()
{
// WAITING FOR THE FRAME TO COMPLETE BEFORE CONTINUING IS NOT BEST PRACTICE.
// This is code implemented as such for simplicity. More advanced samples
// illustrate how to use fences for efficient resource usage.
// Signal and increment the fence value.
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();
}
OnDestroy()
Stäng appen ordentligt.
- Vänta tills GPU:n har slutfört sin uppgift.
- Stäng händelsen.
void D3D12HelloTriangle::OnDestroy()
{
// Wait for the GPU to be done with all resources.
WaitForPreviousFrame();
CloseHandle(m_fenceEvent);
}
Relaterade ämnen