Sdílet prostřednictvím


Použití kontextově lokálních popisovačů DDI

Tato část platí jenom pro Windows 7 a novější a Windows Server 2008 R2 a novější verze operačního systému Windows.

Každý objekt (například prostředek, shader atd.) má popisovače DDI místního kontextu.

Předpokládejme, že se objekt používá se třemi odloženými kontexty. V této situaci čtyři popisovače odkazují na stejný objekt (jeden popisovač pro každý odložený kontext a jiný popisovač pro okamžitý kontext). Vzhledem k tomu, že každý kontext může současně manipulovat vláknem, kontextový místní popisovač zajišťuje, že více vláken procesoru nebude soupeřit o podobnou paměť (buď záměrně, nebo neúmyslně). Kontextové popisovače jsou také intuitivní, protože ovladač pravděpodobně musí upravit většinu těchto dat, která jsou logicky spojená s kontextem v každém případě (například objekt může být vázán kontextem atd.).

Stále existuje rozdíl mezi okamžitým popisovačem kontextu a odloženým popisovačem kontextu. Zejména je zaručeno, že okamžitý kontextový popisovač bude prvním přiděleným popisovačem a posledním zničeným popisovačem. Odpovídající okamžitý popisovač kontextu je k dispozici během "otevření" každého odloženého popisovače kontextu, který je propojí. V současné době neexistuje žádný koncept objektu, který má popisovač DDI pro každé zařízení (to znamená popisovač vytvořený před a zničený po okamžitém popisovači kontextu a odkazoval by se pouze v pořadí vytvořením popisovače kontextu).

Některé popisovače mají vztahy závislosti s jinými popisovači (například zobrazení jsou závislá na svém příslušném prostředku). Záruka vytvoření a zničení, která existuje pro bezprostřední kontext, je rozšířena také na odložené kontextové popisovače (to znamená, že runtime vytvoří kontextově lokální popisovač prostředku před tím, než vytvoří jakékoli kontextově lokální popisovače zobrazení pro daný prostředek, a runtime zničí kontextově lokální popisovač prostředku poté, co zničí všechny kontextově lokální popisovače zobrazení tohoto prostředku). Když modul runtime vytvoří kontextový místní popisovač, modul runtime poskytuje také odpovídající popisovače závislostí místního kontextu.

Organizace dat řidiče

Existuje několik obav ohledně organizace dat řidičů, které vyžadují pozornost. Stejně jako Direct3D verze 10 může správná lokalita dat snížit chybějící mezipaměti mezi rozhraním API a ovladačem. Správné umístění dat může také zabránit přetížení mezipaměti, ke kterému dochází, když se více často používaných dat přeloží na stejný index mezipaměti a vyčerpají asociativitu mezipaměti. DDI byl navržen od verze Direct3D 10 tak, aby se zabránilo projevení takových problémů tím, že ovladač informuje API, kolik paměti je potřeba ke splnění popisovače, a API následně přiřadí hodnotu popisovače. Nové aspekty související s vlákny však ovlivňují návrh DDI v časovém rámci Direct3D verze 11.

Samozřejmě, kontextové popisovače poskytují způsob, jak přidružit data objektů podle kontextu, což zabraňuje problémům s kolizí mezi vlákny. Vzhledem k tomu, že se tato data replikují pro každý odložený kontext, je zásadním problémem velikost těchto dat. To poskytuje přirozené zdůvodnění pro sdílení dat pouze pro čtení mezi přímým popisovačem kontextu a odloženými kontextovými popisovači. Během vytváření odložených popisovačů kontextu je k dispozici okamžitý popisovač kontextu pro navázání propojení mezi popisovači. Všechna data, která se nacházejí mimo odložený kontext, ale získají výhody lokality s daty rozhraní API a další úroveň nepřímých dat jen pro čtení brání výhodám lokality v rozšíření na data jen pro čtení. Některá data jen pro čtení je možné replikovat do každé oblasti zpracování kontextu, pokud výhody lokality odůvodňují duplikaci dat. Paměť, která vrací každý odložený kontextový popisovač, by však měla být považována za takovou úroveň, že by mohlo být vhodné přemístit data, která nejsou nesousedící z popisovače, pokud jsou tato data relativně velká a nepřistupují tak často jako jiná data. V ideálním případě by typ dat, která jsou spojena s každým odloženým kontextovým popisovačem, zahrnoval pouze data s vysokou frekvencí; proto by data nebyla dostatečně velká na to, aby bylo přemístění nezbytné. Samozřejmě, řidič musí vyvážit tyto konfliktní motivace.

Aby byl návrh dat ovladačů účelně kompatibilní s Direct3D verzí 10 a zároveň se neodchyloval v implementaci, měla by se data pouze pro čtení nacházet souvisle (ale stále odděleně a za) údaji okamžitého kontextového ukazatele. Pokud ovladač používá tento návrh, musí mít na paměti, že mezi okamžitým kontextovým popisovačem dat a daty jen pro čtení je vyžadováno odsazení řádku mezipaměti. Vzhledem k tomu, že vlákno může manipulovat s jednotlivými kontextovými daty často (ne-li souběžně), dochází k sankcím za falešné sdílení mezi okamžitým kontextovým popisovačem dat a odloženým kontextovým popisovačem, pokud se nepoužívá zarovnání řádku mezipaměti. Návrh ovladače musí brát v úvahu sankce za falešné sdílení, které se projeví, pokud jsou ukazatele vytvořeny a pravidelně procházeny mezi paměťovými oblastmi kontextových úchytů.

Běhové prostředí Direct3D používá pro odložené místní popisovače kontextu následující rozhraní Direct3D 11 DDI:

