D2D s využitím D3D11on12
Ukázka D3D1211on12 ukazuje, jak vykreslit D2D obsah přes D3D12 pomocí sdílení zdrojů mezi zařízením na bázi 11 a zařízením na bázi 12.
- Vytvoření ID3D11On12Device
- Vytvořte továrnu D2D
- Vytvořit cíl vykreslení pro D2D
- Vytvoření základních objektů textu D2D
- Aktualizace hlavní smyčky vykreslování
- Spusťte ukázku
- související témata
Vytvořte ID3D11On12Device
Prvním krokem je vytvoření ID3D11On12Device po vytvoření ID3D12Device, což zahrnuje vytvoření ID3D11Device, který je zabalen kolem ID3D12Device prostřednictvím rozhraní API D3D11On12CreateDevice. Toto rozhraní API také přebírá mimo jiné parametry ID3D12CommandQueue, aby zařízení 11On12 mohl odesílat své příkazy. Po vytvoření ID3D11Device můžete získat rozhraní ID3D11On12Device z něj. Toto je primární objekt zařízení, který se použije k nastavení D2D.
V metodě LoadPipeline nastavte zařízení.
// Create an 11 device wrapped around the 12 device and share
// 12's command queue.
ComPtr<ID3D11Device> d3d11Device;
ThrowIfFailed(D3D11On12CreateDevice(
m_d3d12Device.Get(),
d3d11DeviceFlags,
nullptr,
0,
reinterpret_cast<IUnknown**>(m_commandQueue.GetAddressOf()),
1,
0,
&d3d11Device,
&m_d3d11DeviceContext,
nullptr
));
// Query the 11On12 device from the 11 device.
ThrowIfFailed(d3d11Device.As(&m_d3d11On12Device));
Průběh hovoru | Parametry |
---|---|
ID3D11Device | |
D3D11On12CreateDevice |
Vytvoření továrny D2D
Nyní, když máme zařízení 11On12, použijeme ho k vytvoření D2D továrny a zařízení, stejně jako by se to normálně dělalo s D3D11.
Přidejte do metody LoadAssets.
// Create D2D/DWrite components.
{
D2D1_DEVICE_CONTEXT_OPTIONS deviceOptions = D2D1_DEVICE_CONTEXT_OPTIONS_NONE;
ThrowIfFailed(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory3), &d2dFactoryOptions, &m_d2dFactory));
ComPtr<IDXGIDevice> dxgiDevice;
ThrowIfFailed(m_d3d11On12Device.As(&dxgiDevice));
ThrowIfFailed(m_d2dFactory->CreateDevice(dxgiDevice.Get(), &m_d2dDevice));
ThrowIfFailed(m_d2dDevice->CreateDeviceContext(deviceOptions, &m_d2dDeviceContext));
ThrowIfFailed(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &m_dWriteFactory));
}
Vytvořte cíl vykreslení pro D2D
D3D12 vlastní swap chain, takže pokud chceme vykreslit na zadní vyrovnávací paměť pomocí našeho zařízení 11On12 (obsah D2D), pak potřebujeme vytvořit zabalené prostředky typu ID3D11Resource ze zadních vyrovnávacích pamětí typu ID3D12Resource. Tím propojíte ID3D12Resource s rozhraním založeným na D3D11, aby bylo možné ho použít se zařízením 11On12. Po zabalení prostředku můžeme vytvořit cílovou plochu vykreslení pro D2D, na kterou se má vykreslovat, a to také v metodě LoadAssets.
// Initialize *hwnd* with the handle of the window displaying the rendered content.
HWND hwnd;
// Query the window's dpi settings, which will be used to create
// D2D's render targets.
float dpi = GetDpiForWindow(hwnd);
D2D1_BITMAP_PROPERTIES1 bitmapProperties = D2D1::BitmapProperties1(
D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
dpi,
dpi);
// Create frame resources.
{
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart());
// Create a RTV, D2D render target, and a command allocator for each frame.
for (UINT n = 0; n < FrameCount; n++)
{
ThrowIfFailed(m_swapChain->GetBuffer(n, IID_PPV_ARGS(&m_renderTargets[n])));
m_d3d12Device->CreateRenderTargetView(m_renderTargets[n].Get(), nullptr, rtvHandle);
// Create a wrapped 11On12 resource of this back buffer. Since we are
// rendering all D3D12 content first and then all D2D content, we specify
// the In resource state as RENDER_TARGET - because D3D12 will have last
// used it in this state - and the Out resource state as PRESENT. When
// ReleaseWrappedResources() is called on the 11On12 device, the resource
// will be transitioned to the PRESENT state.
D3D11_RESOURCE_FLAGS d3d11Flags = { D3D11_BIND_RENDER_TARGET };
ThrowIfFailed(m_d3d11On12Device->CreateWrappedResource(
m_renderTargets[n].Get(),
&d3d11Flags,
D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_PRESENT,
IID_PPV_ARGS(&m_wrappedBackBuffers[n])
));
// Create a render target for D2D to draw directly to this back buffer.
ComPtr<IDXGISurface> surface;
ThrowIfFailed(m_wrappedBackBuffers[n].As(&surface));
ThrowIfFailed(m_d2dDeviceContext->CreateBitmapFromDxgiSurface(
surface.Get(),
&bitmapProperties,
&m_d2dRenderTargets[n]
));
rtvHandle.Offset(1, m_rtvDescriptorSize);
ThrowIfFailed(m_d3d12Device->CreateCommandAllocator(
D3D12_COMMAND_LIST_TYPE_DIRECT,
IID_PPV_ARGS(&m_commandAllocators[n])));
}
}
Postup volání | Parametry |
---|---|
GetDpiForWindow | Úchyt okna |
D2D1_BITMAP_PROPERTIES1 |
[D2D1_BITMAP_OPTIONS](/windows/desktop/api/d2d1_1/ne-d2d1_1-d2d1_bitmap_options) [PixelFormat](/windows/desktop/api/d2d1helper/nf-d2d1helper-pixelformat) [DXGI_FORMAT](/windows/desktop/api/dxgiformat/ne-dxgiformat-dxgi_format) [D2D1_ALPHA_MODE](/windows/desktop/api/dcommon/ne-dcommon-d2d1_alpha_mode) |
CD3DX12_CPU_DESCRIPTOR_HANDLE | GetCPUDescriptorHandleForHeapStart |
IDXGISwapChain::GetBuffer | |
CreateRenderTargetView | |
D3D11_RESOURCE_FLAGS | D3D11_BIND_FLAG |
CreateWrappedResource | D3D12_RESOURCE_STATES |
IDXGISurface | |
ID2D1DeviceContext::CreateBitmapFromDxgiSurface | |
CreateCommandAllocator | D3D12_COMMAND_LIST_TYPE |
Vytváření základních textových objektů D2D
Teď máme ID3D12Device k vykreslení 3D obsahu, a ID2D1Device, který je sdílen s naším zařízením 12 prostřednictvím ID3D11On12Device – což můžeme použít k vykreslení 2D obsahu – a obě zařízení jsou nakonfigurována tak, aby vykreslovala na stejný řetězec výměny. Tato ukázka jednoduše používá zařízení D2D k vykreslení textu přes 3D scénu, podobně jako hry vykreslují uživatelské rozhraní. Pro to potřebujeme vytvořit některé základní objekty D2D, a to stále v metodě LoadAssets.
// Create D2D/DWrite objects for rendering text.
{
ThrowIfFailed(m_d2dDeviceContext->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &m_textBrush));
ThrowIfFailed(m_dWriteFactory->CreateTextFormat(
L"Verdana",
NULL,
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
50,
L"en-us",
&m_textFormat
));
ThrowIfFailed(m_textFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER));
ThrowIfFailed(m_textFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER));
}
Aktualizace hlavní smyčky vykreslování
Nyní, když je inicializace vzorku dokončena, můžeme přejít k hlavní smyčce vykreslování.
// Render the scene.
void D3D1211on12::OnRender()
{
// Record all the commands we need to render the scene into the command list.
PopulateCommandList();
// Execute the command list.
ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
RenderUI();
// Present the frame.
ThrowIfFailed(m_swapChain->Present(0, 0));
MoveToNextFrame();
}
Průběh hovoru | Parametry |
---|---|
ID3D12CommandList | |
ExecuteCommandLists | |
IDXGISwapChain1::Present1 |
Jedinou novinkou v naší smyčce vykreslování je volání RenderUI, které k vykreslení uživatelského rozhraní použije D2D. Všimněte si, že nejprve spustíme všechny seznamy příkazů D3D12, abychom vykreslili naši 3D scénu a pak na něj vykreslili naše uživatelské rozhraní. Než se ponoříme do RenderUI, musíme se podívat na změnu PopulateCommandLists. V jiných ukázkách běžně umisťujeme bariéru prostředků do seznamu příkazů před jeho uzavřením, aby se zadní vyrovnávací paměť převedla ze stavu cíle vykreslení do stavu pro prezentaci. V této ukázce však odebereme tuto bariéru prostředků, protože stále potřebujeme vykreslit do zpětných zásobníků pomocí D2D. Všimněte si, že když jsme vytvořili zabalené prostředky zpětného vyrovnávacího bufferu, určili jsme stav cílového vykreslování jako stav "IN" a stav pro zobrazení jako stav "OUT".
RenderUI je poměrně jednoduchý z hlediska využití D2D. Nastavili jsme cíl vykreslení a vykreslili jsme text. Před použitím jakýchkoli zabalených prostředků na zařízení 11On12, jako je například cíl vykreslení vyrovnávací paměti zpět, musíme volat AcquireWrappedResources API na zařízení 11On12. Po vykreslení zavoláme API ReleaseWrappedResources na zařízení 11On12. Voláním ReleaseWrappedResources na pozadí vznikne bariéra prostředků, která převede zadaný prostředek do stavu „OUT“, jak bylo specifikováno při jeho vytvoření. V našem případě je to aktuální stav. Nakonec aby bylo možné odeslat všechny naše příkazy provedené na zařízení 11On12 do sdíleného ID3D12CommandQueue, musíme zavolat Flush na ID3D11DeviceContext.
// Render text over D3D12 using D2D via the 11On12 device.
void D3D1211on12::RenderUI()
{
D2D1_SIZE_F rtSize = m_d2dRenderTargets[m_frameIndex]->GetSize();
D2D1_RECT_F textRect = D2D1::RectF(0, 0, rtSize.width, rtSize.height);
static const WCHAR text[] = L"11On12";
// Acquire our wrapped render target resource for the current back buffer.
m_d3d11On12Device->AcquireWrappedResources(m_wrappedBackBuffers[m_frameIndex].GetAddressOf(), 1);
// Render text directly to the back buffer.
m_d2dDeviceContext->SetTarget(m_d2dRenderTargets[m_frameIndex].Get());
m_d2dDeviceContext->BeginDraw();
m_d2dDeviceContext->SetTransform(D2D1::Matrix3x2F::Identity());
m_d2dDeviceContext->DrawTextW(
text,
_countof(text) - 1,
m_textFormat.Get(),
&textRect,
m_textBrush.Get()
);
ThrowIfFailed(m_d2dDeviceContext->EndDraw());
// Release our wrapped render target resource. Releasing
// transitions the back buffer resource to the state specified
// as the OutState when the wrapped resource was created.
m_d3d11On12Device->ReleaseWrappedResources(m_wrappedBackBuffers[m_frameIndex].GetAddressOf(), 1);
// Flush to submit the 11 command list to the shared command queue.
m_d3d11DeviceContext->Flush();
}
Spusťte ukázku
Související témata