Průchody vykreslování Direct3D 12
Funkce pro průchody vykreslování je nová pro Windows 10 verze 1809 (10.0; Build 17763) a představuje koncept průchodu vykreslování Direct3D 12. Průchod vykreslení se skládá z podmnožina příkazů, které zaznamenáte do seznamu příkazů.
Chcete-li deklarovat, kde každý průchod vykreslování začíná a končí, vnoření příkazů, které patří do volání ID3D12GraphicsCommandList4::BeginRenderPass a EndRenderPass. Každý seznam příkazů proto obsahuje nula, jeden nebo více předplatných vykreslení.
Scénáře
Předávání vykreslování může mimo jiné zlepšit výkon vykreslovacího modulu, pokud je založen na Tile-Based Deferred Rendering (TBDR). Konkrétněji tato technika pomáhá vykreslovacímu modulu zlepšit efektivitu GPU snížením provozu paměti do/z paměti mimo čip tím, že vaší aplikaci umožníte lépe identifikovat požadavky na řazení prostředků a závislosti dat.
Ovladač zobrazení napsaný výslovně pro využití funkce průchodů vykreslování poskytuje nejlepší výsledky. Vykreslovací rozhraní API se ale můžou spouštět i u existujících ovladačů (i když nemusí nutně s vylepšením výkonu).
Jedná se o scénáře, ve kterých se předá vykreslování, jsou navržené tak, aby poskytovaly hodnotu.
Povolte aplikaci vyhnout se zbytečným zatížením nebo úložištím prostředků z/do hlavní paměti v architektuře Tile-Based Deferred Rendering (TBDR).
Jednou z hodnot předplatných vykreslování je to, že poskytuje centrální umístění, které označuje závislosti dat vaší aplikace pro sadu operací vykreslování. Tyto závislosti dat umožňují ovladači zobrazení kontrolovat tato data v době svázání/bariéry a vydávat pokyny, které minimalizují zatížení nebo úložiště prostředků z/do hlavní paměti.
Povolit architektuře TBDR oportunisticky trvalé prostředky v mezipaměti na čipu napříč průchody vykreslování (i v samostatných seznamech příkazů)
Poznámka
Konkrétně je tento scénář omezený na případy, kdy píšete do stejných cílů vykreslování napříč několika seznamy příkazů.
Běžným vzorem vykreslování je, aby se vaše aplikace vykreslovala do stejných cílů vykreslování napříč několika seznamy příkazů sériově, i když se příkazy vykreslování generují paralelně. Použití průchodů vykreslování v tomto scénáři umožňuje tyto průchody zkombinovat takovým způsobem (protože aplikace ví, že bude pokračovat v vykreslování v okamžitém úspěšném seznamu příkazů), že ovladač zobrazení může zabránit vyprázdnění hlavní paměti na hranicích seznamu příkazů.
Odpovědnosti vaší aplikace
I když funkce projde vykreslováním, ani modul runtime Direct3D 12 ani ovladač displeje nezohlední odpovědnost za odstranění příležitostí k opětovnému objednání/zabránění zatížení a obchodům. Aby bylo možné správně využít funkci průchodu vykreslování, má vaše aplikace tyto odpovědnosti.
- Správně identifikujte závislosti dat a řazení pro své operace.
- Seřazení odesílaných položek způsobem, který minimalizuje vyprázdnění (minimalizujte tak použití příznaků _PRESERVE).
- Správně využijte bariéry prostředků a sledujte stav prostředků.
- Vyhněte se nepotřebným kopiím nebo vymazáním. Abyste je mohli identifikovat, můžete použít automatizované upozornění výkonu z nástroje PIX v systému Windows.
Použití funkce předávání vykreslování
Co je předání vykreslení?
Průchod vykreslení je definován těmito prvky.
- Sadavýstupních Tyto vazby jsou na jedno nebo více cílových zobrazení vykreslování (RTV) a/nebo do hloubkového zobrazení vzorníku (DSV).
- Seznam operací GPU, které cílí na sadu výstupních vazeb.
- Metadata popisující závislosti načtení a úložiště pro všechny výstupní vazby cílené průchodem vykreslování.
Deklarace výstupních vazeb
Na začátku průchodu vykreslování deklarujete vazby pro cíle vykreslování nebo do vyrovnávací paměti vzorníku. Je volitelné vytvořit vazbu k vykreslení cílů a je volitelné vytvořit vazbu s vyrovnávací pamětí hloubky nebo vzorníku. Musíte ale svázat alespoň jednu z těchto dvou a v příkladu kódu níže vytvoříme vazbu k oběma.
Deklarujete tyto vazby ve volání ID3D12GraphicsCommandList4::BeginRenderPass.
void render_passes(::ID3D12GraphicsCommandList4 * pIGCL4,
D3D12_CPU_DESCRIPTOR_HANDLE const& rtvCPUDescriptorHandle,
D3D12_CPU_DESCRIPTOR_HANDLE const& dsvCPUDescriptorHandle)
{
const float clearColor4[]{ 0.f, 0.f, 0.f, 0.f };
CD3DX12_CLEAR_VALUE clearValue{ DXGI_FORMAT_R32G32B32_FLOAT, clearColor4 };
D3D12_RENDER_PASS_BEGINNING_ACCESS renderPassBeginningAccessClear{ D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR, { clearValue } };
D3D12_RENDER_PASS_ENDING_ACCESS renderPassEndingAccessPreserve{ D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE, {} };
D3D12_RENDER_PASS_RENDER_TARGET_DESC renderPassRenderTargetDesc{ rtvCPUDescriptorHandle, renderPassBeginningAccessClear, renderPassEndingAccessPreserve };
D3D12_RENDER_PASS_BEGINNING_ACCESS renderPassBeginningAccessNoAccess{ D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, {} };
D3D12_RENDER_PASS_ENDING_ACCESS renderPassEndingAccessNoAccess{ D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, {} };
D3D12_RENDER_PASS_DEPTH_STENCIL_DESC renderPassDepthStencilDesc{ dsvCPUDescriptorHandle, renderPassBeginningAccessNoAccess, renderPassBeginningAccessNoAccess, renderPassEndingAccessNoAccess, renderPassEndingAccessNoAccess };
pIGCL4->BeginRenderPass(1, &renderPassRenderTargetDesc, &renderPassDepthStencilDesc, D3D12_RENDER_PASS_FLAG_NONE);
// Record command list.
pIGCL4->EndRenderPass();
// Begin/End further render passes and then execute the command list(s).
}
První pole struktury D3D12_RENDER_PASS_RENDER_TARGET_DESC nastavíte na popisovač procesoru odpovídající jednomu nebo více cílovým zobrazením vykreslení (RTV). Podobně D3D12_RENDER_PASS_DEPTH_STENCIL_DESC obsahuje popisovač procesoru odpovídající zobrazení hloubkového vzorníku (DSV). Popisovače procesoru jsou stejné, jako byste jinak předali ID3D12GraphicsCommandList::OMSetRenderTargets. A stejně jako u OMSetRenderTargetsjsou popisovače procesoru přichycené z příslušných hald (popisovač procesoru) v době volání BeginRenderPass.
Verze RTV a DSV se nedědí do průchodu vykreslení. Místo toho musí být nastaveny. V BeginRenderPass nejsou deklarovány ani verze RTV a DSV rozšířeny do seznamu příkazů. Místo toho jsou v nedefinovaném stavu po průchodu vykreslení.
Průchody vykreslování a úlohy
Nemůžete vnořit průchody vykreslování a nemůžete mít průchod vykreslení vnořený více než jeden seznam příkazů (musí začínat a končit při nahrávání do jednoho seznamu příkazů). Optimalizace navržené tak, aby umožňovaly efektivní generování vícevláknových průchodů vykreslování, jsou popsány v části vykreslovat předávací příznakyníže.
Zápis, který provedete z průchodu vykreslení, není platné pro čtení až do následného průchodu vykreslení. To brání některým typům překážek v rámci vykreslovacího průsmyku , například bariéry z RENDER_TARGET na SHADER_RESOURCE na aktuálně vázaném cíli vykreslení. Další informace najdete v části Průchody vykreslení a překážky prostředkůníže.
Jedinou výjimkou omezení zápisu a čtení, které jsme právě zmínili, zahrnuje implicitní čtení, ke kterým dochází v rámci hloubkového testování a prolnutí cíle vykreslování. Tato rozhraní API jsou proto v rámci průchodu vykreslování zakázaná (základní modul runtime odebere seznam příkazů, pokud se některá z nich volá během nahrávání).
- ID3D12GraphicsCommandList1::AtomicCopyBufferUINT
- ID3D12GraphicsCommandList1::AtomicCopyBufferUINT64
- ID3D12GraphicsCommandList4::BeginRenderPass
- ID3D12GraphicsCommandList::ClearDepthStencilView
- ID3D12GraphicsCommandList::ClearRenderTargetView
- ID3D12GraphicsCommandList::ClearState
- ID3D12GraphicsCommandList::ClearUnorderedAccessViewFloat
- ID3D12GraphicsCommandList::ClearUnorderedAccessViewUint
- ID3D12GraphicsCommandList::CopyBufferRegion
- ID3D12GraphicsCommandList::CopyResource
- ID3D12GraphicsCommandList::CopyTextureRegion
- ID3D12GraphicsCommandList::CopyTiles
- ID3D12GraphicsCommandList::D iscardResource
- ID3D12GraphicsCommandList::D ispatch
- ID3D12GraphicsCommandList::OMSetRenderTargets
- ID3D12GraphicsCommandList::ResolveQueryData
- ID3D12GraphicsCommandList::ResolveSubresource
- ID3D12GraphicsCommandList1::ResolveSubresourceRegion
- ID3D12GraphicsCommandList3::SetProtectedResourceSession
Průchody vykreslení a bariéry prostředků
Nesmíte číst ani využívat zápis, ke kterému došlo ve stejném průchodu vykreslování. Některé překážky nevyhovují tomuto omezení, například z D3D12_RESOURCE_STATE_RENDER_TARGET na *_SHADER_RESOURCE na aktuálně vázaném cíli vykreslení (a ladicí vrstva se v tomto efektu zobrazí chybou). Ale stejná bariéra na cíli vykreslení, který byl napsán mimo aktuální průchod vykreslení je vyhovující, protože zápisy se dokončí před spuštěním aktuálního průchodu vykreslení. Pro vás může být užitečné vědět o určitých optimalizacích, které může ovladač displeje v tomto ohledu provést. Vzhledem k vyhovující úloze může ovladač displeje přesunout všechny překážky, ke kterým došlo v vykreslení, na začátek průchodu vykreslení. V této oblasti mohou být sloučeny (a neruší žádné operace dělení nebo binningu). Toto je platná optimalizace za předpokladu, že všechny vaše zápisy byly dokončeny před spuštěním aktuálního průchodu vykreslení.
Tady je ucelenější příklad optimalizace ovladačů, který předpokládá, že máte vykreslovací modul, který má předpřipravený návrh vazby prostředků ve stylu Direct3D 12 – dělá překážky na vyžádání na základě toho, jak jsou prostředky vázané. Při zápisu do neuspořádaného zobrazení přístupu (UAV) ke konci rámce (který se má použít v následujícím rámci), může dojít k tomu, že modul ponechá prostředek v D3D12_RESOURCE_STATE_UNORDERED_ACCESS stavu na konci rámce. V následujícím rámečku, když modul přejde na vazbu prostředku jako zobrazení prostředků shaderu (SRV), zjistí, že prostředek není ve správném stavu a vydá bariéru z D3D12_RESOURCE_STATE_UNORDERED_ACCESS na D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE. Pokud dojde k této bariérě v rámci průchodu vykreslení, ovladač displeje je odůvodněn za předpokladu, že všechny zápisy již nastaly mimo tohoto průchodu vykreslení a následně (a tady je místo, kde přichází optimalizace), ovladač displeje může přesunout bariéru až do začátku průchodu vykreslení. Toto je opět platné, pokud váš kód odpovídá omezení pro zápis a čtení popsané v této části a poslední.
Jedná se o příklady vyhovujících bariér.
- D3D12_RESOURCE_STATE_UNORDERED_ACCESS na D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT.
- D3D12_RESOURCE_STATE_COPY_DEST*_SHADER_RESOURCE.
A to jsou příklady nevyhovujících bariér.
- D3D12_RESOURCE_STATE_RENDER_TARGET do jakéhokoli stavu čtení v aktuálně vázaném zobrazení RTV/DSV.
- D3D12_RESOURCE_STATE_DEPTH_WRITE do jakéhokoli stavu čtení v aktuálně vázaném zobrazení RTV/DSV.
- Jakákoli bariéra aliasingu.
- Neuspořádané bariéry zobrazení přístupu (UAV).
Deklarace přístupu k prostředkům
V BeginRenderPass čas a deklarování všech prostředků, které slouží jako RTV a/nebo DSV v rámci daného průchodu, musíte také zadat jejich počáteční a koncovou přístup charakteristiky. Jak vidíte v příkladu kódu v Deklarujte výstupní vazby oddílu výše, provedete to pomocí D3D12_RENDER_PASS_RENDER_TARGET_DESC a D3D12_RENDER_PASS_DEPTH_STENCIL_DESC struktur.
Další podrobnosti najdete v D3D12_RENDER_PASS_BEGINNING_ACCESS a D3D12_RENDER_PASS_ENDING_ACCESS strukturách a výčtech D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE a D3D12_RENDER_PASS_ENDING_ACCESS_TYPE.
Vykreslení příznaků průchodu
Poslední parametr předaný BeginRenderPass je příznak render pass (hodnota z D3D12_RENDER_PASS_FLAGS výčtu).
enum D3D12_RENDER_PASS_FLAGS
{
D3D12_RENDER_PASS_FLAG_NONE = 0,
D3D12_RENDER_PASS_FLAG_ALLOW_UAV_WRITES = 0x1,
D3D12_RENDER_PASS_FLAG_SUSPENDING_PASS = 0x2,
D3D12_RENDER_PASS_FLAG_RESUMING_PASS = 0x4
};
Zápisy UAV v rámci průchodu vykreslení
Zápisy neuspořádaného zobrazení přístupu (UAV) jsou povoleny v rámci průchodu vykreslení, ale musíte výslovně označit, že budete vydávat zápisy UAV v rámci průchodu vykreslením zadáním D3D12_RENDER_PASS_FLAG_ALLOW_UAV_WRITES, aby ovladač zobrazení mohl v případě potřeby zrušit svázání.
Přístupy UAV musí dodržovat omezení zápisu a čtení popsané výše (zápisy v průchodu vykreslování nejsou platné pro čtení, dokud následný průchod vykreslení neproběhne). Bariéry UAV nejsou povoleny v rámci průchodu vykreslení.
Vazby UAV (prostřednictvím kořenových tabulek nebo kořenových popisovačů) se dědí do průchodů vykreslování a šíří se mimo průchody vykreslování.
Pozastavení průchodů a obnovení
Celý průchod vykreslení můžete označit jako pozastavení a/nebo obnovení průchodu. Pár pozastavení následovaný obnovením musí mít mezi průchody identické příznaky zobrazení a přístupu a nemusí obsahovat žádné operace GPU (například kreslí, odesílá, zahodí, vymaže, zkopíruje, aktualizuje mapování dlaždic, zápis-vyrovnávací paměť, dotazy, překlady dotazů) mezi pozastavením průchodu vykreslování a opětovným předáním vykreslení.
Zamýšlený případ použití je vykreslování ve více vláknech, kde například čtyři seznamy příkazů (každý s vlastními průchody vykreslování) může cílit na stejné cíle vykreslování. Při pozastavení nebo obnovení vykreslování mezi seznamy příkazů musí být seznamy příkazů spuštěny ve stejném volání ID3D12CommandQueue::ExecuteCommandLists.
Průchod vykreslení může být obnovení i pozastavení. V právě zadaném příkladu s více vlákny by příkazy 2 a 3 obnovovaly z 1 a 2. A současně by 2 a 3 byly pozastaveny na 3 a 4, v uvedeném pořadí.
Dotaz na podporu funkcí pro průchody vykreslování
Můžete volat ID3D12Device::CheckFeatureSupport dotazovat rozsahu, do kterého ovladač zařízení nebo hardware efektivně podporuje průchody vykreslování.
D3D12_RENDER_PASS_TIER get_render_passes_tier(::ID3D12Device * pIDevice)
{
D3D12_FEATURE_DATA_D3D12_OPTIONS5 featureSupport{};
winrt::check_hresult(
pIDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS5, &featureSupport, sizeof(featureSupport))
);
return featureSupport.RenderPassesTier;
}
...
D3D12_RENDER_PASS_TIER renderPassesTier{ get_render_passes_tier(pIDevice) };
Vzhledem k logikě mapování modulu runtime předává vykreslení funkci always. V závislosti na podpoře funkcí ale nebudou vždy poskytovat výhodu. Kód podobný výše uvedenému příkladu kódu můžete použít k určení, jestli stojí za to vydat příkazy jako předávky vykreslování a kdy to určitě není výhoda (to znamená, že modul runtime právě mapuje na existující plochu rozhraní API). Provádění této kontroly je zvlášť důležité, pokud používáte D3D11On12).
Popis tří úrovní podpory najdete v D3D12_RENDER_PASS_TIER výčtu.