Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
U kunt Direct3D9-inhoud opnemen in een WPF-toepassing (Windows Presentation Foundation). In dit onderwerp wordt beschreven hoe u Direct3D9-inhoud maakt, zodat deze efficiënt kan samenwerken met WPF.
Opmerking
Wanneer u Direct3D9-inhoud in WPF gebruikt, moet u ook nadenken over prestaties. Zie Prestatieoverwegingen voor Direct3D9 en WPF-interoperabiliteit voor meer informatie over het optimaliseren van prestaties.
Buffers weergeven
De D3DImage klasse beheert twee weergavebuffers, die de backbuffer en de frontbuffer worden genoemd. De achterbuffer is uw Direct3D9-oppervlak. Wijzigingen in de backbuffer worden naar de frontbuffer gekopieerd wanneer u de Unlock methode aanroept.
In de volgende afbeelding ziet u de relatie tussen de achterbuffer en de frontbuffer.
Direct3D9-apparaat maken
Als u Direct3D9-inhoud wilt weergeven, moet u een Direct3D9-apparaat maken. Er zijn twee Direct3D9-objecten die u kunt gebruiken om een apparaat te maken, IDirect3D9 en IDirect3D9Ex. Gebruik deze objecten om respectievelijk IDirect3DDevice9- en IDirect3DDevice9Ex-apparaten te maken.
Maak een apparaat door een van de volgende methoden aan te roepen.
IDirect3D9 * Direct3DCreate9(UINT SDKVersion);HRESULT Direct3DCreate9Ex(UINT SDKVersion, IDirect3D9Ex **ppD3D);
Gebruik in het besturingssysteem Windows Vista of hoger de Direct3DCreate9Ex methode met een beeldscherm dat is geconfigureerd voor het gebruik van het Windows Display Driver Model (WDDM). Gebruik de Direct3DCreate9 methode op elk ander platform.
Beschikbaarheid van de methode Direct3DCreate9Ex
De d3d9.dll heeft de Direct3DCreate9Ex methode alleen op het besturingssysteem Windows Vista of hoger. Als u de functie rechtstreeks koppelt in Windows XP, kan de toepassing niet worden geladen. Als u wilt bepalen of de Direct3DCreate9Ex methode wordt ondersteund, laadt u het DLL-bestand en zoekt u naar het proc-adres. De volgende code laat zien hoe u kunt testen op de Direct3DCreate9Ex methode. Zie Walkthrough voor een volledig codevoorbeeld: Direct3D9-inhoud maken voor hosting in WPF.
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 maken
Voor het maken van een apparaat is een HWND vereist. Over het algemeen maakt u een dummy-HWND voor gebruik met Direct3D9. In het volgende codevoorbeeld ziet u hoe u een dummy HWND maakt.
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;
}
Parameters presenteren
Voor het maken van een apparaat is ook een D3DPRESENT_PARAMETERS struct vereist, maar slechts enkele parameters zijn belangrijk. Deze parameters worden gekozen om de geheugenvoetafdruk te minimaliseren.
Stel de velden BackBufferHeight en BackBufferWidth in op 1. Als u ze instelt op 0, worden ze ingesteld op de afmetingen van de HWND.
Stel altijd de D3DCREATE_MULTITHREADED en D3DCREATE_FPU_PRESERVE vlaggen in om te voorkomen dat het geheugen wordt beschadigd door Direct3D9 en om te voorkomen dat Direct3D9 FPU-instellingen wijzigt.
De volgende code laat zien hoe u de D3DPRESENT_PARAMETERS struct initialiseert.
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;
}
Het renderdoel van de achterbuffer maken
Als u Direct3D9-inhoud in een D3DImagewilt weergeven, maakt u een Direct3D9-oppervlak en wijst u deze toe door de SetBackBuffer methode aan te roepen.
Ondersteuning voor adapter controleren
Controleer voordat u een oppervlak maakt of alle adapters de vereiste oppervlakeigenschappen ondersteunen. Zelfs als u naar slechts één adapter weergeeft, kan het WPF-venster op elke adapter in uw systeem worden weergegeven. U moet altijd Direct3D9-code schrijven die configuraties met meerdere adapters verwerkt en u moet alle adapters controleren op ondersteuning, omdat WPF het oppervlak tussen de beschikbare adapters kan verplaatsen.
In het volgende codevoorbeeld ziet u hoe u alle adapters op het systeem controleert voor direct3D9-ondersteuning.
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;
}
De Surface maken
Voordat u een oppervlak maakt, controleer of de mogelijkheden van het apparaat het doelbesturingssysteem goed ondersteunen. Zie Prestatieoverwegingen voor Direct3D9 en WPF-interoperabiliteit voor meer informatie.
Wanneer u de mogelijkheden van het apparaat hebt geverifieerd, kunt u het oppervlak maken. In het volgende codevoorbeeld ziet u hoe u het renderdoel maakt.
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
Op Windows Vista en latere besturingssystemen, die zijn geconfigureerd voor het gebruik van WDDM, kunt u een render doelpatroon maken en het niveau 0 oppervlak doorgeven aan de SetBackBuffer methode. Deze aanpak wordt niet aanbevolen op Windows XP, omdat u geen vergrendelbare renderdoeltekstuur kunt maken en de prestaties zullen verminderen.
Apparaatstatus verwerken
De D3DImage klasse beheert twee weergavebuffers, die de backbuffer en de frontbuffer worden genoemd. De achterbuffer is uw Direct3D-oppervlak. Wijzigingen in de achterbuffer worden naar de frontbuffer gekopieerd wanneer u de Unlock methode aanroept, waar deze op de hardware wordt weergegeven. Af en toe is de frontbuffer niet meer beschikbaar. Dit gebrek aan beschikbaarheid kan worden veroorzaakt door schermvergrendeling, volledig scherm exclusieve Direct3D-toepassingen, gebruikerswisseling of andere systeemactiviteiten. Wanneer dit gebeurt, wordt uw WPF-toepassing op de hoogte gesteld door de IsFrontBufferAvailableChanged gebeurtenis te verwerken. Hoe uw toepassing reageert op de frontbuffer die niet beschikbaar is, is afhankelijk van of WPF is ingeschakeld om terug te vallen op softwarerendering. De SetBackBuffer methode heeft een overbelasting die een parameter gebruikt die aangeeft of WPF terugvalt op softwarerendering.
Wanneer u de SetBackBuffer(D3DResourceType, IntPtr) overload aanroept of de SetBackBuffer(D3DResourceType, IntPtr, Boolean) overload aanroept waarbij de enableSoftwareFallback parameter is ingesteld op false, geeft het renderingsysteem de verwijzing naar de achterbuffer vrij wanneer de frontbuffer niet meer beschikbaar is en er niets wordt weergegeven. Wanneer de frontbuffer weer beschikbaar is, wordt de IsFrontBufferAvailableChanged gebeurtenis geactiveerd om uw WPF-toepassing op de hoogte te brengen. U kunt een gebeurtenis-handler voor de gebeurtenis maken om de IsFrontBufferAvailableChanged rendering opnieuw te starten met een geldig Direct3D-oppervlak. Als u de rendering opnieuw wilt starten, moet u aanroepen SetBackBuffer.
Wanneer u de SetBackBuffer(D3DResourceType, IntPtr, Boolean) overbelasting aanroept waarbij de enableSoftwareFallback parameter is ingesteld true, behoudt het renderingsysteem de verwijzing naar de achterbuffer wanneer de frontbuffer niet meer beschikbaar is, zodat er geen noodzaak is om aan te roepen SetBackBuffer wanneer de frontbuffer weer beschikbaar is.
Wanneer softwarerendering is ingeschakeld, kunnen er situaties zijn waarin het apparaat van de gebruiker niet meer beschikbaar is, maar het renderingsysteem een verwijzing naar het Direct3D-oppervlak behoudt. Als u wilt controleren of een Direct3D9-apparaat niet beschikbaar is, roept u de TestCooperativeLevel methode aan. Om een Direct3D9Ex-apparaat te controleren, roept u de CheckDeviceState-methode aan omdat de TestCooperativeLevel-methode is afgeschaft en altijd succes retourneert. Als het apparaat niet meer beschikbaar is, bel SetBackBuffer om de verwijzing van WPF naar de backbuffer vrij te geven. Als u uw apparaat opnieuw moet instellen, belt u `SetBackBuffer` met de parameter `backBuffer` ingesteld op `null`, en daarna belt u `SetBackBuffer` opnieuw met `backBuffer` ingesteld op een geldig Direct3D-oppervlak.
Roep de Reset methode aan om van een ongeldig apparaat te herstellen als u alleen ondersteuning voor meerdere adapters implementeert. Anders laat u alle Direct3D9-interfaces los en maak ze volledig opnieuw. Als de adapterindeling is gewijzigd, worden Direct3D9-objecten die zijn gemaakt voordat de wijziging plaatsvond niet bijgewerkt.
Omgaan met formaatwijzigingen
Als een D3DImage wordt weergegeven op een resolutie anders dan de oorspronkelijke grootte, wordt deze geschaald volgens de huidige BitmapScalingMode, behalve dat Bilinear wordt vervangen door Fant.
Als u een hogere betrouwbaarheid nodig hebt, moet u een nieuw oppervlak maken wanneer de container van de D3DImage grootte verandert.
Er zijn drie mogelijke benaderingen voor het afhandelen van formaatwijziging.
Neem deel aan het indelingssysteem en maak een nieuw oppervlak wanneer de grootte verandert. Maak niet te veel oppervlakken, omdat u videogeheugen kunt uitputten of fragmenten.
Wacht totdat er gedurende een bepaalde tijd geen gebeurtenis voor het wijzigen van de grootte plaatsvindt, om het nieuwe oppervlak te maken.
Maak een DispatcherTimer container die de containerdimensies meerdere keren per seconde controleert.
Optimalisatie van meerdere beeldschermen
Aanzienlijk verminderde prestaties kunnen het gevolg zijn wanneer het renderingsysteem een D3DImage naar een andere monitor verplaatst.
Op WDDM, zolang de monitors zich op dezelfde videokaart bevinden en u gebruikt Direct3DCreate9Ex, is er geen vermindering van de prestaties. Als de beeldschermen op afzonderlijke videokaarten staan, worden de prestaties verminderd. In Windows XP worden de prestaties altijd verminderd.
Wanneer de D3DImage naar een andere monitor verhuist, kunt u een nieuw oppervlak op de bijbehorende adapter creëren om de prestaties te optimaliseren.
Schrijf code specifiek voor de case met meerdere beeldschermen om de prestatiestraf te voorkomen. In de volgende lijst ziet u één manier om code met meerdere beeldschermen te schrijven.
Zoek een punt van de D3DImage schermruimte met de
Visual.ProjectToScreenmethode.Gebruik de
MonitorFromPointGDI-methode om de monitor te vinden die het punt weergeeft.Gebruik de
IDirect3D9::GetAdapterMonitormethode om te bepalen op welke Direct3D9-adapter de monitor is ingeschakeld.Als de adapter niet hetzelfde is als de adapter met de backbuffer, maakt u een nieuwe backbuffer op de nieuwe monitor en wijst u deze toe aan de D3DImage backbuffer.
Opmerking
Als de D3DImage over meerdere monitoren verdeeld is, zijn de prestaties traag, behalve in het geval van WDDM en IDirect3D9Ex op dezelfde adapter. Er is geen manier om de prestaties in deze situatie te verbeteren.
In het volgende codevoorbeeld ziet u hoe u de huidige monitor kunt vinden.
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;
}
}
}
}
Werk de monitor bij wanneer de grootte of positie van de D3DImage container verandert of werk de monitor bij met behulp van een monitor die DispatcherTimer een paar keer per seconde wordt bijgewerkt.
WPF Software Renderen
WPF wordt in de volgende situaties synchroon op de UI-thread in software weergegeven.
Drukkerij
Wanneer een van deze situaties zich voordoet, roept het renderingsysteem de CopyBackBuffer methode aan om de hardwarebuffer naar software te kopiëren. De standaard implementatie roept de GetRenderTargetData methode aan met uw surface. Omdat deze aanroep buiten het patroon Vergrendelen/Ontgrendelen valt, kan dit mislukken. In dit geval geeft de CopyBackBuffer methode null terug en wordt er geen afbeelding weergegeven.
U kunt de CopyBackBuffer methode overschrijven, de basisimplementatie aanroepen en als deze null retourneert, kunt u een tijdelijke aanduiding BitmapSource retourneren.
U kunt ook uw eigen softwarerendering implementeren in plaats van de basis-implementatie aan te roepen.
Opmerking
Als WPF volledig via software rendert, wordt D3DImage niet getoond omdat WPF geen frontbuffer heeft.
Zie ook
.NET Desktop feedback