Some directx cleaning.

This commit is contained in:
jmsgrogan 2023-01-06 13:03:51 +00:00
parent 850bd6906f
commit 55ed0e9299
19 changed files with 900 additions and 487 deletions

View file

@ -21,7 +21,6 @@
#include "File.h" #include "File.h"
#include <windows.h> #include <windows.h>
#include <directx/d3dx12.h>
#include <iostream> #include <iostream>
@ -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 }; const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr); commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);

View file

@ -13,8 +13,6 @@ class DrawingContext;
class DirectXMeshPainter; class DirectXMeshPainter;
class DirectXTextPainter; class DirectXTextPainter;
struct CD3DX12_CPU_DESCRIPTOR_HANDLE;
class DirectXPainter : public AbstractPainter class DirectXPainter : public AbstractPainter
{ {
public: public:
@ -28,7 +26,7 @@ public:
void initializeText(ID2D1DeviceContext2* d2dContext, IDWriteFactory* directWriteFactory); 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); void paintMesh(ID3D12GraphicsCommandList* commandList);

View file

@ -54,7 +54,7 @@ void DirectXTextPainter::updateTextFormat(IDWriteFactory* directWriteFactory, un
void DirectXTextPainter::paint(SceneText* text, DrawingContext* context, ID2D1DeviceContext2* d2dContext, IDWriteFactory* directWriteFactory) void DirectXTextPainter::paint(SceneText* text, DrawingContext* context, ID2D1DeviceContext2* d2dContext, IDWriteFactory* directWriteFactory)
{ {
const auto location = text->getTransform().getLocation(); 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()); updateTextFormat(directWriteFactory, text->getTextData().mFont.getSize());

View file

@ -58,10 +58,18 @@ else()
ui_interfaces/win32/Win32WindowInterface.cpp ui_interfaces/win32/Win32WindowInterface.cpp
ui_interfaces/win32/Win32Window.h ui_interfaces/win32/Win32Window.h
ui_interfaces/win32/Win32Window.cpp ui_interfaces/win32/Win32Window.cpp
ui_interfaces/win32/Win32DxInterface.h ui_interfaces/win32/directx/Win32DxInterface.h
ui_interfaces/win32/Win32DxInterface.cpp ui_interfaces/win32/directx/Win32DxInterface.cpp
ui_interfaces/win32/Win32DxWindowInterface.h ui_interfaces/win32/directx/Win32DxWindowInterface.h
ui_interfaces/win32/Win32DxWindowInterface.cpp 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) 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}) add_library(windows SHARED ${windows_LIB_INCLUDES} ${platform_INCLUDES})
target_include_directories(windows PUBLIC target_include_directories(windows PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}" ${CMAKE_CURRENT_SOURCE_DIR}
"${CMAKE_CURRENT_SOURCE_DIR}/managers" ${CMAKE_CURRENT_SOURCE_DIR}/managers
"${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces" ${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces
"${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces/x11" ${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces/x11
"${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces/wayland" ${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces/wayland
"${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces/win32" ${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces/win32
${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces/win32/directx
${WAYLAND_INCLUDE_DIRS} ${WAYLAND_INCLUDE_DIRS}
${X11_INCLUDE_DIRS} ${X11_INCLUDE_DIRS}
) )

View file

@ -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 <dxgi.h>
#include <dxgi1_6.h>
#include <d3dcompiler.h>
#include <d3d12sdklayers.h>
#include <d3d11.h>
#include <d3d11on12.h>
#include <d2d1_3.h>
#include <d2d1_1.h>
#include <D3Dcommon.h>
#include <dwrite.h>
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<DirectXPainter*>(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<INT>(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<DirectXPainter*>(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<float>(width), static_cast<float>(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<Win32Window*>(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<IDXGISwapChain1> 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<IDXGISurface> surface;
mWrappedBackBuffers[idx].As(&surface);
mDxInterface->getD2dContext()->CreateBitmapFromDxgiSurface(surface.Get(), &bitmapProps, &mD2dRenderTargets[idx]);
}
bool Win32DxWindowInterface::loadAssets()
{
auto painter = dynamic_cast<DirectXPainter*>(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();
}

View file

@ -1,91 +0,0 @@
#pragma once
#include <memory>
#include <wrl.h>
#include <d3d12.h>
#include <directx/d3dx12.h>
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<ID3D12CommandAllocator> mCommandAllocator;
Microsoft::WRL::ComPtr<ID3D12GraphicsCommandList> mCommandList;
Microsoft::WRL::ComPtr<IDXGISwapChain4> mSwapChain;
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> mRtvHeap;
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> mSrvHeap;
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> mCbvHeap;
UINT mRtvDescriptorSize{ 0 };
Microsoft::WRL::ComPtr<ID3D12Resource> mRenderTargets[FrameCount];
Microsoft::WRL::ComPtr<ID3D11Resource> mWrappedBackBuffers[FrameCount];
Microsoft::WRL::ComPtr<ID2D1Bitmap1> mD2dRenderTargets[FrameCount];
Microsoft::WRL::ComPtr<ID3D12Fence> mFence;
uint64_t mFenceValue = 0;
uint64_t mFrameFenceValues[FrameCount] = {};
HANDLE mFenceEvent{};
uint64_t mFrameIndex{ 0 };
};
using XcbGlWindowInterfacePtr = std::unique_ptr<Win32DxWindowInterface>;

View file

@ -39,6 +39,11 @@ void Win32UIInterface::loop()
MSG msg = { }; MSG msg = { };
while (::GetMessage(&msg, NULL, 0, 0)) while (::GetMessage(&msg, NULL, 0, 0))
{ {
if (msg.message == WM_QUIT)
{
break;
}
::TranslateMessage(&msg); ::TranslateMessage(&msg);
::DispatchMessage(&msg); ::DispatchMessage(&msg);
} }

View file

@ -0,0 +1,91 @@
#include "DirectX2dIntegration.h"
#include "Window.h"
#include "Widget.h"
#include "DirectXPainter.h"
#include "DrawingContext.h"
#include "Win32DxInterface.h"
#include <d3d11.h>
#include <d3d11on12.h>
#include <d2d1_3.h>
#include <d2d1_1.h>
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<DirectXPainter*>(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<ID3D11Resource>());
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<ID2D1Bitmap1>());
Microsoft::WRL::ComPtr<IDXGISurface> 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;
}

View file

@ -0,0 +1,40 @@
#pragma once
#include <wrl.h>
#include <stdint.h>
#include <vector>
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<Microsoft::WRL::ComPtr<ID3D11Resource> > mWrappedBackBuffers;
std::vector<Microsoft::WRL::ComPtr<ID2D1Bitmap1> > mD2dRenderTargets;
};

View file

@ -0,0 +1,97 @@
#include "DirectXBuffers.h"
#include "DirectXDescriptors.h"
#include <dxgi.h>
#include <dxgi1_6.h>
#include <d3d12.h>
#include <directx/d3dx12.h>
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<ID3D12Resource>());
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());
}

View file

@ -0,0 +1,39 @@
#pragma once
#include <wrl.h>
#include <vector>
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<Microsoft::WRL::ComPtr<ID3D12Resource> > mBackBuffers;
Microsoft::WRL::ComPtr<ID3D12Resource> mDepthStencilBuffer;
};

View file

@ -0,0 +1,37 @@
#include "DirectXCommandList.h"
#include <d3d12.h>
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();
}

