Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Om het totale CPU-gebruik te verminderen en multithreading en preverwerking van stuurprogramma's mogelijk te maken, verplaatst Direct3D 12 de verantwoordelijkheid van beheer per resourcestatus van het grafische stuurprogramma naar de toepassing. Een voorbeeld van de status per resource is of een textuur-resource momenteel wordt geopend via een Shader-resourceweergave of als Render Target View. In Direct3D 11 moesten stuurprogramma's deze status op de achtergrond volgen. Dit is duur vanuit cpu-perspectief en maakt elk soort ontwerp met meerdere threads aanzienlijk ingewikkeld. In Microsoft Direct3D 12 wordt de meeste status per resource beheerd door de toepassing met één API, ID3D12GraphicsCommandList::ResourceBarrier.
- de ResourceBarrier-API gebruiken om de status per resource te beheren
- impliciete statusovergangen
- Splitschermen
- Voorbeeldscenario resourcebarrière
- Gemeenschappelijk staatspromotie en verval voorbeeld
- Voorbeeld van splitsingsbarrières
- Verwante onderwerpen
De ResourceBarrier-API gebruiken om de status per resource te beheren
ResourceBarrier het grafische stuurprogramma op de hoogte stelt van situaties waarin het stuurprogramma mogelijk meerdere toegang moet synchroniseren met het geheugen waarin een resource is opgeslagen. De methode wordt aangeroepen met een of meer structuren die de resourcebarrières beschrijven en aangeven welk type resourcebarrière wordt gedeclareerd.
Er zijn drie typen resourcebarrières:
overgangsbarrière - Een overgangsbarrière geeft aan dat een set subresources overgaat tussen verschillende toepassingen. Een D3D12_RESOURCE_TRANSITION_BARRIER structuur wordt gebruikt om de subresource op te geven die wordt overgestapt, evenals de vóór en na statussen van de subresource.
Het systeem controleert of subresourceovergangen in een opdrachtlijst consistent zijn met eerdere overgangen in dezelfde opdrachtlijst. De foutopsporingslaag houdt de status van de subresource verder bij om andere fouten te vinden, maar deze validatie is conservatief en niet volledig.
Houd er rekening mee dat u de vlag "D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES" kunt gebruiken om aan te geven dat alle subresources binnen een resource worden overgezet.
aliasing-barrière: een aliasing-barrière geeft een overgang tussen het gebruik van twee verschillende resources met overlappende toewijzingen binnen dezelfde heap aan. Dit geldt zowel voor gereserveerde als geplaatste resources. Een D3D12_RESOURCE_ALIASING_BARRIER structuur wordt gebruikt om zowel de op te geven vóór resource als de na resource.
Houd er rekening mee dat een of beide resources NULL kunnen zijn, wat aangeeft dat een gedeelde resource aliasing kan veroorzaken. Zie Tegelresources en voor meer informatie over het gebruik van tegelresources.
UAV-barrière (Unordered Access View) - Een UAV-barrière geeft aan dat alle UAV-toegang, zowel lezen als schrijven, naar een bepaalde resource moet worden voltooid voordat toekomstige UAV-toegang, zowel lezen als schrijven, kan plaatsvinden. Het is niet nodig dat een app een UAV-barrière plaatst tussen twee trek- of verzendgesprekken die alleen lezen van een UAV. Ook is het niet nodig om een UAV-barrière te plaatsen tussen twee draw- of dispatch-calls die naar dezelfde UAV schrijven als de applicatie weet dat het veilig is om de UAV-toegang in willekeurige volgorde uit te voeren. Een D3D12_RESOURCE_UAV_BARRIER structuur wordt gebruikt om de UAV-resource op te geven waarop de barrière van toepassing is. De toepassing kan NULL opgeven voor de UAV van de barrière, wat aangeeft dat elke UAV-toegang de barrière kan vereisen.
Wanneer ResourceBarrier wordt aangeroepen met een matrix met beschrijvingen van resourcebarrières, gedraagt de API zich alsof deze eenmaal voor elk element is aangeroepen, in de volgorde waarin ze zijn opgegeven.
Op elk gewenst moment heeft een subresource precies één status, die wordt bepaald door de set D3D12_RESOURCE_STATES vlaggen die aan ResourceBarrierworden geleverd. De toepassing moet ervoor zorgen dat de status van de opeenvolgende aanroepen naar ResourceBarrier overeenkomen, met vóór en na.
Fooi
Toepassingen moeten waar mogelijk meerdere overgangen batchgewijs in één API-aanroep plaatsen.
Statussen van bronnen
Zie het naslagonderwerp voor de opsomming D3D12_RESOURCE_STATES voor de volledige lijst van resource-statussen waarnaar een resource kan overgaan.
Raadpleeg ook D3D12_RESOURCE_BARRIER_FLAGSvoor splitsingsresourcebarrières.
Initiële status van bronnen
Resources kunnen worden gemaakt met elke door de gebruiker opgegeven initiële status (geldig voor de beschrijving van de resource), met de volgende uitzonderingen:
- Upload-heaps moeten beginnen in de status D3D12_RESOURCE_STATE_GENERIC_READ, een bitsgewijze OF-combinatie van:
- D3D12_RESOURCE_STATE_VERTEX_EN_CONSTANT_BUFFER
- D3D12_RESOURCE_STATE_INDEX_BUFFER
- D3D12_RESOURCE_STATE_COPY_SOURCE
- D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE
- D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
- D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT
- Readback-heaps moeten beginnen met de status D3D12_RESOURCE_STATE_COPY_DEST.
- Wisselketenbackbuffers worden automatisch gestart in de status D3D12_RESOURCE_STATE_COMMON.
Voordat een heap het doel kan zijn van een GPU-kopieerbewerking, moet de heap normaal gesproken eerst worden overgezet naar de status D3D12_RESOURCE_STATE_COPY_DEST. Echter, bronnen die zijn aangemaakt op UPLOAD-heaps moeten beginnen in de GENERIC_READ-status en kunnen hier niet van afwijken, omdat alleen de CPU schrijft. Vastgelegde resources die zijn gemaakt in READBACK-stapels, moeten beginnen in de status COPY_DEST en mogen daar niet van veranderen.
Beperkingen voor lees-/schrijfresourcestatus
De gebruiksstatusbits voor resources die worden gebruikt om een resourcestatus te beschrijven, zijn onderverdeeld in alleen-lezen en lees-/schrijfstatussen. Het naslagonderwerp voor de D3D12_RESOURCE_STATES geeft het lees-/schrijftoegangsniveau voor elke bit in de opsomming aan.
Maximaal één lees-/schrijf-bit kan worden ingesteld voor elke resource. Als een schrijf-bit is ingesteld, kan er geen alleen-lezen-bit worden ingesteld voor die resource. Als er geen schrijfbit is ingesteld, kan een willekeurig aantal lees-bits worden ingesteld.
Resourcestatussen voor het presenteren van backbuffers
Voordat een backbuffer wordt weergegeven, moet deze de status D3D12_RESOURCE_STATE_COMMON hebben. Opmerking: de resourcestatus D3D12_RESOURCE_STATE_PRESENT is een synoniem voor D3D12_RESOURCE_STATE_COMMON en beide hebben een waarde van 0. Als IDXGISwapChain::Present (of IDXGISwapChain1::Present1) wordt aangeroepen voor een resource die momenteel niet in deze staat is, wordt er een waarschuwing in de foutopsporingslaag geproduceerd.
Resources verwijderen
Alle subresources in een resource moeten in de status RENDER_TARGET of respectievelijk DEPTH_WRITE zijn voor respectievelijk renderdoelen/dieptesteekproefresources wanneer ID3D12GraphicsCommandList::DiscardResource wordt aangeroepen.
Impliciete statusovergangen
Resources kunnen alleen worden 'gepromoveerd' uit D3D12_RESOURCE_STATE_COMMON. Op dezelfde manier zullen resources alleen 'verval' tot D3D12_RESOURCE_STATE_COMMON.
Algemene staats-promotie
Alle bufferbronnen en patronen met de D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS vlagset worden impliciet gepromoveerd van D3D12_RESOURCE_STATE_COMMON naar de relevante status voor de eerste GPU-toegang, inclusief GENERIC_READ om elk leesscenario te behandelen. Elke bron in de status COMMON kan worden benaderd alsof deze zich in een enkele status bevindt, met
- 1 WRITE-vlag, of 1 of meer LEESvlagken
Resources kunnen worden gepromoveerd vanuit de ALGEMENE status op basis van de volgende tabel:
Statusvlag | Buffers en Simultaneous-Access Texturen | Niet-Simultaneous-Access texturen |
---|---|---|
VERTEX_EN_CONSTANT_BUFFER | Ja | Nee |
Indexbuffer | Ja | Nee |
RENDER_TARGET | Ja | Nee |
ONGEORDENDE_TOEGANG | Ja | Nee |
DEPTH_WRITE | Geen* | Nee |
DEPTH_READ | Geen* | Nee |
NIET-PIXEL-SHADER-HULPMIDDEL | Ja | Ja |
PIXEL_SHADER_RESOURCE | Ja | Ja |
STREAM_OUT | Ja | Nee |
INDIRECTE_ARGUMENT | Ja | Nee |
KOPIE_BESTEMMING | Ja | Ja |
COPY_SOURCE | Ja | Ja |
RESOLVE_DEST | Ja | Nee |
RESOLVE_SOURCE | Ja | Nee |
PREDICATIE | Ja | Nee |
*Diepte-stencilbronnen moeten niet-gelijktijdig toegankelijke texturen zijn en kunnen dus nooit impliciet worden gepromoveerd.
Wanneer deze toegang plaatsvindt, fungeert de promotie als een impliciete resourcebarrière. Voor volgende toegangen moeten resourcebarrières zo nodig de resourcestatus wijzigen. Houd er rekening mee dat promotie van één gepromoveerde leesstatus naar meerdere leesstatussen toegestaan is, maar dit is niet het geval voor schrijfstatussen.
Als een resource bijvoorbeeld in de gezamenlijke status wordt gepromoveerd tot PIXEL_SHADER_RESOURCE in een Draw-aanroep, kan deze nog steeds worden gepromoveerd naar NON_PIXEL_SHADER_RESOURCE | PIXEL_SHADER_RESOURCE in een andere Draw-aanroep. Als het echter wordt gebruikt in een schrijfbewerking, zoals als kopieerbestemming, is een statusovergangsbarrière van de gecombineerde gepromoveerde leesstatussen, namelijk NON_PIXEL_SHADER_RESOURCE | PIXEL_SHADER_RESOURCE, naar COPY_DEST nodig.
Op dezelfde manier is, indien gepromoveerd van COMMON naar COPY_DEST, nog steeds een barrière nodig om over te stappen van COPY_DEST naar RENDER_TARGET.
Algemene statuspromotie is 'gratis' omdat de GPU geen synchronisatiewachttijden hoeft uit te voeren. De promotie vertegenwoordigt het feit dat resources in de COMMON-status geen extra GPU-werk- of stuurprogrammatracering nodig hebben om bepaalde toegang te ondersteunen.
Staatsverval tot algemeen
De keerzijde van promotie naar een algemene staat is terugval naar D3D12_RESOURCE_STATE_COMMON. Resources die aan bepaalde vereisten voldoen, worden beschouwd als staatloos en keren effectief terug naar de algemene status wanneer de GPU klaar is met het uitvoeren van een ExecuteCommandLists-bewerking. Verval vindt niet plaats tussen opdrachtlijsten die samen worden uitgevoerd in dezelfde ExecuteCommandLists aanroep.
De volgende resources zullen vervallen wanneer een ExecuteCommandLists bewerking is voltooid op de GPU:
- Resources die worden geopend in een kopieerwachtrij, of
- Resources bufferen voor een wachtrijtype, of
- Textuurbronnen op elk type wachtrij waarop de vlag D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS is ingesteld, of
- Elke resource die impliciet wordt gepromoveerd naar de leesmodus.
Net als bij algemene statuspromotie is het verval vrij, omdat er geen extra synchronisatie nodig is. Het combineren van algemene statuspromotie en verval kan helpen om veel onnodige ResourceBarrier overgangen te elimineren. In sommige gevallen kan dit aanzienlijke prestatieverbeteringen opleveren.
Buffers en Simultaneous-Access-resources zullen vervallen naar de algemene status, ongeacht of ze expliciet zijn getransporteerd met behulp van resourcebarrières of impliciet zijn bevorderd.
Gevolgen voor prestaties
Wanneer u expliciete ResourceBarrier overgangen op resources in de gemeenschappelijke status opneemt, is het juist om D3D12_RESOURCE_STATE_COMMON of een promotabelstatus te gebruiken als de BeforeState--waarde in de D3D12_RESOURCE_TRANSITION_BARRIER structuur. Hierdoor is traditioneel statusbeheer mogelijk dat geen rekening houdt met het automatische verval van buffers en gelijktijdige toegang tot texturen. Dit kan echter niet wenselijk zijn, omdat het vermijden van de overgang ResourceBarrier aanroepen met resources die bekend zijn in de algemene staat, de prestaties aanzienlijk kunnen verbeteren. Resourcebarrières kunnen duur zijn. Ze zijn ontworpen om het leegmaken van de cache, wijzigingen in de geheugenindeling en andere synchronisatie af te dwingen die mogelijk niet nodig zijn voor resources die al in de algemene status staan. Een opdrachtlijst die gebruikmaakt van een resourcebarrière van een niet-gemeenschappelijke status naar een andere niet-gemeenschappelijke status voor een resource die momenteel in de algemene status staat, kan leiden tot veel onnodige overhead.
Vermijd ook expliciete ResourceBarrier overgangen naar D3D12_RESOURCE_STATE_COMMON tenzij dit absoluut noodzakelijk is (bijvoorbeeld de volgende toegang bevindt zich in een COPY-opdrachtwachtrij waarvoor een resource in de algemene status moet beginnen). Overmatige overgangen naar de algemene status kunnen de GPU-prestaties aanzienlijk vertragen.
Kortom, probeer te vertrouwen op algemene statusverhoging en -verval wanneer de semantiek het toelaat om zonder het uitgeven van ResourceBarrier aanroepen weg te komen.
Scheidingsbarrières
Een resourceovergangsbarrière met de vlag D3D12_RESOURCE_BARRIER_FLAG_BEGIN_ONLY begint een splitsingsbarrière en de overgangsbarrière wordt gezegd in behandeling te zijn. Hoewel de barrière in behandeling is, kan de (sub)resource niet worden gelezen of geschreven door de GPU. De enige wettelijke overgangsbarrière die kan worden toegepast op een (sub)resource met een in behandeling zijnde barrière, is een met dezelfde vóór en na staten en de D3D12_RESOURCE_BARRIER_FLAG_END_ONLY vlag, die de overgang in behandeling voltooit.
Split-barrières bieden hints aan de GPU dat een resource in de status A- later wordt gebruikt in de status B. Dit geeft de GPU de mogelijkheid om de werkbelasting bij de overgang te optimaliseren, wat mogelijk kan leiden tot het verminderen of elimineren van stagneringen in de uitvoering. Het uitgeven van de eindbarrière garandeert dat alle GPU-overgangsprocessen zijn voltooid voordat men naar de volgende opdracht overgaat.
Het gebruik van splitsbarrières kan helpen om de prestaties te verbeteren, met name in scenario's met meerdere engines of wanneer resources geparseerd worden gelezen/geschreven in een of meer opdrachtlijsten.
Voorbeeldscenario van resourcebarrière
In de volgende fragmenten ziet u het gebruik van de ResourceBarrier methode in een voorbeeld met meerdere threads.
Het creëren van de dieptestencilweergave en deze vervolgens naar een schrijfbare status overzetten.
// Create the depth stencil.
{
CD3DX12_RESOURCE_DESC shadowTextureDesc(
D3D12_RESOURCE_DIMENSION_TEXTURE2D,
0,
static_cast<UINT>(m_viewport.Width),
static_cast<UINT>(m_viewport.Height),
1,
1,
DXGI_FORMAT_D32_FLOAT,
1,
0,
D3D12_TEXTURE_LAYOUT_UNKNOWN,
D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL | D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE);
D3D12_CLEAR_VALUE clearValue; // Performance tip: Tell the runtime at resource creation the desired clear value.
clearValue.Format = DXGI_FORMAT_D32_FLOAT;
clearValue.DepthStencil.Depth = 1.0f;
clearValue.DepthStencil.Stencil = 0;
ThrowIfFailed(m_device->CreateCommittedResource(
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
D3D12_HEAP_FLAG_NONE,
&shadowTextureDesc,
D3D12_RESOURCE_STATE_DEPTH_WRITE,
&clearValue,
IID_PPV_ARGS(&m_depthStencil)));
// Create the depth stencil view.
m_device->CreateDepthStencilView(m_depthStencil.Get(), nullptr, m_dsvHeap->GetCPUDescriptorHandleForHeapStart());
}
Bij het maken van de vertexbufferweergave, verandert u deze eerst van een algemene toestand naar een doeltoestand, en vervolgens van een doeltoestand naar een algemene leesbare toestand.
// Create the vertex buffer.
{
ThrowIfFailed(m_device->CreateCommittedResource(
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
D3D12_HEAP_FLAG_NONE,
&CD3DX12_RESOURCE_DESC::Buffer(SampleAssets::VertexDataSize),
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
IID_PPV_ARGS(&m_vertexBuffer)));
{
ThrowIfFailed(m_device->CreateCommittedResource(
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
D3D12_HEAP_FLAG_NONE,
&CD3DX12_RESOURCE_DESC::Buffer(SampleAssets::VertexDataSize),
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&m_vertexBufferUpload)));
// Copy data to the upload heap and then schedule a copy
// from the upload heap to the vertex buffer.
D3D12_SUBRESOURCE_DATA vertexData = {};
vertexData.pData = pAssetData + SampleAssets::VertexDataOffset;
vertexData.RowPitch = SampleAssets::VertexDataSize;
vertexData.SlicePitch = vertexData.RowPitch;
PIXBeginEvent(commandList.Get(), 0, L"Copy vertex buffer data to default resource...");
UpdateSubresources<1>(commandList.Get(), m_vertexBuffer.Get(), m_vertexBufferUpload.Get(), 0, 0, 1, &vertexData);
commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER));
PIXEndEvent(commandList.Get());
}
Als u de indexbufferweergave maakt, wijzigt u deze eerst van een algemene status in een bestemming en vervolgens van een bestemming naar een algemene leesbare status.
// Create the index buffer.
{
ThrowIfFailed(m_device->CreateCommittedResource(
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
D3D12_HEAP_FLAG_NONE,
&CD3DX12_RESOURCE_DESC::Buffer(SampleAssets::IndexDataSize),
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
IID_PPV_ARGS(&m_indexBuffer)));
{
ThrowIfFailed(m_device->CreateCommittedResource(
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
D3D12_HEAP_FLAG_NONE,
&CD3DX12_RESOURCE_DESC::Buffer(SampleAssets::IndexDataSize),
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&m_indexBufferUpload)));
// Copy data to the upload heap and then schedule a copy
// from the upload heap to the index buffer.
D3D12_SUBRESOURCE_DATA indexData = {};
indexData.pData = pAssetData + SampleAssets::IndexDataOffset;
indexData.RowPitch = SampleAssets::IndexDataSize;
indexData.SlicePitch = indexData.RowPitch;
PIXBeginEvent(commandList.Get(), 0, L"Copy index buffer data to default resource...");
UpdateSubresources<1>(commandList.Get(), m_indexBuffer.Get(), m_indexBufferUpload.Get(), 0, 0, 1, &indexData);
commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_indexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_INDEX_BUFFER));
PIXEndEvent(commandList.Get());
}
// Initialize the index buffer view.
m_indexBufferView.BufferLocation = m_indexBuffer->GetGPUVirtualAddress();
m_indexBufferView.SizeInBytes = SampleAssets::IndexDataSize;
m_indexBufferView.Format = SampleAssets::StandardIndexFormat;
}
"Texturen en shader-resourceweergaven maken." De textuur wordt gewijzigd van een algemene staat naar een bestemming en vervolgens van een bestemming naar een pixel-shader-resource.
// Create each texture and SRV descriptor.
const UINT srvCount = _countof(SampleAssets::Textures);
PIXBeginEvent(commandList.Get(), 0, L"Copy diffuse and normal texture data to default resources...");
for (int i = 0; i < srvCount; i++)
{
// Describe and create a Texture2D.
const SampleAssets::TextureResource &tex = SampleAssets::Textures[i];
CD3DX12_RESOURCE_DESC texDesc(
D3D12_RESOURCE_DIMENSION_TEXTURE2D,
0,
tex.Width,
tex.Height,
1,
static_cast<UINT16>(tex.MipLevels),
tex.Format,
1,
0,
D3D12_TEXTURE_LAYOUT_UNKNOWN,
D3D12_RESOURCE_FLAG_NONE);
ThrowIfFailed(m_device->CreateCommittedResource(
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
D3D12_HEAP_FLAG_NONE,
&texDesc,
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
IID_PPV_ARGS(&m_textures[i])));
{
const UINT subresourceCount = texDesc.DepthOrArraySize * texDesc.MipLevels;
UINT64 uploadBufferSize = GetRequiredIntermediateSize(m_textures[i].Get(), 0, subresourceCount);
ThrowIfFailed(m_device->CreateCommittedResource(
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
D3D12_HEAP_FLAG_NONE,
&CD3DX12_RESOURCE_DESC::Buffer(uploadBufferSize),
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&m_textureUploads[i])));
// Copy data to the intermediate upload heap and then schedule a copy
// from the upload heap to the Texture2D.
D3D12_SUBRESOURCE_DATA textureData = {};
textureData.pData = pAssetData + tex.Data->Offset;
textureData.RowPitch = tex.Data->Pitch;
textureData.SlicePitch = tex.Data->Size;
UpdateSubresources(commandList.Get(), m_textures[i].Get(), m_textureUploads[i].Get(), 0, 0, subresourceCount, &textureData);
commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_textures[i].Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE));
}
// Describe and create an SRV.
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
srvDesc.Format = tex.Format;
srvDesc.Texture2D.MipLevels = tex.MipLevels;
srvDesc.Texture2D.MostDetailedMip = 0;
srvDesc.Texture2D.ResourceMinLODClamp = 0.0f;
m_device->CreateShaderResourceView(m_textures[i].Get(), &srvDesc, cbvSrvHandle);
// Move to the next descriptor slot.
cbvSrvHandle.Offset(cbvSrvDescriptorSize);
}
Een frame beginnen; dit maakt niet alleen gebruik van ResourceBarrier om aan te geven dat de backbuffer moet worden gebruikt als renderdoel, maar ook de frameresource initialiseert (die ResourceBarrier aanroept op de dieptestencilbuffer).
// Assemble the CommandListPre command list.
void D3D12Multithreading::BeginFrame()
{
m_pCurrentFrameResource->Init();
// Indicate that the back buffer will be used as a render target.
m_pCurrentFrameResource->m_commandLists[CommandListPre]->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));
// Clear the render target and depth stencil.
const float clearColor[] = { 0.0f, 0.0f, 0.0f, 1.0f };
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), m_frameIndex, m_rtvDescriptorSize);
m_pCurrentFrameResource->m_commandLists[CommandListPre]->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);
m_pCurrentFrameResource->m_commandLists[CommandListPre]->ClearDepthStencilView(m_dsvHeap->GetCPUDescriptorHandleForHeapStart(), D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);
ThrowIfFailed(m_pCurrentFrameResource->m_commandLists[CommandListPre]->Close());
}
// Assemble the CommandListMid command list.
void D3D12Multithreading::MidFrame()
{
// Transition our shadow map from the shadow pass to readable in the scene pass.
m_pCurrentFrameResource->SwapBarriers();
ThrowIfFailed(m_pCurrentFrameResource->m_commandLists[CommandListMid]->Close());
}
Het beëindigen van een frame, waarmee wordt aangegeven dat de achtergrondbuffer nu wordt gebruikt om te tonen.
// Assemble the CommandListPost command list.
void D3D12Multithreading::EndFrame()
{
m_pCurrentFrameResource->Finish();
// Indicate that the back buffer will now be used to present.
m_pCurrentFrameResource->m_commandLists[CommandListPost]->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
ThrowIfFailed(m_pCurrentFrameResource->m_commandLists[CommandListPost]->Close());
}
Het initialiseren van een frame-resource, dat wordt aangeroepen bij het starten van een frame, maakt de dieptestencilbuffer beschrijfbaar.
void FrameResource::Init()
{
// Reset the command allocators and lists for the main thread.
for (int i = 0; i < CommandListCount; i++)
{
ThrowIfFailed(m_commandAllocators[i]->Reset());
ThrowIfFailed(m_commandLists[i]->Reset(m_commandAllocators[i].Get(), m_pipelineState.Get()));
}
// Clear the depth stencil buffer in preparation for rendering the shadow map.
m_commandLists[CommandListPre]->ClearDepthStencilView(m_shadowDepthView, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);
// Reset the worker command allocators and lists.
for (int i = 0; i < NumContexts; i++)
{
ThrowIfFailed(m_shadowCommandAllocators[i]->Reset());
ThrowIfFailed(m_shadowCommandLists[i]->Reset(m_shadowCommandAllocators[i].Get(), m_pipelineStateShadowMap.Get()));
ThrowIfFailed(m_sceneCommandAllocators[i]->Reset());
ThrowIfFailed(m_sceneCommandLists[i]->Reset(m_sceneCommandAllocators[i].Get(), m_pipelineState.Get()));
}
}
Barrières worden halverwege het frame verwisseld, waarbij de schaduwkaart overgaat van schrijfbaar naar leesbaar.
void FrameResource::SwapBarriers()
{
// Transition the shadow map from writeable to readable.
m_commandLists[CommandListMid]->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_shadowTexture.Get(), D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE));
}
"Finish wordt aangeroepen wanneer een frame wordt beëindigd, waarbij de schaduwkaart naar een gemeenschappelijke status wordt overgezet."
void FrameResource::Finish()
{
m_commandLists[CommandListPost]->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_shadowTexture.Get(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE));
}
Algemene statuspromotie- en vervalsmonster
// Create a buffer resource using D3D12_RESOURCE_STATE_COMMON as the init state
ID3D12Resource *pResource;
CreateCommittedVertexBufferInCommonState(1024, &pResource);
// Copy data to the buffer without the need for a barrier.
// Promotes pResource state to D3D12_RESOURCE_STATE_COPY_DEST.
pCommandList->CopyBufferRegion(pResource, 0, pOtherResource, 0, 1024);
// To use pResource as a vertex buffer a transition barrier is needed.
// Note the StateBefore is D3D12_RESOURCE_STATE_COPY_DEST.
D3D12_RESOURCE_BARRIER BarrierDesc = {};
BarrierDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
BarrierDesc.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
BarrierDesc.Transition.pResource = pResource;
BarrierDesc.Transition.Subresource = 0;
BarrierDesc.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
BarrierDesc.Transition.StateAfter = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
pCommandList->ResourceBarrier( 1, &BarrierDesc );
// Use pResource as a vertex buffer
D3D12_VERTEX_BUFFER_VIEW vbView;
vbView.BufferLocation = pResource->GetGPUVirtualAddress();
vbView.SizeInBytes = 1024;
vbView.StrideInBytes = sizeof(MyVertex);
pCommandList->IASetVertexBuffers(0, 1, &vbView);
pCommandList->Draw();
pCommandQueue->ExecuteCommandLists(1, &pCommandList);
pCommandList->Reset(pAllocator, pPipelineState);
// Since the reset command list will be executed in a separate call to
// ExecuteCommandLists, the previous state of pResource
// will have decayed to D3D12_RESOURCE_STATE_COMMON so, again, no barrier is needed
pCommandList->CopyBufferRegion(pResource, 0, pDifferentResource, 0, 1024);
FinishRecordingCommandList(pCommandList);
pCommandQueue->ExecuteCommandLists(1, &pCommandList);
WaitForQueue(pCommandQueue);
// The previous ExecuteCommandLists call has finished so
// pResource has decayed to D3D12_RESOURCE_STATE_COMMON
Voorbeeld van splitsingsbarrières
In het volgende voorbeeld ziet u hoe u een splitsbarrière gebruikt om pijplijnstallen te verminderen. De volgende code maakt geen gebruik van gesplitste barrières:
D3D12_RESOURCE_BARRIER BarrierDesc = {};
BarrierDesc.Type = D3D12_RESOURCE_BARRIER_TRANSITION;
BarrierDesc.Flags = D3D12_RESOURCE_BARRIER_NONE;
BarrierDesc.Transition.pResource = pResource;
BarrierDesc.Transition.Subresource = 0;
BarrierDesc.Transition.StateBefore = D3D12_RESOURCE_STATE_COMMON;
BarrierDesc.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
pCommandList->ResourceBarrier( 1, &BarrierDesc );
Write(pResource); // ... render to pResource
OtherStuff(); // .. other gpu work
// Transition pResource to PIXEL_SHADER_RESOURCE
BarrierDesc.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
BarrierDesc.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
pCommandList->ResourceBarrier( 1, &BarrierDesc );
Read(pResource); // ... read from pResource
De volgende code maakt gebruik van gesplitste barrières:
D3D12_RESOURCE_BARRIER BarrierDesc = {};
BarrierDesc.Type = D3D12_RESOURCE_BARRIER_TRANSITION;
BarrierDesc.Flags = D3D12_RESOURCE_BARRIER_NONE;
BarrierDesc.Transition.pResource = pResource;
BarrierDesc.Transition.Subresource = 0;
BarrierDesc.Transition.StateBefore = D3D12_RESOURCE_STATE_COMMON;
BarrierDesc.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
pCommandList->ResourceBarrier( 1, &BarrierDesc );
Write(pResource); // ... render to pResource
// Done writing to pResource. Start barrier to PIXEL_SHADER_RESOURCE and
// then do other work
BarrierDesc.Flags = D3D12_RESOURCE_BARRIER_BEGIN_ONLY;
BarrierDesc.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
BarrierDesc.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
pCommandList->ResourceBarrier( 1, &BarrierDesc );
OtherStuff(); // .. other gpu work
// Need to read from pResource so end barrier
BarrierDesc.Flags = D3D12_RESOURCE_BARRIER_END_ONLY;
pCommandList->ResourceBarrier( 1, &BarrierDesc );
Read(pResource); // ... read from pResource
Verwante onderwerpen
Geavanceerde leerzame videotutorials voor DirectX: Resourcebarrières en statustracking