Start aligning Dx and OpenGl approaches.

This commit is contained in:
jmsgrogan 2023-01-05 08:46:01 +00:00
parent d1ec8b4f68
commit d99a36f24f
22 changed files with 899 additions and 366 deletions

View file

@ -31,7 +31,6 @@ void Win32DxInterface::getHardwareAdapter(IDXGIAdapter1** ppAdapter)
IDXGIAdapter1* pAdapter = nullptr;
if (DXGI_ERROR_NOT_FOUND == mFactory->EnumAdapters1(adapterIndex, &pAdapter))
{
// No more adapters to enumerate.
break;
}
@ -92,50 +91,71 @@ ID3D11DeviceContext* Win32DxInterface::getD3d11DeviceContext() const
void Win32DxInterface::initialize()
{
if (!DirectX::XMVerifyCPUSupport())
{
MLOG_ERROR("Directx math not supported");
return;
}
MLOG_INFO("Initialize DX");
UINT dxgiFactoryFlags = 0;
#if defined(DEBUG) || defined(_DEBUG)
// Enable the D3D12 debug layer.
{
ID3D12Debug* debugController;
D3D12GetDebugInterface(IID_PPV_ARGS(&debugController));
debugController->EnableDebugLayer();
Microsoft::WRL::ComPtr<ID3D12Debug> debugController;
if (SUCCEEDED(::D3D12GetDebugInterface(IID_PPV_ARGS(&debugController))))
{
debugController->EnableDebugLayer();
dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
}
}
#endif
HRESULT hr = CreateDXGIFactory(__uuidof(IDXGIFactory7), (void**)(&mFactory));
HRESULT hr = ::CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&mFactory));
IDXGIAdapter1* pAdapter{ nullptr };
Microsoft::WRL::ComPtr<IDXGIAdapter1> pAdapter;
getHardwareAdapter(&pAdapter);
if (pAdapter)
{
MLOG_INFO("Found adapter");
if (SUCCEEDED(D3D12CreateDevice(pAdapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&mDevice))))
if (!SUCCEEDED(D3D12CreateDevice(pAdapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&mDevice))))
{
MLOG_INFO("Got device");
MLOG_ERROR("Failed to create D3D12 device.");
return;
}
}
else
{
MLOG_INFO("No adapter found");
MLOG_ERROR("Failed to get DX hardware adapter.");
return;
}
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))))
{
MLOG_ERROR("Failed to create command queue.");
return;
}
mDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&mCommandQueue));
mIsValid = initializeD2d();
const auto init_2d_ok = initializeD2d();
mIsValid = init_2d_ok;
}
bool Win32DxInterface::initializeD2d()
{
if (!initializeD11on12())
{
return false;
}
D2D1_FACTORY_OPTIONS d2dFactoryOptions = {};
D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory3), &d2dFactoryOptions, &mD2dFactory);
Microsoft::WRL::ComPtr<IDXGIDevice> dxgiDevice;
mD3d11On12Device.As(&dxgiDevice);
mD2dFactory->CreateDevice(dxgiDevice.Get(), &mD2dDevice);
D2D1_DEVICE_CONTEXT_OPTIONS deviceOptions = D2D1_DEVICE_CONTEXT_OPTIONS_NONE;
mD2dDevice->CreateDeviceContext(deviceOptions, &mD2dDeviceContext);
return initializeDirectWrite();
}
bool Win32DxInterface::initializeD11on12()
{
Microsoft::WRL::ComPtr<ID3D11Device> d3d11Device;
UINT d3d11DeviceFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
@ -151,24 +171,12 @@ bool Win32DxInterface::initializeD2d()
&mD3d11DeviceContext,
nullptr
);
d3d11Device.As(&mD3d11On12Device);
return true;
}
// Create D2D/DWrite components.
{
D2D1_DEVICE_CONTEXT_OPTIONS deviceOptions = D2D1_DEVICE_CONTEXT_OPTIONS_NONE;
D2D1_FACTORY_OPTIONS d2dFactoryOptions = {};
D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory3), &d2dFactoryOptions, &mD2dFactory);
Microsoft::WRL::ComPtr<IDXGIDevice> dxgiDevice;
mD3d11On12Device.As(&dxgiDevice);
mD2dFactory->CreateDevice(dxgiDevice.Get(), &mD2dDevice);
mD2dDevice->CreateDeviceContext(deviceOptions, &mD2dDeviceContext);
DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &mDWriteFactory);
}
bool Win32DxInterface::initializeDirectWrite()
{
DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &mDWriteFactory);
return true;
}