View file

@ -0,0 +1,29 @@
#pragma once
#include <wrl.h>
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<ID3D12CommandAllocator> mCommandAllocator;
Microsoft::WRL::ComPtr<ID3D12GraphicsCommandList> mCommandList;
};

View file

@ -0,0 +1,76 @@
#include "DirectXDescriptors.h"
#include <directx/d3dx12.h>
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));
}

View file

@ -0,0 +1,29 @@
#pragma once
#include <wrl.h>
#include <d3d12.h>
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<ID3D12DescriptorHeap> mRtvHeap;
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> mDsvHeap;
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> mSrvHeap;
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> mCbvHeap;
};

View file

@ -2,9 +2,6 @@
#include "FileLogger.h" #include "FileLogger.h"
#include <DirectXMath.h>
#include <DirectXPackedVector.h>
#include <dxgi.h> #include <dxgi.h>
#include <dxgi1_6.h> #include <dxgi1_6.h>
#include <d3d11.h> #include <d3d11.h>
@ -17,25 +14,17 @@
#include <dwrite.h> #include <dwrite.h>
#include <iostream>
#include <vector>
#include <windows.h>
#include <wrl.h>
void Win32DxInterface::getHardwareAdapter(IDXGIAdapter1** ppAdapter) void Win32DxInterface::getHardwareAdapter(IDXGIAdapter1** ppAdapter)
{ {
*ppAdapter = nullptr; *ppAdapter = nullptr;
for (UINT adapterIndex = 0; ; ++adapterIndex) for (UINT adapterIndex = 0; ; ++adapterIndex)
{ {
IDXGIAdapter1* pAdapter = nullptr; IDXGIAdapter1* pAdapter = nullptr;
if (DXGI_ERROR_NOT_FOUND == mFactory->EnumAdapters1(adapterIndex, &pAdapter)) if (mDxgiFactory->EnumAdapters1(adapterIndex, &pAdapter) == DXGI_ERROR_NOT_FOUND)
{ {
break; break;
} }
if (SUCCEEDED(::D3D12CreateDevice(pAdapter, D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr)))
// 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)))
{ {
*ppAdapter = pAdapter; *ppAdapter = pAdapter;
return; return;
@ -49,9 +38,9 @@ bool Win32DxInterface::isValid() const
return mIsValid; return mIsValid;
} }
ID3D12Device* Win32DxInterface::getDevice() const ID3D12Device* Win32DxInterface::getD3dDevice() const
{ {
return mDevice.Get(); return mD3dDevice.Get();
} }
ID3D11On12Device* Win32DxInterface::get11On12Device() const ID3D11On12Device* Win32DxInterface::get11On12Device() const
@ -59,9 +48,9 @@ ID3D11On12Device* Win32DxInterface::get11On12Device() const
return mD3d11On12Device.Get(); return mD3d11On12Device.Get();
} }
IDXGIFactory7* Win32DxInterface::getFactory() const IDXGIFactory7* Win32DxInterface::getDxgiFactory() const
{ {
return mFactory.Get(); return mDxgiFactory.Get();
} }
ID2D1Factory3* Win32DxInterface::getD2dFactory() const ID2D1Factory3* Win32DxInterface::getD2dFactory() const
@ -91,7 +80,20 @@ ID3D11DeviceContext* Win32DxInterface::getD3d11DeviceContext() const
void Win32DxInterface::initialize() void Win32DxInterface::initialize()
{ {
MLOG_INFO("Initialize DX"); MLOG_INFO("Initialize DirectX");
createD3dFactory();
Microsoft::WRL::ComPtr<IDXGIAdapter1> pAdapter;
getHardwareAdapter(&pAdapter);
createD3dDevice(pAdapter.Get());
createCommandQueue();
mIsValid = initializeD2d();
}
bool Win32DxInterface::createD3dFactory()
{
UINT dxgiFactoryFlags = 0; UINT dxgiFactoryFlags = 0;
#if defined(DEBUG) || defined(_DEBUG) #if defined(DEBUG) || defined(_DEBUG)
{ {
@ -103,36 +105,52 @@ void Win32DxInterface::initialize()
} }
} }
#endif #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)); bool Win32DxInterface::createD3dDevice(IDXGIAdapter1* pAdapter)
{
Microsoft::WRL::ComPtr<IDXGIAdapter1> pAdapter;
getHardwareAdapter(&pAdapter);
if (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."); MLOG_ERROR("Failed to create D3D12 device, will try WARP.");
return; return false;
}
else
{
Microsoft::WRL::ComPtr<IDXGIAdapter> 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 else
{ {
MLOG_ERROR("Failed to get DX hardware adapter."); MLOG_ERROR("Failed to get DirectX adapter.");
return; return false;
}
return true;
} }
bool Win32DxInterface::createCommandQueue()
{
D3D12_COMMAND_QUEUE_DESC queueDesc = {}; D3D12_COMMAND_QUEUE_DESC queueDesc = {};
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; 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."); MLOG_ERROR("Failed to create command queue.");
return; return false;
} }
return true;
const auto init_2d_ok = initializeD2d();
mIsValid = init_2d_ok;
} }
bool Win32DxInterface::initializeD2d() bool Win32DxInterface::initializeD2d()
@ -159,24 +177,17 @@ bool Win32DxInterface::initializeD11on12()
{ {
Microsoft::WRL::ComPtr<ID3D11Device> d3d11Device; Microsoft::WRL::ComPtr<ID3D11Device> d3d11Device;
UINT d3d11DeviceFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; UINT d3d11DeviceFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
D3D11On12CreateDevice( auto pCommandQueue = reinterpret_cast<IUnknown**>(mCommandQueue.GetAddressOf());
mDevice.Get(), if (FAILED(D3D11On12CreateDevice(mD3dDevice.Get(), d3d11DeviceFlags, nullptr, 0, pCommandQueue, 1, 0, &d3d11Device, &mD3d11DeviceContext, nullptr)))
d3d11DeviceFlags, {
nullptr, MLOG_ERROR("Failed to create D3D11 on 12 Device");
0, return false;
reinterpret_cast<IUnknown**>(mCommandQueue.GetAddressOf()), }
1,
0,
&d3d11Device,
&mD3d11DeviceContext,
nullptr
);
d3d11Device.As(&mD3d11On12Device); d3d11Device.As(&mD3d11On12Device);
return true; return true;
} }
bool Win32DxInterface::initializeDirectWrite() bool Win32DxInterface::initializeDirectWrite()
{ {
DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &mDWriteFactory); return SUCCEEDED(::DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &mDWriteFactory));
return true;
} }

