Megosztás a következőn keresztül:


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:

  1. A lekérdezési állapotot adja vissza a visszatérési kódban.
  2. 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();
}

Speciális témakörök