From 55ed0e9299c8f91b8c5624f54b7bd25f8f63a07c Mon Sep 17 00:00:00 2001 From: jmsgrogan Date: Fri, 6 Jan 2023 13:03:51 +0000 Subject: [PATCH] Some directx cleaning. --- src/graphics/directx/DirectXPainter.cpp | 3 +- src/graphics/directx/DirectXPainter.h | 4 +- src/graphics/directx/DirectXTextPainter.cpp | 2 +- src/windows/CMakeLists.txt | 29 +- .../win32/Win32DxWindowInterface.cpp | 320 ------------------ .../win32/Win32DxWindowInterface.h | 91 ----- .../ui_interfaces/win32/Win32UIInterface.cpp | 5 + .../win32/directx/DirectX2dIntegration.cpp | 91 +++++ .../win32/directx/DirectX2dIntegration.h | 40 +++ .../win32/directx/DirectXBuffers.cpp | 97 ++++++ .../win32/directx/DirectXBuffers.h | 39 +++ .../win32/directx/DirectXCommandList.cpp | 37 ++ .../win32/directx/DirectXCommandList.h | 29 ++ .../win32/directx/DirectXDescriptors.cpp | 76 +++++ .../win32/directx/DirectXDescriptors.h | 29 ++ .../win32/{ => directx}/Win32DxInterface.cpp | 103 +++--- .../win32/{ => directx}/Win32DxInterface.h | 27 +- .../win32/directx/Win32DxWindowInterface.cpp | 283 ++++++++++++++++ .../win32/directx/Win32DxWindowInterface.h | 82 +++++ 19 files changed, 900 insertions(+), 487 deletions(-) delete mode 100644 src/windows/ui_interfaces/win32/Win32DxWindowInterface.cpp delete mode 100644 src/windows/ui_interfaces/win32/Win32DxWindowInterface.h create mode 100644 src/windows/ui_interfaces/win32/directx/DirectX2dIntegration.cpp create mode 100644 src/windows/ui_interfaces/win32/directx/DirectX2dIntegration.h create mode 100644 src/windows/ui_interfaces/win32/directx/DirectXBuffers.cpp create mode 100644 src/windows/ui_interfaces/win32/directx/DirectXBuffers.h create mode 100644 src/windows/ui_interfaces/win32/directx/DirectXCommandList.cpp create mode 100644 src/windows/ui_interfaces/win32/directx/DirectXCommandList.h create mode 100644 src/windows/ui_interfaces/win32/directx/DirectXDescriptors.cpp create mode 100644 src/windows/ui_interfaces/win32/directx/DirectXDescriptors.h rename src/windows/ui_interfaces/win32/{ => directx}/Win32DxInterface.cpp (58%) rename src/windows/ui_interfaces/win32/{ => directx}/Win32DxInterface.h (80%) create mode 100644 src/windows/ui_interfaces/win32/directx/Win32DxWindowInterface.cpp create mode 100644 src/windows/ui_interfaces/win32/directx/Win32DxWindowInterface.h diff --git a/src/graphics/directx/DirectXPainter.cpp b/src/graphics/directx/DirectXPainter.cpp index 54f12ab..d8b46ac 100644 --- a/src/graphics/directx/DirectXPainter.cpp +++ b/src/graphics/directx/DirectXPainter.cpp @@ -21,7 +21,6 @@ #include "File.h" #include -#include #include @@ -62,7 +61,7 @@ void DirectXPainter::paint() { } -void DirectXPainter::paintBackground(const CD3DX12_CPU_DESCRIPTOR_HANDLE& rtvHandle, ID3D12GraphicsCommandList* commandList) +void DirectXPainter::paintBackground(const D3D12_CPU_DESCRIPTOR_HANDLE& rtvHandle, ID3D12GraphicsCommandList* commandList) { const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f }; commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr); diff --git a/src/graphics/directx/DirectXPainter.h b/src/graphics/directx/DirectXPainter.h index ea455f2..7933a95 100644 --- a/src/graphics/directx/DirectXPainter.h +++ b/src/graphics/directx/DirectXPainter.h @@ -13,8 +13,6 @@ class DrawingContext; class DirectXMeshPainter; class DirectXTextPainter; -struct CD3DX12_CPU_DESCRIPTOR_HANDLE; - class DirectXPainter : public AbstractPainter { public: @@ -28,7 +26,7 @@ public: void initializeText(ID2D1DeviceContext2* d2dContext, IDWriteFactory* directWriteFactory); - void paintBackground(const CD3DX12_CPU_DESCRIPTOR_HANDLE& rtvHandle, ID3D12GraphicsCommandList* commandList); + void paintBackground(const D3D12_CPU_DESCRIPTOR_HANDLE& rtvHandle, ID3D12GraphicsCommandList* commandList); void paintMesh(ID3D12GraphicsCommandList* commandList); diff --git a/src/graphics/directx/DirectXTextPainter.cpp b/src/graphics/directx/DirectXTextPainter.cpp index 0155bf1..f1c6bab 100644 --- a/src/graphics/directx/DirectXTextPainter.cpp +++ b/src/graphics/directx/DirectXTextPainter.cpp @@ -54,7 +54,7 @@ void DirectXTextPainter::updateTextFormat(IDWriteFactory* directWriteFactory, un void DirectXTextPainter::paint(SceneText* text, DrawingContext* context, ID2D1DeviceContext2* d2dContext, IDWriteFactory* directWriteFactory) { const auto location = text->getTransform().getLocation(); - D2D1_RECT_F textRect = D2D1::RectF(location.getX(), location.getY(), location.getX() + 100, location.getY() + 100); + D2D1_RECT_F textRect = D2D1::RectF(location.getX(), location.getY(), location.getX() + 200, location.getY() + 100); updateTextFormat(directWriteFactory, text->getTextData().mFont.getSize()); diff --git a/src/windows/CMakeLists.txt b/src/windows/CMakeLists.txt index 96097c6..53d71cf 100644 --- a/src/windows/CMakeLists.txt +++ b/src/windows/CMakeLists.txt @@ -58,10 +58,18 @@ else() ui_interfaces/win32/Win32WindowInterface.cpp ui_interfaces/win32/Win32Window.h ui_interfaces/win32/Win32Window.cpp - ui_interfaces/win32/Win32DxInterface.h - ui_interfaces/win32/Win32DxInterface.cpp - ui_interfaces/win32/Win32DxWindowInterface.h - ui_interfaces/win32/Win32DxWindowInterface.cpp + ui_interfaces/win32/directx/Win32DxInterface.h + ui_interfaces/win32/directx/Win32DxInterface.cpp + ui_interfaces/win32/directx/Win32DxWindowInterface.h + ui_interfaces/win32/directx/Win32DxWindowInterface.cpp + ui_interfaces/win32/directx/DirectXDescriptors.h + ui_interfaces/win32/directx/DirectXDescriptors.cpp + ui_interfaces/win32/directx/DirectX2dIntegration.h + ui_interfaces/win32/directx/DirectX2dIntegration.cpp + ui_interfaces/win32/directx/DirectXBuffers.h + ui_interfaces/win32/directx/DirectXBuffers.cpp + ui_interfaces/win32/directx/DirectXCommandList.h + ui_interfaces/win32/directx/DirectXCommandList.cpp ) list(APPEND platform_LIBS D3D12.lib D3DCompiler.lib DXGI.lib Dwrite.lib D2d1.lib D3D11.lib) @@ -81,12 +89,13 @@ list(APPEND windows_LIB_INCLUDES add_library(windows SHARED ${windows_LIB_INCLUDES} ${platform_INCLUDES}) target_include_directories(windows PUBLIC - "${CMAKE_CURRENT_SOURCE_DIR}" - "${CMAKE_CURRENT_SOURCE_DIR}/managers" - "${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces" - "${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces/x11" - "${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces/wayland" - "${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces/win32" + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/managers + ${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces + ${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces/x11 + ${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces/wayland + ${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces/win32 + ${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces/win32/directx ${WAYLAND_INCLUDE_DIRS} ${X11_INCLUDE_DIRS} ) diff --git a/src/windows/ui_interfaces/win32/Win32DxWindowInterface.cpp b/src/windows/ui_interfaces/win32/Win32DxWindowInterface.cpp deleted file mode 100644 index fbbce69..0000000 --- a/src/windows/ui_interfaces/win32/Win32DxWindowInterface.cpp +++ /dev/null @@ -1,320 +0,0 @@ -#include "Win32DxWindowInterface.h" - -#include "Win32DxInterface.h" -#include "Win32Window.h" -#include "Window.h" -#include "Widget.h" -#include "FileLogger.h" - -#include "DrawingContext.h" -#include "DirectXPainter.h" -#include "DirectXMeshPainter.h" -#include "DirectXTextPainter.h" -#include "DirectXShaderProgram.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -Win32DxWindowInterface::Win32DxWindowInterface(mt::Window* window, Win32DxInterface* dxInterface) - : mWindow(window), - mDxInterface(dxInterface) -{ - -} - -Win32DxWindowInterface::~Win32DxWindowInterface() -{ - -} - -void Win32DxWindowInterface::destroyWindow() -{ - waitForPreviousFrame(); - - ::CloseHandle(mFenceEvent); -} - -void Win32DxWindowInterface::onRender() -{ - if (!mIsValid) - { - return; - } - - // Record all the commands we need to render the scene into the command list. - populateCommandList(); - - // Execute the command list. - ID3D12CommandList* ppCommandLists[] = { mCommandList.Get() }; - mDxInterface->getCommandQueue()->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); - - renderD2d(); - - // Present the frame. - mSwapChain->Present(1, 0); - - waitForPreviousFrame(); -} - -void Win32DxWindowInterface::populateCommandList() -{ - auto painter = dynamic_cast(mWindow->getDrawingContent()->getPainter()); - - // Command list allocators can only be reset when the associated - // command lists have finished execution on the GPU; apps should use - // fences to determine GPU execution progress. - mCommandAllocator->Reset(); - - // However, when ExecuteCommandList() is called on a particular command - // list, that command list can then be reset at any time and must be before - // re-recording. - mCommandList->Reset(mCommandAllocator.Get(), painter->getMeshPainter()->getPipelineState()); - - // Set necessary state. - mCommandList->SetGraphicsRootSignature(painter->getMeshPainter()->getRootSignature()); - mCommandList->RSSetViewports(1, &mViewport); - mCommandList->RSSetScissorRects(1, &mScissorRect); - - // Indicate that the back buffer will be used as a render target. - auto barrier = CD3DX12_RESOURCE_BARRIER::Transition(mRenderTargets[mFrameIndex].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET); - mCommandList->ResourceBarrier(1, &barrier); - - CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(mRtvHeap->GetCPUDescriptorHandleForHeapStart(), static_cast(mFrameIndex), mRtvDescriptorSize); - mCommandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr); - - painter->paintBackground(rtvHandle, mCommandList.Get()); - painter->paintMesh(mCommandList.Get()); - - // 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); - - mCommandList->Close(); -} - -void Win32DxWindowInterface::renderD2d() -{ - // 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()); - - auto painter = dynamic_cast(mWindow->getDrawingContent()->getPainter()); - painter->paintText(mDxInterface->getD2dContext(), mDxInterface->getDirectWriteFactory()); - - // 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(); -} - -bool Win32DxWindowInterface::initialize() -{ - if (mInitialized) - { - return true; - } - mInitialized = true; - - const auto width = mWindow->getWidth(); - const auto height = mWindow->getHeight(); - mViewport = CD3DX12_VIEWPORT(0.0f, 0.0f, static_cast(width), static_cast(height)); - mScissorRect = CD3DX12_RECT(0, 0, width, height); - - if (!loadPipeline()) - { - return false; - } - - if (!loadAssets()) - { - return false; - } - - mIsValid = true; - return true; -} - -bool Win32DxWindowInterface::loadPipeline() -{ - if (!setupSwapChain()) - { - return false; - } - - setupDescriptorHeaps(); - - setupFrameResources(); - - mDxInterface->getDevice()->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&mCommandAllocator)); - - return true; -} - -bool Win32DxWindowInterface::setupSwapChain() -{ - const auto width = mWindow->getWidth(); - const auto height = mWindow->getHeight(); - const auto hwnd = dynamic_cast(mWindow->getPlatformWindow())->getHandle(); - - DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {}; - swapChainDesc.BufferCount = FrameCount; - swapChainDesc.Width = width; - swapChainDesc.Height = height; - swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; - swapChainDesc.SampleDesc.Count = 1; - - auto command_queue = mDxInterface->getCommandQueue(); - Microsoft::WRL::ComPtr swapChain; - const auto hr = mDxInterface->getFactory()->CreateSwapChainForHwnd(command_queue, hwnd, &swapChainDesc, nullptr, nullptr, &swapChain); - if (!SUCCEEDED(hr)) - { - MLOG_ERROR("Failed to create swap chain for hwnd: " << hwnd); - return false; - } - swapChain.As(&mSwapChain); - - // Prevent fullscreen toggle - mDxInterface->getFactory()->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER); - - // Update index for backbuffer - mFrameIndex = mSwapChain->GetCurrentBackBufferIndex(); - return true; -} - -void Win32DxWindowInterface::setupDescriptorHeaps() -{ - D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {}; - rtvHeapDesc.NumDescriptors = FrameCount; - rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; - rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; - mDxInterface->getDevice()->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&mRtvHeap)); - - D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {}; - srvHeapDesc.NumDescriptors = 1; - srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; - srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; - mDxInterface->getDevice()->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&mSrvHeap)); - - D3D12_DESCRIPTOR_HEAP_DESC cbvHeapDesc = {}; - cbvHeapDesc.NumDescriptors = 1; - cbvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; - cbvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; - mDxInterface->getDevice()->CreateDescriptorHeap(&cbvHeapDesc, IID_PPV_ARGS(&mCbvHeap)); - - mRtvDescriptorSize = mDxInterface->getDevice()->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); -} - -void Win32DxWindowInterface::setupFrameResources() -{ - CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(mRtvHeap->GetCPUDescriptorHandleForHeapStart()); - - 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 - ); - - for (UINT n = 0; n < FrameCount; n++) - { - setupFrameResource(n, rtvHandle, bitmapProperties); - } -} - -void Win32DxWindowInterface::setupFrameResource(UINT idx, CD3DX12_CPU_DESCRIPTOR_HANDLE& descriptorHandle, const D2D1_BITMAP_PROPERTIES1& bitmapProps) -{ - mSwapChain->GetBuffer(idx, IID_PPV_ARGS(&mRenderTargets[idx])); - mDxInterface->getDevice()->CreateRenderTargetView(mRenderTargets[idx].Get(), nullptr, descriptorHandle); - - setupFrameD2DResource(idx, bitmapProps); - - descriptorHandle.Offset(1, mRtvDescriptorSize); -} - -void Win32DxWindowInterface::setupFrameD2DResource(UINT idx, const D2D1_BITMAP_PROPERTIES1& bitmapProps) -{ - D3D11_RESOURCE_FLAGS d3d11Flags = { D3D11_BIND_RENDER_TARGET }; - mDxInterface->get11On12Device()->CreateWrappedResource(mRenderTargets[idx].Get(),&d3d11Flags, - D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT, IID_PPV_ARGS(&mWrappedBackBuffers[idx])); - - Microsoft::WRL::ComPtr surface; - mWrappedBackBuffers[idx].As(&surface); - mDxInterface->getD2dContext()->CreateBitmapFromDxgiSurface(surface.Get(), &bitmapProps, &mD2dRenderTargets[idx]); -} - -bool Win32DxWindowInterface::loadAssets() -{ - auto painter = dynamic_cast(mWindow->getDrawingContent()->getPainter()); - - painter->initializeMesh(mDxInterface->getDevice()); - - // Create the command list. - mDxInterface->getDevice()->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, mCommandAllocator.Get(), - painter->getMeshPainter()->getPipelineState(), IID_PPV_ARGS(&mCommandList)); - - // Create D2D/DWrite objects for rendering text. - painter->initializeText(mDxInterface->getD2dContext(), mDxInterface->getDirectWriteFactory()); - - // 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(); - - painter->updateMesh(mDxInterface->getDevice()); - - createSyncObjects(); - return true; -} - -void Win32DxWindowInterface::createSyncObjects() -{ - mDxInterface->getDevice()->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&mFence)); - mFenceValue = 1; - - // Create an event handle to use for frame synchronization. - mFenceEvent = ::CreateEvent(nullptr, FALSE, FALSE, nullptr); - if (mFenceEvent == nullptr) - { - //ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError())); - } - - // Wait for the command list to execute; we are reusing the same command - // list in our main loop but for now, we just want to wait for setup to - // complete before continuing. - waitForPreviousFrame(); -} - -void Win32DxWindowInterface::waitForPreviousFrame() -{ - // Signal and increment the fence value. - const UINT64 fence = mFenceValue; - mDxInterface->getCommandQueue()->Signal(mFence.Get(), fence); - mFenceValue++; - - // Wait until the previous frame is finished. - if (mFence->GetCompletedValue() < fence) - { - mFence->SetEventOnCompletion(fence, mFenceEvent); - ::WaitForSingleObject(mFenceEvent, INFINITE); - } - mFrameIndex = mSwapChain->GetCurrentBackBufferIndex(); -} \ No newline at end of file diff --git a/src/windows/ui_interfaces/win32/Win32DxWindowInterface.h b/src/windows/ui_interfaces/win32/Win32DxWindowInterface.h deleted file mode 100644 index cbf1a3c..0000000 --- a/src/windows/ui_interfaces/win32/Win32DxWindowInterface.h +++ /dev/null @@ -1,91 +0,0 @@ -#pragma once - -#include - -#include -#include -#include - -class Win32DxInterface; -namespace mt -{ - class Window; -} - -struct ID3D12CommandQueue; -struct ID3D12CommandAllocator; -struct ID3D12GraphicsCommandList; -struct IDXGISwapChain4; -struct ID3D12DescriptorHeap; -struct ID3D12Resource; -struct ID3D12Fence; -struct ID3D12RootSignature; -struct ID3D12PipelineState; - -struct ID3D11Resource; -struct ID2D1Bitmap1; -struct D2D1_BITMAP_PROPERTIES1; -struct CD3DX12_CPU_DESCRIPTOR_HANDLE; - -class Win32DxWindowInterface -{ -public: - Win32DxWindowInterface(mt::Window* window, Win32DxInterface* dxInterface); - - ~Win32DxWindowInterface(); - - bool initialize(); - - void onRender(); - -private: - bool loadPipeline(); - bool loadAssets(); - - void populateCommandList(); - void waitForPreviousFrame(); - void destroyWindow(); - - void renderD2d(); - - bool setupSwapChain(); - void setupDescriptorHeaps(); - - void setupFrameResources(); - void setupFrameResource(UINT idx, CD3DX12_CPU_DESCRIPTOR_HANDLE& descriptorHandle, const D2D1_BITMAP_PROPERTIES1& bitmapProps); - void setupFrameD2DResource(UINT idx, const D2D1_BITMAP_PROPERTIES1& bitmapProps); - - void createSyncObjects(); - - static const UINT FrameCount = 2; - Win32DxInterface* mDxInterface{ nullptr }; - bool mInitialized{ false }; - bool mIsValid{ false }; - - mt::Window* mWindow{ nullptr }; - CD3DX12_VIEWPORT mViewport; - CD3DX12_RECT mScissorRect; - - Microsoft::WRL::ComPtr mCommandAllocator; - Microsoft::WRL::ComPtr mCommandList; - - Microsoft::WRL::ComPtr mSwapChain; - - Microsoft::WRL::ComPtr mRtvHeap; - Microsoft::WRL::ComPtr mSrvHeap; - Microsoft::WRL::ComPtr mCbvHeap; - UINT mRtvDescriptorSize{ 0 }; - - Microsoft::WRL::ComPtr mRenderTargets[FrameCount]; - Microsoft::WRL::ComPtr mWrappedBackBuffers[FrameCount]; - Microsoft::WRL::ComPtr mD2dRenderTargets[FrameCount]; - - Microsoft::WRL::ComPtr mFence; - uint64_t mFenceValue = 0; - uint64_t mFrameFenceValues[FrameCount] = {}; - HANDLE mFenceEvent{}; - - uint64_t mFrameIndex{ 0 }; -}; - -using XcbGlWindowInterfacePtr = std::unique_ptr; \ No newline at end of file diff --git a/src/windows/ui_interfaces/win32/Win32UIInterface.cpp b/src/windows/ui_interfaces/win32/Win32UIInterface.cpp index 8fb090d..bd949b4 100644 --- a/src/windows/ui_interfaces/win32/Win32UIInterface.cpp +++ b/src/windows/ui_interfaces/win32/Win32UIInterface.cpp @@ -39,6 +39,11 @@ void Win32UIInterface::loop() MSG msg = { }; while (::GetMessage(&msg, NULL, 0, 0)) { + if (msg.message == WM_QUIT) + { + break; + } + ::TranslateMessage(&msg); ::DispatchMessage(&msg); } diff --git a/src/windows/ui_interfaces/win32/directx/DirectX2dIntegration.cpp b/src/windows/ui_interfaces/win32/directx/DirectX2dIntegration.cpp new file mode 100644 index 0000000..a1c711d --- /dev/null +++ b/src/windows/ui_interfaces/win32/directx/DirectX2dIntegration.cpp @@ -0,0 +1,91 @@ +#include "DirectX2dIntegration.h" + +#include "Window.h" +#include "Widget.h" +#include "DirectXPainter.h" +#include "DrawingContext.h" + +#include "Win32DxInterface.h" + +#include +#include +#include +#include + +DirectX2dIntegration::DirectX2dIntegration(mt::Window* window, Win32DxInterface* dxInterface, UINT frameCount) + : mDxInterface(dxInterface), + mWindow(window), + mFrameCount(frameCount) +{ + +} + +ID3D11Resource* const* DirectX2dIntegration::getD11on12WrappedBackBuffer() const +{ + return mWrappedBackBuffers[mFrameIndex].GetAddressOf(); +} + +ID2D1Bitmap1* DirectX2dIntegration::getD2dRenderTarget() const +{ + return mD2dRenderTargets[mFrameIndex].Get(); +} + +void DirectX2dIntegration::render() +{ + // Acquire our wrapped render target resource for the current back buffer. + mDxInterface->get11On12Device()->AcquireWrappedResources(getD11on12WrappedBackBuffer(), 1); + + // Render text directly to the back buffer. + mDxInterface->getD2dContext()->SetTarget(getD2dRenderTarget()); + + auto painter = dynamic_cast(mWindow->getDrawingContent()->getPainter()); + painter->paintText(mDxInterface->getD2dContext(), mDxInterface->getDirectWriteFactory()); + + // 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(getD11on12WrappedBackBuffer(), 1); + + // Flush to submit the 11 command list to the shared command queue. + mDxInterface->getD3d11DeviceContext()->Flush(); +} + +void DirectX2dIntegration::clearBuffers() +{ + for (auto& buffer : mWrappedBackBuffers) + { + buffer.Reset(); + } + mWrappedBackBuffers.clear(); + + for (auto& buffer : mD2dRenderTargets) + { + buffer.Reset(); + } + mD2dRenderTargets.clear(); +} + +void DirectX2dIntegration::wrapBuffer(ID3D12Resource* renderTarget) +{ + mWrappedBackBuffers.push_back(Microsoft::WRL::ComPtr()); + + D3D11_RESOURCE_FLAGS d3d11Flags = { D3D11_BIND_RENDER_TARGET }; + mDxInterface->get11On12Device()->CreateWrappedResource(renderTarget, &d3d11Flags, + D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT, IID_PPV_ARGS(&mWrappedBackBuffers[mWrappedBackBuffers.size()-1])); + + float dpiX{ 0.0 }; + float dpiY{ 0.0 }; + mDxInterface->getD2dFactory()->GetDesktopDpi(&dpiX, &dpiY); + const auto pixel_format = D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED); + const auto bitmap_props = D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW, pixel_format, dpiX, dpiY); + + mD2dRenderTargets.push_back(Microsoft::WRL::ComPtr()); + Microsoft::WRL::ComPtr surface; + mWrappedBackBuffers[mWrappedBackBuffers.size() - 1].As(&surface); + mDxInterface->getD2dContext()->CreateBitmapFromDxgiSurface(surface.Get(), &bitmap_props, &mD2dRenderTargets[mD2dRenderTargets.size()-1]); +} + +void DirectX2dIntegration::updateBackbufferIndex(UINT idx) +{ + mFrameIndex = idx; +} diff --git a/src/windows/ui_interfaces/win32/directx/DirectX2dIntegration.h b/src/windows/ui_interfaces/win32/directx/DirectX2dIntegration.h new file mode 100644 index 0000000..5313c95 --- /dev/null +++ b/src/windows/ui_interfaces/win32/directx/DirectX2dIntegration.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include +#include + +class Win32DxInterface; +namespace mt +{ + class Window; +} +struct ID3D12Resource; +struct ID3D11Resource; +struct ID2D1Bitmap1; + +class DirectX2dIntegration +{ +public: + DirectX2dIntegration(mt::Window* window, Win32DxInterface* dxInterface, UINT frameCount); + + void clearBuffers(); + + void render(); + + void updateBackbufferIndex(UINT idx); + + void wrapBuffer(ID3D12Resource* referenceBuffer); + +private: + ID3D11Resource* const* getD11on12WrappedBackBuffer() const; + ID2D1Bitmap1* getD2dRenderTarget() const; + + Win32DxInterface* mDxInterface{ nullptr }; + mt::Window* mWindow{ nullptr }; + + UINT mFrameCount{ 2 }; + UINT mFrameIndex{ 0 }; + std::vector > mWrappedBackBuffers; + std::vector > mD2dRenderTargets; +}; \ No newline at end of file diff --git a/src/windows/ui_interfaces/win32/directx/DirectXBuffers.cpp b/src/windows/ui_interfaces/win32/directx/DirectXBuffers.cpp new file mode 100644 index 0000000..e8fe2cf --- /dev/null +++ b/src/windows/ui_interfaces/win32/directx/DirectXBuffers.cpp @@ -0,0 +1,97 @@ +#include "DirectXBuffers.h" + +#include "DirectXDescriptors.h" + +#include +#include +#include +#include + +DirectXBuffers::DirectXBuffers(UINT frameCount) + : mFrameCount(frameCount) +{ + +} + +void DirectXBuffers::clear() +{ + for (auto& buffer : mBackBuffers) + { + buffer.Reset(); + } + mBackBuffers.clear(); + mDepthStencilBuffer.Reset(); +} + +UINT DirectXBuffers::getCurrentBackBufferIndex() const +{ + return mBackBufferIndex; +} + +ID3D12Resource* DirectXBuffers::getCurrentBackBuffer() const +{ + return mBackBuffers[mBackBufferIndex].Get(); +} + +ID3D12Resource* DirectXBuffers::getBackBuffer(UINT index) const +{ + return mBackBuffers[index].Get(); +} + +ID3D12Resource* DirectXBuffers::getDepthStencilBuffer() const +{ + return mDepthStencilBuffer.Get(); +} + +void DirectXBuffers::updateBackbufferIndex(UINT index) +{ + mBackBufferIndex = index; +} + +void DirectXBuffers::setupBackBuffers(ID3D12Device* device, IDXGISwapChain4* swapChain, DirectXDescriptors* descriptors) +{ + CD3DX12_CPU_DESCRIPTOR_HANDLE rtv_heap_handle(descriptors->getRtvHandle()); + for (UINT i = 0; i < mFrameCount; i++) + { + mBackBuffers.push_back(Microsoft::WRL::ComPtr()); + + swapChain->GetBuffer(i, IID_PPV_ARGS(&mBackBuffers[mBackBuffers.size()-1])); + device->CreateRenderTargetView(mBackBuffers[mBackBuffers.size() - 1].Get(), nullptr, rtv_heap_handle); + rtv_heap_handle.Offset(1, descriptors->getRtvDescriptorSize()); + } +} + +void DirectXBuffers::setupDepthStencilHeap(ID3D12Device* device, unsigned width, unsigned height) +{ + D3D12_RESOURCE_DESC depthStencilDesc; + depthStencilDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; + depthStencilDesc.Alignment = 0; + depthStencilDesc.Width = width; + depthStencilDesc.Height = height; + depthStencilDesc.DepthOrArraySize = 1; + depthStencilDesc.MipLevels = 1; + depthStencilDesc.Format = DXGI_FORMAT_R24G8_TYPELESS; + depthStencilDesc.SampleDesc.Count = 1; + depthStencilDesc.SampleDesc.Quality = 0; + depthStencilDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; + depthStencilDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; + + D3D12_CLEAR_VALUE optClear; + optClear.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; + optClear.DepthStencil.Depth = 1.0f; + optClear.DepthStencil.Stencil = 0; + + auto props = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT); + device->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, + &depthStencilDesc, D3D12_RESOURCE_STATE_COMMON, &optClear, IID_PPV_ARGS(mDepthStencilBuffer.GetAddressOf())); +} + +void DirectXBuffers::setupDepthStencilView(ID3D12Device* device, DirectXDescriptors* descriptors) +{ + D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Flags = D3D12_DSV_FLAG_NONE; + dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; + dsvDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; + dsvDesc.Texture2D.MipSlice = 0; + device->CreateDepthStencilView(mDepthStencilBuffer.Get(), &dsvDesc, descriptors->getDsvHandle()); +} \ No newline at end of file diff --git a/src/windows/ui_interfaces/win32/directx/DirectXBuffers.h b/src/windows/ui_interfaces/win32/directx/DirectXBuffers.h new file mode 100644 index 0000000..71d3dd8 --- /dev/null +++ b/src/windows/ui_interfaces/win32/directx/DirectXBuffers.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include + +class DirectXDescriptors; +struct ID3D12Resource; +struct ID3D12Device; +struct IDXGISwapChain4; + +class DirectXBuffers +{ +public: + DirectXBuffers(UINT frameCount); + + void clear(); + + UINT getCurrentBackBufferIndex() const; + + ID3D12Resource* getCurrentBackBuffer() const; + + ID3D12Resource* getBackBuffer(UINT index) const; + + ID3D12Resource* getDepthStencilBuffer() const; + + void setupBackBuffers(ID3D12Device* device, IDXGISwapChain4* swapChain, DirectXDescriptors* descriptors); + + void setupDepthStencilHeap(ID3D12Device* device, unsigned width, unsigned height); + + void setupDepthStencilView(ID3D12Device* device, DirectXDescriptors* descriptors); + + void updateBackbufferIndex(UINT index); + +private: + UINT mFrameCount{ 2 }; + UINT mBackBufferIndex{ 0 }; + std::vector > mBackBuffers; + Microsoft::WRL::ComPtr mDepthStencilBuffer; +}; \ No newline at end of file diff --git a/src/windows/ui_interfaces/win32/directx/DirectXCommandList.cpp b/src/windows/ui_interfaces/win32/directx/DirectXCommandList.cpp new file mode 100644 index 0000000..01c3e04 --- /dev/null +++ b/src/windows/ui_interfaces/win32/directx/DirectXCommandList.cpp @@ -0,0 +1,37 @@ +#include "DirectXCommandList.h" + +#include + +void DirectXCommandList::close() +{ + mCommandList->Close(); +} + +void DirectXCommandList::create(ID3D12Device* device, ID3D12PipelineState* pso) +{ + device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&mCommandAllocator)); + device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, mCommandAllocator.Get(), pso, IID_PPV_ARGS(&mCommandList)); + mCommandList->Close(); +} + +ID3D12GraphicsCommandList* DirectXCommandList::get() const +{ + return mCommandList.Get(); +} + +void DirectXCommandList::execute(ID3D12CommandQueue* queue) +{ + ID3D12CommandList* ppCommandLists[] = { mCommandList.Get() }; + queue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); +} + +void DirectXCommandList::reset(ID3D12PipelineState* pso) +{ + mCommandList->Reset(mCommandAllocator.Get(), pso); +} + +void DirectXCommandList::resetAllocator() +{ + mCommandAllocator.Reset(); +} + diff --git a/src/windows/ui_interfaces/win32/directx/DirectXCommandList.h b/src/windows/ui_interfaces/win32/directx/DirectXCommandList.h new file mode 100644 index 0000000..fb855b2 --- /dev/null +++ b/src/windows/ui_interfaces/win32/directx/DirectXCommandList.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +struct ID3D12CommandAllocator; +struct ID3D12GraphicsCommandList; +struct ID3D12PipelineState; +struct ID3D12CommandQueue; +struct ID3D12Device; + +class DirectXCommandList +{ +public: + void close(); + + void create(ID3D12Device* device, ID3D12PipelineState* pso); + + ID3D12GraphicsCommandList* get() const; + + void execute(ID3D12CommandQueue* queue); + + void resetAllocator(); + + void reset(ID3D12PipelineState* pso); + +private: + Microsoft::WRL::ComPtr mCommandAllocator; + Microsoft::WRL::ComPtr mCommandList; +}; \ No newline at end of file diff --git a/src/windows/ui_interfaces/win32/directx/DirectXDescriptors.cpp b/src/windows/ui_interfaces/win32/directx/DirectXDescriptors.cpp new file mode 100644 index 0000000..2c84db8 --- /dev/null +++ b/src/windows/ui_interfaces/win32/directx/DirectXDescriptors.cpp @@ -0,0 +1,76 @@ +#include "DirectXDescriptors.h" + +#include + +UINT DirectXDescriptors::getRtvDescriptorSize() const +{ + return mRtvDescriptorSize; +} + +D3D12_CPU_DESCRIPTOR_HANDLE DirectXDescriptors::getRtvHandle(int index) const +{ + if (index == -1) + { + return CD3DX12_CPU_DESCRIPTOR_HANDLE(mRtvHeap->GetCPUDescriptorHandleForHeapStart()); + } + else + { + return CD3DX12_CPU_DESCRIPTOR_HANDLE(mRtvHeap->GetCPUDescriptorHandleForHeapStart(), index, mRtvDescriptorSize); + } +} + +D3D12_CPU_DESCRIPTOR_HANDLE DirectXDescriptors::getDsvHandle() const +{ + return mDsvHeap->GetCPUDescriptorHandleForHeapStart(); +} + +void DirectXDescriptors::updateDescriptorSizes(ID3D12Device* device) +{ + mRtvDescriptorSize = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); + mDsvDescriptorSize = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV); + mCbvSrvDescriptorSize = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); +} + +void DirectXDescriptors::setupDefaultDescriptorHeaps(ID3D12Device* device, unsigned numFrames) +{ + updateDescriptorSizes(device); + setupRtvDescriptorHeap(device, numFrames); + setupDsvDescriptorHeap(device); +} + +void DirectXDescriptors::setupRtvDescriptorHeap(ID3D12Device* device, unsigned numFrames) +{ + D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {}; + rtvHeapDesc.NumDescriptors = numFrames; + rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; + rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; + device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&mRtvHeap)); +} + +void DirectXDescriptors::setupDsvDescriptorHeap(ID3D12Device* device) +{ + D3D12_DESCRIPTOR_HEAP_DESC dsvHeapDesc = {}; + dsvHeapDesc.NumDescriptors = 1; + dsvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; + dsvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; + dsvHeapDesc.NodeMask = 0; + device->CreateDescriptorHeap(&dsvHeapDesc, IID_PPV_ARGS(&mDsvHeap)); +} + +void DirectXDescriptors::setupSrvDescriptorHeap(ID3D12Device* device) +{ + D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {}; + srvHeapDesc.NumDescriptors = 1; + srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + device->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&mSrvHeap)); +} + +void DirectXDescriptors::setupCbvDescriptorHeap(ID3D12Device* device) +{ + D3D12_DESCRIPTOR_HEAP_DESC cbvHeapDesc = {}; + cbvHeapDesc.NumDescriptors = 1; + cbvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + cbvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + device->CreateDescriptorHeap(&cbvHeapDesc, IID_PPV_ARGS(&mCbvHeap)); +} \ No newline at end of file diff --git a/src/windows/ui_interfaces/win32/directx/DirectXDescriptors.h b/src/windows/ui_interfaces/win32/directx/DirectXDescriptors.h new file mode 100644 index 0000000..132ceec --- /dev/null +++ b/src/windows/ui_interfaces/win32/directx/DirectXDescriptors.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include + +class DirectXDescriptors +{ +public: + UINT getRtvDescriptorSize() const; + D3D12_CPU_DESCRIPTOR_HANDLE getRtvHandle(int index = -1) const; + D3D12_CPU_DESCRIPTOR_HANDLE getDsvHandle() const; + + void setupDefaultDescriptorHeaps(ID3D12Device* device, unsigned numFrames = 2); +private: + void updateDescriptorSizes(ID3D12Device* device); + void setupRtvDescriptorHeap(ID3D12Device* device, unsigned numFrames); + void setupDsvDescriptorHeap(ID3D12Device* device); + void setupSrvDescriptorHeap(ID3D12Device* device); + void setupCbvDescriptorHeap(ID3D12Device* device); + + UINT mRtvDescriptorSize{ 0 }; + UINT mDsvDescriptorSize{ 0 }; + UINT mCbvSrvDescriptorSize{ 0 }; + + Microsoft::WRL::ComPtr mRtvHeap; + Microsoft::WRL::ComPtr mDsvHeap; + Microsoft::WRL::ComPtr mSrvHeap; + Microsoft::WRL::ComPtr mCbvHeap; +}; \ No newline at end of file diff --git a/src/windows/ui_interfaces/win32/Win32DxInterface.cpp b/src/windows/ui_interfaces/win32/directx/Win32DxInterface.cpp similarity index 58% rename from src/windows/ui_interfaces/win32/Win32DxInterface.cpp rename to src/windows/ui_interfaces/win32/directx/Win32DxInterface.cpp index ef581ce..52b5f0d 100644 --- a/src/windows/ui_interfaces/win32/Win32DxInterface.cpp +++ b/src/windows/ui_interfaces/win32/directx/Win32DxInterface.cpp @@ -2,9 +2,6 @@ #include "FileLogger.h" -#include -#include - #include #include #include @@ -17,25 +14,17 @@ #include -#include -#include - -#include -#include - void Win32DxInterface::getHardwareAdapter(IDXGIAdapter1** ppAdapter) { *ppAdapter = nullptr; for (UINT adapterIndex = 0; ; ++adapterIndex) { IDXGIAdapter1* pAdapter = nullptr; - if (DXGI_ERROR_NOT_FOUND == mFactory->EnumAdapters1(adapterIndex, &pAdapter)) + if (mDxgiFactory->EnumAdapters1(adapterIndex, &pAdapter) == DXGI_ERROR_NOT_FOUND) { break; } - - // Check to see if the adapter supports Direct3D 12, but don't create the actual device yet. - if (SUCCEEDED(D3D12CreateDevice(pAdapter, D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr))) + if (SUCCEEDED(::D3D12CreateDevice(pAdapter, D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr))) { *ppAdapter = pAdapter; return; @@ -49,9 +38,9 @@ bool Win32DxInterface::isValid() const return mIsValid; } -ID3D12Device* Win32DxInterface::getDevice() const +ID3D12Device* Win32DxInterface::getD3dDevice() const { - return mDevice.Get(); + return mD3dDevice.Get(); } ID3D11On12Device* Win32DxInterface::get11On12Device() const @@ -59,9 +48,9 @@ ID3D11On12Device* Win32DxInterface::get11On12Device() const return mD3d11On12Device.Get(); } -IDXGIFactory7* Win32DxInterface::getFactory() const +IDXGIFactory7* Win32DxInterface::getDxgiFactory() const { - return mFactory.Get(); + return mDxgiFactory.Get(); } ID2D1Factory3* Win32DxInterface::getD2dFactory() const @@ -91,7 +80,20 @@ ID3D11DeviceContext* Win32DxInterface::getD3d11DeviceContext() const void Win32DxInterface::initialize() { - MLOG_INFO("Initialize DX"); + MLOG_INFO("Initialize DirectX"); + createD3dFactory(); + + Microsoft::WRL::ComPtr pAdapter; + getHardwareAdapter(&pAdapter); + createD3dDevice(pAdapter.Get()); + + createCommandQueue(); + + mIsValid = initializeD2d(); +} + +bool Win32DxInterface::createD3dFactory() +{ UINT dxgiFactoryFlags = 0; #if defined(DEBUG) || defined(_DEBUG) { @@ -103,36 +105,52 @@ void Win32DxInterface::initialize() } } #endif + if (FAILED(::CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&mDxgiFactory)))) + { + MLOG_ERROR("Failed to create DXGI Factory"); + } + return true; +} - HRESULT hr = ::CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&mFactory)); - - Microsoft::WRL::ComPtr pAdapter; - getHardwareAdapter(&pAdapter); +bool Win32DxInterface::createD3dDevice(IDXGIAdapter1* pAdapter) +{ if (pAdapter) { - if (!SUCCEEDED(D3D12CreateDevice(pAdapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&mDevice)))) + if (FAILED(::D3D12CreateDevice(pAdapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&mD3dDevice)))) { - MLOG_ERROR("Failed to create D3D12 device."); - return; + MLOG_ERROR("Failed to create D3D12 device, will try WARP."); + return false; + } + else + { + Microsoft::WRL::ComPtr pWarpAdapter; + mDxgiFactory->EnumWarpAdapter(IID_PPV_ARGS(&pWarpAdapter)); + if (FAILED(::D3D12CreateDevice(pWarpAdapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&mD3dDevice)))) + { + MLOG_ERROR("Failed to create WARP device."); + return false; + } } } else { - MLOG_ERROR("Failed to get DX hardware adapter."); - return; + MLOG_ERROR("Failed to get DirectX adapter."); + return false; } + return true; +} +bool Win32DxInterface::createCommandQueue() +{ D3D12_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - if (!SUCCEEDED(mDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&mCommandQueue)))) + if (FAILED(mD3dDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&mCommandQueue)))) { MLOG_ERROR("Failed to create command queue."); - return; + return false; } - - const auto init_2d_ok = initializeD2d(); - mIsValid = init_2d_ok; + return true; } bool Win32DxInterface::initializeD2d() @@ -159,24 +177,17 @@ bool Win32DxInterface::initializeD11on12() { 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 - ); + auto pCommandQueue = reinterpret_cast(mCommandQueue.GetAddressOf()); + if (FAILED(D3D11On12CreateDevice(mD3dDevice.Get(), d3d11DeviceFlags, nullptr, 0, pCommandQueue, 1, 0, &d3d11Device, &mD3d11DeviceContext, nullptr))) + { + MLOG_ERROR("Failed to create D3D11 on 12 Device"); + return false; + } d3d11Device.As(&mD3d11On12Device); return true; } bool Win32DxInterface::initializeDirectWrite() { - DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &mDWriteFactory); - return true; + return SUCCEEDED(::DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &mDWriteFactory)); } \ No newline at end of file diff --git a/src/windows/ui_interfaces/win32/Win32DxInterface.h b/src/windows/ui_interfaces/win32/directx/Win32DxInterface.h similarity index 80% rename from src/windows/ui_interfaces/win32/Win32DxInterface.h rename to src/windows/ui_interfaces/win32/directx/Win32DxInterface.h index ee8a0d6..bf7ecf2 100644 --- a/src/windows/ui_interfaces/win32/Win32DxInterface.h +++ b/src/windows/ui_interfaces/win32/directx/Win32DxInterface.h @@ -21,24 +21,24 @@ struct ID2D1DeviceContext2; class Win32DxInterface { public: - ID3D12Device* getDevice() const; - ID3D11On12Device* get11On12Device() const; - ID3D11DeviceContext* getD3d11DeviceContext() const; - - IDXGIFactory7* getFactory() const; - - ID2D1Factory3* getD2dFactory() const; - ID2D1DeviceContext2* getD2dContext() const; - + IDXGIFactory7* getDxgiFactory() const; + ID3D12Device* getD3dDevice() const; ID3D12CommandQueue* getCommandQueue() const; + ID3D11On12Device* get11On12Device() const; + ID3D11DeviceContext* getD3d11DeviceContext() const; + ID2D1Factory3* getD2dFactory() const; + ID2D1DeviceContext2* getD2dContext() const; IDWriteFactory* getDirectWriteFactory() const; void initialize(); - bool isValid() const; private: + bool createD3dFactory(); + bool createD3dDevice(IDXGIAdapter1* ppAdapter); + bool createCommandQueue(); + void getHardwareAdapter(IDXGIAdapter1** ppAdapter); bool initializeD2d(); @@ -47,16 +47,15 @@ private: bool mIsValid{ false }; - Microsoft::WRL::ComPtr mFactory; - Microsoft::WRL::ComPtr mDevice; + Microsoft::WRL::ComPtr mDxgiFactory; + Microsoft::WRL::ComPtr mD3dDevice; Microsoft::WRL::ComPtr mCommandQueue; + // 2D Rendering - e.g. text 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/directx/Win32DxWindowInterface.cpp b/src/windows/ui_interfaces/win32/directx/Win32DxWindowInterface.cpp new file mode 100644 index 0000000..96142f6 --- /dev/null +++ b/src/windows/ui_interfaces/win32/directx/Win32DxWindowInterface.cpp @@ -0,0 +1,283 @@ +#include "Win32DxWindowInterface.h" + +#include "Win32DxInterface.h" +#include "Win32Window.h" +#include "Window.h" +#include "Widget.h" +#include "FileLogger.h" + +#include "DirectXDescriptors.h" +#include "DirectX2dIntegration.h" +#include "DirectXBuffers.h" +#include "DirectXCommandList.h" + +#include "DrawingContext.h" +#include "DirectXPainter.h" +#include "DirectXMeshPainter.h" +#include "DirectXTextPainter.h" +#include "DirectXShaderProgram.h" + +#include +#include +#include +#include + +#include + +Win32DxWindowInterface::Win32DxWindowInterface(mt::Window* window, Win32DxInterface* dxInterface) + : mWindow(window), + mDxInterface(dxInterface) +{ + +} + +Win32DxWindowInterface::~Win32DxWindowInterface() +{ + +} + +void Win32DxWindowInterface::destroyWindow() +{ + flushCommandQueue(); + ::CloseHandle(mFenceEvent); +} + +void Win32DxWindowInterface::onRender() +{ + if (!mIsValid) + { + return; + } + + updateCommandList(); + + mCommandList->execute(mDxInterface->getCommandQueue()); + + mD2dIntegration->render(); + + mSwapChain->Present(1, 0); + + flushCommandQueue(); +} + +void Win32DxWindowInterface::updateCommandList() +{ + // Command list allocators can only be reset when the associated + // command lists have finished execution on the GPU; apps should use + // fences to determine GPU execution progress. + mCommandList->resetAllocator(); + + // However, when ExecuteCommandList() is called on a particular command + // list, that command list can then be reset at any time and must be before + // re-recording. + mCommandList->reset(getPipelineState()); + + // Set necessary state. + auto painter = dynamic_cast(mWindow->getDrawingContent()->getPainter()); + mCommandList->get()->SetGraphicsRootSignature(painter->getMeshPainter()->getRootSignature()); + mCommandList->get()->RSSetViewports(1, &mViewport); + mCommandList->get()->RSSetScissorRects(1, &mScissorRect); + + // Indicate that the back buffer will be used as a render target. + auto barrier = CD3DX12_RESOURCE_BARRIER::Transition(mBuffers->getCurrentBackBuffer(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET); + mCommandList->get()->ResourceBarrier(1, &barrier); + + auto rtv_handle = mDescriptors->getRtvHandle(static_cast(mBuffers->getCurrentBackBufferIndex())); + mCommandList->get()->OMSetRenderTargets(1, &rtv_handle, FALSE, nullptr); + + painter->paintBackground(rtv_handle, mCommandList->get()); + painter->paintMesh(mCommandList->get()); + + // Indicate that the back buffer will now be used to present. (Exclude as handled by D2D integration later) + //barrier = CD3DX12_RESOURCE_BARRIER::Transition(mRenderTargets[mFrameIndex].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT); + //mCommandList->ResourceBarrier(1, &barrier); + + mCommandList->close(); +} + +bool Win32DxWindowInterface::initialize() +{ + if (mInitialized) + { + return true; + } + mInitialized = true; + + if (!createSwapChain()) + { + return false; + } + + mCommandList = std::make_unique(); + mCommandList->create(mDxInterface->getD3dDevice(), getPipelineState()); + + createSyncObjects(); + + mDescriptors = std::make_unique(); + mDescriptors->setupDefaultDescriptorHeaps(mDxInterface->getD3dDevice()); + mD2dIntegration = std::make_unique(mWindow, mDxInterface, FrameCount); + mBuffers = std::make_unique(FrameCount); + + onResize(); + + if (!loadAssets()) + { + return false; + } + + flushCommandQueue(); + + mIsValid = true; + return true; +} + +void Win32DxWindowInterface::onResize() +{ + flushCommandQueue(); + + mCommandList->reset(getPipelineState()); + + clearBuffers(); + + resizeSwapChain(); + + populateBuffers(); + + mCommandList->close(); + + mCommandList->execute(mDxInterface->getCommandQueue()); + + flushCommandQueue(); + + updateViewport(); +} + +void Win32DxWindowInterface::resizeSwapChain() +{ + const auto width = mWindow->getWidth(); + const auto height = mWindow->getHeight(); + mSwapChain->ResizeBuffers(FrameCount, width, height, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH); + updateBackbufferIndex(0); +} + +void Win32DxWindowInterface::updateViewport() +{ + const auto width = mWindow->getWidth(); + const auto height = mWindow->getHeight(); + mViewport = CD3DX12_VIEWPORT(0.0f, 0.0f, static_cast(width), static_cast(height)); + mScissorRect = CD3DX12_RECT(0, 0, width, height); +} + +void Win32DxWindowInterface::clearBuffers() +{ + mBuffers->clear(); + mD2dIntegration->clearBuffers(); +} + +ID3D12PipelineState* Win32DxWindowInterface::getPipelineState() const +{ + auto painter = dynamic_cast(mWindow->getDrawingContent()->getPainter()); + return painter->getMeshPainter()->getPipelineState(); +} + +void Win32DxWindowInterface::populateBuffers() +{ + auto d3d_device = mDxInterface->getD3dDevice(); + mBuffers->setupBackBuffers(d3d_device, mSwapChain.Get(), mDescriptors.get()); + for (UINT idx = 0; idx < FrameCount; idx++) + { + mD2dIntegration->wrapBuffer(mBuffers->getBackBuffer(idx)); + } + + const auto width = mWindow->getWidth(); + const auto height = mWindow->getHeight(); + mBuffers->setupDepthStencilHeap(mDxInterface->getD3dDevice(), width, height); + mBuffers->setupDepthStencilView(mDxInterface->getD3dDevice(), mDescriptors.get()); + + auto barrier = CD3DX12_RESOURCE_BARRIER::Transition(mBuffers->getDepthStencilBuffer(), D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_DEPTH_WRITE); + mCommandList->get()->ResourceBarrier(1, &barrier); +} + +bool Win32DxWindowInterface::createSwapChain() +{ + mSwapChain.Reset(); + + const auto width = mWindow->getWidth(); + const auto height = mWindow->getHeight(); + const auto hwnd = dynamic_cast(mWindow->getPlatformWindow())->getHandle(); + + DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {}; + swapChainDesc.BufferCount = FrameCount; + swapChainDesc.Width = width; + swapChainDesc.Height = height; + swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + swapChainDesc.SampleDesc.Count = 1; + + Microsoft::WRL::ComPtr swapChain; + if (FAILED(mDxInterface->getDxgiFactory()->CreateSwapChainForHwnd(mDxInterface->getCommandQueue(), hwnd, &swapChainDesc, nullptr, nullptr, &swapChain))) + { + MLOG_ERROR("Failed to create swap chain for hwnd: " << hwnd); + return false; + } + swapChain.As(&mSwapChain); + + // Prevent fullscreen toggle + mDxInterface->getDxgiFactory()->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER); + + // Update index for backbuffer + updateBackbufferIndex(mSwapChain->GetCurrentBackBufferIndex()); + return true; +} + +void Win32DxWindowInterface::updateBackbufferIndex(UINT index) +{ + mBuffers->updateBackbufferIndex(index); + mD2dIntegration->updateBackbufferIndex(index); +} + +bool Win32DxWindowInterface::loadAssets() +{ + auto painter = dynamic_cast(mWindow->getDrawingContent()->getPainter()); + painter->initializeMesh(mDxInterface->getD3dDevice()); + painter->initializeText(mDxInterface->getD2dContext(), mDxInterface->getDirectWriteFactory()); + + painter->updateMesh(mDxInterface->getD3dDevice()); + return true; +} + +void Win32DxWindowInterface::createSyncObjects() +{ + mDxInterface->getD3dDevice()->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&mFence)); + mFenceValue = 1; + + // Create an event handle to use for frame synchronization. + mFenceEvent = ::CreateEvent(nullptr, FALSE, FALSE, nullptr); + if (mFenceEvent == nullptr) + { + //ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError())); + } + + // Wait for the command list to execute; we are reusing the same command + // list in our main loop but for now, we just want to wait for setup to + // complete before continuing. + flushCommandQueue(); +} + +void Win32DxWindowInterface::flushCommandQueue() +{ + // Signal and increment the fence value. + const UINT64 fence = mFenceValue; + mDxInterface->getCommandQueue()->Signal(mFence.Get(), fence); + mFenceValue++; + + // Wait until the previous frame is finished. + if (mFence->GetCompletedValue() < fence) + { + mFence->SetEventOnCompletion(fence, mFenceEvent); + ::WaitForSingleObject(mFenceEvent, INFINITE); + } + + updateBackbufferIndex(mSwapChain->GetCurrentBackBufferIndex()); +} \ No newline at end of file diff --git a/src/windows/ui_interfaces/win32/directx/Win32DxWindowInterface.h b/src/windows/ui_interfaces/win32/directx/Win32DxWindowInterface.h new file mode 100644 index 0000000..4680062 --- /dev/null +++ b/src/windows/ui_interfaces/win32/directx/Win32DxWindowInterface.h @@ -0,0 +1,82 @@ +#pragma once + +#include + +#include +#include +#include + +class Win32DxInterface; +class DirectXDescriptors; +class DirectX2dIntegration; +class DirectXBuffers; +class DirectXCommandList; +namespace mt +{ + class Window; +} + +struct ID3D12CommandAllocator; +struct ID3D12GraphicsCommandList; +struct IDXGISwapChain4; +struct ID3D12Resource; +struct ID3D12Fence; +struct ID3D12PipelineState; + +class Win32DxWindowInterface +{ +public: + Win32DxWindowInterface(mt::Window* window, Win32DxInterface* dxInterface); + + ~Win32DxWindowInterface(); + + bool initialize(); + + void onResize(); + + void onRender(); + +private: + bool loadAssets(); + + void updateCommandList(); + + void destroyWindow(); + + bool createSwapChain(); + void resizeSwapChain(); + + void clearBuffers(); + void populateBuffers(); + void updateBackbufferIndex(UINT index); + + void createSyncObjects(); + void flushCommandQueue(); + + void updateViewport(); + + ID3D12PipelineState* getPipelineState() const; + + Win32DxInterface* mDxInterface{ nullptr }; + bool mInitialized{ false }; + bool mIsValid{ false }; + + mt::Window* mWindow{ nullptr }; + CD3DX12_VIEWPORT mViewport; + CD3DX12_RECT mScissorRect; + + std::unique_ptr mDescriptors; + std::unique_ptr mD2dIntegration; + std::unique_ptr mBuffers; + std::unique_ptr mCommandList; + + Microsoft::WRL::ComPtr mSwapChain; + + static const UINT FrameCount = 2; + Microsoft::WRL::ComPtr mFence; + uint64_t mFenceValue = 0; + uint64_t mFrameFenceValues[FrameCount] = {}; + HANDLE mFenceEvent{}; +}; + +using XcbGlWindowInterfacePtr = std::unique_ptr; \ No newline at end of file