D2D con D3D11on12
L'esempio D3D1211on12 illustra come eseguire il rendering del contenuto D2D su D3D12 condividendo le risorse tra un dispositivo basato su 11 e un dispositivo basato su 12.
- Creare un oggetto ID3D11On12Device
- Creare una fabbrica D2D
- Creare una destinazione di rendering per D2D
- Creare oggetti di testo D2D di base
- Aggiornamento del ciclo di rendering principale
- Esegui l'esempio
- argomenti correlati
Creare un ID3D11On12Device
Il primo passaggio consiste nel creare un ID3D11On12Device dopo la creazione del ID3D12Device, che implica la creazione di un ID3D11Device di cui viene eseguito il wrapping intorno al ID3D12Device tramite l'API D3D11On12CreateDevice. Questa API accetta anche, tra gli altri parametri, un ID3D12CommandQueue in modo che il dispositivo 11On12 possa inviare i comandi. Dopo aver creato ID3D11Device, è possibile interrogare l'interfaccia ID3D11On12Device. Si tratta dell'oggetto dispositivo primario che verrà usato per configurare D2D.
Nel metodo LoadPipeline, configura i dispositivi.
// 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));
Flusso di chiamata | Parametri |
---|---|
ID3D11Device | |
D3D11On12CreateDevice |
Creare una fabbrica D2D
Ora che abbiamo un dispositivo 11On12, lo utilizziamo per creare una fabbrica e un dispositivo D2D esattamente come si farebbe normalmente con D3D11.
Aggiungere al metodo 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));
}
Creare una destinazione di rendering per D2D
D3D12 è proprietario della catena di scambio, quindi se si vuole eseguire il rendering nel buffer posteriore usando il dispositivo 11On12 (contenuto D2D), è necessario creare risorse di tipo wrapped ID3D11Resource dai buffer posteriori di tipo ID3D12Resource. Questo collega il ID3D12Resource con un'interfaccia basata su D3D11 in modo che possa essere usata con il dispositivo 11On12. Dopo aver eseguito il wrapping di una risorsa, è possibile creare una superficie di destinazione di rendering per D2D in cui eseguire il rendering, anche nel metodo 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])));
}
}
Flusso di chiamata | Parametri |
---|---|
GetDpiForWindow | Maniglia di finestra |
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 | |
CreaCommandAllocator | D3D12_COMMAND_LIST_TYPE |
Creare oggetti di testo D2D di base
Ora abbiamo a disposizione un ID3D12Device per eseguire il rendering del contenuto 3D, un ID2D1Device che è condiviso con il nostro dispositivo 12 tramite un ID3D11On12Device, che possiamo usare per eseguire il rendering del contenuto 2D, e sono entrambi configurati per il rendering sulla stessa catena di scambio. Questo esempio usa semplicemente il dispositivo D2D per eseguire il rendering del testo sulla scena 3D, in modo analogo al rendering dell'interfaccia utente dei giochi. A tale scopo, è necessario creare alcuni oggetti D2D di base, ancora nel metodo 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));
}
Aggiornamento del ciclo di rendering principale
Ora che l'inizializzazione dell'esempio è stata completata, è possibile passare al ciclo di rendering principale.
// 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();
}
Flusso di chiamata | Parametri |
---|---|
ID3D12CommandList | |
ExecuteCommandLists | |
IDXGISwapChain1::Present1 |
L'unica novità del ciclo di rendering è la chiamata renderUI, che userà D2D per eseguire il rendering dell'interfaccia utente. Si noti che tutti gli elenchi di comandi D3D12 vengono eseguiti prima per eseguire il rendering della scena 3D e quindi si esegue il rendering dell'interfaccia utente. Prima di approfondire RenderUI, è necessario esaminare una modifica a PopulateCommandLists. In altri casi, viene in genere inserita una barriera di risorse nell'elenco dei comandi prima di chiuderlo per eseguire la transizione del buffer posteriore dallo stato di destinazione di rendering allo stato di presentazione. Tuttavia, in questo esempio viene rimossa tale barriera di risorse, perché è comunque necessario eseguire il rendering nei buffer back con D2D. Si noti che quando abbiamo creato le risorse del back buffer racchiuse, abbiamo specificato lo stato di destinazione di rendering come stato "IN" e lo stato di presentazione come stato "OUT".
RenderUI è piuttosto semplice in termini di utilizzo di D2D. Impostiamo la destinazione di rendering e visualizziamo il nostro testo. Tuttavia, prima di usare qualsiasi risorsa sottoposta a wrapping su un dispositivo 11On12, ad esempio i target di rendering del back buffer, è necessario chiamare l'API AcquireWrappedResources sul dispositivo 11On12. Dopo il rendering, chiamiamo l'API ReleaseWrappedResources sul dispositivo 11On12. Chiamando ReleaseWrappedResources si incorre in una barriera di risorse dietro le quinte che eseguirà la transizione della risorsa specificata allo stato "OUT" specificato in fase di creazione. In questo caso, questo è lo stato attuale. Infine, per inviare tutti i comandi eseguiti sul dispositivo 11On12 al condiviso ID3D12CommandQueue, è necessario chiamare Flush su 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();
}
Esegui l'esempio
Argomenti correlati