Lekérdezések (Direct3D 9)
Számos lekérdezéstípus létezik, amelyek az erőforrások állapotának lekérdezésére szolgálnak. Egy adott erőforrás állapota magában foglalja a grafikus feldolgozási egység (GPU) állapotát, az illesztőprogram állapotát vagy a futtatókörnyezet állapotát. A különböző lekérdezéstípusok közötti különbség megértéséhez ismernie kell a lekérdezési állapotokat. Az alábbi állapotáttraszt-diagram az egyes lekérdezési állapotokat ismerteti.
lekérdezésállapotok közötti átmeneteket bemutató diagram
Az ábrán három állapot látható, amelyeket körök határoznak meg. Az egyes folytonos vonalak alkalmazásalapú események, amelyek állapotváltást okoznak. A szaggatott vonal egy erőforrás-alapú esemény, amely a lekérdezést a kiadott állapotról a jelzett állapotra váltja. Mindegyik állapotnak más a célja:
- A jelzett állapot olyan, mint egy tétlen állapot. A lekérdezési objektum létrejött, és arra vár, hogy az alkalmazás kiadja a lekérdezést. Miután egy lekérdezés befejeződött, és visszaállt a jelzett állapotra, a lekérdezésre adott válasz lekérhető.
- Az épület állapota olyan, mint egy lekérdezés átmeneti területe. Az épület állapotából lekérdezést adtak ki (D3DISSUE_BEGINmeghívásával), de még nem váltott át a kiadott állapotra. Amikor egy alkalmazás lekérdezésvégzést ad ki (D3DISSUE_ENDmeghívásával), a lekérdezés átáll a kiadott állapotra.
- A kiadott állapot azt jelenti, hogy a lekérdezett erőforrás rendelkezik a lekérdezés vezérlésével. Miután az erőforrás befejezte a munkát, az erőforrás áttűnés az állapotgépet a jelzett állapotra. A kiadott állapot során az alkalmazásnak le kell kérdeznie a jelzett állapotra való áttérés észleléséhez. A jelzett állapotra való áttérés után GetData visszaadja a lekérdezés eredményét (argumentumon keresztül) az alkalmazásnak.
Az alábbi táblázat az elérhető lekérdezéstípusokat sorolja fel.
Lekérdezés típusa | Problémaesemény | GetData puffer | Runtime | A lekérdezés implicit kezdete |
---|---|---|---|---|
SÁVSZÉLESSÉG-INGEREK | D3DISSUE_BEGIN, D3DISSUE_END | D3DDEVINFO_D3D9BANDWIDTHTIMINGS | Kiskereskedelmi/hibakeresési | N/A |
GYORSÍTÓTÁR-KIHASZNÁLÁS | D3DISSUE_BEGIN, D3DISSUE_END | D3DDEVINFO_D3D9CACHEUTILIZATION | Kiskereskedelmi/hibakeresési | N/A |
ESEMÉNY | D3DISSUE_END | BOOL | Kiskereskedelmi/hibakeresési | CreateDevice |
INTERFACETIMINGS | D3DISSUE_BEGIN, D3DISSUE_END | D3DDEVINFO_D3D9INTERFACETIMINGS | Kiskereskedelmi/hibakeresési | N/A |
ELZÁRÓDÁS | D3DISSUE_BEGIN, D3DISSUE_END | DWORD | Kiskereskedelmi/hibakeresési | N/A |
PIPELINETIMINGS | D3DISSUE_BEGIN, D3DISSUE_END | D3DDEVINFO_D3D9PIPELINETIMINGS | Kiskereskedelmi/hibakeresési | N/A |
RESOURCEMANAGER | D3DISSUE_END | D3DDEVINFO_ResourceManager | Csak hibakeresés | Bemutató |
IDŐBÉLYEG | D3DISSUE_END | UINT64 | Kiskereskedelmi/hibakeresési | N/A |
TIMESTAMPDISJOINT | D3DISSUE_BEGIN, D3DISSUE_END | BOOL | Kiskereskedelmi/hibakeresési | N/A |
TIMESTAMPFREQ | D3DISSUE_END | UINT64 | Kiskereskedelmi/hibakeresési | N/A |
VCACHE | D3DISSUE_END | D3DDEVINFO_VCACHE | Kiskereskedelmi/hibakeresési | CreateDevice |
CSÚCSPONTOK | D3DISSUE_END | D3DDEVINFO_D3DVERTEXSTATS | Csak hibakeresés | Bemutató |
VERTEXTIMINGS | D3DISSUE_BEGIN, D3DISSUE_END | D3DDEVINFO_D3D9STAGETIMINGS | Kiskereskedelmi/hibakeresési | N/A |
Egyes lekérdezések kezdési és befejezési eseményt igényelnek, míg mások csak záróeseményt igényelnek. A csak záró eseményt igénylő lekérdezések egy másik implicit esemény bekövetkezésekor kezdődnek (amely szerepel a táblázatban). Minden lekérdezés választ ad vissza, kivéve azt az eseményes lekérdezést, amelynek a válasza mindig IGAZ. Az alkalmazások a lekérdezés állapotát vagy a GetDatavisszatérési kódját használják.
Lekérdezés létrehozása
Mielőtt létrehozna egy lekérdezést, ellenőrizheti, hogy a futtatókörnyezet támogatja-e a lekérdezéseket, ha meghívja CreateQuery egy NULL mutatóval az alábbihoz hasonló módon:
IDirect3DQuery9* pEventQuery;
// Create a device pointer m_pd3dDevice
// Create a query object
HRESULT hr = m_pd3dDevice->CreateQuery(D3DQUERYTYPE_EVENT, NULL);
Ez a metódus egy sikeres kódot ad vissza, ha létre lehet hozni egy lekérdezést; ellenkező esetben hibakódot ad vissza. A CreateQuerysikeresután létrehozhat egy ilyen lekérdezési objektumot:
IDirect3DQuery9* pEventQuery;
m_pd3dDevice->CreateQuery(D3DQUERYTYPE_EVENT, &pEventQuery);
Ha ez a hívás sikeres, létrejön egy lekérdezési objektum. A lekérdezés lényegében tétlen a kibocsátásra váró jeles állapotban (nem inicializált válaszsal). Ha végzett a lekérdezéssel, engedje fel, mint bármely más felületet.
Lekérdezés kiállítása
Az alkalmazások lekérdezési állapotot módosítanak egy lekérdezés kiadásával. Íme egy példa egy lekérdezés kiadására:
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);
A jelzett állapotú lekérdezések a következő módon fognak átállni, amikor kibocsátják:
Probléma típusa | A lekérdezés áttűnés a . . . |
---|---|
D3DISSUE_BEGIN | Az épület állapota. |
D3DISSUE_END | Kibocsátott állapot. |
Az épület állapotában lévő lekérdezések a következő módon fognak átállni, amikor kibocsátják:
Probléma típusa | A lekérdezés áttűnés a . . . |
---|---|
D3DISSUE_BEGIN | (Nincs áttűnés, az épület állapota marad. Újraindítja a lekérdezési zárójelet.) |
D3DISSUE_END | Kibocsátott állapot. |
A kiadott állapotú lekérdezések a következő módon fognak átállni a kiállításkor:
Probléma típusa | A lekérdezés áttűnés a . . . |
---|---|
D3DISSUE_BEGIN | Állapot létrehozása és a lekérdezési zárójel újraindítása. |
D3DISSUE_END | A meglévő lekérdezés megszakítása után kiadott állapot. |
Ellenőrizze a lekérdezés állapotát, és kérje le a választ a lekérdezésre
GetData két dolgot tesz:
- A lekérdezési állapotot adja vissza a visszatérési kódban.
- A lekérdezésre adott választ adja vissza pData.
A három lekérdezési állapot mindegyikében az GetData visszatérési kódjai találhatók:
Lekérdezés állapota | GetData visszatérési kód |
---|---|
Jelzés | S_OK |
Épület | Hibakód |
Kiadott | S_FALSE |
Ha például egy lekérdezés kibocsátott állapotban van, és a lekérdezésre adott válasz nem érhető el, GetData S_FALSE ad vissza. Amikor az erőforrás befejezi a munkát, és az alkalmazás lekérdezési véget állított ki, az erőforrás áttűné a lekérdezést a jelzett állapotra. A jelzett állapotból GetData S_OK ad vissza, ami azt jelenti, hogy a lekérdezésre adott választ pDatais visszaadja. Itt látható például az események sorozata, amely visszaadja a renderelési sorrendben rajzolt képpontok számát (vagy a többpéldányos megjelenítés engedélyezése esetén a mintákat):
- Hozza létre a lekérdezést.
- Hozzon létre egy kezdő eseményt.
- Rajzoljon valamit.
- Kibocsát egy záróeseményt.
A kód megfelelő sorozata a következő:
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.
Ezek a kódsorok számos műveletet hajtanak végre:
- Hívja meg GetData a rajzolt képpontok/minták számának visszaadásához.
- Adja meg a D3DGETDATA_FLUSH, hogy az erőforrás át tudja állítani a lekérdezést a jelzett állapotba.
- A lekérdezési erőforrás lekérdezéséhez hívja meg GetData egy hurokból. Ha GetData S_FALSE ad vissza, ez azt jelenti, hogy az erőforrás még nem adta vissza a választ.
A GetData visszatérési értéke lényegében azt jelzi, hogy milyen állapotban van a lekérdezés. A lehetséges értékek a S_OK, a S_FALSE és a hiba. Ne hívja meg GetData épületállapotú lekérdezésen.
- S_OK azt jelenti, hogy az erőforrás (GPU, illesztőprogram vagy futtatókörnyezet) befejeződött. A lekérdezés a jelzett állapotba tér vissza. A választ (ha van ilyen) GetDataadja vissza.
- S_FALSE azt jelenti, hogy az erőforrás (GPU, illesztőprogram vagy futtatókörnyezet) még nem tud választ adni. Ennek az lehet az oka, hogy a GPU még nem fejeződött be, vagy még nem látta a munkát.
- A hiba azt jelenti, hogy a lekérdezés olyan hibát generált, amelyből nem állítható helyre. Ez akkor fordulhat elő, ha az eszköz elveszik egy lekérdezés során. Miután egy lekérdezés hibát generált (a S_FALSE kivételével), újra létre kell hozni a lekérdezést, amely újraindítja a lekérdezéssorozatot a jelzett állapotból.
Ahelyett, hogy D3DGETDATA_FLUSHadna meg , amely több up-todátuminformációt biztosít, nulla értéket adhat meg, ami kisebb súlyú ellenőrzés, ha a lekérdezés a kiadott állapotban van. Ha nullát ad meg, GetData nem üríti ki a parancspuffert. Ezért ügyelni kell a végtelen hurkok elkerülésére (részletekért lásd GetData). Mivel a futtatókörnyezeti üzenetsorok a parancspufferben működnek, D3DGETDATA_FLUSH a parancspuffernek az illesztőprogramba (és így a GPU-ba) való kiürítésére szolgáló mechanizmus, lásd Direct3D API-hívások (Direct3D 9) pontos profilozása). A parancspuffer kiürítése során a lekérdezés áttérhet a jelzett állapotra.
Példa: Esemény lekérdezése
Az esemény-lekérdezések nem támogatják a kezdő eseményeket.
- Hozza létre a lekérdezést.
- Kibocsát egy záróeseményt.
- Lekérdezés, amíg a GPU tétlen.
- Kibocsát egy záróeseményt.
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 ))
;
Ez a parancsok sorozata, amelyet az esemény-lekérdezés az alkalmazásprogramozási felület (API) hívásainak profilozásához használ (lásd a Direct3D API-hívások (Direct3D 9)pontos profilozását). Ez a sorozat jelölőkkel szabályozza a parancspufferben lévő munka mennyiségét.
Vegye figyelembe, hogy az alkalmazásoknak különös figyelmet kell fordítaniuk a parancspuffer kiürítésével járó nagy költségekre, mivel ez miatt az operációs rendszer kernel módra vált, ami jelentős teljesítménybeli büntetést von maga után. Az alkalmazásoknak tisztában kell lenniük azzal is, hogy a cpu-ciklusokat a lekérdezések befejezésére várva elsietik.
A lekérdezések a renderelés során a teljesítmény növelése érdekében használandó optimalizálási lehetőségek. Ezért nem előnyös időt tölteni a lekérdezés befejezésére való várakozással. Ha egy lekérdezést adnak ki, és az eredmények még nem állnak készen, mire az alkalmazás ellenőrzi őket, az optimalizálási kísérlet nem sikerült, és a renderelésnek a szokásos módon kell folytatódnia.
Erre a klasszikus példa az Occlusion Culling során van. Ahelyett, hogy a a fenti ciklust, a lekérdezéseket használó alkalmazások végrehajthatják az elzáródási selejtezést annak ellenőrzésére, hogy egy lekérdezés befejeződött-e addig, amíg az eredményre szüksége van. Ha a lekérdezés még nem fejeződött be, folytassa (legrosszabb esetben), mintha a tesztelt objektum nincs elzárva (azaz látható lenne), és renderelné. A kód a következőhöz hasonlóan fog kinézni.
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();
}
Kapcsolódó témakörök