Add directwrite to example.

This commit is contained in:
jmsgrogan 2023-01-04 11:28:29 +00:00
parent 92d1f24613
commit d1ec8b4f68
5 changed files with 235 additions and 21 deletions

View file

@ -64,7 +64,7 @@ else()
ui_interfaces/win32/Win32DxWindowInterface.cpp
)
list(APPEND platform_LIBS D3D12.lib D3DCompiler.lib DXGI.lib)
list(APPEND platform_LIBS D3D12.lib D3DCompiler.lib DXGI.lib Dwrite.lib D2d1.lib D3D11.lib)
find_package(DirectX-Headers REQUIRED)
list(APPEND platform_LIBS Microsoft::DirectX-Headers)

View file

@ -7,9 +7,16 @@
#include <dxgi.h>
#include <dxgi1_6.h>
#include <d3d11.h>
#include <d3d11on12.h>
#include <d3d12.h>
#include <d3d12sdklayers.h>
#include <d2d1_3.h>
#include <d2d1_1.h>
#include <dwrite.h>
#include <iostream>
#include <vector>
@ -38,16 +45,51 @@ void Win32DxInterface::getHardwareAdapter(IDXGIAdapter1** ppAdapter)
}
}
bool Win32DxInterface::isValid() const
{
return mIsValid;
}
ID3D12Device* Win32DxInterface::getDevice() const
{
return mDevice.Get();
}
ID3D11On12Device* Win32DxInterface::get11On12Device() const
{
return mD3d11On12Device.Get();
}
IDXGIFactory7* Win32DxInterface::getFactory() const
{
return mFactory.Get();
}
ID2D1Factory3* Win32DxInterface::getD2dFactory() const
{
return mD2dFactory.Get();
}
IDWriteFactory* Win32DxInterface::getDirectWriteFactory() const
{
return mDWriteFactory.Get();
}
ID2D1DeviceContext2* Win32DxInterface::getD2dContext() const
{
return mD2dDeviceContext.Get();
}
ID3D12CommandQueue* Win32DxInterface::getCommandQueue() const
{
return mCommandQueue.Get();
}
ID3D11DeviceContext* Win32DxInterface::getD3d11DeviceContext() const
{
return mD3d11DeviceContext.Get();
}
void Win32DxInterface::initialize()
{
if (!DirectX::XMVerifyCPUSupport())
@ -66,10 +108,6 @@ void Win32DxInterface::initialize()
#endif
HRESULT hr = CreateDXGIFactory(__uuidof(IDXGIFactory7), (void**)(&mFactory));
if (hr == S_OK)
{
MLOG_INFO("FACTORY IS OK");
}
IDXGIAdapter1* pAdapter{ nullptr };
getHardwareAdapter(&pAdapter);
@ -87,5 +125,50 @@ void Win32DxInterface::initialize()
MLOG_INFO("No adapter found");
return;
}
return;
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
mDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&mCommandQueue));
mIsValid = initializeD2d();
}
bool Win32DxInterface::initializeD2d()
{
Microsoft::WRL::ComPtr<ID3D11Device> d3d11Device;
UINT d3d11DeviceFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
D3D11On12CreateDevice(
mDevice.Get(),
d3d11DeviceFlags,
nullptr,
0,
reinterpret_cast<IUnknown**>(mCommandQueue.GetAddressOf()),
1,
0,
&d3d11Device,
&mD3d11DeviceContext,
nullptr
);
d3d11Device.As(&mD3d11On12Device);
// Create D2D/DWrite components.
{
D2D1_DEVICE_CONTEXT_OPTIONS deviceOptions = D2D1_DEVICE_CONTEXT_OPTIONS_NONE;
D2D1_FACTORY_OPTIONS d2dFactoryOptions = {};
D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory3), &d2dFactoryOptions, &mD2dFactory);
Microsoft::WRL::ComPtr<IDXGIDevice> dxgiDevice;
mD3d11On12Device.As(&dxgiDevice);
mD2dFactory->CreateDevice(dxgiDevice.Get(), &mD2dDevice);
mD2dDevice->CreateDeviceContext(deviceOptions, &mD2dDeviceContext);
DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &mDWriteFactory);
}
return true;
}

View file