View file

@ -42,6 +42,8 @@ private:
void getHardwareAdapter(IDXGIAdapter1** ppAdapter);
bool initializeD2d();
bool initializeD11on12();
bool initializeDirectWrite();
bool mIsValid{ false };

View file

@ -4,6 +4,13 @@
#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>
@ -14,11 +21,13 @@
#include <d3d11on12.h>
#include <d2d1_3.h>
#include <d2d1_1.h>
#include <D3Dcommon.h>
#include <dwrite.h>
Win32DxWindowInterface::Win32DxWindowInterface(Win32DxInterface* dxInterface)
: mDxInterface(dxInterface)
Win32DxWindowInterface::Win32DxWindowInterface(mt::Window* window, Win32DxInterface* dxInterface)
: mWindow(window),
mDxInterface(dxInterface)
{
}
@ -37,6 +46,11 @@ void Win32DxWindowInterface::destroyWindow()
void Win32DxWindowInterface::onRender()
{
if (!mIsValid)
{
return;
}
// Record all the commands we need to render the scene into the command list.
populateCommandList();
@ -54,6 +68,8 @@ void Win32DxWindowInterface::onRender()
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.
@ -62,10 +78,10 @@ void Win32DxWindowInterface::populateCommandList()
// 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(), mPipelineState.Get());
mCommandList->Reset(mCommandAllocator.Get(), painter->getMeshPainter()->getPipelineState());
// Set necessary state.
mCommandList->SetGraphicsRootSignature(mRootSignature.Get());
mCommandList->SetGraphicsRootSignature(painter->getMeshPainter()->getRootSignature());
mCommandList->RSSetViewports(1, &mViewport);
mCommandList->RSSetScissorRects(1, &mScissorRect);
@ -76,12 +92,7 @@ void Win32DxWindowInterface::populateCommandList()
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(mRtvHeap->GetCPUDescriptorHandleForHeapStart(), static_cast<INT>(mFrameIndex), mRtvDescriptorSize);
mCommandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr);
// Record commands.
const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
mCommandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);
mCommandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
mCommandList->IASetVertexBuffers(0, 1, &mVertexBufferView);
mCommandList->DrawInstanced(3, 1, 0, 0);
painter->getMeshPainter()->updateCommandList(rtvHandle, 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);
@ -90,276 +101,17 @@ void Win32DxWindowInterface::populateCommandList()
mCommandList->Close();
}
bool Win32DxWindowInterface::initialize(mt::Window* window)
{
if (mInitialized)
{
return true;
}
const auto width = window->getWidth();
const auto height = window->getHeight();
mViewport = CD3DX12_VIEWPORT(0.0f, 0.0f, width, height);
mScissorRect = CD3DX12_RECT(0, 0, width, height);
loadPipeline(window);
loadAssets();
return true;
}
void Win32DxWindowInterface::loadPipeline(mt::Window* window)
{
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
swapChainDesc.BufferCount = FrameCount;
const auto width = window->getWidth();
const auto height = window->getHeight();
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;
const auto hwnd = dynamic_cast<Win32Window*>(window->getPlatformWindow())->getHandle();
Microsoft::WRL::ComPtr<IDXGISwapChain1> swapChain;
mDxInterface->getFactory()->CreateSwapChainForHwnd(
mDxInterface->getCommandQueue(),
hwnd,
&swapChainDesc,
nullptr,
nullptr,
&swapChain
);
mDxInterface->getFactory()->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER);
swapChain.As(&mSwapChain);
auto mFrameIndex = mSwapChain->GetCurrentBackBufferIndex();
// Query the desktop's dpi settings, which will be used to create
// D2D's render targets.
float dpiX{ 0.0 };
float dpiY{ 0.0 };
mDxInterface->getD2dFactory()->GetDesktopDpi(&dpiX, &dpiY);
D2D1_BITMAP_PROPERTIES1 bitmapProperties = D2D1::BitmapProperties1(
D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
dpiX,
dpiY
);
// Create descriptor heaps.
{
// Describe and create a render target view (RTV) descriptor heap.
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));
mRtvDescriptorSize = mDxInterface->getDevice()->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
}
// Create frame resources.
{
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(mRtvHeap->GetCPUDescriptorHandleForHeapStart());
// Create a RTV for each frame.
for (UINT n = 0; n < FrameCount; n++)
{
mSwapChain->GetBuffer(n, IID_PPV_ARGS(&mRenderTargets[n]));
mDxInterface->getDevice()->CreateRenderTargetView(mRenderTargets[n].Get(), nullptr, rtvHandle);
D3D11_RESOURCE_FLAGS d3d11Flags = { D3D11_BIND_RENDER_TARGET };
mDxInterface->get11On12Device()->CreateWrappedResource(
mRenderTargets[n].Get(),
&d3d11Flags,
D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_PRESENT,
IID_PPV_ARGS(&mWrappedBackBuffers[n])
);
// Create a render target for D2D to draw directly to this back buffer.
Microsoft::WRL::ComPtr<IDXGISurface> surface;
mWrappedBackBuffers[n].As(&surface);
mDxInterface->getD2dContext()->CreateBitmapFromDxgiSurface(
surface.Get(),
&bitmapProperties,
&mD2dRenderTargets[n]
);
rtvHandle.Offset(1, mRtvDescriptorSize);
}
}
mDxInterface->getDevice()->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&mCommandAllocator));
}
void Win32DxWindowInterface::loadAssets()
{
// Create an empty root signature.
{
CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc;
rootSignatureDesc.Init(0, nullptr, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
Microsoft::WRL::ComPtr<ID3DBlob> signature;
Microsoft::WRL::ComPtr<ID3DBlob> error;
D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error);
mDxInterface->getDevice()->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&mRootSignature));
}
// Create the pipeline state, which includes compiling and loading shaders.
{
Microsoft::WRL::ComPtr<ID3DBlob> vertexShader;
Microsoft::WRL::ComPtr<ID3DBlob> pixelShader;
#if defined(_DEBUG)
// Enable better shader debugging with the graphics debugging tools.
// UINT compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
UINT compileFlags = 0;
#else
UINT compileFlags = 0;
#endif
auto shader_path = std::filesystem::path(__FILE__).parent_path() / "shaders.hlsl";
D3DCompileFromFile(shader_path.c_str(), nullptr, nullptr, "VSMain", "vs_5_0", compileFlags, 0, &vertexShader, nullptr);
D3DCompileFromFile(shader_path.c_str(), nullptr, nullptr, "PSMain", "ps_5_0", compileFlags, 0, &pixelShader, nullptr);
// Define the vertex input layout.
D3D12_INPUT_ELEMENT_DESC inputElementDescs[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
};
// Describe and create the graphics pipeline state object (PSO).
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) };
psoDesc.pRootSignature = mRootSignature.Get();
psoDesc.VS = CD3DX12_SHADER_BYTECODE(vertexShader.Get());
psoDesc.PS = CD3DX12_SHADER_BYTECODE(pixelShader.Get());
psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
psoDesc.DepthStencilState.DepthEnable = FALSE;
psoDesc.DepthStencilState.StencilEnable = FALSE;
psoDesc.SampleMask = UINT_MAX;
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
psoDesc.NumRenderTargets = 1;
psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
psoDesc.SampleDesc.Count = 1;
mDxInterface->getDevice()->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&mPipelineState));
}
// Create the command list.
mDxInterface->getDevice()->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, mCommandAllocator.Get(), mPipelineState.Get(), IID_PPV_ARGS(&mCommandList));
// Create D2D/DWrite objects for rendering text.
{
mDxInterface->getD2dContext()->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &mTextBrush);
mDxInterface->getDirectWriteFactory()->CreateTextFormat(
L"Verdana",
NULL,
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
50,
L"en-us",
&mTextFormat
);
mTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
mTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
}
// Command lists are created in the recording state, but there is nothing
// to record yet. The main loop expects it to be closed, so close it now.
mCommandList->Close();
// Create the vertex buffer.
{
// Define the geometry for a triangle.
const float aspectRatio = 1.0;
Vertex triangleVertices[] =
{
{ { 0.0f, 0.25f * aspectRatio, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f } },
{ { 0.25f, -0.25f * aspectRatio, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f } },
{ { -0.25f, -0.25f * aspectRatio, 0.0f }, { 0.0f, 0.0f, 1.0f, 1.0f } }
};
const UINT vertexBufferSize = sizeof(triangleVertices);
// Note: using upload heaps to transfer static data like vert buffers is not
// recommended. Every time the GPU needs it, the upload heap will be marshalled
// over. Please read up on Default Heap usage. An upload heap is used here for
// code simplicity and because there are very few verts to actually transfer.
CD3DX12_HEAP_PROPERTIES heapProps(D3D12_HEAP_TYPE_UPLOAD);
auto desc = CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize);
mDxInterface->getDevice()->CreateCommittedResource(
&heapProps,
D3D12_HEAP_FLAG_NONE,
&desc,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&mVertexBuffer));
// Copy the triangle data to the vertex buffer.
UINT8* pVertexDataBegin;
CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU.
mVertexBuffer->Map(0, &readRange, reinterpret_cast<void**>(&pVertexDataBegin));
memcpy(pVertexDataBegin, triangleVertices, sizeof(triangleVertices));
mVertexBuffer->Unmap(0, nullptr);
// Initialize the vertex buffer view.
mVertexBufferView.BufferLocation = mVertexBuffer->GetGPUVirtualAddress();
mVertexBufferView.StrideInBytes = sizeof(Vertex);
mVertexBufferView.SizeInBytes = vertexBufferSize;
}
// Create synchronization objects and wait until assets have been uploaded to the GPU.
{
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::renderD2d()
{
D2D1_SIZE_F rtSize = mD2dRenderTargets[mFrameIndex]->GetSize();
D2D1_RECT_F textRect = D2D1::RectF(0, 0, rtSize.width, rtSize.height);
static const WCHAR text[] = L"11On12";
// Acquire our wrapped render target resource for the current back buffer.
mDxInterface->get11On12Device()->AcquireWrappedResources(mWrappedBackBuffers[mFrameIndex].GetAddressOf(), 1);
// Render text directly to the back buffer.
mDxInterface->getD2dContext()->SetTarget(mD2dRenderTargets[mFrameIndex].Get());
mDxInterface->getD2dContext()->BeginDraw();
mDxInterface->getD2dContext()->SetTransform(D2D1::Matrix3x2F::Identity());
mDxInterface->getD2dContext()->DrawText(
text,
_countof(text) - 1,
mTextFormat.Get(),
&textRect,
mTextBrush.Get()
);
mDxInterface->getD2dContext()->EndDraw();
auto painter = dynamic_cast<DirectXPainter*>(mWindow->getDrawingContent()->getPainter());
D2D1_SIZE_F rtSize = mD2dRenderTargets[mFrameIndex]->GetSize();
painter->getTextPainter()->paint(mDxInterface->getD2dContext(), rtSize.width, rtSize.height);
// Release our wrapped render target resource. Releasing
// transitions the back buffer resource to the state specified
@ -370,6 +122,177 @@ void Win32DxWindowInterface::renderD2d()
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));
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->getMeshPainter()->createRootSignature(mDxInterface->getDevice());
painter->getMeshPainter()->createPipelineStateObject(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->getTextPainter()->initializeBrush(mDxInterface->getD2dContext());
painter->getTextPainter()->initializeTextFormat(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->getMeshPainter()->createVertexBuffer(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.

View file

@ -4,7 +4,6 @@
#include <wrl.h>
#include <d3d12.h>
#include <directxmath.h>
#include <directx/d3dx12.h>
class Win32DxInterface;
@ -25,27 +24,23 @@ struct ID3D12PipelineState;
struct ID3D11Resource;
struct ID2D1Bitmap1;
struct ID2D1SolidColorBrush;
struct IDWriteTextFormat;
struct D2D1_BITMAP_PROPERTIES1;
struct CD3DX12_CPU_DESCRIPTOR_HANDLE;
class Win32DxWindowInterface
{
public:
Win32DxWindowInterface(Win32DxInterface* dxInterface);
Win32DxWindowInterface(mt::Window* window, Win32DxInterface* dxInterface);
~Win32DxWindowInterface();
bool initialize(mt::Window* window);
bool initialize();
void onRender();
//void afterPaint();
//void resizeViewPort(unsigned width, unsigned height);
private:
void loadPipeline(mt::Window* window);
void loadAssets();
bool loadPipeline();
bool loadAssets();
void populateCommandList();
void waitForPreviousFrame();
@ -53,16 +48,21 @@ private:
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 };
struct Vertex
{
DirectX::XMFLOAT3 position;
DirectX::XMFLOAT4 color;
};
mt::Window* mWindow{ nullptr };
CD3DX12_VIEWPORT mViewport;
CD3DX12_RECT mScissorRect;
@ -71,9 +71,6 @@ private:
Microsoft::WRL::ComPtr<IDXGISwapChain4> mSwapChain;
Microsoft::WRL::ComPtr<ID3D12RootSignature> mRootSignature;
Microsoft::WRL::ComPtr<ID3D12PipelineState> mPipelineState;
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> mRtvHeap;
UINT mRtvDescriptorSize{ 0 };
@ -81,12 +78,6 @@ private:
Microsoft::WRL::ComPtr<ID3D11Resource> mWrappedBackBuffers[FrameCount];
Microsoft::WRL::ComPtr<ID2D1Bitmap1> mD2dRenderTargets[FrameCount];
Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> mTextBrush;
Microsoft::WRL::ComPtr<IDWriteTextFormat> mTextFormat;
Microsoft::WRL::ComPtr<ID3D12Resource> mVertexBuffer;
D3D12_VERTEX_BUFFER_VIEW mVertexBufferView{};
Microsoft::WRL::ComPtr<ID3D12Fence> mFence;
uint64_t mFenceValue = 0;
uint64_t mFrameFenceValues[FrameCount] = {};

View file

@ -20,7 +20,7 @@ Win32Window::Win32Window(mt::Window* window, Win32DxInterface* dxInterface)
{
if (dxInterface)
{
mDxInterface = std::make_unique<Win32DxWindowInterface>(dxInterface);
mDxInterface = std::make_unique<Win32DxWindowInterface>(window, dxInterface);
}
}
@ -80,6 +80,13 @@ void Win32Window::createNative(Win32ApplicationContext* context, DesktopManager*
MLOG_INFO("Request window create got handle: " << "0x" << mHandle);
}
void Win32Window::onPaintMessage()
{
mDesktopManager->onUiEvent(PaintEvent::Create());
mWindow->doPaint(nullptr);
}
LRESULT CALLBACK Win32Window::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
@ -89,7 +96,6 @@ LRESULT CALLBACK Win32Window::WindowProc(UINT message, WPARAM wParam, LPARAM lPa
PostQuitMessage(0);
return 0;
}
case WM_CHAR:
{
auto key_event = std::make_unique<KeyboardEvent>();
@ -99,25 +105,9 @@ LRESULT CALLBACK Win32Window::WindowProc(UINT message, WPARAM wParam, LPARAM lPa
key_event->setKeyString(StringUtils::convert(std::wstring(1, keyChar)));
mDesktopManager->onUiEvent(std::move(key_event));
}
case WM_PAINT:
{
if (mDxInterface)
{
mDxInterface->onRender();
}
else
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(mHandle, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
auto text = L"Hello World";
auto val = DrawText(hdc, (LPCSTR)(&text[0]), -1, &ps.rcPaint, 0);
EndPaint(mHandle, &ps);
}
onPaintMessage();
}
}
return DefWindowProc(mHandle, message, wParam, lParam);
@ -136,7 +126,9 @@ static LRESULT CALLBACK FreeWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPAR
if (::SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)window) == 0)
{
if (GetLastError() != 0)
{
return FALSE;
}
}
}
else
@ -157,6 +149,26 @@ void Win32Window::beforePaint(mt::Screen* screen)
{
if (mDxInterface)
{
mDxInterface->initialize(mWindow);
mDxInterface->initialize();
}
}
void Win32Window::afterPaint(mt::Screen* screen)
{
if (mDxInterface)
{
mDxInterface->onRender();
}
else
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(mHandle, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
auto text = L"Hello World";
auto val = DrawText(hdc, (LPCSTR)(&text[0]), -1, &ps.rcPaint, 0);
EndPaint(mHandle, &ps);
}
}

View file

@ -47,12 +47,11 @@ public:
void beforePaint(mt::Screen* screen);
void afterPaint(mt::Screen* screen)
{
}
void afterPaint(mt::Screen* screen);
private:
void onPaintMessage();
HWND mHandle{ 0 };
int mCmdShow{ 0 };
DesktopManager* mDesktopManager{ nullptr };

View file

@ -1,20 +0,0 @@
struct PSInput
{
float4 position : SV_POSITION;
float4 color : COLOR;
};
PSInput VSMain(float4 position : POSITION, float4 color : COLOR)
{
PSInput result;
result.position = position;
result.color = color;
return result;
}
float4 PSMain(PSInput input) : SV_TARGET
{
return input.color;
}