Start aligning Dx and OpenGl approaches.
This commit is contained in:
parent
d1ec8b4f68
commit
d99a36f24f
22 changed files with 899 additions and 366 deletions
|
@ -44,9 +44,20 @@ if(UNIX)
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
list(APPEND graphics_LIB_INCLUDES
|
list(APPEND graphics_LIB_INCLUDES
|
||||||
directx/DirectXPainter.cpp)
|
directx/DirectXPainter.cpp
|
||||||
|
directx/DirectXTextPainter.cpp
|
||||||
|
directx/DirectXMeshPainter.cpp
|
||||||
|
directx/DirectXShaderProgram.cpp
|
||||||
|
)
|
||||||
list(APPEND graphics_HEADERS
|
list(APPEND graphics_HEADERS
|
||||||
directx/DirectXPainter.h)
|
directx/DirectXPainter.h
|
||||||
|
directx/DirectXTextPainter.h
|
||||||
|
directx/DirectXMeshPainter.h
|
||||||
|
directx/DirectXShaderProgram.h
|
||||||
|
)
|
||||||
|
|
||||||
|
find_package(DirectX-Headers REQUIRED)
|
||||||
|
list(APPEND platform_LIBS D3D12.lib D3DCompiler.lib Dwrite.lib D2d1.lib Microsoft::DirectX-Headers)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_library(${MODULE_NAME} SHARED
|
add_library(${MODULE_NAME} SHARED
|
||||||
|
@ -57,6 +68,7 @@ target_include_directories(${MODULE_NAME} PUBLIC
|
||||||
${platform_INCLUDE_DIRS}
|
${platform_INCLUDE_DIRS}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/opengl
|
${CMAKE_CURRENT_SOURCE_DIR}/opengl
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/directx
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_definitions(${MODULE_NAME} PRIVATE ${DEFINES})
|
target_compile_definitions(${MODULE_NAME} PRIVATE ${DEFINES})
|
||||||
|
|
|
@ -41,3 +41,8 @@ void DrawingContext::paint()
|
||||||
|
|
||||||
mPainter->paint(this);
|
mPainter->paint(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AbstractPainter* DrawingContext::getPainter() const
|
||||||
|
{
|
||||||
|
return mPainter.get();
|
||||||
|
}
|
||||||
|
|
|
@ -26,6 +26,8 @@ public:
|
||||||
|
|
||||||
void paint();
|
void paint();
|
||||||
|
|
||||||
|
AbstractPainter* getPainter() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DrawingMode mDrawingMode;
|
DrawingMode mDrawingMode;
|
||||||
FontsManager* mFontsManager{nullptr};
|
FontsManager* mFontsManager{nullptr};
|
||||||
|
|
|
@ -8,6 +8,13 @@
|
||||||
#include "OpenGlFontTexture.h"
|
#include "OpenGlFontTexture.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include "DirectXPainter.h"
|
||||||
|
//#include "DirectXMeshPainter.h"
|
||||||
|
//#include "DirectXTextPainter.h"
|
||||||
|
//#include "DirectXShaderProgram.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "Grid.h"
|
#include "Grid.h"
|
||||||
|
|
||||||
#include "RasterPainter.h"
|
#include "RasterPainter.h"
|
||||||
|
@ -16,17 +23,28 @@
|
||||||
|
|
||||||
std::unique_ptr<AbstractPainter> PainterFactory::Create(DrawingMode drawMode)
|
std::unique_ptr<AbstractPainter> PainterFactory::Create(DrawingMode drawMode)
|
||||||
{
|
{
|
||||||
#ifdef HAS_OPENGL
|
#ifdef _WIN32
|
||||||
if (drawMode == DrawingMode::GRAPH)
|
if (drawMode == DrawingMode::GRAPH)
|
||||||
{
|
{
|
||||||
return std::make_unique<OpenGlPainter>();
|
return std::make_unique<DirectXPainter>();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return std::make_unique<RasterPainter>();
|
return std::make_unique<RasterPainter>();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
return std::make_unique<RasterPainter>();
|
#ifdef HAS_OPENGL
|
||||||
|
if (drawMode == DrawingMode::GRAPH)
|
||||||
|
{
|
||||||
|
return std::make_unique<OpenGlPainter>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return std::make_unique<RasterPainter>();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return std::make_unique<RasterPainter>();
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
242
src/graphics/directx/DirectXMeshPainter.cpp
Normal file
242
src/graphics/directx/DirectXMeshPainter.cpp
Normal file
|
@ -0,0 +1,242 @@
|
||||||
|
#include "DirectXMeshPainter.h"
|
||||||
|
|
||||||
|
#include "DrawingContext.h"
|
||||||
|
#include "DrawingSurface.h"
|
||||||
|
#include "SceneModel.h"
|
||||||
|
|
||||||
|
#include "TriMesh.h"
|
||||||
|
#include "LineMesh.h"
|
||||||
|
|
||||||
|
#include "DirectXShaderProgram.h"
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
#include <directx/d3dx12.h>
|
||||||
|
|
||||||
|
DirectXMeshPainter::DirectXMeshPainter()
|
||||||
|
{
|
||||||
|
const float aspectRatio = 1.0;
|
||||||
|
mVertexBuffer =
|
||||||
|
{
|
||||||
|
{ { 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 } }
|
||||||
|
};
|
||||||
|
|
||||||
|
auto shader_path = std::filesystem::path(__FILE__).parent_path() / "shaders.hlsl";
|
||||||
|
mShaderProgram = std::make_unique<DirectXShaderProgram>(shader_path, shader_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DirectXMeshPainter::initializeShader()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectXShaderProgram* DirectXMeshPainter::getShaderProgram() const
|
||||||
|
{
|
||||||
|
return mShaderProgram.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int DirectXMeshPainter::getVertexBufferSize() const
|
||||||
|
{
|
||||||
|
return mVertexBuffer.size()*sizeof(Vertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int DirectXMeshPainter::getVertexSize() const
|
||||||
|
{
|
||||||
|
return sizeof(Vertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
ID3D12PipelineState* DirectXMeshPainter::getPipelineState() const
|
||||||
|
{
|
||||||
|
return mPipelineState.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
ID3D12RootSignature* DirectXMeshPainter::getRootSignature() const
|
||||||
|
{
|
||||||
|
return mRootSignature.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DirectXMeshPainter::updateVertexBuffer(unsigned char* pBuffer) const
|
||||||
|
{
|
||||||
|
memcpy(pBuffer, mVertexBuffer.data(), getVertexBufferSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DirectXMeshPainter::updateCommandList(const CD3DX12_CPU_DESCRIPTOR_HANDLE& rtvHandle, ID3D12GraphicsCommandList* commandList)
|
||||||
|
{
|
||||||
|
const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
|
||||||
|
commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);
|
||||||
|
commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||||
|
commandList->IASetVertexBuffers(0, 1, &mVertexBufferView);
|
||||||
|
commandList->DrawInstanced(3, 1, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DirectXMeshPainter::initializeBuffers()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
glGenBuffers(1, &mVertexBuffer);
|
||||||
|
|
||||||
|
glGenBuffers(1, &mElementBuffer);
|
||||||
|
|
||||||
|
glGenVertexArrays(1, &mVertexArray);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void DirectXMeshPainter::paint(const std::vector<float>& verts, const std::vector<unsigned>& elements, const std::vector<float>& color, bool lines)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
glBindVertexArray(mVertexArray);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, verts.size() * sizeof(float), verts.data(), GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mElementBuffer);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, elements.size() * sizeof(unsigned), elements.data(), GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
|
||||||
|
//glm::mat4 projection = glm::ortho(0.0f, width, 0.0f, height);
|
||||||
|
//glUniformMatrix4fv(glGetUniformLocation(mShaderProgram->getHandle(), "projection"), 1, GL_FALSE, glm::value_ptr(projection));
|
||||||
|
|
||||||
|
glUseProgram(mShaderProgram->getHandle());
|
||||||
|
glBindVertexArray(mVertexArray);
|
||||||
|
|
||||||
|
int vertexColorLocation = glGetUniformLocation(mShaderProgram->getHandle(), "ourColor");
|
||||||
|
glUniform4f(vertexColorLocation, float(color[0]), float(color[1]), float(color[2]), float(color[3]));
|
||||||
|
|
||||||
|
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||||
|
|
||||||
|
if (lines)
|
||||||
|
{
|
||||||
|
glDrawElements(GL_LINES, elements.size(), GL_UNSIGNED_INT, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glDrawElements(GL_TRIANGLES, elements.size(), GL_UNSIGNED_INT, 0);
|
||||||
|
}
|
||||||
|
glBindVertexArray(0);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void DirectXMeshPainter::paint(SceneModel* model, DrawingContext* context)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
/*
|
||||||
|
if (!mShaderProgram)
|
||||||
|
{
|
||||||
|
initializeShader();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mVertexArray == 0)
|
||||||
|
{
|
||||||
|
initializeBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto surface = context->getSurface();
|
||||||
|
const auto width = float(surface->getWidth());
|
||||||
|
const auto height = float(surface->getHeight());
|
||||||
|
|
||||||
|
auto transform = model->getTransform();
|
||||||
|
auto vertices = model->getMesh()->getVerticesFlat<float>();
|
||||||
|
for (std::size_t idx = 0; idx < vertices.size(); idx++)
|
||||||
|
{
|
||||||
|
if (idx % 3 == 0)
|
||||||
|
{
|
||||||
|
auto x = vertices[idx] * transform.getScaleX() + transform.getLocation().getX();
|
||||||
|
vertices[idx] = 2 * x / width - 1.0;
|
||||||
|
}
|
||||||
|
else if (idx % 3 == 1)
|
||||||
|
{
|
||||||
|
auto y = vertices[idx] * transform.getScaleY() + transform.getLocation().getY();
|
||||||
|
vertices[idx] = 1.0 - 2 * y / height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned> indices;
|
||||||
|
const bool line_mesh = model->getMesh()->getType() == AbstractMesh::MeshType::LINE;
|
||||||
|
if (line_mesh)
|
||||||
|
{
|
||||||
|
indices = dynamic_cast<LineMesh*>(model->getMesh())->getEdgeNodeIds();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
indices = dynamic_cast<TriMesh*>(model->getMesh())->getFaceNodeIds();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto model_color = model->getColor().getAsVectorDouble();
|
||||||
|
std::vector<float> color = { float(model_color[0]), float(model_color[1]), float(model_color[2]), float(model_color[3]) };
|
||||||
|
|
||||||
|
paint(vertices, indices, color, line_mesh);
|
||||||
|
|
||||||
|
if (model->getShowOutline())
|
||||||
|
{
|
||||||
|
auto edge_indices = dynamic_cast<TriMesh*>(model->getMesh())->getEdgeNodeIds();
|
||||||
|
paint(vertices, edge_indices, { 0, 0, 0, 1 }, true);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void DirectXMeshPainter::createVertexBuffer(ID3D12Device* device)
|
||||||
|
{
|
||||||
|
// 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(getVertexBufferSize());
|
||||||
|
device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&mD3dVertexBuffer));
|
||||||
|
|
||||||
|
// Copy the mesh data to the vertex buffer.
|
||||||
|
UINT8* pVertexDataBegin;
|
||||||
|
CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU.
|
||||||
|
mD3dVertexBuffer->Map(0, &readRange, reinterpret_cast<void**>(&pVertexDataBegin));
|
||||||
|
updateVertexBuffer(pVertexDataBegin);
|
||||||
|
mD3dVertexBuffer->Unmap(0, nullptr);
|
||||||
|
|
||||||
|
// Initialize the vertex buffer view.
|
||||||
|
mVertexBufferView.BufferLocation = mD3dVertexBuffer->GetGPUVirtualAddress();
|
||||||
|
mVertexBufferView.StrideInBytes = getVertexSize();
|
||||||
|
mVertexBufferView.SizeInBytes = getVertexBufferSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DirectXMeshPainter::createRootSignature(ID3D12Device* device)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&mRootSignature));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DirectXMeshPainter::createPipelineStateObject(ID3D12Device* device)
|
||||||
|
{
|
||||||
|
auto vert_shader = mShaderProgram->getVertexShader();
|
||||||
|
auto pixel_shader = mShaderProgram->getPixelShader();
|
||||||
|
|
||||||
|
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 }
|
||||||
|
};
|
||||||
|
|
||||||
|
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
|
||||||
|
psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) };
|
||||||
|
psoDesc.pRootSignature = mRootSignature.Get();
|
||||||
|
psoDesc.VS = CD3DX12_SHADER_BYTECODE(vert_shader);
|
||||||
|
psoDesc.PS = CD3DX12_SHADER_BYTECODE(pixel_shader);
|
||||||
|
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;
|
||||||
|
device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&mPipelineState));
|
||||||
|
}
|
60
src/graphics/directx/DirectXMeshPainter.h
Normal file
60
src/graphics/directx/DirectXMeshPainter.h
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <wrl.h>
|
||||||
|
#include <directxmath.h>
|
||||||
|
#include <d3d12.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class DrawingContext;
|
||||||
|
class DirectXShaderProgram;
|
||||||
|
class SceneModel;
|
||||||
|
|
||||||
|
struct CD3DX12_CPU_DESCRIPTOR_HANDLE;
|
||||||
|
|
||||||
|
class DirectXMeshPainter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DirectXMeshPainter();
|
||||||
|
|
||||||
|
void paint(SceneModel* model, DrawingContext* context);
|
||||||
|
|
||||||
|
DirectXShaderProgram* getShaderProgram() const;
|
||||||
|
|
||||||
|
void createVertexBuffer(ID3D12Device* device);
|
||||||
|
void createRootSignature(ID3D12Device* device);
|
||||||
|
void createPipelineStateObject(ID3D12Device* device);
|
||||||
|
|
||||||
|
ID3D12PipelineState* getPipelineState() const;
|
||||||
|
ID3D12RootSignature* getRootSignature() const;
|
||||||
|
|
||||||
|
void updateCommandList(const CD3DX12_CPU_DESCRIPTOR_HANDLE& rtvHandle, ID3D12GraphicsCommandList* commandList);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Vertex
|
||||||
|
{
|
||||||
|
DirectX::XMFLOAT3 position;
|
||||||
|
DirectX::XMFLOAT4 color;
|
||||||
|
};
|
||||||
|
|
||||||
|
void initializeShader();
|
||||||
|
void initializeBuffers();
|
||||||
|
|
||||||
|
unsigned int getVertexBufferSize() const;
|
||||||
|
unsigned int getVertexSize() const;
|
||||||
|
void updateVertexBuffer(unsigned char* pBuffer) const;
|
||||||
|
|
||||||
|
void paint(const std::vector<float>& verts, const std::vector<unsigned>& elements, const std::vector<float>& color, bool lines = false);
|
||||||
|
|
||||||
|
unsigned int mVertexBufferSize{ 0 };
|
||||||
|
std::vector<Vertex> mVertexBuffer;
|
||||||
|
|
||||||
|
Microsoft::WRL::ComPtr<ID3D12Resource> mD3dVertexBuffer;
|
||||||
|
D3D12_VERTEX_BUFFER_VIEW mVertexBufferView{};
|
||||||
|
|
||||||
|
Microsoft::WRL::ComPtr<ID3D12RootSignature> mRootSignature;
|
||||||
|
Microsoft::WRL::ComPtr<ID3D12PipelineState> mPipelineState;
|
||||||
|
|
||||||
|
std::unique_ptr<DirectXShaderProgram> mShaderProgram;
|
||||||
|
};
|
|
@ -0,0 +1,73 @@
|
||||||
|
#include "DirectXPainter.h"
|
||||||
|
|
||||||
|
#include "DrawingContext.h"
|
||||||
|
#include "DrawingSurface.h"
|
||||||
|
#include "Scene.h"
|
||||||
|
#include "SceneItem.h"
|
||||||
|
#include "SceneModel.h"
|
||||||
|
#include "SceneText.h"
|
||||||
|
|
||||||
|
#include "TriMesh.h"
|
||||||
|
|
||||||
|
#include "FontsManager.h"
|
||||||
|
#include "FontGlyph.h"
|
||||||
|
#include "TextData.h"
|
||||||
|
|
||||||
|
#include "DirectXShaderProgram.h"
|
||||||
|
#include "DirectXMeshPainter.h"
|
||||||
|
#include "DirectXTextPainter.h"
|
||||||
|
|
||||||
|
#include "File.h"
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
DirectXPainter::DirectXPainter()
|
||||||
|
: mMeshPainter(std::make_unique<DirectXMeshPainter>()),
|
||||||
|
mTextPainter(std::make_unique<DirectXTextPainter>())
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectXMeshPainter* DirectXPainter::getMeshPainter() const
|
||||||
|
{
|
||||||
|
return mMeshPainter.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectXTextPainter* DirectXPainter::getTextPainter() const
|
||||||
|
{
|
||||||
|
return mTextPainter.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DirectXPainter::paint(DrawingContext* context)
|
||||||
|
{
|
||||||
|
auto surface = context->getSurface();
|
||||||
|
const auto width = double(surface->getWidth());
|
||||||
|
const auto height = double(surface->getHeight());
|
||||||
|
|
||||||
|
/*
|
||||||
|
glViewport(0, 0, width, height);
|
||||||
|
glOrtho(0, width, 0, height, -1.0, 1.0);
|
||||||
|
|
||||||
|
glClearColor(0.5, 0.5, 1.0, 0.0);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
*/
|
||||||
|
|
||||||
|
auto scene = context->getSurface()->getScene();
|
||||||
|
for (const auto item : scene->getItems())
|
||||||
|
{
|
||||||
|
if (item->getType() == SceneItem::Type::MODEL)
|
||||||
|
{
|
||||||
|
mMeshPainter->paint(dynamic_cast<SceneModel*>(item), context);
|
||||||
|
}
|
||||||
|
else if (item->getType() == SceneItem::Type::TEXT)
|
||||||
|
{
|
||||||
|
mTextPainter->paint(dynamic_cast<SceneText*>(item), context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
glFlush();
|
||||||
|
*/
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "AbstractPainter.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class DrawingContext;
|
||||||
|
class DirectXMeshPainter;
|
||||||
|
class DirectXTextPainter;
|
||||||
|
|
||||||
|
class DirectXPainter : public AbstractPainter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DirectXPainter();
|
||||||
|
void paint(DrawingContext* context) override;
|
||||||
|
|
||||||
|
DirectXMeshPainter* getMeshPainter() const;
|
||||||
|
DirectXTextPainter* getTextPainter() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<DirectXMeshPainter> mMeshPainter;
|
||||||
|
std::unique_ptr<DirectXTextPainter> mTextPainter;
|
||||||
|
};
|
31
src/graphics/directx/DirectXShaderProgram.cpp
Normal file
31
src/graphics/directx/DirectXShaderProgram.cpp
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#include "DirectXShaderProgram.h"
|
||||||
|
|
||||||
|
#include "File.h"
|
||||||
|
#include "FileLogger.h"
|
||||||
|
|
||||||
|
#include <d3d12.h>
|
||||||
|
#include <d3dcompiler.h>
|
||||||
|
|
||||||
|
DirectXShaderProgram::DirectXShaderProgram(const Path& vertShaderPath, const Path& fragShaderPath)
|
||||||
|
{
|
||||||
|
#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
|
||||||
|
|
||||||
|
D3DCompileFromFile(vertShaderPath.c_str(), nullptr, nullptr, "VSMain", "vs_5_0", compileFlags, 0, &mVertexShader, nullptr);
|
||||||
|
D3DCompileFromFile(fragShaderPath.c_str(), nullptr, nullptr, "PSMain", "ps_5_0", compileFlags, 0, &mPixelShader, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
ID3DBlob* DirectXShaderProgram::getVertexShader() const
|
||||||
|
{
|
||||||
|
return mVertexShader.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
ID3DBlob* DirectXShaderProgram::getPixelShader() const
|
||||||
|
{
|
||||||
|
return mPixelShader.Get();
|
||||||
|
}
|
20
src/graphics/directx/DirectXShaderProgram.h
Normal file
20
src/graphics/directx/DirectXShaderProgram.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <wrl.h>
|
||||||
|
#include <D3Dcommon.h>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
using Path = std::filesystem::path;
|
||||||
|
|
||||||
|
class DirectXShaderProgram
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DirectXShaderProgram(const Path& vertShaderPath, const Path& pixelShaderPath);
|
||||||
|
|
||||||
|
ID3DBlob* getVertexShader() const;
|
||||||
|
ID3DBlob* getPixelShader() const;
|
||||||
|
private:
|
||||||
|
Microsoft::WRL::ComPtr<ID3DBlob> mVertexShader;
|
||||||
|
Microsoft::WRL::ComPtr<ID3DBlob> mPixelShader;
|
||||||
|
};
|
64
src/graphics/directx/DirectXTextPainter.cpp
Normal file
64
src/graphics/directx/DirectXTextPainter.cpp
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
#include "DirectXTextPainter.h"
|
||||||
|
|
||||||
|
#include "DrawingContext.h"
|
||||||
|
#include "DrawingSurface.h"
|
||||||
|
|
||||||
|
#include "FontsManager.h"
|
||||||
|
#include "FontGlyph.h"
|
||||||
|
|
||||||
|
#include "DirectXShaderProgram.h"
|
||||||
|
#include "TextData.h"
|
||||||
|
|
||||||
|
#include "SceneText.h"
|
||||||
|
|
||||||
|
#include "File.h"
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <d2d1_3.h>
|
||||||
|
#include <d2d1_1.h>
|
||||||
|
#include <dwrite.h>
|
||||||
|
|
||||||
|
DirectXTextPainter::DirectXTextPainter()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DirectXTextPainter::paint(SceneText* text, DrawingContext* context)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void DirectXTextPainter::paint(ID2D1DeviceContext2* d2dContext, float width, float height)
|
||||||
|
{
|
||||||
|
D2D1_RECT_F textRect = D2D1::RectF(0, 0, width, height);
|
||||||
|
static const WCHAR text[] = L"11On12";
|
||||||
|
|
||||||
|
d2dContext->BeginDraw();
|
||||||
|
d2dContext->SetTransform(D2D1::Matrix3x2F::Identity());
|
||||||
|
d2dContext->DrawText(text, _countof(text) - 1, mTextFormat.Get(), &textRect, mTextBrush.Get());
|
||||||
|
d2dContext->EndDraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DirectXTextPainter::initializeBrush(ID2D1DeviceContext2* d2dContext)
|
||||||
|
{
|
||||||
|
d2dContext->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &mTextBrush);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DirectXTextPainter::initializeTextFormat(IDWriteFactory* directWriteFactory)
|
||||||
|
{
|
||||||
|
directWriteFactory->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);
|
||||||
|
}
|
||||||
|
|
37
src/graphics/directx/DirectXTextPainter.h
Normal file
37
src/graphics/directx/DirectXTextPainter.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <wrl.h>
|
||||||
|
#include <dwrite.h>
|
||||||
|
#include <d2d1_3.h>
|
||||||
|
#include <d2d1_1.h>
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class DrawingContext;
|
||||||
|
class DirectXShaderProgram;
|
||||||
|
|
||||||
|
class TextData;
|
||||||
|
class SceneText;
|
||||||
|
|
||||||
|
struct ID2D1DeviceContext2;
|
||||||
|
struct ID2D1SolidColorBrush;
|
||||||
|
struct IDWriteFactory;
|
||||||
|
|
||||||
|
class DirectXTextPainter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DirectXTextPainter();
|
||||||
|
|
||||||
|
void paint(SceneText* text, DrawingContext* context);
|
||||||
|
|
||||||
|
void paint(ID2D1DeviceContext2* d2dContext, float width, float height);
|
||||||
|
|
||||||
|
void initializeBrush(ID2D1DeviceContext2* d2dContext);
|
||||||
|
|
||||||
|
void initializeTextFormat(IDWriteFactory* directWriteFactory);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> mTextBrush;
|
||||||
|
Microsoft::WRL::ComPtr<IDWriteTextFormat> mTextFormat;
|
||||||
|
};
|
|
@ -116,6 +116,11 @@ void Window::show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DrawingContext* Window::getDrawingContent() const
|
||||||
|
{
|
||||||
|
return mDrawingContext.get();
|
||||||
|
}
|
||||||
|
|
||||||
void Window::doPaint(mt::Screen* screen)
|
void Window::doPaint(mt::Screen* screen)
|
||||||
{
|
{
|
||||||
if (mPlatformWindow)
|
if (mPlatformWindow)
|
||||||
|
|
|
@ -98,6 +98,8 @@ public:
|
||||||
return mParent;
|
return mParent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DrawingContext* getDrawingContent() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WidgetPtr mWidget {nullptr};
|
WidgetPtr mWidget {nullptr};
|
||||||
std::string mTitle;
|
std::string mTitle;
|
||||||
|
|
|
@ -97,6 +97,11 @@ unsigned TextNode::getNumSceneItems() const
|
||||||
|
|
||||||
void TextNode::updateLines(FontsManager* fontsManager)
|
void TextNode::updateLines(FontsManager* fontsManager)
|
||||||
{
|
{
|
||||||
|
if (!fontsManager)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto original_count = mTextData.mLines.size();
|
auto original_count = mTextData.mLines.size();
|
||||||
std::vector<std::string> lines = StringUtils::toLines(mTextData.mContent);
|
std::vector<std::string> lines = StringUtils::toLines(mTextData.mContent);
|
||||||
std::vector<std::string> output_lines;
|
std::vector<std::string> output_lines;
|
||||||
|
|
|
@ -31,7 +31,6 @@ void Win32DxInterface::getHardwareAdapter(IDXGIAdapter1** ppAdapter)
|
||||||
IDXGIAdapter1* pAdapter = nullptr;
|
IDXGIAdapter1* pAdapter = nullptr;
|
||||||
if (DXGI_ERROR_NOT_FOUND == mFactory->EnumAdapters1(adapterIndex, &pAdapter))
|
if (DXGI_ERROR_NOT_FOUND == mFactory->EnumAdapters1(adapterIndex, &pAdapter))
|
||||||
{
|
{
|
||||||
// No more adapters to enumerate.
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,50 +91,71 @@ ID3D11DeviceContext* Win32DxInterface::getD3d11DeviceContext() const
|
||||||
|
|
||||||
void Win32DxInterface::initialize()
|
void Win32DxInterface::initialize()
|
||||||
{
|
{
|
||||||
if (!DirectX::XMVerifyCPUSupport())
|
MLOG_INFO("Initialize DX");
|
||||||
{
|
UINT dxgiFactoryFlags = 0;
|
||||||
MLOG_ERROR("Directx math not supported");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(DEBUG) || defined(_DEBUG)
|
#if defined(DEBUG) || defined(_DEBUG)
|
||||||
// Enable the D3D12 debug layer.
|
|
||||||
{
|
{
|
||||||
ID3D12Debug* debugController;
|
Microsoft::WRL::ComPtr<ID3D12Debug> debugController;
|
||||||
D3D12GetDebugInterface(IID_PPV_ARGS(&debugController));
|
if (SUCCEEDED(::D3D12GetDebugInterface(IID_PPV_ARGS(&debugController))))
|
||||||
debugController->EnableDebugLayer();
|
{
|
||||||
|
debugController->EnableDebugLayer();
|
||||||
|
dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#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);
|
getHardwareAdapter(&pAdapter);
|
||||||
|
|
||||||
if (pAdapter)
|
if (pAdapter)
|
||||||
{
|
{
|
||||||
MLOG_INFO("Found adapter");
|
if (!SUCCEEDED(D3D12CreateDevice(pAdapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&mDevice))))
|
||||||
if (SUCCEEDED(D3D12CreateDevice(pAdapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&mDevice))))
|
|
||||||
{
|
{
|
||||||
MLOG_INFO("Got device");
|
MLOG_ERROR("Failed to create D3D12 device.");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MLOG_INFO("No adapter found");
|
MLOG_ERROR("Failed to get DX hardware adapter.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
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))))
|
||||||
|
{
|
||||||
|
MLOG_ERROR("Failed to create command queue.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&mCommandQueue));
|
const auto init_2d_ok = initializeD2d();
|
||||||
|
mIsValid = init_2d_ok;
|
||||||
mIsValid = initializeD2d();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Win32DxInterface::initializeD2d()
|
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;
|
Microsoft::WRL::ComPtr<ID3D11Device> d3d11Device;
|
||||||
UINT d3d11DeviceFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
|
UINT d3d11DeviceFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
|
||||||
|
@ -151,24 +171,12 @@ bool Win32DxInterface::initializeD2d()
|
||||||
&mD3d11DeviceContext,
|
&mD3d11DeviceContext,
|
||||||
nullptr
|
nullptr
|
||||||
);
|
);
|
||||||
|
|
||||||
d3d11Device.As(&mD3d11On12Device);
|
d3d11Device.As(&mD3d11On12Device);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Create D2D/DWrite components.
|
bool Win32DxInterface::initializeDirectWrite()
|
||||||
{
|
{
|
||||||
D2D1_DEVICE_CONTEXT_OPTIONS deviceOptions = D2D1_DEVICE_CONTEXT_OPTIONS_NONE;
|
DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &mDWriteFactory);
|
||||||
D2D1_FACTORY_OPTIONS d2dFactoryOptions = {};
|
|
||||||
|
|
||||||
D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory3), &d2dFactoryOptions, &mD2dFactory);
|
|
||||||
Microsoft::WRL::ComPtr<IDXGIDevice> dxgiDevice;
|
|
||||||
mD3d11On12Device.As(&dxgiDevice);
|
|
||||||
|
|
||||||
mD2dFactory->CreateDevice(dxgiDevice.Get(), &mD2dDevice);
|
|
||||||
|
|
||||||
mD2dDevice->CreateDeviceContext(deviceOptions, &mD2dDeviceContext);
|
|
||||||
|
|
||||||
DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &mDWriteFactory);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
|
@ -42,6 +42,8 @@ private:
|
||||||
void getHardwareAdapter(IDXGIAdapter1** ppAdapter);
|
void getHardwareAdapter(IDXGIAdapter1** ppAdapter);
|
||||||
|
|
||||||
bool initializeD2d();
|
bool initializeD2d();
|
||||||
|
bool initializeD11on12();
|
||||||
|
bool initializeDirectWrite();
|
||||||
|
|
||||||
bool mIsValid{ false };
|
bool mIsValid{ false };
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,13 @@
|
||||||
#include "Win32Window.h"
|
#include "Win32Window.h"
|
||||||
#include "Window.h"
|
#include "Window.h"
|
||||||
#include "Widget.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 <dxgi.h>
|
||||||
#include <dxgi1_6.h>
|
#include <dxgi1_6.h>
|
||||||
|
@ -14,11 +21,13 @@
|
||||||
#include <d3d11on12.h>
|
#include <d3d11on12.h>
|
||||||
#include <d2d1_3.h>
|
#include <d2d1_3.h>
|
||||||
#include <d2d1_1.h>
|
#include <d2d1_1.h>
|
||||||
|
#include <D3Dcommon.h>
|
||||||
|
|
||||||
#include <dwrite.h>
|
#include <dwrite.h>
|
||||||
|
|
||||||
Win32DxWindowInterface::Win32DxWindowInterface(Win32DxInterface* dxInterface)
|
Win32DxWindowInterface::Win32DxWindowInterface(mt::Window* window, Win32DxInterface* dxInterface)
|
||||||
: mDxInterface(dxInterface)
|
: mWindow(window),
|
||||||
|
mDxInterface(dxInterface)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -37,6 +46,11 @@ void Win32DxWindowInterface::destroyWindow()
|
||||||
|
|
||||||
void Win32DxWindowInterface::onRender()
|
void Win32DxWindowInterface::onRender()
|
||||||
{
|
{
|
||||||
|
if (!mIsValid)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Record all the commands we need to render the scene into the command list.
|
// Record all the commands we need to render the scene into the command list.
|
||||||
populateCommandList();
|
populateCommandList();
|
||||||
|
|
||||||
|
@ -54,6 +68,8 @@ void Win32DxWindowInterface::onRender()
|
||||||
|
|
||||||
void Win32DxWindowInterface::populateCommandList()
|
void Win32DxWindowInterface::populateCommandList()
|
||||||
{
|
{
|
||||||
|
auto painter = dynamic_cast<DirectXPainter*>(mWindow->getDrawingContent()->getPainter());
|
||||||
|
|
||||||
// Command list allocators can only be reset when the associated
|
// Command list allocators can only be reset when the associated
|
||||||
// command lists have finished execution on the GPU; apps should use
|
// command lists have finished execution on the GPU; apps should use
|
||||||
// fences to determine GPU execution progress.
|
// fences to determine GPU execution progress.
|
||||||
|
@ -62,10 +78,10 @@ void Win32DxWindowInterface::populateCommandList()
|
||||||
// However, when ExecuteCommandList() is called on a particular command
|
// However, when ExecuteCommandList() is called on a particular command
|
||||||
// list, that command list can then be reset at any time and must be before
|
// list, that command list can then be reset at any time and must be before
|
||||||
// re-recording.
|
// re-recording.
|
||||||
mCommandList->Reset(mCommandAllocator.Get(), mPipelineState.Get());
|
mCommandList->Reset(mCommandAllocator.Get(), painter->getMeshPainter()->getPipelineState());
|
||||||
|
|
||||||
// Set necessary state.
|
// Set necessary state.
|
||||||
mCommandList->SetGraphicsRootSignature(mRootSignature.Get());
|
mCommandList->SetGraphicsRootSignature(painter->getMeshPainter()->getRootSignature());
|
||||||
mCommandList->RSSetViewports(1, &mViewport);
|
mCommandList->RSSetViewports(1, &mViewport);
|
||||||
mCommandList->RSSetScissorRects(1, &mScissorRect);
|
mCommandList->RSSetScissorRects(1, &mScissorRect);
|
||||||
|
|
||||||
|
@ -76,12 +92,7 @@ void Win32DxWindowInterface::populateCommandList()
|
||||||
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(mRtvHeap->GetCPUDescriptorHandleForHeapStart(), static_cast<INT>(mFrameIndex), mRtvDescriptorSize);
|
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(mRtvHeap->GetCPUDescriptorHandleForHeapStart(), static_cast<INT>(mFrameIndex), mRtvDescriptorSize);
|
||||||
mCommandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr);
|
mCommandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr);
|
||||||
|
|
||||||
// Record commands.
|
painter->getMeshPainter()->updateCommandList(rtvHandle, mCommandList.Get());
|
||||||
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);
|
|
||||||
|
|
||||||
// Indicate that the back buffer will now be used to present.
|
// 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);
|
//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();
|
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()
|
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.
|
// Acquire our wrapped render target resource for the current back buffer.
|
||||||
mDxInterface->get11On12Device()->AcquireWrappedResources(mWrappedBackBuffers[mFrameIndex].GetAddressOf(), 1);
|
mDxInterface->get11On12Device()->AcquireWrappedResources(mWrappedBackBuffers[mFrameIndex].GetAddressOf(), 1);
|
||||||
|
|
||||||
// Render text directly to the back buffer.
|
// Render text directly to the back buffer.
|
||||||
mDxInterface->getD2dContext()->SetTarget(mD2dRenderTargets[mFrameIndex].Get());
|
mDxInterface->getD2dContext()->SetTarget(mD2dRenderTargets[mFrameIndex].Get());
|
||||||
mDxInterface->getD2dContext()->BeginDraw();
|
|
||||||
mDxInterface->getD2dContext()->SetTransform(D2D1::Matrix3x2F::Identity());
|
auto painter = dynamic_cast<DirectXPainter*>(mWindow->getDrawingContent()->getPainter());
|
||||||
mDxInterface->getD2dContext()->DrawText(
|
D2D1_SIZE_F rtSize = mD2dRenderTargets[mFrameIndex]->GetSize();
|
||||||
text,
|
painter->getTextPainter()->paint(mDxInterface->getD2dContext(), rtSize.width, rtSize.height);
|
||||||
_countof(text) - 1,
|
|
||||||
mTextFormat.Get(),
|
|
||||||
&textRect,
|
|
||||||
mTextBrush.Get()
|
|
||||||
);
|
|
||||||
mDxInterface->getD2dContext()->EndDraw();
|
|
||||||
|
|
||||||
// Release our wrapped render target resource. Releasing
|
// Release our wrapped render target resource. Releasing
|
||||||
// transitions the back buffer resource to the state specified
|
// transitions the back buffer resource to the state specified
|
||||||
|
@ -370,6 +122,177 @@ void Win32DxWindowInterface::renderD2d()
|
||||||
mDxInterface->getD3d11DeviceContext()->Flush();
|
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()
|
void Win32DxWindowInterface::waitForPreviousFrame()
|
||||||
{
|
{
|
||||||
// Signal and increment the fence value.
|
// Signal and increment the fence value.
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
#include <wrl.h>
|
#include <wrl.h>
|
||||||
#include <d3d12.h>
|
#include <d3d12.h>
|
||||||
#include <directxmath.h>
|
|
||||||
#include <directx/d3dx12.h>
|
#include <directx/d3dx12.h>
|
||||||
|
|
||||||
class Win32DxInterface;
|
class Win32DxInterface;
|
||||||
|
@ -25,27 +24,23 @@ struct ID3D12PipelineState;
|
||||||
|
|
||||||
struct ID3D11Resource;
|
struct ID3D11Resource;
|
||||||
struct ID2D1Bitmap1;
|
struct ID2D1Bitmap1;
|
||||||
struct ID2D1SolidColorBrush;
|
struct D2D1_BITMAP_PROPERTIES1;
|
||||||
struct IDWriteTextFormat;
|
struct CD3DX12_CPU_DESCRIPTOR_HANDLE;
|
||||||
|
|
||||||
class Win32DxWindowInterface
|
class Win32DxWindowInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Win32DxWindowInterface(Win32DxInterface* dxInterface);
|
Win32DxWindowInterface(mt::Window* window, Win32DxInterface* dxInterface);
|
||||||
|
|
||||||
~Win32DxWindowInterface();
|
~Win32DxWindowInterface();
|
||||||
|
|
||||||
bool initialize(mt::Window* window);
|
bool initialize();
|
||||||
|
|
||||||
void onRender();
|
void onRender();
|
||||||
|
|
||||||
//void afterPaint();
|
|
||||||
|
|
||||||
//void resizeViewPort(unsigned width, unsigned height);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void loadPipeline(mt::Window* window);
|
bool loadPipeline();
|
||||||
void loadAssets();
|
bool loadAssets();
|
||||||
|
|
||||||
void populateCommandList();
|
void populateCommandList();
|
||||||
void waitForPreviousFrame();
|
void waitForPreviousFrame();
|
||||||
|
@ -53,16 +48,21 @@ private:
|
||||||
|
|
||||||
void renderD2d();
|
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;
|
static const UINT FrameCount = 2;
|
||||||
Win32DxInterface* mDxInterface{ nullptr };
|
Win32DxInterface* mDxInterface{ nullptr };
|
||||||
bool mInitialized{ false };
|
bool mInitialized{ false };
|
||||||
|
bool mIsValid{ false };
|
||||||
|
|
||||||
struct Vertex
|
mt::Window* mWindow{ nullptr };
|
||||||
{
|
|
||||||
DirectX::XMFLOAT3 position;
|
|
||||||
DirectX::XMFLOAT4 color;
|
|
||||||
};
|
|
||||||
|
|
||||||
CD3DX12_VIEWPORT mViewport;
|
CD3DX12_VIEWPORT mViewport;
|
||||||
CD3DX12_RECT mScissorRect;
|
CD3DX12_RECT mScissorRect;
|
||||||
|
|
||||||
|
@ -71,9 +71,6 @@ private:
|
||||||
|
|
||||||
Microsoft::WRL::ComPtr<IDXGISwapChain4> mSwapChain;
|
Microsoft::WRL::ComPtr<IDXGISwapChain4> mSwapChain;
|
||||||
|
|
||||||
Microsoft::WRL::ComPtr<ID3D12RootSignature> mRootSignature;
|
|
||||||
Microsoft::WRL::ComPtr<ID3D12PipelineState> mPipelineState;
|
|
||||||
|
|
||||||
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> mRtvHeap;
|
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> mRtvHeap;
|
||||||
UINT mRtvDescriptorSize{ 0 };
|
UINT mRtvDescriptorSize{ 0 };
|
||||||
|
|
||||||
|
@ -81,12 +78,6 @@ private:
|
||||||
Microsoft::WRL::ComPtr<ID3D11Resource> mWrappedBackBuffers[FrameCount];
|
Microsoft::WRL::ComPtr<ID3D11Resource> mWrappedBackBuffers[FrameCount];
|
||||||
Microsoft::WRL::ComPtr<ID2D1Bitmap1> mD2dRenderTargets[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;
|
Microsoft::WRL::ComPtr<ID3D12Fence> mFence;
|
||||||
uint64_t mFenceValue = 0;
|
uint64_t mFenceValue = 0;
|
||||||
uint64_t mFrameFenceValues[FrameCount] = {};
|
uint64_t mFrameFenceValues[FrameCount] = {};
|
||||||
|
|
|
@ -20,7 +20,7 @@ Win32Window::Win32Window(mt::Window* window, Win32DxInterface* dxInterface)
|
||||||
{
|
{
|
||||||
if (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);
|
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)
|
LRESULT CALLBACK Win32Window::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
switch (message)
|
switch (message)
|
||||||
|
@ -89,7 +96,6 @@ LRESULT CALLBACK Win32Window::WindowProc(UINT message, WPARAM wParam, LPARAM lPa
|
||||||
PostQuitMessage(0);
|
PostQuitMessage(0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
case WM_CHAR:
|
case WM_CHAR:
|
||||||
{
|
{
|
||||||
auto key_event = std::make_unique<KeyboardEvent>();
|
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)));
|
key_event->setKeyString(StringUtils::convert(std::wstring(1, keyChar)));
|
||||||
mDesktopManager->onUiEvent(std::move(key_event));
|
mDesktopManager->onUiEvent(std::move(key_event));
|
||||||
}
|
}
|
||||||
|
|
||||||
case WM_PAINT:
|
case WM_PAINT:
|
||||||
{
|
{
|
||||||
if (mDxInterface)
|
onPaintMessage();
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return DefWindowProc(mHandle, message, wParam, lParam);
|
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 (::SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)window) == 0)
|
||||||
{
|
{
|
||||||
if (GetLastError() != 0)
|
if (GetLastError() != 0)
|
||||||
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -157,6 +149,26 @@ void Win32Window::beforePaint(mt::Screen* screen)
|
||||||
{
|
{
|
||||||
if (mDxInterface)
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -47,12 +47,11 @@ public:
|
||||||
|
|
||||||
void beforePaint(mt::Screen* screen);
|
void beforePaint(mt::Screen* screen);
|
||||||
|
|
||||||
void afterPaint(mt::Screen* screen)
|
void afterPaint(mt::Screen* screen);
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void onPaintMessage();
|
||||||
|
|
||||||
HWND mHandle{ 0 };
|
HWND mHandle{ 0 };
|
||||||
int mCmdShow{ 0 };
|
int mCmdShow{ 0 };
|
||||||
DesktopManager* mDesktopManager{ nullptr };
|
DesktopManager* mDesktopManager{ nullptr };
|
||||||
|
|
Loading…
Reference in a new issue