Query's (Direct3D 9)
Er zijn verschillende typen query's die zijn ontworpen om de status van resources op te vragen. De status van een bepaalde resource bevat gpu-status (Graphics Processing Unit), stuurprogrammastatus of runtimestatus. Als u het verschil tussen de verschillende querytypen wilt begrijpen, moet u de querystatussen begrijpen. In het volgende statusovergangsdiagram wordt elk van de querystatussen uitgelegd.
In het diagram ziet u drie statussen, elk gedefinieerd door cirkels. Elk van de ononderbroken lijnen zijn toepassingsgestuurde gebeurtenissen die een statusovergang veroorzaken. De stippellijn is een resourcegestuurde gebeurtenis waarmee een query wordt overgeschakeld van de uitgegeven status naar de gesignaleerde status. Elk van deze statussen heeft een ander doel:
- De gesignaleerde status is als een niet-actieve status. Het queryobject is gegenereerd en wacht totdat de toepassing de query heeft uitgevoerd. Zodra een query is voltooid en teruggezet naar de gesignaleerde status, kan het antwoord op de query worden opgehaald.
- De bouwstatus is als een faseringsgebied voor een query. Vanuit de bouwstatus is een query uitgegeven (door D3DISSUE_BEGINaan te roepen) maar is nog niet overgezet naar de uitgegeven status. Wanneer een toepassing een query beëindigt (door D3DISSUE_ENDaan te roepen), gaat de query over naar de uitgegeven status.
- De uitgegeven status betekent dat de resource waarop een query wordt uitgevoerd, controle heeft over de query. Zodra de resource het werk heeft voltooid, wordt de statusmachine overgezet naar de gesignaleerde status. Tijdens de uitgegeven status moet de toepassing peilen om de overgang naar de gesignaleerde status te detecteren. Zodra de overgang naar de gesignaleerde status plaatsvindt, retourneert GetData het queryresultaat (via een argument) naar de toepassing retourneert.
De volgende tabel bevat de beschikbare querytypen.
Querytype | Probleem-gebeurtenis | GetData-buffer | Runtime | Impliciet begin van query |
---|---|---|---|---|
BANDBREEDTETIMINGS | D3DISSUE_BEGIN, D3DISSUE_END | D3DDEVINFO_D3D9BANDWIDTHTIMINGS | Detailhandel/foutopsporing | N.V.T |
CACHEGEBRUIK | D3DISSUE_BEGIN, D3DISSUE_END | D3DDEVINFO_D3D9CACHEUTILIZATION | Detailhandel/foutopsporing | N.V.T |
GEBEURTENIS | D3DISSUE_END | BOOL | Detailhandel/foutopsporing | CreateDevice- |
INTERFACETIMINGS | D3DISSUE_BEGIN, D3DISSUE_END | D3DDEVINFO_D3D9INTERFACETIMINGS | Detailhandel/foutopsporing | N.V.T |
OCCLUSIE | D3DISSUE_BEGIN, D3DISSUE_END | DWORD | Detailhandel/foutopsporing | N.V.T |
PIPELINETIMINGS | D3DISSUE_BEGIN, D3DISSUE_END | D3DDEVINFO_D3D9PIPELINETIMINGS | Detailhandel/foutopsporing | N.V.T |
RESOURCEMANAGER | D3DISSUE_END | D3DDEVINFO_ResourceManager | Alleen fouten opsporen | presenteren |
TIJDSTEMPEL | D3DISSUE_END | UINT64 | Detailhandel/foutopsporing | N.V.T |
TIMESTAMPDISJOINT | D3DISSUE_BEGIN, D3DISSUE_END | BOOL | Detailhandel/foutopsporing | N.V.T |
TIMESTAMPFREQ | D3DISSUE_END | UINT64 | Detailhandel/foutopsporing | N.V.T |
VCACHE | D3DISSUE_END | D3DDEVINFO_VCACHE | Detailhandel/foutopsporing | CreateDevice- |
HOEKPUNTSTATS | D3DISSUE_END | D3DDEVINFO_D3DVERTEXSTATS | Alleen fouten opsporen | presenteren |
VERTEXTIMINGS | D3DISSUE_BEGIN, D3DISSUE_END | D3DDEVINFO_D3D9STAGETIMINGS | Detailhandel/foutopsporing | N.V.T |
Voor sommige query's is een begin- en eindbeurtenis vereist, terwijl andere alleen een eind-gebeurtenis vereisen. De query's waarvoor alleen een eindevenement is vereist, beginnen wanneer een andere impliciete gebeurtenis plaatsvindt (die wordt vermeld in de tabel). Alle query's retourneren een antwoord, behalve de gebeurtenisquery waarvan het antwoord altijd TRUEis. Een toepassing gebruikt de status van de query of de retourcode van GetData-.
Een query maken
Voordat u een query maakt, kunt u controleren of de runtime query's ondersteunt door CreateQuery- aan te roepen met een NULL- aanwijzer als volgt:
IDirect3DQuery9* pEventQuery;
// Create a device pointer m_pd3dDevice
// Create a query object
HRESULT hr = m_pd3dDevice->CreateQuery(D3DQUERYTYPE_EVENT, NULL);
Deze methode retourneert een succescode als een query kan worden gemaakt; anders wordt er een foutcode geretourneerd. Zodra CreateQuery slaagt, kunt u een queryobject als volgt maken:
IDirect3DQuery9* pEventQuery;
m_pd3dDevice->CreateQuery(D3DQUERYTYPE_EVENT, &pEventQuery);
Als deze aanroep slaagt, wordt er een queryobject gemaakt. De query is in feite inactief in de gesignaleerde status (met een niet-geïnitialiseerd antwoord) die moet worden uitgegeven. Wanneer u klaar bent met de query, laat u deze los zoals elke andere interface.
Een query uitgeven
Een toepassing wijzigt een querystatus door een query uit te geven. Hier volgt een voorbeeld van het uitgeven van een query:
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);
Een query met de gesignaleerde status wordt als volgt overgezet wanneer deze wordt uitgegeven:
Type probleem | Queryovergangen naar de . . . |
---|---|
D3DISSUE_BEGIN | Bouwstatus. |
D3DISSUE_END | Uitgegeven staat. |
Een query in de bouwstatus gaat als volgt over wanneer deze wordt uitgegeven:
Type probleem | Queryovergangen naar de . . . |
---|---|
D3DISSUE_BEGIN | (Geen overgang, blijft in de bouwstatus. Hiermee start u de queryhaak opnieuw op.) |
D3DISSUE_END | Uitgegeven staat. |
Een query met de uitgegeven status gaat als volgt over wanneer deze wordt uitgegeven:
Type probleem | Queryovergangen naar de . . . |
---|---|
D3DISSUE_BEGIN | Bouwstatus en start de queryhaak opnieuw op. |
D3DISSUE_END | Status Verleend na het afbreken van de bestaande query. |
Controleer de querystatus en haal het antwoord op de query op
GetData doet twee dingen:
- Retourneert de querystatus in de retourcode.
- Retourneert het antwoord op de query in pData.
Hier ziet u de GetData retourcodes uit elk van de drie querystatussen:
Querystatus | GetData-retourcode |
---|---|
Gesignaleerd | S_OK |
Gebouw | Foutcode |
Uitgegeven | S_FALSE |
Wanneer een query bijvoorbeeld de status Uitgegeven heeft en het antwoord op de query niet beschikbaar is, retourneert GetData- S_FALSE. Wanneer de resource klaar is met het werk en de toepassing een query heeft uitgegeven, zet de resource de query over naar de gesignaleerde status. Vanuit de gesignaleerde status retourneert GetData- S_OK wat betekent dat het antwoord op de query ook wordt geretourneerd in pData-. Hier ziet u bijvoorbeeld de reeks gebeurtenissen om het aantal pixels (of voorbeelden wanneer multisampling is ingeschakeld) te retourneren die zijn getekend in een renderreeks:
- Maak de query.
- Geef een begin-gebeurtenis.
- Teken iets.
- Een eindevenement uitgeven.
Hier volgt de bijbehorende reeks code:
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.
Deze regels code doen verschillende dingen:
- Roep GetData- aan om het aantal pixels/steekproeven te retourneren dat is getekend.
- Geef D3DGETDATA_FLUSH op om de resource in staat te stellen de query over te schakelen naar de gesignaleerde status.
- Peil de queryresource door GetData- aan te roepen vanuit een lus. Zolang GetData- S_FALSE retourneert, betekent dit dat de resource het antwoord nog niet heeft geretourneerd.
De retourwaarde van GetData- geeft in feite aan in welke staat de query is. Mogelijke waarden zijn S_OK, S_FALSE en een fout. Roep GetData- niet aan voor een query die de status van het gebouw heeft.
- S_OK betekent dat de resource (GPU of stuurprogramma of runtime) is voltooid. De query keert terug naar de gesignaleerde status. Het antwoord (indien aanwezig) wordt geretourneerd door GetData-.
- S_FALSE betekent dat de resource (GPU of stuurprogramma of runtime) nog geen antwoord kan retourneren. Dit kan zijn omdat de GPU niet is voltooid of het werk nog niet heeft gezien.
- Een fout betekent dat de query een fout heeft gegenereerd waaruit deze niet kan worden hersteld. Dit kan het geval zijn als het apparaat verloren gaat tijdens een query. Zodra een query een fout heeft gegenereerd (anders dan S_FALSE), moet de query opnieuw worden gemaakt, waardoor de queryreeks opnieuw wordt gestart vanuit de gesignaleerde status.
In plaats van D3DGETDATA_FLUSHop te geven, wat meer up-to-datumgegevens biedt, kunt u nul opgeven. Dit is een meer lichte controle als de query de status Heeft. Als u nul opgeeft, wordt GetData- de opdrachtbuffer niet leeggemaakt. Daarom moet u ervoor zorgen dat oneindige lussen worden vermeden (zie GetData- voor meer informatie). Omdat de runtime in de opdrachtbuffer wordt geplaatst, is D3DGETDATA_FLUSH een mechanisme voor het leegmaken van de opdrachtbuffer naar het stuurprogramma (en daarom de GPU; zie Nauwkeurig Profileren van Direct3D API-aanroepen (Direct3D 9)). Tijdens het leegmaken van de opdrachtbuffer kan een query overschakelen naar de gesignaleerde status.
Voorbeeld: een gebeurtenisquery
Een gebeurtenisquery biedt geen ondersteuning voor een begin-gebeurtenis.
- Maak de query.
- Een eindevenement uitgeven.
- Poll totdat de GPU inactief is.
- Een eindevenement uitgeven.
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 ))
;
Dit is de reeks opdrachten die een gebeurtenisquery gebruikt om API-aanroepen (Application Programming Interface) te profileren (zie Nauwkeurig Profileren van Direct3D API-aanroepen (Direct3D 9)). In deze reeks worden markeringen gebruikt om de hoeveelheid werk in de opdrachtbuffer te beheren.
Houd er rekening mee dat toepassingen speciale aandacht moeten besteden aan de grote kosten die zijn gekoppeld aan het leegmaken van de opdrachtbuffer, omdat dit ervoor zorgt dat het besturingssysteem overschakelt naar de kernelmodus, waardoor er een grote prestatiestraf wordt opgelegd. Toepassingen moeten zich ook bewust zijn van het verspillen van CPU-cycli door te wachten tot query's zijn voltooid.
Query's zijn een optimalisatie die moet worden gebruikt tijdens het weergeven om de prestaties te verbeteren. Daarom is het niet nuttig om tijd te besteden aan het wachten tot een query is voltooid. Als er een query wordt uitgegeven en de resultaten nog niet gereed zijn op het moment dat de toepassing erop controleert, is de poging om te optimaliseren niet geslaagd en moet de rendering als normaal worden voortgezet.
Het klassieke voorbeeld hiervan is tijdens Occlusion Culling. In plaats van de terwijl lus hierboven, kan een toepassing die query's gebruikt, occlusieverruiming implementeren om te controleren of een query is voltooid op het moment dat het resultaat nodig is. Als de query niet is voltooid, gaat u verder (als een slechtst scenario) alsof het object waarop wordt getest, niet is afgekeurd (dit is zichtbaar) en geeft u het weer. De code ziet er ongeveer als volgt uit.
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();
}
Verwante onderwerpen