Frågor (Direct3D 9)
Det finns flera typer av frågor som är utformade för att fråga efter resursers status. Statusen för en viss resurs inkluderar GPU-status (graphics processing unit), drivrutinsstatus eller körningsstatus. För att förstå skillnaden mellan de olika frågetyperna måste du förstå frågetillstånden. Följande tillståndsövergångsdiagram förklarar var och en av frågetillstånden.
Diagrammet visar tre tillstånd, som var och en definieras av cirklar. Var och en av de solida linjerna är programdrivna händelser som orsakar en tillståndsövergång. Den streckade linjen är en resursdriven händelse som växlar en fråga från det utfärdade tillståndet till det signalerade tillståndet. Var och en av dessa tillstånd har ett annat syfte:
- Det signalerade tillståndet är som ett inaktivt tillstånd. Frågeobjektet har genererats och väntar på att programmet ska utfärda frågan. När en fråga har slutförts och övergått till det signalerade tillståndet kan svaret på frågan hämtas.
- Byggnadstillståndet är som ett mellanlagringsområde för en fråga. Från byggnadstillståndet har en fråga utfärdats (genom att anropa D3DISSUE_BEGIN) men har ännu inte övergått till det utfärdade tillståndet. När ett program utfärdar ett frågeslut (genom att anropa D3DISSUE_END) övergår frågan till det utfärdade tillståndet.
- Det utfärdade tillståndet innebär att resursen som efterfrågas har kontroll över frågan. När resursen har slutfört sitt arbete övergår resursen tillståndsdatorn till det signalerade tillståndet. Under det utfärdade tillståndet måste programmet avsöka för att identifiera övergången till det signalerade tillståndet. När övergången till det signalerade tillståndet inträffar returnerar GetData frågeresultatet (via ett argument) till programmet.
I följande tabell visas tillgängliga frågetyper.
Frågetyp | Problemhändelse | GetData-buffert | Runtime | Implicit början av frågan |
---|---|---|---|---|
BANDBREDDSTIMING | D3DISSUE_BEGIN, D3DISSUE_END | D3DDEVINFO_D3D9BANDWIDTHTIMINGS | Detaljhandel/felsökning | Ej tillämpligt |
CACHEUTILISERING | D3DISSUE_BEGIN, D3DISSUE_END | D3DDEVINFO_D3D9CACHEUTILIZATION | Detaljhandel/felsökning | Ej tillämpligt |
HÄNDELSE | D3DISSUE_END | BOOL | Detaljhandel/felsökning | CreateDevice |
GRÄNSSNITTSTIMINGS | D3DISSUE_BEGIN, D3DISSUE_END | D3DDEVINFO_D3D9INTERFACETIMINGS | Detaljhandel/felsökning | Ej tillämpligt |
OCKLUSION | D3DISSUE_BEGIN, D3DISSUE_END | DWORD | Detaljhandel/felsökning | Ej tillämpligt |
PIPELINETIMINGS | D3DISSUE_BEGIN, D3DISSUE_END | D3DDEVINFO_D3D9PIPELINETIMINGS | Detaljhandel/felsökning | Ej tillämpligt |
RESOURCEMANAGER | D3DISSUE_END | D3DDEVINFO_ResourceManager | Endast felsökning | närvarande |
TIDSSTÄMPEL | D3DISSUE_END | UINT64 | Detaljhandel/felsökning | Ej tillämpligt |
TIMESTAMPDISJOINT | D3DISSUE_BEGIN, D3DISSUE_END | BOOL | Detaljhandel/felsökning | Ej tillämpligt |
TIMESTAMPFREQ | D3DISSUE_END | UINT64 | Detaljhandel/felsökning | Ej tillämpligt |
VCACHE | D3DISSUE_END | D3DDEVINFO_VCACHE | Detaljhandel/felsökning | CreateDevice |
VERTEXSTATS | D3DISSUE_END | D3DDEVINFO_D3DVERTEXSTATS | Endast felsökning | närvarande |
VERTEXTIMINGS | D3DISSUE_BEGIN, D3DISSUE_END | D3DDEVINFO_D3D9STAGETIMINGS | Detaljhandel/felsökning | Ej tillämpligt |
Vissa av frågorna kräver en start- och sluthändelse, medan andra endast kräver en sluthändelse. De frågor som bara kräver en sluthändelse börjar när en annan implicit händelse inträffar (som visas i tabellen). Alla frågor returnerar ett svar, förutom den händelsefråga vars svar alltid är TRUE-. Ett program använder antingen frågans tillstånd eller returkoden för GetData.
Skapa en fråga
Innan du skapar en fråga kan du kontrollera om körningen stöder frågor genom att anropa CreateQuery med en NULL- pekare så här:
IDirect3DQuery9* pEventQuery;
// Create a device pointer m_pd3dDevice
// Create a query object
HRESULT hr = m_pd3dDevice->CreateQuery(D3DQUERYTYPE_EVENT, NULL);
Den här metoden returnerar en lyckad kod om en fråga kan skapas. annars returneras en felkod. När CreateQuery- lyckas kan du skapa ett frågeobjekt så här:
IDirect3DQuery9* pEventQuery;
m_pd3dDevice->CreateQuery(D3DQUERYTYPE_EVENT, &pEventQuery);
Om det här anropet lyckas skapas ett frågeobjekt. Frågan är i princip inaktiv i det signalerade tillståndet (med ett oinitierat svar) som väntar på att utfärdas. När du är klar med frågan släpper du den som alla andra gränssnitt.
Utfärda en fråga
Ett program ändrar ett frågetillstånd genom att utfärda en fråga. Här är ett exempel på hur du utfärdar en fråga:
IDirect3DQuery9* pEventQuery;
m_pD3DDevice->CreateQuery(D3DQUERYTYPE_EVENT, &pEventQuery);
// Issue a Begin event
pEventQuery->Issue(D3DISSUE_BEGIN);
or
// Issue an End event
pEventQuery->Issue(D3DISSUE_END);
En fråga i det signalerade tillståndet övergår så här när den utfärdas:
Problemtyp | Frågan övergår till . . . |
---|---|
D3DISSUE_BEGIN | Byggnadstillstånd. |
D3DISSUE_END | Utfärdat tillstånd. |
En fråga i byggtillståndet övergår så här när den utfärdas:
Problemtyp | Frågan övergår till . . . |
---|---|
D3DISSUE_BEGIN | (Ingen övergång, förblir i byggnadstillståndet. Startar om frågeparentesen.) |
D3DISSUE_END | Utfärdat tillstånd. |
En fråga i det utfärdade tillståndet övergår så här när den utfärdas:
Problemtyp | Frågan övergår till . . . |
---|---|
D3DISSUE_BEGIN | Skapar tillstånd och startar om frågeparentesen. |
D3DISSUE_END | Utfärdat tillstånd efter att den befintliga frågan har avbrutits. |
Kontrollera frågetillståndet och hämta svaret på frågan
GetData gör två saker:
- Returnerar frågetillståndet i returkoden.
- Returnerar svaret på frågan i pData.
Här är GetData returkoder från var och en av de tre frågetillstånden:
Frågetillstånd | GetData-returkod |
---|---|
Signalerade | S_OK |
Byggnad | Felkod |
Utfärdats | S_FALSE |
Om en fråga till exempel är i utfärdat tillstånd och svaret på frågan inte är tillgängligt, returnerar GetData S_FALSE. När resursen har slutfört sitt arbete och programmet har utfärdat ett frågeslut övergår resursen frågan till det signalerade tillståndet. Från det signalerade tillståndet returnerar GetData S_OK vilket innebär att svaret på frågan också returneras i pData. Här är till exempel sekvensen med händelser för att returnera antalet pixlar (eller exempel när multisampling är aktiverat) som ritats i en återgivningssekvens:
- Skapa frågan.
- Utfärda en starthändelse.
- Rita något.
- Utfärda en sluthändelse.
Följande är motsvarande kodsekvens:
IDirect3DQuery9* pOcclusionQuery;
DWORD numberOfSamplesDrawn;
m_pD3DDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &pOcclusionQuery);
// Add an end marker to the command buffer queue.
pOcclusionQuery->Issue(D3DISSUE_BEGIN);
// API render loop
...
Draw(...)
...
// Add an end marker to the command buffer queue.
pOcclusionQuery->Issue(D3DISSUE_END);
// Force the driver to execute the commands from the command buffer.
// Empty the command buffer and wait until the GPU is idle.
while(S_FALSE == pOcclusionQuery->GetData( &numberOfSamplesDrawn,
sizeof(DWORD), D3DGETDATA_FLUSH ))
;
// To get the number of pixels drawn when multisampling is enabled,
// divide numberOfSamplesDrawn by the sample count of the render target.
Dessa kodrader gör flera saker:
- Anropa GetData för att returnera antalet bildpunkter/exempel som har ritats.
- Ange D3DGETDATA_FLUSH så att resursen kan överföra frågan till det signalerade tillståndet.
- Avsök frågeresursen genom att anropa GetData från en loop. Så länge GetData- returnerar S_FALSE innebär det att resursen inte har returnerat svaret ännu.
Returvärdet för GetData anger i princip i vilket tillstånd frågan är. Möjliga värden är S_OK, S_FALSE och ett fel. Anropa inte GetData på en fråga som är i byggnadstillståndet.
- S_OK innebär att resursen (GPU eller drivrutinen eller körningen) är klar. Frågan återgår till det signalerade tillståndet. Svaret (om det finns något) returneras av GetData.
- S_FALSE innebär att resursen (GPU eller drivrutin eller körning) inte kan returnera ett svar ännu. Det kan bero på att GPU:n inte är klar eller inte har sett arbetet ännu.
- Ett fel innebär att frågan har genererat ett fel som den inte kan återställas från. Detta kan vara fallet om enheten går förlorad under en fråga. När en fråga har genererat ett fel (förutom S_FALSE) måste frågan återskapas som startar om frågesekvensen från det signalerade tillståndet.
I stället för att ange D3DGETDATA_FLUSH, som ger mer up-to-date-information, kan du ange noll, vilket är en mer lättviktskontroll om frågan är i utfärdat tillstånd. Om du anger noll kommer GetData- inte att tömma kommandobufferten. Därför måste du vara noga med att undvika oändliga loopar (se GetData- för mer information). Eftersom körningsköerna fungerar i kommandobufferten är D3DGETDATA_FLUSH en mekanism för att tömma kommandobufferten till drivrutinen (och därmed GPU:n. Se Korrekt profilering av Direct3D API-anrop (Direct3D 9)). Under kommandobuffertens tömning kan en fråga övergå till det signalerade tillståndet.
Exempel: En händelsefråga
En händelsefråga stöder inte en starthändelse.
- Skapa frågan.
- Utfärda en sluthändelse.
- Avsök tills GPU:n är inaktiv.
- Utfärda en sluthändelse.
IDirect3DQuery9* pEventQuery = NULL;
m_pD3DDevice->CreateQuery(D3DQUERYTYPE_EVENT, &pEventQuery);
// Add an end marker to the command buffer queue.
pEventQuery->Issue(D3DISSUE_END);
// Empty the command buffer and wait until the GPU is idle.
while(S_FALSE == pEventQuery->GetData( NULL, 0, D3DGETDATA_FLUSH ))
;
... // API calls
// Add an end marker to the command buffer queue.
pEventQuery->Issue(D3DISSUE_END);
// Force the driver to execute the commands from the command buffer.
// Empty the command buffer and wait until the GPU is idle.
while(S_FALSE == pEventQuery->GetData( NULL, 0, D3DGETDATA_FLUSH ))
;
Det här är sekvensen med kommandon som en händelsefråga använder för att profilera API-anrop (application programming interface) (se Korrekt profilering av Direct3D API-anrop (Direct3D 9)). Den här sekvensen använder markörer för att styra mängden arbete i kommandobufferten.
Observera att program bör vara särskilt uppmärksamma på den stora kostnaden som är kopplad till att rensa kommandobufferten eftersom detta gör att operativsystemet växlar till kernelläge, vilket medför en betydande prestandaavgift. Program bör också vara medvetna om att slösa cpu-cykler genom att vänta på att frågor ska slutföras.
Frågor är en optimering som ska användas under återgivningen för att öka prestandan. Därför är det inte fördelaktigt att ägna tid åt att vänta på att en fråga ska slutföras. Om en fråga utfärdas och om resultaten ännu inte är klara när programmet söker efter dem, lyckades inte optimeringsförsöket och återgivningen bör fortsätta som vanligt.
Det klassiska exemplet på detta är under Ocklusion Culling. I stället för medan loop ovan, kan ett program som använder frågor implementera ocklusionsgallring för att kontrollera om en fråga har slutförts när den behöver resultatet. Om frågan inte har slutförts fortsätter du (som ett värsta scenario) som om objektet som testas mot inte är occluded (dvs. det är synligt) och renderar det. Koden skulle se ut ungefär så här.
IDirect3DQuery9* pOcclusionQuery = NULL;
m_pD3DDevice->CreateQuery( D3DQUERYTYPE_OCCLUSION, &pOcclusionQuery );
// Add a begin marker to the command buffer queue.
pOcclusionQuery->Issue( D3DISSUE_BEGIN );
... // API calls
// Add an end marker to the command buffer queue.
pOcclusionQuery->Issue( D3DISSUE_END );
// Avoid flushing and letting the CPU go idle by not using a while loop.
// Check if queries are finished:
DWORD dwOccluded = 0;
if( S_FALSE == pOcclusionQuery->GetData( &dwOccluded, sizeof(DWORD), 0 ) )
{
// Query is not done yet or object not occluded; avoid flushing/wait by continuing with worst-case scenario
pSomeComplexMesh->Render();
}
else if( dwOccluded != 0 )
{
// Query is done and object is not occluded.
pSomeComplexMesh->Render();
}
Relaterade ämnen