Aby modul runtime Direct3D načetl odloženou velikost popisovače kontextu vyžadovanou ovladačem, musí být použity předchozí funkce DDI. Ihned po vytvoření objektu pro okamžitý kontext modul runtime volá CalcDeferredContextHandleSize, aby zjistil množství úložného prostoru potřebného ovladačem ke splnění odložených kontextových popisovačů tohoto objektu. Rozhraní API Direct3D však musí vyladit svůj alokátor paměti CLS určením počtu jedinečných velikostí popisovačů a jejich hodnot, ke kterým se přistupuje; modul runtime volá funkci CheckDeferredContextHandleSizes ovladače k získání těchto informací. Proto rozhraní API během vytváření instancí zařízení požaduje pole velikostí odložených kontextových popisovačů dvojím dotazováním. Prvním průzkumem je zjištění, kolik velikostí se vrátí, zatímco druhý průzkum předává pole (array) pro získání hodnoty každé velikosti. Ovladač musí uvést, jaké množství paměti vyžaduje ke správnému fungování úchytu spolu s typem úchytu. Ovladač může vrátit více velikostí přidružených k určitému typu popisovače. Není však definováno, aby ovladač někdy vrátil hodnotu z CalcDeferredContextHandleSize, která nebyla také odpovídajícím způsobem vrácena v poli CheckDeferredContextHandleSizes.

Pokud jde o vytváření popisovačů DDI, použijí se metody create v odloženém kontextu. Prozkoumejte například funkce CreateBlendState(D3D10_1) a DestroyBlendState . HDEVICE přirozeně odkazuje na příslušný odložený kontext (v porovnání s okamžitým kontextem); ostatní ukazatele struktury CONST jsou NULL (za předpokladu, že objekt nemá žádné závislosti); a popisovač D3D10DDI_HRT* je popisovač D3D10DDI_H* odpovídající objektu bezprostředního kontextu.

U objektů, které mají závislosti (například zobrazení mají vztah závislostí na příslušném prostředku), ukazatel struktury, který poskytuje popisovač závislosti, není NULL. Jediným platným členem struktury je popisovač závislostí, zatímco ostatní členové jsou vyplněni nulou. Například D3D11DDIARG_CREATESHADERRESOURCEVIEW ukazatel ve volání funkce CreateShaderResourceView(D3D11) ovladače nebude NULL, když běhové prostředí volá tuto funkci v odloženém kontextu. V tomto volání CreateShaderResourceView(D3D11) modul runtime přiřadí členovi hDrvResource v D3D11DDIARG_CREATESHADERRESOURCEVIEW odpovídající kontextově místní popisovač prostředku. Zbývající členové D3D11DDIARG_CREATESHADERRESOURCEVIEW jsou ale naplněni nulou.

Následující příklad kódu ukazuje, jak modul runtime Direct3D překládá požadavek na vytvoření aplikace a první použití odloženého kontextu k volání ovladače zobrazení v uživatelském režimu k vytvoření okamžitých a odložených kontextů. Volání aplikace ID3D11Device::CreateTexture2D iniciuje kód běhového prostředí v následující části „Vytváření prostředku“. Volání aplikace ID3D11Device::CopyResource inicializuje kód modulu runtime v následující části "Deferred Context Resource Usage".

// Device Create
 IC::pfnCheckDeferredContextHandleSizes( hIC, &u, NULL );
pArray = malloc( u * ... );
IC::pfnCheckDeferredContextHandleSizes( hIC, &u, pArray );

// Resource Create
 s = IC::pfnCalcPrivateResourceSize( hIC, &Args );
pICRHandle = malloc( s );
 IC::pfnCreateResource( hIC, &Args, pICRHandle, hRTResource );
 s2 = IC::pfnCalcDeferredContextHandleSize( hIC, D3D10DDI_HT_RESOURCE, pICRHandle );

// Deferred Context Resource Usage
pDCRHandle = malloc( s2 );
 DC::pfnCreateResource( hDC, NULL, pDCRHandle, pICRHandle );

Problémy s pfnSetErrorCb

Žádná funkce pro vytváření nevrací kód chyby, který by byl ideální pro model vláken Direct3D verze 11. Všechny funkce pro vytváření používají pfnSetErrorCb k načtení kódů chyb zpět z ovladače. Aby se maximalizovala kompatibilita s modelem ovladače Direct3D verze 10, nebyly zavedeny žádné nové funkce DDI, které by vracely kódy chyb. Místo toho musí ovladač při vytváření funkcí dál používat popisovač sjednoceného kontextu zařízení/přímého kontextu D3D10DDI_HRTCORELAYER s pfnSetErrorCb. Pokud ovladač podporuje seznamy příkazů, měl by ovladač použít odpovídající pfnSetErrorCb , který je přidružený k odpovídajícímu kontextu. To znamená, že odložené chyby kontextu by měly jít na konkrétní odložené volání kontextu pfnSetErrorCb s odpovídajícím popisovačem atd.

Odložené kontexty můžou vracet E_OUTOFMEMORY voláním pfnSetErrorCb z funkcí DDI, které dříve povolily pouze D3DDDIERR_DEVICEREMOVED (například Draw, SetBlendState atd.), protože odložené požadavky na paměť kontextu se neustále zvětšují s každým voláním funkce DDI. Rozhraní API Direct3D aktivuje odebrání místního kontextu, aby pomohlo ovladači v případě selhání, které efektivně odstraní částečně sestavený seznam příkazů. Aplikace nadále zjišťuje, že nahrává seznam příkazů; Nicméně, když aplikace nakonec volá FinishCommandList funkce, FinishCommandList vrátí kód selhání E_OUTOFMEMORY.