View file

@ -21,24 +21,24 @@ struct ID2D1DeviceContext2;
class Win32DxInterface class Win32DxInterface
{ {
public: public:
ID3D12Device* getDevice() const; IDXGIFactory7* getDxgiFactory() const;
ID3D11On12Device* get11On12Device() const; ID3D12Device* getD3dDevice() const;
ID3D11DeviceContext* getD3d11DeviceContext() const;
IDXGIFactory7* getFactory() const;
ID2D1Factory3* getD2dFactory() const;
ID2D1DeviceContext2* getD2dContext() const;
ID3D12CommandQueue* getCommandQueue() const; ID3D12CommandQueue* getCommandQueue() const;
ID3D11On12Device* get11On12Device() const;
ID3D11DeviceContext* getD3d11DeviceContext() const;
ID2D1Factory3* getD2dFactory() const;
ID2D1DeviceContext2* getD2dContext() const;
IDWriteFactory* getDirectWriteFactory() const; IDWriteFactory* getDirectWriteFactory() const;
void initialize(); void initialize();
bool isValid() const; bool isValid() const;
private: private:
bool createD3dFactory();
bool createD3dDevice(IDXGIAdapter1* ppAdapter);
bool createCommandQueue();
void getHardwareAdapter(IDXGIAdapter1** ppAdapter); void getHardwareAdapter(IDXGIAdapter1** ppAdapter);
bool initializeD2d(); bool initializeD2d();
@ -47,16 +47,15 @@ private:
bool mIsValid{ false }; bool mIsValid{ false };
Microsoft::WRL::ComPtr<IDXGIFactory7> mFactory; Microsoft::WRL::ComPtr<IDXGIFactory7> mDxgiFactory;
Microsoft::WRL::ComPtr<ID3D12Device> mDevice; Microsoft::WRL::ComPtr<ID3D12Device> mD3dDevice;
Microsoft::WRL::ComPtr<ID3D12CommandQueue> mCommandQueue; Microsoft::WRL::ComPtr<ID3D12CommandQueue> mCommandQueue;
// 2D Rendering - e.g. text
Microsoft::WRL::ComPtr<ID3D11DeviceContext> mD3d11DeviceContext; Microsoft::WRL::ComPtr<ID3D11DeviceContext> mD3d11DeviceContext;
Microsoft::WRL::ComPtr<ID3D11On12Device> mD3d11On12Device; Microsoft::WRL::ComPtr<ID3D11On12Device> mD3d11On12Device;
Microsoft::WRL::ComPtr<ID2D1Factory3> mD2dFactory; Microsoft::WRL::ComPtr<ID2D1Factory3> mD2dFactory;
Microsoft::WRL::ComPtr<ID2D1Device2> mD2dDevice; Microsoft::WRL::ComPtr<ID2D1Device2> mD2dDevice;
Microsoft::WRL::ComPtr<ID2D1DeviceContext2> mD2dDeviceContext; Microsoft::WRL::ComPtr<ID2D1DeviceContext2> mD2dDeviceContext;
Microsoft::WRL::ComPtr<IDWriteFactory> mDWriteFactory; Microsoft::WRL::ComPtr<IDWriteFactory> mDWriteFactory;
}; };

