Kopiera och komma åt resursdata (Direct3D 10)

Det är inte längre nödvändigt att tänka på resurser som skapas i antingen videominne eller systemminne. Eller om körningen ska hantera minnet eller inte. Tack vare arkitekturen för den nya WDDM (Windows Display Driver Model) skapar program nu Direct3D 10-resurser med olika användning flaggor för att ange hur programmet tänker använda resursdata. Den nya drivrutinsmodellen virtualiserar det minne som används av resurser. det blir sedan ansvaret för operativsystemet/drivrutinen/minneshanteraren att placera resurser i det mest högpresterande minnesområdet som möjligt med tanke på den förväntade användningen.

Standardfallet är att resurser ska vara tillgängliga för GPU:n. Naturligtvis, med det sagt, finns det tillfällen då resursdata måste vara tillgängliga för processorn. Om du kopierar resursdata så att rätt processor kan komma åt dem utan att påverka prestandan krävs viss kunskap om hur API-metoderna fungerar.

Kopiera resursdata

Resurser skapas i minnet när Direct3D kör ett Skapa-anrop. De kan skapas i videominne, systemminne eller någon annan typ av minne. Eftersom WDDM-drivrutinsmodellen virtualiserar det här minnet behöver programmen inte längre hålla reda på vilken typ av minnesresurser som skapas i.

Helst skulle alla resurser finnas i videominnet så att GPU:n kan få omedelbar åtkomst till dem. Det är dock ibland nödvändigt att processorn läser resursdata eller att GPU:n får åtkomst till resursdata som processorn har skrivit till. Direct3D 10 hanterar dessa olika scenarier genom att begära att programmet anger en användning och erbjuder sedan flera metoder för att kopiera resursdata vid behov.

Beroende på hur resursen skapades är det inte alltid möjligt att komma åt underliggande data direkt. Det kan innebära att resursdata måste kopieras från källresursen till en annan resurs som är tillgänglig för lämplig processor. När det gäller Direct3D 10 kan standardresurser nås direkt av GPU:n, dynamiska resurser och mellanlagringsresurser kan nås direkt av processorn.

När en resurs har skapats kan inte dess användning ändras. Kopiera i stället innehållet i en resurs till en annan resurs som skapades med en annan användning. Direct3D 10 tillhandahåller den här funktionen med tre olika metoder. De första två metoderna( ID3D10Device::CopyResource och ID3D10Device::CopySubresourceRegion) är utformade för att kopiera resursdata från en resurs till en annan. Den tredje metoden (ID3D10Device::UpdateSubresource) är utformad för att kopiera data från minnet till en resurs.

Det finns två huvudsakliga typer av resurser: mappbara och icke-mappbara. Resurser som skapas med dynamisk användning eller mellanlagringsanvändning kan mappas, medan resurser som skapas med standardanvändning eller oföränderliga användningar inte kan mappas.

Det går mycket snabbt att kopiera data mellan icke-mappbara resurser eftersom detta är det vanligaste fallet och har optimerats för att fungera bra. Eftersom dessa resurser inte är direkt åtkomliga av processorn optimeras de så att GPU:n kan manipulera dem snabbt.

Det är mer problematiskt att kopiera data mellan mappbara resurser eftersom prestandan beror på vilken användning resursen skapades med. GPU:n kan till exempel läsa en dynamisk resurs ganska snabbt men kan inte skriva till dem och GPU:n kan inte läsa eller skriva till mellanlagringsresurser direkt.

Program som vill kopiera data från en resurs med standardanvändning till en resurs med mellanlagringsanvändning (så att processorn kan läsa data – dvs. GPU-återläsningsproblemet) måste göra det med försiktighet. Mer information om det här sista fallet finns i Åtkomst till resursdata.

Åtkomst till resursdata

Åtkomst till en resurs kräver mappning av resursen. mappning innebär i princip att programmet försöker ge CPU-åtkomst till minnet. Processen med att mappa en resurs så att processorn kan komma åt det underliggande minnet kan orsaka vissa flaskhalsar i prestanda och därför måste man vara noga med hur och när den här uppgiften ska utföras.

Prestanda kan stoppas om programmet försöker mappa en resurs vid fel tidpunkt. Om programmet försöker komma åt resultatet av en åtgärd innan åtgärden har slutförts, inträffar ett pipeline-stopp.

Om du utför en kartåtgärd vid fel tidpunkt kan det orsaka en allvarlig prestandaminskning genom att tvinga GPU:n och processorn att synkronisera med varandra. Den här synkroniseringen sker om programmet vill komma åt en resurs innan GPU:n är färdig med att kopiera den till en resurs som processorn kan mappa.

Processorn kan bara läsa från resurser som skapats med flaggan D3D10_USAGE_STAGING. Eftersom resurser som skapats med den här flaggan inte kan anges som utdata från pipelinen måste data kopieras till en resurs som skapas med mellanlagringsflaggan om processorn vill läsa data i en resurs som genereras av GPU:n. Programmet kan göra detta med hjälp av ID3D10Device::CopyResource eller ID3D10Device::CopySubresourceRegion metoderna för att kopiera innehållet i en resurs till en annan. Programmet kan sedan få åtkomst till den här resursen genom att anropa lämplig map-metod. När åtkomsten till resursen inte längre behövs bör programmet anropa motsvarande Unmap-metod. Till exempel ID3D10Texture2D::Map och ID3D10Texture2D::Unmap. De olika kartmetoderna returnerar vissa specifika värden beroende på indataflaggor. Mer information finns i avsnittet Kartkommentarer.

