Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
A Direct3D9-tartalmat a Windows Presentation Foundation (WPF) alkalmazásba is belefoglalhatja. Ez a témakör azt ismerteti, hogyan hozhat létre Direct3D9-tartalmat, hogy az hatékonyan működjön együtt a WPF-vel.
Megjegyzés:
Ha Direct3D9-tartalmat használ a WPF-ben, a teljesítményre is gondolnia kell. A teljesítmény optimalizálásával kapcsolatos további információkért lásd Direct3D9 és WPF együttműködésiteljesítményével kapcsolatos szempontokat.
Pufferek megjelenítése
A D3DImage osztály két megjelenítési puffert kezel, amelyek az háttér-puffer és az előlap-puffer. A hátsó puffer a Direct3D9 felület. A rendszer a Unlock metódus meghívásakor a háttérpuffer módosításait az első pufferbe másolja.
Az alábbi ábra a háttérpuffer és az első puffer közötti kapcsolatot mutatja be.
Direct3D9-eszköz létrehozása
A Direct3D9-tartalmak megjelenítéséhez létre kell hoznia egy Direct3D9-eszközt. Két Direct3D9-objektumot használhat eszköz, IDirect3D9 és IDirect3D9Exlétrehozásához. Ezekkel az objektumokkal IDirect3DDevice9 és IDirect3DDevice9Ex eszközöket hozhat létre.
Hozzon létre egy eszközt az alábbi módszerek egyikének meghívásával.
IDirect3D9 * Direct3DCreate9(UINT SDKVersion);HRESULT Direct3DCreate9Ex(UINT SDKVersion, IDirect3D9Ex **ppD3D);
Windows Vista vagy újabb operációs rendszeren használja a Direct3DCreate9Ex metódust a Windows megjelenítési illesztőprogram-modell (WDDM) használatára konfigurált kijelzővel. Használja a Direct3DCreate9 metódust bármely más platformon.
A Direct3DCreate9Ex metódus elérhetősége
A d3d9.dll Direct3DCreate9Ex metódus csak Windows Vista vagy újabb operációs rendszeren használható. Ha közvetlenül összekapcsolja a függvényt Windows XP rendszeren, az alkalmazás nem töltődik be. Annak megállapításához, hogy a Direct3DCreate9Ex metódus támogatott-e, töltse be a DLL-t, és keresse meg a proc címet. Az alábbi kód bemutatja, hogyan tesztelheti a Direct3DCreate9Ex metódust. A teljes példakódért tekintse meg a útmutatót: Direct3D9 tartalom létrehozása és hosztolása a WPF-ben.
HRESULT
CRendererManager::EnsureD3DObjects()
{
HRESULT hr = S_OK;
HMODULE hD3D = NULL;
if (!m_pD3D)
{
hD3D = LoadLibrary(TEXT("d3d9.dll"));
DIRECT3DCREATE9EXFUNCTION pfnCreate9Ex = (DIRECT3DCREATE9EXFUNCTION)GetProcAddress(hD3D, "Direct3DCreate9Ex");
if (pfnCreate9Ex)
{
IFC((*pfnCreate9Ex)(D3D_SDK_VERSION, &m_pD3DEx));
IFC(m_pD3DEx->QueryInterface(__uuidof(IDirect3D9), reinterpret_cast<void **>(&m_pD3D)));
}
else
{
m_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
if (!m_pD3D)
{
IFC(E_FAIL);
}
}
m_cAdapters = m_pD3D->GetAdapterCount();
}
Cleanup:
if (hD3D)
{
FreeLibrary(hD3D);
}
return hr;
}
HWND létrehozása
Az eszköz létrehozásához HWND szükséges. Általában létrehoz egy ál-HWND-t, hogy a Direct3D9 használhassa. Az alábbi példakód bemutatja, hogyan hozhat létre hamis HWND-t.
HRESULT
CRendererManager::EnsureHWND()
{
HRESULT hr = S_OK;
if (!m_hwnd)
{
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = DefWindowProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = NULL;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
IFC(E_FAIL);
}
m_hwnd = CreateWindow(szAppName,
TEXT("D3DImageSample"),
WS_OVERLAPPEDWINDOW,
0, // Initial X
0, // Initial Y
0, // Width
0, // Height
NULL,
NULL,
NULL,
NULL);
}
Cleanup:
return hr;
}
Paraméterek bemutatása
Az eszköz létrehozásához D3DPRESENT_PARAMETERS szerkezetre is szükség van, de csak néhány paraméter fontos. Ezek a paraméterek a memóriaigény minimalizálása érdekében vannak kiválasztva.
Állítsa a BackBufferHeight és BackBufferWidth mezőket 1 értékre. Ha 0-ra állítja őket, akkor azokat a HWND méreteihez igazítják.
Mindig állítsa be a D3DCREATE_MULTITHREADED és D3DCREATE_FPU_PRESERVE jelzőket, hogy megakadályozza a Direct3D9 által használt memória sérülését, és megakadályozza, hogy a Direct3D9 módosítsa az FPU-beállításokat.
Az alábbi kód bemutatja, hogyan inicializálhatja a D3DPRESENT_PARAMETERS szerkezetet.
HRESULT
CRenderer::Init(IDirect3D9 *pD3D, IDirect3D9Ex *pD3DEx, HWND hwnd, UINT uAdapter)
{
HRESULT hr = S_OK;
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
d3dpp.BackBufferHeight = 1;
d3dpp.BackBufferWidth = 1;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
D3DCAPS9 caps;
DWORD dwVertexProcessing;
IFC(pD3D->GetDeviceCaps(uAdapter, D3DDEVTYPE_HAL, &caps));
if ((caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == D3DDEVCAPS_HWTRANSFORMANDLIGHT)
{
dwVertexProcessing = D3DCREATE_HARDWARE_VERTEXPROCESSING;
}
else
{
dwVertexProcessing = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}
if (pD3DEx)
{
IDirect3DDevice9Ex *pd3dDevice = NULL;
IFC(pD3DEx->CreateDeviceEx(
uAdapter,
D3DDEVTYPE_HAL,
hwnd,
dwVertexProcessing | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
&d3dpp,
NULL,
&m_pd3dDeviceEx
));
IFC(m_pd3dDeviceEx->QueryInterface(__uuidof(IDirect3DDevice9), reinterpret_cast<void**>(&m_pd3dDevice)));
}
else
{
assert(pD3D);
IFC(pD3D->CreateDevice(
uAdapter,
D3DDEVTYPE_HAL,
hwnd,
dwVertexProcessing | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
&d3dpp,
&m_pd3dDevice
));
}
Cleanup:
return hr;
}
A háttérpuffer renderelési céljának létrehozása
Ha Direct3D9-tartalmat szeretne megjeleníteni egy D3DImage, hozzon létre egy Direct3D9 felületet, és rendelje hozzá a SetBackBuffer metódus meghívásával.
Az adapter támogatásának ellenőrzése
Mielőtt létrehoz egy felületet, ellenőrizze, hogy az összes adapter támogatja-e a szükséges felületi tulajdonságokat. Még ha csak egy adapterre is renderel, előfordulhat, hogy a WPF ablak a rendszer bármely adapterén megjelenik. Mindig olyan Direct3D9-kódot kell írnia, amely kezeli a többadapteres konfigurációkat, és ellenőriznie kell az összes adapter támogatását, mert a WPF áthelyezheti a felületet a rendelkezésre álló adapterek között.
Az alábbi példakód bemutatja, hogyan ellenőrizheti a rendszer összes adapterét a Direct3D9-támogatáshoz.
HRESULT
CRendererManager::TestSurfaceSettings()
{
HRESULT hr = S_OK;
D3DFORMAT fmt = m_fUseAlpha ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;
//
// We test all adapters because because we potentially use all adapters.
// But even if this sample only rendered to the default adapter, you
// should check all adapters because WPF may move your surface to
// another adapter for you!
//
for (UINT i = 0; i < m_cAdapters; ++i)
{
// Can we get HW rendering?
IFC(m_pD3D->CheckDeviceType(
i,
D3DDEVTYPE_HAL,
D3DFMT_X8R8G8B8,
fmt,
TRUE
));
// Is the format okay?
IFC(m_pD3D->CheckDeviceFormat(
i,
D3DDEVTYPE_HAL,
D3DFMT_X8R8G8B8,
D3DUSAGE_RENDERTARGET | D3DUSAGE_DYNAMIC, // We'll use dynamic when on XP
D3DRTYPE_SURFACE,
fmt
));
// D3DImage only allows multisampling on 9Ex devices. If we can't
// multisample, overwrite the desired number of samples with 0.
if (m_pD3DEx && m_uNumSamples > 1)
{
assert(m_uNumSamples <= 16);
if (FAILED(m_pD3D->CheckDeviceMultiSampleType(
i,
D3DDEVTYPE_HAL,
fmt,
TRUE,
static_cast<D3DMULTISAMPLE_TYPE>(m_uNumSamples),
NULL
)))
{
m_uNumSamples = 0;
}
}
else
{
m_uNumSamples = 0;
}
}
Cleanup:
return hr;
}
A Surface létrehozása
A felület létrehozása előtt ellenőrizze, hogy az eszköz képességei támogatják-e a megfelelő teljesítményt a cél operációs rendszeren. További információkért lásd: A Direct3D9 és a WPF interoperabilitási teljesítményszempontjai.
Ha igazolt eszközképességekkel rendelkezik, létrehozhatja a felületet. Az alábbi példakód bemutatja, hogyan hozható létre a renderelési cél.
HRESULT
CRenderer::CreateSurface(UINT uWidth, UINT uHeight, bool fUseAlpha, UINT m_uNumSamples)
{
HRESULT hr = S_OK;
SAFE_RELEASE(m_pd3dRTS);
IFC(m_pd3dDevice->CreateRenderTarget(
uWidth,
uHeight,
fUseAlpha ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8,
static_cast<D3DMULTISAMPLE_TYPE>(m_uNumSamples),
0,
m_pd3dDeviceEx ? FALSE : TRUE, // Lockable RT required for good XP perf
&m_pd3dRTS,
NULL
));
IFC(m_pd3dDevice->SetRenderTarget(0, m_pd3dRTS));
Cleanup:
return hr;
}
WDDM
A WDDM használatára konfigurált Windows Vista és újabb operációs rendszereken létrehozhat egy renderelési célmintát, és átadhatja a 0. szintű felületet a SetBackBuffer metódusnak. Ez a módszer Windows XP rendszeren nem ajánlott, mert nem lehet zárolható renderelési célmintát létrehozni, és a teljesítmény csökken.
Eszközállapot kezelése
A D3DImage osztály két megjelenítési puffert kezel, amelyek az háttér-puffer és az előlap-puffer. Ez a hátsó puffer az Ön Direct3D felülete. A háttérpuffer módosításait a rendszer a Unlock metódus meghívásakor az első pufferbe másolja, ahol az megjelenik a hardveren. Időnként az első puffer elérhetetlenné válik. A rendelkezésre állás hiányát okozhatja a képernyőzárolás, a teljes képernyős exkluzív Direct3D-alkalmazások, a felhasználóváltás vagy más rendszertevékenységek. Ha ez történik, a WPF-alkalmazás értesítést kap a IsFrontBufferAvailableChanged esemény kezelésével. Az, hogy az alkalmazás hogyan reagál az első puffer elérhetetlenné válására, attól függ, hogy a WPF engedélyezve van-e a szoftveres renderelésre való visszalépéshez. A SetBackBuffer metódus túlterheléssel rendelkezik, amely egy paramétert használ, amely meghatározza, hogy a WPF visszaesik-e a szoftveres renderelésre.
Amikor a SetBackBuffer(D3DResourceType, IntPtr) túlterhelést hívja meg, vagy a SetBackBuffer(D3DResourceType, IntPtr, Boolean) túlterhelést a enableSoftwareFallback paraméter falseértékre állítja, a renderelő rendszer a háttérpufferre mutató hivatkozást bocsátja ki, amikor az első puffer elérhetetlenné válik, és semmi sem jelenik meg. Ha az első puffer ismét elérhető, a renderelő rendszer a IsFrontBufferAvailableChanged eseményt aktiválja, amely értesíti a WPF-alkalmazást. Létrehozhat egy eseménykezelőt a IsFrontBufferAvailableChanged eseményhez, hogy újrainduljon a renderelés egy érvényes Direct3D-felülettel. A renderelés újraindításához meg kell hívnia SetBackBuffer.
Amikor a SetBackBuffer(D3DResourceType, IntPtr, Boolean) túlterhelést a enableSoftwareFallback paraméter trueértékre állítja, a renderelő rendszer megőrzi a háttérpufferre mutató hivatkozását, amikor az első puffer elérhetetlenné válik, így nem kell meghívni SetBackBuffer, ha az első puffer ismét elérhető.
Ha engedélyezve van a szoftveres renderelés, előfordulhat, hogy a felhasználó eszköze elérhetetlenné válik, de a renderelő rendszer megőrzi a Direct3D felületre mutató hivatkozást. Ha ellenőrizni szeretné, hogy egy Direct3D9-eszköz nem érhető-e el, hívja meg a TestCooperativeLevel metódust. Direct3D9Ex-eszközök ellenőrzéséhez hívja meg a CheckDeviceState metódust, mert a TestCooperativeLevel metódus elavult, és mindig sikert ad vissza. Ha a felhasználói eszköz elérhetetlenné vált, hívja fel a SetBackBuffer, hogy engedje fel a WPF-nek a háttérpufferre mutató hivatkozását. Ha alaphelyzetbe kell állítania az eszközt, hívja meg a SetBackBuffer parancsot a backBuffer paramétert null-re állítva, majd hívja meg ismét a SetBackBuffer-at, és állítsa a backBuffer-et egy érvényes Direct3D felületre.
Hívja meg a Reset metódust az érvénytelen eszközről való helyreállításhoz, csak akkor, ha többadapteres támogatást valósít meg. Máskülönben engedje fel az összes Direct3D9-felületet, és hozza létre őket teljes mértékben újra. Ha az adapter elrendezése megváltozott, a módosítás előtt létrehozott Direct3D9-objektumok nem frissülnek.
Átméretezés kezelése
Ha egy D3DImage a natív méretétől eltérő felbontásban jelenik meg, akkor a jelenlegi BitmapScalingModeszerint skálázódik, azzal a kivételével, hogy a BilinearFanthelyettesít.
Ha nagyobb hűségre van szüksége, új felületet kell létrehoznia, amikor a D3DImage tároló mérete megváltozik.
Három lehetséges módszer van az átméretezés kezelésére.
Vegyen részt az elrendezési rendszerben, és hozzon létre egy új felületet a méret változásakor. Ne hozzon létre túl sok felületet, mert a videomemória elfogyhat vagy töredezett lehet.
Várjon addig, amíg egy adott időszakig nem következik be átméretezési esemény, hogy létrehozhassa az új felületet.
Hozzon létre egy DispatcherTimer, amely másodpercenként többször ellenőrzi a tárolódimenziókat.
Többmonitoros optimalizálás
A teljesítmény jelentősen csökkenhet, ha a renderelő rendszer áthelyez egy D3DImage egy másik monitorra.
A WDDM esetén, amíg a monitorok ugyanazon a videokártyán vannak, és a Direct3DCreate9Ex-t használja, a teljesítmény nem csökken. Ha a monitorok külön videokártyákon vannak, a teljesítmény csökken. Windows XP rendszeren a teljesítmény mindig csökken.
Amikor a D3DImage másik monitorra kerül, létrehozhat egy új felületet a megfelelő adapteren a jó teljesítmény visszaállításához.
A teljesítménybírság elkerülése érdekében írjon kódot kifejezetten a többmonitoros esethez. Az alábbi lista egy többmonitoros kód írásának egyik módját mutatja be.
Keresse meg a D3DImage egy pontját a képernyőtérben a
Visual.ProjectToScreenmetódussal.A
MonitorFromPointGDI metódussal keresse meg a pontot megjelenítő monitort.A
IDirect3D9::GetAdapterMonitormetódus használatával állapítsa meg, hogy melyik Direct3D9-adapteren van a monitor.Ha az adapter nem ugyanaz, mint a háttérpufferrel rendelkező adapter, hozzon létre egy új háttérpuffert az új monitoron, és rendelje hozzá a D3DImage háttérpufferhez.
Megjegyzés:
Ha a D3DImage monitorokat hidal át, a teljesítmény lassú lesz, kivéve, ha a WDDM és a IDirect3D9Ex ugyanazon az adapteren van. Ebben a helyzetben nincs mód a teljesítmény javítására.
Az alábbi példakód bemutatja, hogyan keresheti meg az aktuális figyelőt.
void
CRendererManager::SetAdapter(POINT screenSpacePoint)
{
CleanupInvalidDevices();
//
// After CleanupInvalidDevices, we may not have any D3D objects. Rather than
// recreate them here, ignore the adapter update and wait for render to recreate.
//
if (m_pD3D && m_rgRenderers)
{
HMONITOR hMon = MonitorFromPoint(screenSpacePoint, MONITOR_DEFAULTTONULL);
for (UINT i = 0; i < m_cAdapters; ++i)
{
if (hMon == m_pD3D->GetAdapterMonitor(i))
{
m_pCurrentRenderer = m_rgRenderers[i];
break;
}
}
}
}
Frissítse a figyelőt, amikor a D3DImage tároló mérete vagy pozíciója megváltozik, vagy frissítse a figyelőt egy másodpercenként néhányszor frissülő DispatcherTimer használatával.
WPF szoftveres renderelés
A WPF szinkron módon jeleníti meg a felhasználói felület szálát a szoftverben az alábbi helyzetekben.
Nyomtatás
Az ilyen helyzetek egyike esetén a renderelő rendszer meghívja a CopyBackBuffer metódust a hardverpuffer szoftverbe másolásához. Az alapértelmezett implementáció meghívja a GetRenderTargetData metódust a felülettel. Mivel ez a hívás a zárolás/feloldás mintán kívül történik, ezért sikertelen lehet. Ebben az esetben a CopyBackBuffer metódus null ad vissza, és nem jelenik meg kép.
Felülbírálhatja a CopyBackBuffer metódust, meghívhatja az alapimplementációt, és ha az null-et adja vissza, visszaadhat egy BitmapSourcehelyőrzőt.
Saját szoftverleképezést is implementálhat ahelyett, hogy meghívná az alap implementációt.
Megjegyzés:
Ha a WPF teljes mértékben a szoftverben jelenik meg, D3DImage nem jelenik meg, mert a WPF nem rendelkezik előtérpufferrel.
Lásd még
- D3DImage
- Direct3D9 és WPF együttműködési teljesítményével kapcsolatos szempontok
- Útmutató: Direct3D9-tartalom létrehozása a WPF-ben való üzemeltetéshez
- Útmutató: Direct3D9-tartalmak integrálása a WPF-ben
.NET Desktop feedback