@ -1,24 +1,60 @@
#pragma once
#include <wrl.h>
#include <dwrite.h>
#include <d2d1_3.h>
#include <d3d11on12.h>
struct ID3D12Device;
struct IDXGIFactory7;
struct IDXGIAdapter1;
struct ID3D12CommandQueue;
struct ID3D11DeviceContext;
struct ID3D11On12Device;
struct IDWriteFactory;
struct ID2D1Factory3;
struct ID2D1Device2;
struct ID2D1DeviceContext2;
class Win32DxInterface
{
public:
ID3D12Device* getDevice() const;
ID3D11On12Device* get11On12Device() const;
ID3D11DeviceContext* getD3d11DeviceContext() const;
IDXGIFactory7* getFactory() const;
ID2D1Factory3* getD2dFactory() const;
ID2D1DeviceContext2* getD2dContext() const;
ID3D12CommandQueue* getCommandQueue() const;
IDWriteFactory* getDirectWriteFactory() const;
void initialize();
ID3D12Device* getDevice() const;
IDXGIFactory7* getFactory() const;
bool isValid() const;
private:
void getHardwareAdapter(IDXGIAdapter1** ppAdapter);
bool initializeD2d();
bool mIsValid{ false };
Microsoft::WRL::ComPtr<IDXGIFactory7> mFactory;
Microsoft::WRL::ComPtr<ID3D12Device> mDevice;
Microsoft::WRL::ComPtr<ID3D12CommandQueue> mCommandQueue;
Microsoft::WRL::ComPtr<ID3D11DeviceContext> mD3d11DeviceContext;
Microsoft::WRL::ComPtr<ID3D11On12Device> mD3d11On12Device;
Microsoft::WRL::ComPtr<ID2D1Factory3> mD2dFactory;
Microsoft::WRL::ComPtr<ID2D1Device2> mD2dDevice;
Microsoft::WRL::ComPtr<ID2D1DeviceContext2> mD2dDeviceContext;
Microsoft::WRL::ComPtr<IDWriteFactory> mDWriteFactory;
};

View file