Obs

När programmet anropar map-metoden får det en pekare till resursdata att komma åt. Körtiden säkerställer att pekaren har en specifik inriktning, beroende på funktionsnivå . För D3D_FEATURE_LEVEL_10_0 och högre justeras pekaren till 16 byte. För lägre än D3D_FEATURE_LEVEL_10_0justeras pekaren till 4 byte. Justeringen på 16 byte gör att programmet kan utföra SSE-optimerade åtgärder på data internt, utan omjustering eller kopiering.

 

Prestandaöverväganden

Det är bäst att tänka på en dator som en dator som körs som en parallell arkitektur med två huvudtyper av processorer: en eller flera processorer och en eller flera GPU:er. Precis som i alla parallella arkitekturer uppnås den bästa prestandan när varje processor schemaläggs med tillräckligt med uppgifter för att förhindra att den går inaktiv och när en processors arbete inte väntar på en annan processors arbete.

Det värsta scenariot för GPU/CPU-parallellitet är behovet av att tvinga en processor att vänta på resultatet av arbete som utförs av en annan. Direct3D 10 försöker ta bort den här kostnaden genom att göra ID3D10Device::CopyResource och ID3D10Device::CopySubresourceRegion metoder asynkrona; kopian har inte nödvändigtvis körts när metoden returnerar. Fördelen med detta är att programmet inte betalar prestandakostnaden för att faktiskt kopiera data förrän PROCESSORn kommer åt data, vilket är när Map anropas. Om map-metoden anropas efter att data faktiskt har kopierats sker ingen prestandaförlust. Å andra sidan, om Map-metoden anropas innan data har kopierats, så uppstår ett pipeline-stopp.

Asynkrona anrop i Direct3D 10 (som är de allra flesta metoder och särskilt återgivningsanrop) lagras i vad som kallas en kommandobuffert. Den här bufferten är intern för grafikdrivrutinen och används för batchanrop till den underliggande maskinvaran så att den kostsamma övergången från användarläge till kernelläge i Microsoft Windows sker så sällan som möjligt.

Kommandobufferten töms, vilket orsakar ett användar-/kärnlägesbyte i en av fyra situationer, som följer nedan.

  1. Present kallas.
  2. ID3D10Enhet::Töm anropas.
  3. Kommandobufferten är full. dess storlek är dynamisk och styrs av operativsystemet och grafikdrivrutinen.
  4. Processorn kräver åtkomst till resultatet av ett kommando som väntar på att köras i kommandobufferten.

Av de fyra situationerna ovan är nummer fyra den mest kritiska för prestanda. Om programmet utfärdar ett ID3D10Device::CopyResource eller ID3D10Device::CopySubresourceRegion anrop placeras det här anropet i kommandobufferten. Om programmet sedan försöker mappa mellanlagringsresursen som var målet för kopieringsanropet innan kommandobufferten har tömts, uppstår ett pipeline-stopp eftersom inte bara kopieringsmetodanropet behöver köras, utan även alla andra buffrade kommandon i kommandobufferten måste köras. Detta gör att GPU och CPU synkroniseras eftersom processorn väntar på att få åtkomst till mellanlagringsresursen medan GPU:n tömmer kommandobufferten och slutligen fyller den resurs som processorn behöver. När GPU:n har slutfört kopian börjar processorn komma åt mellanlagringsresursen, men under den här tiden är GPU:n inaktiv.

Om du gör detta ofta vid körningen försämras prestandan avsevärt. Därför bör mappning av resurser som skapats med standardanvändning utföras med försiktighet. Programmet måste vänta tillräckligt länge för att kommandobufferten ska tömmas och därmed slutföra körningen av alla dessa kommandon innan det försöker mappa motsvarande mellanlagringsresurs. Hur länge ska programmet vänta? Minst två bildrutor eftersom detta gör det möjligt att utnyttja parallelliteten mellan processorerna och GPU:n maximalt. GPU:n fungerar så att medan programmet bearbetar bildrutan N genom att skicka anrop till kommandobufferten är GPU:n upptagen med att köra anropen från föregående bildruta, N-1.

Så om ett program vill mappa en resurs som kommer från videominnet och anropar ID3D10Enhet::CopyResource eller ID3D10Enhet::CopySubresourceRegion vid bildruta N, börjar det här anropet faktiskt att köras vid bildrutan N+1, när programmet skickar anrop för nästa bildruta. Kopian ska vara klar när programmet bearbetar bildrutan N+2.

Ram GPU/CPU-status
N
  • CPU-problem renderar anrop för aktuell bildruta.
N+1
  • GPU kör anrop som skickas från CPU under bildruta N.
  • Processorproblem bearbetar anrop för aktuell bildruta.
N+2
  • GPU slutförde körningen av anrop som skickades från CPU under ram N. Resultatet är redo.
  • GPU kör anrop som skickas från CPU under ramen N+1.
  • CPU-problem återger anrop för aktuell ram.
N+3
  • GPU slutförde under ram N+1 körningen av anrop som skickades från CPU. Resultat klara.
  • GPU kör anrop som skickas från CPU under ramen N+2.
  • CPU-problem återger anrop för aktuell ram.
N+4 ...

 

resurser (Direct3D 10)