D2D met D3D11on12
Het D3D1211on12 voorbeeld laat zien hoe u D2D-inhoud over D3D12-inhoud kunt weergeven door resources te delen tussen een apparaat op basis van 11 en een apparaat met 12.
- Maak een ID3D11On12Device
- Maak een D2D-fabriek
- Een renderdoel maken voor D2D-
- Eenvoudige D2D-tekstobjecten maken
- de hoofdweergavelus bijwerken
- de voorbeeld- uitvoeren
- Verwante onderwerpen
Een ID3D11On12Device maken
De eerste stap is het maken van een ID3D11On12Device- nadat de ID3D12Device- is gemaakt, waarbij een ID3D11Device- wordt gemaakt die is verpakt rond de ID3D12Device- via de API D3D11On12CreateDevice. Deze API neemt onder andere de parameter ID3D12CommandQueue- op, zodat het 11On12-apparaat zijn opdrachten kan verzenden. Nadat de ID3D11Device- is gemaakt, kunt u een query uitvoeren op de ID3D11On12Device interface. Dit is het primaire apparaatobject dat wordt gebruikt voor het instellen van D2D.
In de methode LoadPipeline moet u de apparaten instellen.
// 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));
Oproepstroom | Parameters |
---|---|
ID3D11Device | |
D3D11On12CreateDevice |
Een D2D-factory maken
Nu we een 11On12-apparaat hebben, gebruiken we het om een D2D-fabriek en -apparaat te maken, net zoals het normaal zou worden gedaan met D3D11.
Voeg toe aan de methode 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));
}
Een renderdoel maken voor D2D
D3D12 is eigenaar van de swap chain, dus als we naar de backbuffer willen renderen met ons 11On12-apparaat (D2D-inhoud), moeten we ingepakte resources van het type ID3D11Resource maken vanuit de backbuffers van het type ID3D12Resource. Hiermee wordt de ID3D12Resource- gekoppeld aan een D3D11-gebaseerde interface, zodat deze kan worden gebruikt met het 11On12-apparaat. Nadat we een verpakte resource hebben, kunnen we vervolgens een renderdoeloppervlak voor D2D maken om te renderen, ook in de methode 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])));
}
}
Oproepstroom | Parameters |
---|---|
GetDpiForWindow | Een venstergreep |
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 |
Eenvoudige D2D-tekstobjecten maken
We hebben nu een ID3D12Device- om 3D-inhoud weer te geven, een ID2D1Device- die wordt gedeeld met onze ID3D12Device via een ID3D11On12Device- - die we kunnen gebruiken om 2D-inhoud weer te geven - en ze zijn beide geconfigureerd om te renderen naar dezelfde swap chain. In dit voorbeeld wordt eenvoudig het D2D-apparaat gebruikt om tekst weer te geven over de 3D-scène, vergelijkbaar met hoe games hun gebruikersinterface weergeven. Hiervoor moeten we enkele eenvoudige D2D-objecten maken, nog steeds in de methode 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));
}
De hoofdweergavelus bijwerken
Nu de initialisatie van het voorbeeld is voltooid, kunnen we verdergaan met de hoofdweergavelus.
// 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();
}
Oproepstroom | Parameters |
---|---|
ID3D12CommandList | |
ExecuteCommandLists | |
IDXGISwapChain1::Present1 |
Het enige wat nieuw is in onze renderlus is de RenderUI--aanroep, die D2D gebruikt om onze gebruikersinterface weer te geven. U ziet dat we al onze D3D12-opdrachtlijsten eerst uitvoeren om onze 3D-scène weer te geven en vervolgens onze gebruikersinterface weer te geven. Voordat we ingaan op RenderUI, moeten we kijken naar een wijziging in PopulateCommandLists. In andere voorbeelden plaatsen we vaak een resource-barrière in de opdrachtlijst voordat we deze sluiten om de backbuffer van de rendertarget-status over te zetten naar de presentatiestatus. In dit voorbeeld verwijderen we echter die resourcebarrière, omdat we nog steeds met D2D naar de achterbuffers moeten renderen. Houd er rekening mee dat toen we onze verpakte resources van de backbuffer creëerden, we de doeltoestand voor weergave als de status 'IN' en de presentatiestatus als de status 'OUT' hadden gespecificeerd.
RenderUI- is redelijk eenvoudig in termen van D2D-gebruik. We stellen ons renderdoel in en geven onze tekst weer. Echter, voordat we verpakte bronnen op een 11On12-apparaat gebruiken, zoals onze backbuffer-renderdoelen, moeten we de AcquireWrappedResources API aanroepen op het 11On12-apparaat. Na het renderen roepen we de --ReleaseWrappedResources---API aan op het 11On12-apparaat. Door ReleaseWrappedResources aan te roepen zorgt ervoor dat er achter de schermen een resourcebarrière optreedt waarmee de opgegeven resource wordt overgezet naar de status "OUT" die tijdens het maken is opgegeven. In ons geval is dit de huidige status. Ten slotte moeten we Flush aanroepen op de ID3D11DeviceContextom al onze opdrachten die op het 11On12-apparaat worden uitgevoerd in te dienen bij de gedeelde ID3D12CommandQueue.
// 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();
}
Het voorbeeld uitvoeren
Verwante onderwerpen