@ -10,6 +10,13 @@
#include <d3dcompiler.h>
#include <d3d12sdklayers.h>
#include <d3d11.h>
#include <d3d11on12.h>
#include <d2d1_3.h>
#include <d2d1_1.h>
#include <dwrite.h>
Win32DxWindowInterface::Win32DxWindowInterface(Win32DxInterface* dxInterface)
: mDxInterface(dxInterface)
{
@ -35,7 +42,9 @@ void Win32DxWindowInterface::onRender()
// Execute the command list.
ID3D12CommandList* ppCommandLists[] = { mCommandList.Get() };
mCommandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
mDxInterface->getCommandQueue()->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
renderD2d();
// Present the frame.
mSwapChain->Present(1, 0);
@ -75,8 +84,8 @@ void Win32DxWindowInterface::populateCommandList()
mCommandList->DrawInstanced(3, 1, 0, 0);
// Indicate that the back buffer will now be used to present.
barrier = CD3DX12_RESOURCE_BARRIER::Transition(mRenderTargets[mFrameIndex].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
mCommandList->ResourceBarrier(1, &barrier);
//barrier = CD3DX12_RESOURCE_BARRIER::Transition(mRenderTargets[mFrameIndex].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
//mCommandList->ResourceBarrier(1, &barrier);
mCommandList->Close();
}
@ -102,12 +111,6 @@ bool Win32DxWindowInterface::initialize(mt::Window* window)
void Win32DxWindowInterface::loadPipeline(mt::Window* window)
{
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
mDxInterface->getDevice()->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&mCommandQueue));
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
swapChainDesc.BufferCount = FrameCount;
@ -125,7 +128,7 @@ void Win32DxWindowInterface::loadPipeline(mt::Window* window)
Microsoft::WRL::ComPtr<IDXGISwapChain1> swapChain;
mDxInterface->getFactory()->CreateSwapChainForHwnd(
mCommandQueue.Get(), // Swap chain needs the queue so that it can force a flush on it.
mDxInterface->getCommandQueue(),
hwnd,
&swapChainDesc,
nullptr,
@ -136,6 +139,19 @@ void Win32DxWindowInterface::loadPipeline(mt::Window* window)
swapChain.As(&mSwapChain);
auto mFrameIndex = mSwapChain->GetCurrentBackBufferIndex();
// Query the desktop's dpi settings, which will be used to create
// D2D's render targets.
float dpiX{ 0.0 };
float dpiY{ 0.0 };
mDxInterface->getD2dFactory()->GetDesktopDpi(&dpiX, &dpiY);
D2D1_BITMAP_PROPERTIES1 bitmapProperties = D2D1::BitmapProperties1(
D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
dpiX,
dpiY
);
// Create descriptor heaps.
{
// Describe and create a render target view (RTV) descriptor heap.
@ -157,6 +173,25 @@ void Win32DxWindowInterface::loadPipeline(mt::Window* window)
{
mSwapChain->GetBuffer(n, IID_PPV_ARGS(&mRenderTargets[n]));
mDxInterface->getDevice()->CreateRenderTargetView(mRenderTargets[n].Get(), nullptr, rtvHandle);
D3D11_RESOURCE_FLAGS d3d11Flags = { D3D11_BIND_RENDER_TARGET };
mDxInterface->get11On12Device()->CreateWrappedResource(
mRenderTargets[n].Get(),
&d3d11Flags,
D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_PRESENT,
IID_PPV_ARGS(&mWrappedBackBuffers[n])
);
// Create a render target for D2D to draw directly to this back buffer.
Microsoft::WRL::ComPtr<IDXGISurface> surface;
mWrappedBackBuffers[n].As(&surface);
mDxInterface->getD2dContext()->CreateBitmapFromDxgiSurface(
surface.Get(),
&bitmapProperties,
&mD2dRenderTargets[n]
);
rtvHandle.Offset(1, mRtvDescriptorSize);
}
}
@ -223,6 +258,24 @@ void Win32DxWindowInterface::loadAssets()
// Create the command list.
mDxInterface->getDevice()->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, mCommandAllocator.Get(), mPipelineState.Get(), IID_PPV_ARGS(&mCommandList));
// Create D2D/DWrite objects for rendering text.
{
mDxInterface->getD2dContext()->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &mTextBrush);
mDxInterface->getDirectWriteFactory()->CreateTextFormat(
L"Verdana",
NULL,
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
50,
L"en-us",
&mTextFormat
);
mTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
mTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
}
// Command lists are created in the recording state, but there is nothing
// to record yet. The main loop expects it to be closed, so close it now.
mCommandList->Close();
@ -286,11 +339,42 @@ void Win32DxWindowInterface::loadAssets()
}
}
void Win32DxWindowInterface::renderD2d()
{
D2D1_SIZE_F rtSize = mD2dRenderTargets[mFrameIndex]->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.
mDxInterface->get11On12Device()->AcquireWrappedResources(mWrappedBackBuffers[mFrameIndex].GetAddressOf(), 1);
// Render text directly to the back buffer.
mDxInterface->getD2dContext()->SetTarget(mD2dRenderTargets[mFrameIndex].Get());
mDxInterface->getD2dContext()->BeginDraw();
mDxInterface->getD2dContext()->SetTransform(D2D1::Matrix3x2F::Identity());
mDxInterface->getD2dContext()->DrawText(
text,
_countof(text) - 1,
mTextFormat.Get(),
&textRect,
mTextBrush.Get()
);
mDxInterface->getD2dContext()->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.
mDxInterface->get11On12Device()->ReleaseWrappedResources(mWrappedBackBuffers[mFrameIndex].GetAddressOf(), 1);
// Flush to submit the 11 command list to the shared command queue.
mDxInterface->getD3d11DeviceContext()->Flush();
}
void Win32DxWindowInterface::waitForPreviousFrame()
{
// Signal and increment the fence value.
const UINT64 fence = mFenceValue;
mCommandQueue->Signal(mFence.Get(), fence);
mDxInterface->getCommandQueue()->Signal(mFence.Get(), fence);
mFenceValue++;
// Wait until the previous frame is finished.

View file

@ -23,6 +23,11 @@ struct ID3D12Fence;
struct ID3D12RootSignature;
struct ID3D12PipelineState;
struct ID3D11Resource;
struct ID2D1Bitmap1;
struct ID2D1SolidColorBrush;
struct IDWriteTextFormat;
class Win32DxWindowInterface
{
public:
@ -46,6 +51,8 @@ private:
void waitForPreviousFrame();
void destroyWindow();
void renderD2d();
static const UINT FrameCount = 2;
Win32DxInterface* mDxInterface{ nullptr };
bool mInitialized{ false };
@ -59,7 +66,6 @@ private:
CD3DX12_VIEWPORT mViewport;
CD3DX12_RECT mScissorRect;
Microsoft::WRL::ComPtr<ID3D12CommandQueue> mCommandQueue;
Microsoft::WRL::ComPtr<ID3D12CommandAllocator> mCommandAllocator;
Microsoft::WRL::ComPtr<ID3D12GraphicsCommandList> mCommandList;
@ -72,6 +78,11 @@ private:
UINT mRtvDescriptorSize{ 0 };
Microsoft::WRL::ComPtr<ID3D12Resource> mRenderTargets[FrameCount];
Microsoft::WRL::ComPtr<ID3D11Resource> mWrappedBackBuffers[FrameCount];
Microsoft::WRL::ComPtr<ID2D1Bitmap1> mD2dRenderTargets[FrameCount];
Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> mTextBrush;
Microsoft::WRL::ComPtr<IDWriteTextFormat> mTextFormat;
Microsoft::WRL::ComPtr<ID3D12Resource> mVertexBuffer;
D3D12_VERTEX_BUFFER_VIEW mVertexBufferView{};