diff --git a/src/windows/CMakeLists.txt b/src/windows/CMakeLists.txt index 874f650..96097c6 100644 --- a/src/windows/CMakeLists.txt +++ b/src/windows/CMakeLists.txt @@ -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) diff --git a/src/windows/ui_interfaces/win32/Win32DxInterface.cpp b/src/windows/ui_interfaces/win32/Win32DxInterface.cpp index 9f3f516..6cc121c 100644 --- a/src/windows/ui_interfaces/win32/Win32DxInterface.cpp +++ b/src/windows/ui_interfaces/win32/Win32DxInterface.cpp @@ -7,9 +7,16 @@ #include #include +#include +#include #include #include +#include +#include + +#include + #include #include @@ -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 d3d11Device; + UINT d3d11DeviceFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; + D3D11On12CreateDevice( + mDevice.Get(), + d3d11DeviceFlags, + nullptr, + 0, + reinterpret_cast(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 dxgiDevice; + mD3d11On12Device.As(&dxgiDevice); + + mD2dFactory->CreateDevice(dxgiDevice.Get(), &mD2dDevice); + + mD2dDevice->CreateDeviceContext(deviceOptions, &mD2dDeviceContext); + + DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &mDWriteFactory); + } + + return true; } \ No newline at end of file diff --git a/src/windows/ui_interfaces/win32/Win32DxInterface.h b/src/windows/ui_interfaces/win32/Win32DxInterface.h index 691bb02..43db734 100644 --- a/src/windows/ui_interfaces/win32/Win32DxInterface.h +++ b/src/windows/ui_interfaces/win32/Win32DxInterface.h @@ -1,24 +1,60 @@ #pragma once #include +#include +#include +#include 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 mFactory; Microsoft::WRL::ComPtr mDevice; + Microsoft::WRL::ComPtr mCommandQueue; + + Microsoft::WRL::ComPtr mD3d11DeviceContext; + Microsoft::WRL::ComPtr mD3d11On12Device; + + Microsoft::WRL::ComPtr mD2dFactory; + Microsoft::WRL::ComPtr mD2dDevice; + Microsoft::WRL::ComPtr mD2dDeviceContext; + + Microsoft::WRL::ComPtr mDWriteFactory; }; \ No newline at end of file diff --git a/src/windows/ui_interfaces/win32/Win32DxWindowInterface.cpp b/src/windows/ui_interfaces/win32/Win32DxWindowInterface.cpp index 89d8241..087a017 100644 --- a/src/windows/ui_interfaces/win32/Win32DxWindowInterface.cpp +++ b/src/windows/ui_interfaces/win32/Win32DxWindowInterface.cpp @@ -10,6 +10,13 @@ #include #include +#include +#include +#include +#include + +#include + 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 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 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. diff --git a/src/windows/ui_interfaces/win32/Win32DxWindowInterface.h b/src/windows/ui_interfaces/win32/Win32DxWindowInterface.h index f1547f9..8297284 100644 --- a/src/windows/ui_interfaces/win32/Win32DxWindowInterface.h +++ b/src/windows/ui_interfaces/win32/Win32DxWindowInterface.h @@ -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 mCommandQueue; Microsoft::WRL::ComPtr mCommandAllocator; Microsoft::WRL::ComPtr mCommandList; @@ -72,6 +78,11 @@ private: UINT mRtvDescriptorSize{ 0 }; Microsoft::WRL::ComPtr mRenderTargets[FrameCount]; + Microsoft::WRL::ComPtr mWrappedBackBuffers[FrameCount]; + Microsoft::WRL::ComPtr mD2dRenderTargets[FrameCount]; + + Microsoft::WRL::ComPtr mTextBrush; + Microsoft::WRL::ComPtr mTextFormat; Microsoft::WRL::ComPtr mVertexBuffer; D3D12_VERTEX_BUFFER_VIEW mVertexBufferView{};