Initialisieren von Direct3D 11
Zusammenfassung
- Teil 1: Initialisieren von Direct3D 11
- Teil 2: Konvertieren des Renderingframeworks
- Teil 3: Porten der Spielschleife
Zeigt, wie Sie Direct3D 9-Initialisierungscode in Direct3D 11 konvertieren, einschließlich der Vorgehensweise zum Abrufen von Handles auf das Direct3D-Gerät und den Gerätekontext und die Verwendung von DXGI zum Einrichten einer Swapchain. Teil 1 der exemplarischen Vorgehensweise zum Portieren einer einfachen Direct3D 9-App zu DirectX 11 und Universelle Windows-Plattform (UWP).
Initialisieren des Direct3D-Geräts
In Direct3D 9 haben wir ein Handle für das Direct3D-Gerät erstellt, indem IDirect3D9::CreateDevice aufgerufen wird. Zunächst erhalten wir einen Zeiger auf die IDirect3D9-Schnittstelle und haben eine Reihe von Parametern angegeben, um die Konfiguration des Direct3D-Geräts und der Swapchain zu steuern. Bevor wir dies tun, haben wir GetDeviceCaps aufgerufen, um sicherzustellen, dass wir das Gerät nicht auffordern, etwas zu tun, was nicht möglich war.
Direct3D 9
UINT32 AdapterOrdinal = 0;
D3DDEVTYPE DeviceType = D3DDEVTYPE_HAL;
D3DCAPS9 caps;
m_pD3D->GetDeviceCaps(AdapterOrdinal, DeviceType, &caps); // caps bits
D3DPRESENT_PARAMETERS params;
ZeroMemory(¶ms, sizeof(D3DPRESENT_PARAMETERS));
// Swap chain parameters:
params.hDeviceWindow = m_hWnd;
params.AutoDepthStencilFormat = D3DFMT_D24X8;
params.BackBufferFormat = D3DFMT_X8R8G8B8;
params.MultiSampleQuality = D3DMULTISAMPLE_NONE;
params.MultiSampleType = D3DMULTISAMPLE_NONE;
params.SwapEffect = D3DSWAPEFFECT_DISCARD;
params.Windowed = true;
params.PresentationInterval = 0;
params.BackBufferCount = 2;
params.BackBufferWidth = 0;
params.BackBufferHeight = 0;
params.EnableAutoDepthStencil = true;
params.Flags = 2;
m_pD3D->CreateDevice(
0,
D3DDEVTYPE_HAL,
m_hWnd,
64,
¶ms,
&m_pd3dDevice
);
In Direct3D 11 wird der Gerätekontext und die Grafikinfrastruktur vom Gerät selbst getrennt betrachtet. Die Initialisierung ist in mehrere Schritte unterteilt.
Zuerst erstellen wir das Gerät. Wir erhalten eine Liste der Featureebenen, die das Gerät unterstützt – dies informiert die meisten informationen, was wir über die GPU wissen müssen. Außerdem müssen wir keine Schnittstelle erstellen, um nur auf Direct3D zuzugreifen. Stattdessen verwenden wir die D3D11CreateDevice Core-API. Dadurch erhalten wir einen Handle für das Gerät und den unmittelbaren Kontext des Geräts. Der Gerätekontext wird verwendet, um den Pipelinestatus festzulegen und Renderingbefehle zu generieren.
Nach dem Erstellen des Direct3D 11-Geräts und -Kontexts können wir die COM-Zeigerfunktionalität nutzen, um die neueste Version der Schnittstellen abzurufen, die zusätzliche Funktionen enthalten und immer empfohlen werden.
Beachten Sie , dass D3D_FEATURE_LEVEL_9_1 (die dem Shadermodell 2.0 entspricht) das Mindestniveau ist, das Für die Unterstützung Ihres Microsoft Store-Spiels erforderlich ist. (Die Arm-Pakete Ihres Spiels werden nicht zertifiziert, wenn Sie 9_1 nicht unterstützen.) Wenn Ihr Spiel auch einen Renderingpfad für Shadermodell 3-Features enthält, sollten Sie D3D_FEATURE_LEVEL_9_3 in das Array einschließen.
Direct3D 11
// This flag adds support for surfaces with a different color channel
// ordering than the API default. It is required for compatibility with
// Direct2D.
UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
#if defined(_DEBUG)
// If the project is in a debug build, enable debugging via SDK Layers.
creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
// This example only uses feature level 9.1.
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_9_1
};
// Create the Direct3D 11 API device object and a corresponding context.
ComPtr<ID3D11Device> device;
ComPtr<ID3D11DeviceContext> context;
D3D11CreateDevice(
nullptr, // Specify nullptr to use the default adapter.
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
creationFlags,
featureLevels,
ARRAYSIZE(featureLevels),
D3D11_SDK_VERSION, // UWP apps must set this to D3D11_SDK_VERSION.
&device, // Returns the Direct3D device created.
nullptr,
&context // Returns the device immediate context.
);
// Store pointers to the Direct3D 11.2 API device and immediate context.
device.As(&m_d3dDevice);
context.As(&m_d3dContext);
Erstellen einer Swapchain
Direct3D 11 enthält eine Geräte-API namens DirectX-Grafikinfrastruktur (DXGI). Über die DXGI-Schnittstelle können wir (z. B.) steuern, wie die Swapchain konfiguriert und gemeinsam genutzte Geräte eingerichtet wird. In diesem Schritt bei der Initialisierung von Direct3D verwenden wir DXGI zum Erstellen einer Swapchain. Da wir das Gerät erstellt haben, können wir eine Schnittstellenkette zurück zum DXGI-Adapter folgen.
Das Direct3D-Gerät implementiert eine COM-Schnittstelle für DXGI. Zuerst müssen wir diese Schnittstelle abrufen und verwenden, um den DXGI-Adapter anzufordern, der das Gerät hosten wird. Anschließend verwenden wir den DXGI-Adapter, um eine DXGI-Factory zu erstellen.
Beachten Sie, dass es sich um COM-Schnittstellen handelt, damit Ihre erste Antwort möglicherweise QueryInterface verwendet. Sie sollten stattdessen Microsoft::WRL::ComPtr smart pointers verwenden. Rufen Sie dann einfach die As()- Methode auf, und geben Sie einen leeren COM-Zeiger des richtigen Schnittstellentyps an.
Direct3D 11
ComPtr<IDXGIDevice2> dxgiDevice;
m_d3dDevice.As(&dxgiDevice);
// Then, the adapter hosting the device;
ComPtr<IDXGIAdapter> dxgiAdapter;
dxgiDevice->GetAdapter(&dxgiAdapter);
// Then, the factory that created the adapter interface:
ComPtr<IDXGIFactory2> dxgiFactory;
dxgiAdapter->GetParent(
__uuidof(IDXGIFactory2),
&dxgiFactory
);
Da wir nun über die DXGI-Factory verfügen, können wir sie verwenden, um die Swapchain zu erstellen. Definieren wir die Swapchainparameter. Wir müssen das Oberflächenformat angeben; wir wählen DXGI_FORMAT_B8G8R8A8_UNORM aus, da sie mit Direct2D kompatibel ist. Wir deaktivieren die Anzeigeskalierung, das Multisampling und das Stereorendering, da sie in diesem Beispiel nicht verwendet werden. Da wir direkt in einem CoreWindow ausgeführt werden, können wir die Breite und Höhe auf 0 festlegen und Vollbildwerte automatisch abrufen.
Hinweis: Legen Sie den SDKVersion-Parameter immer auf D3D11_SDK_VERSION für UWP-Apps fest.
Direct3D 11
ComPtr<IDXGISwapChain1> swapChain;
dxgiFactory->CreateSwapChainForCoreWindow(
m_d3dDevice.Get(),
reinterpret_cast<IUnknown*>(window),
&swapChainDesc,
nullptr,
&swapChain
);
swapChain.As(&m_swapChain);
Um sicherzustellen, dass wir nicht häufiger rendern, als der Bildschirm tatsächlich anzeigen kann, legen wir die Framelatenz auf 1 fest und verwenden DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL. Dies spart Strom und ist eine Speicherzertifizierungsanforderung; In Teil 2 dieser exemplarischen Vorgehensweise erfahren wir mehr über die Präsentation auf dem Bildschirm.
Hinweis: Sie können Multithreading (z. B. ThreadPool-Arbeitsaufgaben) verwenden, um andere Arbeiten fortzusetzen, während der Renderingthread blockiert wird.
Direct3D 11
dxgiDevice->SetMaximumFrameLatency(1);
Jetzt können wir den Hintergrundpuffer für das Rendern einrichten.
Konfigurieren des Hintergrundpuffers als Renderziel
Zuerst müssen wir einen Handle für den Hintergrundpuffer abrufen. (Beachten Sie, dass der Hintergrundpuffer im Besitz der DXGI-Swapchain ist, während er in DirectX 9 im Besitz des Direct3D-Geräts war.) Anschließend wird das Direct3D-Gerät aufgefordert, es als Renderziel zu verwenden, indem eine Renderzielansicht mithilfe des Hintergrundpuffers erstellt wird.
Direct3D 11
ComPtr<ID3D11Texture2D> backBuffer;
m_swapChain->GetBuffer(
0,
__uuidof(ID3D11Texture2D),
&backBuffer
);
// Create a render target view on the back buffer.
m_d3dDevice->CreateRenderTargetView(
backBuffer.Get(),
nullptr,
&m_renderTargetView
);
Jetzt kommt der Gerätekontext ins Spiel. Wir teilen Direct3D mit, unsere neu erstellte Renderzielansicht mithilfe der Gerätekontextschnittstelle zu verwenden. Wir rufen die Breite und Höhe des Hintergrundpuffers ab, damit wir das gesamte Fenster als Viewport als Ziel festlegen können. Beachten Sie, dass der Hintergrundpuffer an die Swapchain angefügt ist. Wenn sich die Fenstergröße ändert (z. B. wenn der Benutzer das Spielfenster auf einen anderen Monitor zieht), muss die Größe des Hintergrundpuffers geändert werden, und einige Setupvorgänge müssen erneut ausgeführt werden.
Direct3D 11
D3D11_TEXTURE2D_DESC backBufferDesc = {0};
backBuffer->GetDesc(&backBufferDesc);
CD3D11_VIEWPORT viewport(
0.0f,
0.0f,
static_cast<float>(backBufferDesc.Width),
static_cast<float>(backBufferDesc.Height)
);
m_d3dContext->RSSetViewports(1, &viewport);
Da wir nun über ein Gerätehandle und ein Renderziel im Vollbildmodus verfügen, können wir Geometrie laden und zeichnen. Fahren Sie mit Teil 2 fort: Rendern.