View file

@ -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 <dxgi.h>
#include <dxgi1_6.h>
#include <d3d12sdklayers.h>
#include <D3Dcommon.h>
#include <dwrite.h>
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<DirectXPainter*>(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<int>(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<DirectXCommandList>();
mCommandList->create(mDxInterface->getD3dDevice(), getPipelineState());
createSyncObjects();
mDescriptors = std::make_unique<DirectXDescriptors>();
mDescriptors->setupDefaultDescriptorHeaps(mDxInterface->getD3dDevice());
mD2dIntegration = std::make_unique<DirectX2dIntegration>(mWindow, mDxInterface, FrameCount);
mBuffers = std::make_unique<DirectXBuffers>(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<float>(width), static_cast<float>(height));
mScissorRect = CD3DX12_RECT(0, 0, width, height);
}
void Win32DxWindowInterface::clearBuffers()
{
mBuffers->clear();
mD2dIntegration->clearBuffers();
}
ID3D12PipelineState* Win32DxWindowInterface::getPipelineState() const
{
auto painter = dynamic_cast<DirectXPainter*>(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<Win32Window*>(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<IDXGISwapChain1> 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<DirectXPainter*>(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());
}

View file

@ -0,0 +1,82 @@
#pragma once
#include <memory>
#include <wrl.h>
#include <d3d12.h>
#include <directx/d3dx12.h>
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<DirectXDescriptors> mDescriptors;
std::unique_ptr<DirectX2dIntegration> mD2dIntegration;
std::unique_ptr<DirectXBuffers> mBuffers;
std::unique_ptr<DirectXCommandList> mCommandList;
Microsoft::WRL::ComPtr<IDXGISwapChain4> mSwapChain;
static const UINT FrameCount = 2;
Microsoft::WRL::ComPtr<ID3D12Fence> mFence;
uint64_t mFenceValue = 0;
uint64_t mFrameFenceValues[FrameCount] = {};
HANDLE mFenceEvent{};
};
using XcbGlWindowInterfacePtr = std::unique_ptr<Win32DxWindowInterface>;