This commit is contained in:
Dmitry 2019-04-03 01:02:02 +03:00
parent 70a1778d22
commit 85f90cda62
49 changed files with 1755 additions and 135 deletions

View File

@ -92,11 +92,19 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\CGI\CGI.h" />
<ClInclude Include="src\CGI\CommandBufferD3D12.h" />
<ClInclude Include="src\CGI\GeometryD3D12.h" />
<ClInclude Include="src\CGI\PipelineD3D12.h" />
<ClInclude Include="src\CGI\RendererD3D12.h" />
<ClInclude Include="src\CGI\ShaderD3D12.h" />
<ClInclude Include="src\stdafx.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\CGI\CommandBufferD3D12.cpp" />
<ClCompile Include="src\CGI\GeometryD3D12.cpp" />
<ClCompile Include="src\CGI\PipelineD3D12.cpp" />
<ClCompile Include="src\CGI\RendererD3D12.cpp" />
<ClCompile Include="src\CGI\ShaderD3D12.cpp" />
<ClCompile Include="src\main.cpp" />
<ClCompile Include="src\stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>

View File

@ -30,6 +30,18 @@
<ClInclude Include="src\CGI\RendererD3D12.h">
<Filter>src\CGI</Filter>
</ClInclude>
<ClInclude Include="src\CGI\CommandBufferD3D12.h">
<Filter>src\CGI</Filter>
</ClInclude>
<ClInclude Include="src\CGI\GeometryD3D12.h">
<Filter>src\CGI</Filter>
</ClInclude>
<ClInclude Include="src\CGI\PipelineD3D12.h">
<Filter>src\CGI</Filter>
</ClInclude>
<ClInclude Include="src\CGI\ShaderD3D12.h">
<Filter>src\CGI</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\main.cpp">
@ -41,5 +53,17 @@
<ClCompile Include="src\CGI\RendererD3D12.cpp">
<Filter>src\CGI</Filter>
</ClCompile>
<ClCompile Include="src\CGI\CommandBufferD3D12.cpp">
<Filter>src\CGI</Filter>
</ClCompile>
<ClCompile Include="src\CGI\GeometryD3D12.cpp">
<Filter>src\CGI</Filter>
</ClCompile>
<ClCompile Include="src\CGI\PipelineD3D12.cpp">
<Filter>src\CGI</Filter>
</ClCompile>
<ClCompile Include="src\CGI\ShaderD3D12.cpp">
<Filter>src\CGI</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -1,3 +1,7 @@
#pragma once
#include "CommandBufferD3D12.h"
#include "GeometryD3D12.h"
#include "PipelineD3D12.h"
#include "ShaderD3D12.h"
#include "RendererD3D12.h"

View File

@ -0,0 +1,92 @@
#include "stdafx.h"
using namespace verus;
using namespace verus::CGI;
ID3D12GraphicsCommandList* CommandBufferD3D12::GetGraphicsCommandList() const
{
VERUS_QREF_RENDERER;
return _pCommandLists[renderer->GetRingBufferIndex()].Get();
}
CommandBufferD3D12::CommandBufferD3D12()
{
}
CommandBufferD3D12::~CommandBufferD3D12()
{
Done();
}
void CommandBufferD3D12::Init()
{
VERUS_INIT();
}
void CommandBufferD3D12::Done()
{
VERUS_DONE(CommandBufferD3D12);
}
void CommandBufferD3D12::Begin()
{
HRESULT hr = 0;
if (FAILED(hr = GetGraphicsCommandList()->Reset(nullptr, nullptr)))
throw VERUS_RUNTIME_ERROR << "Reset(), hr=" << VERUS_HR(hr);
}
void CommandBufferD3D12::End()
{
HRESULT hr = 0;
if (FAILED(hr = GetGraphicsCommandList()->Close()))
throw VERUS_RUNTIME_ERROR << "Close(), hr=" << VERUS_HR(hr);
}
void CommandBufferD3D12::BindVertexBuffers()
{
GetGraphicsCommandList()->IASetVertexBuffers(0, 1, nullptr);
}
void CommandBufferD3D12::BindIndexBuffer()
{
GetGraphicsCommandList()->IASetIndexBuffer(nullptr);
}
void CommandBufferD3D12::SetScissor()
{
GetGraphicsCommandList()->RSSetScissorRects(1, nullptr);
}
void CommandBufferD3D12::SetViewport()
{
GetGraphicsCommandList()->RSSetViewports(1, nullptr);
}
void CommandBufferD3D12::BindPipeline()
{
GetGraphicsCommandList()->SetPipelineState(nullptr);
}
void CommandBufferD3D12::Clear(ClearFlags clearFlags)
{
VERUS_QREF_RENDERER;
if (clearFlags & ClearFlags::color)
GetGraphicsCommandList()->ClearRenderTargetView({}, renderer.GetClearColor().ToPointer(), 0, nullptr);
UINT cf = 0;
if (clearFlags & ClearFlags::depth) cf |= D3D12_CLEAR_FLAG_DEPTH;
if (clearFlags & ClearFlags::stencil) cf |= D3D12_CLEAR_FLAG_STENCIL;
if (cf)
GetGraphicsCommandList()->ClearDepthStencilView({}, static_cast<D3D12_CLEAR_FLAGS>(cf), 0, 0, 0, nullptr);
}
void CommandBufferD3D12::Draw()
{
GetGraphicsCommandList()->DrawInstanced(0, 0, 0, 0);
}
void CommandBufferD3D12::DrawIndexed()
{
GetGraphicsCommandList()->DrawIndexedInstanced(0, 0, 0, 0, 0);
}

View File

@ -0,0 +1,35 @@
#pragma once
namespace verus
{
namespace CGI
{
class CommandBufferD3D12 : public BaseCommandBuffer
{
ComPtr<ID3D12GraphicsCommandList> _pCommandLists[BaseRenderer::ringBufferSize];
ID3D12GraphicsCommandList* GetGraphicsCommandList() const;
public:
CommandBufferD3D12();
virtual ~CommandBufferD3D12() override;
virtual void Init() override;
virtual void Done() override;
virtual void Begin() override;
virtual void End() override;
virtual void BindVertexBuffers() override;
virtual void BindIndexBuffer() override;
virtual void SetScissor() override;
virtual void SetViewport() override;
virtual void BindPipeline() override;
virtual void Clear(ClearFlags clearFlags) override;
virtual void Draw() override;
virtual void DrawIndexed() override;
};
}
}

View File

@ -0,0 +1,23 @@
#include "stdafx.h"
using namespace verus;
using namespace verus::CGI;
GeometryD3D12::GeometryD3D12()
{
}
GeometryD3D12::~GeometryD3D12()
{
Done();
}
void GeometryD3D12::Init(RcGeometryDesc desc)
{
VERUS_INIT();
}
void GeometryD3D12::Done()
{
VERUS_DONE(GeometryD3D12);
}

View File

@ -0,0 +1,20 @@
#pragma once
namespace verus
{
namespace CGI
{
class GeometryD3D12 : public BaseGeometry
{
ComPtr<ID3D12Resource> _pVertexBuffer;
ComPtr<ID3D12Resource> _pIndexBuffer;
public:
GeometryD3D12();
virtual ~GeometryD3D12() override;
virtual void Init(RcGeometryDesc desc) override;
virtual void Done() override;
};
}
}

View File

@ -0,0 +1,23 @@
#include "stdafx.h"
using namespace verus;
using namespace verus::CGI;
PipelineD3D12::PipelineD3D12()
{
}
PipelineD3D12::~PipelineD3D12()
{
Done();
}
void PipelineD3D12::Init()
{
VERUS_INIT();
}
void PipelineD3D12::Done()
{
VERUS_DONE(PipelineD3D12);
}

View File

@ -0,0 +1,19 @@
#pragma once
namespace verus
{
namespace CGI
{
class PipelineD3D12 : public BasePipeline
{
ComPtr<ID3D12PipelineState> _pPipelineState;
public:
PipelineD3D12();
virtual ~PipelineD3D12() override;
virtual void Init() override;
virtual void Done() override;
};
}
}

View File

@ -27,20 +27,38 @@ void RendererD3D12::Init()
void RendererD3D12::Done()
{
if (_pCommandQueue)
QueueWaitIdle();
if (_hFence != INVALID_HANDLE_VALUE)
{
CloseHandle(_hFence);
_hFence = INVALID_HANDLE_VALUE;
}
_pFence.Reset();
VERUS_FOR(i, ringBufferSize)
_pCommandLists[i].Reset();
VERUS_FOR(i, ringBufferSize)
_mapCommandAllocators[i].clear();
_dSwapChainBuffersRTVs.Reset();
_vSwapChainBuffers.clear();
_pSwapChain.Reset();
_pCommandQueue.Reset();
_pDevice.Reset();
VERUS_DONE(RendererD3D12);
}
void RendererD3D12::EnableDebugLayer()
{
CComPtr<ID3D12Debug> pDebug;
ComPtr<ID3D12Debug> pDebug;
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&pDebug))))
pDebug->EnableDebugLayer();
}
CComPtr<IDXGIFactory7> RendererD3D12::CreateDXGIFactory()
ComPtr<IDXGIFactory6> RendererD3D12::CreateDXGIFactory()
{
HRESULT hr = 0;
CComPtr<IDXGIFactory7> pFactory;
ComPtr<IDXGIFactory6> pFactory;
UINT flags = 0;
#if defined(_DEBUG) || defined(VERUS_DEBUG)
flags = DXGI_CREATE_FACTORY_DEBUG;
@ -50,16 +68,16 @@ CComPtr<IDXGIFactory7> RendererD3D12::CreateDXGIFactory()
return pFactory;
}
CComPtr<IDXGIAdapter4> RendererD3D12::GetAdapter(CComPtr<IDXGIFactory7> pFactory)
ComPtr<IDXGIAdapter4> RendererD3D12::GetAdapter(ComPtr<IDXGIFactory6> pFactory)
{
HRESULT hr = 0;
CComPtr<IDXGIAdapter4> pAdapter;
ComPtr<IDXGIAdapter4> pAdapter;
if (FAILED(hr = pFactory->EnumAdapterByGpuPreference(0, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, IID_PPV_ARGS(&pAdapter))))
throw VERUS_RUNTIME_ERROR << "EnumAdapterByGpuPreference(), hr=" << VERUS_HR(hr);
return pAdapter;
}
bool RendererD3D12::CheckFeatureSupportAllowTearing(CComPtr<IDXGIFactory7> pFactory)
bool RendererD3D12::CheckFeatureSupportAllowTearing(ComPtr<IDXGIFactory6> pFactory)
{
BOOL data = FALSE;
if (FAILED(pFactory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &data, sizeof(data))))
@ -70,15 +88,15 @@ bool RendererD3D12::CheckFeatureSupportAllowTearing(CComPtr<IDXGIFactory7> pFact
void RendererD3D12::CreateSwapChainBuffersRTVs()
{
HRESULT hr = 0;
_swapChainBuffersRTVs = CreateDescriptorHeap(D3D12_DESCRIPTOR_HEAP_TYPE_RTV, _swapChainDesc.BufferCount);
_vSwapChainBuffers.resize(_swapChainDesc.BufferCount);
auto dh = _swapChainBuffersRTVs->GetCPUDescriptorHandleForHeapStart();
VERUS_U_FOR(i, _swapChainDesc.BufferCount)
_vSwapChainBuffers.resize(_numSwapChainBuffers);
_dSwapChainBuffersRTVs = CreateDescriptorHeap(D3D12_DESCRIPTOR_HEAP_TYPE_RTV, _numSwapChainBuffers);
auto dh = _dSwapChainBuffersRTVs->GetCPUDescriptorHandleForHeapStart();
VERUS_U_FOR(i, _numSwapChainBuffers)
{
CComPtr<ID3D12Resource> pBuffer;
ComPtr<ID3D12Resource> pBuffer;
if (FAILED(hr = _pSwapChain->GetBuffer(i, IID_PPV_ARGS(&pBuffer))))
throw VERUS_RUNTIME_ERROR << "GetBuffer(), hr=" << VERUS_HR(hr);
_pDevice->CreateRenderTargetView(pBuffer, nullptr, dh);
_pDevice->CreateRenderTargetView(pBuffer.Get(), nullptr, dh);
_vSwapChainBuffers[i] = pBuffer;
dh.ptr += _descHandleIncSizeRTV;
}
@ -86,6 +104,7 @@ void RendererD3D12::CreateSwapChainBuffersRTVs()
void RendererD3D12::InitD3D()
{
VERUS_QREF_RENDERER;
VERUS_QREF_SETTINGS;
HRESULT hr = 0;
@ -94,15 +113,17 @@ void RendererD3D12::InitD3D()
EnableDebugLayer();
#endif
CComPtr<IDXGIFactory7> pFactory = CreateDXGIFactory();
ComPtr<IDXGIFactory6> pFactory = CreateDXGIFactory();
CComPtr<IDXGIAdapter4> pAdapter = GetAdapter(pFactory);
ComPtr<IDXGIAdapter4> pAdapter = GetAdapter(pFactory);
if (FAILED(hr = D3D12CreateDevice(pAdapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&_pDevice))))
if (FAILED(hr = D3D12CreateDevice(pAdapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&_pDevice))))
throw VERUS_RUNTIME_ERROR << "D3D12CreateDevice(), hr=" << VERUS_HR(hr);
_pCommandQueue = CreateCommandQueue(D3D12_COMMAND_LIST_TYPE_DIRECT);
_numSwapChainBuffers = settings._screenVSync ? 3 : 2;
_swapChainDesc.Width = settings._screenSizeWidth;
_swapChainDesc.Height = settings._screenSizeHeight;
_swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
@ -110,39 +131,45 @@ void RendererD3D12::InitD3D()
_swapChainDesc.SampleDesc.Count = 1;
_swapChainDesc.SampleDesc.Quality = 0;
_swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
_swapChainDesc.BufferCount = 2;
_swapChainDesc.BufferCount = _numSwapChainBuffers;
_swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
_swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
_swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
_swapChainDesc.Flags = CheckFeatureSupportAllowTearing(pFactory) ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;
CComPtr<IDXGISwapChain1> pSwapChain1;
if (FAILED(hr = pFactory->CreateSwapChainForHwnd(_pCommandQueue, GetActiveWindow(), &_swapChainDesc, nullptr, nullptr, &pSwapChain1)))
SDL_Window* pWnd = renderer.GetMainWindow()->GetSDL();
VERUS_RT_ASSERT(pWnd);
SDL_SysWMinfo wmInfo;
SDL_VERSION(&wmInfo.version);
SDL_GetWindowWMInfo(pWnd, &wmInfo);
HWND hWnd = wmInfo.info.win.window;
ComPtr<IDXGISwapChain1> pSwapChain1;
if (FAILED(hr = pFactory->CreateSwapChainForHwnd(_pCommandQueue.Get(), hWnd, &_swapChainDesc, nullptr, nullptr, &pSwapChain1)))
throw VERUS_RUNTIME_ERROR << "CreateSwapChainForHwnd(), hr=" << VERUS_HR(hr);
if (FAILED(hr = pSwapChain1.QueryInterface(&_pSwapChain)))
if (FAILED(hr = pSwapChain1.As(&_pSwapChain)))
throw VERUS_RUNTIME_ERROR << "QueryInterface(), hr=" << VERUS_HR(hr);
_descHandleIncSizeRTV = _pDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
_currentBackBufferIndex = _pSwapChain->GetCurrentBackBufferIndex();
_swapChainBufferIndex = _pSwapChain->GetCurrentBackBufferIndex();
CreateSwapChainBuffersRTVs();
_vCommandAllocators.resize(_swapChainDesc.BufferCount);
VERUS_U_FOR(i, _swapChainDesc.BufferCount)
_vCommandAllocators[i] = CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT);
VERUS_FOR(i, ringBufferSize)
_mapCommandAllocators[i][std::this_thread::get_id()] = CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT);
_pCommandList = CreateCommandList(D3D12_COMMAND_LIST_TYPE_DIRECT, _vCommandAllocators[_currentBackBufferIndex]);
VERUS_FOR(i, ringBufferSize)
_pCommandLists[i] = CreateCommandList(D3D12_COMMAND_LIST_TYPE_DIRECT, _mapCommandAllocators[i][std::this_thread::get_id()]);
_pFence = CreateFence();
_hFence = CreateEvent(nullptr, FALSE, FALSE, nullptr);
_vFenceValues.resize(_swapChainDesc.BufferCount);
}
CComPtr<ID3D12CommandQueue> RendererD3D12::CreateCommandQueue(D3D12_COMMAND_LIST_TYPE type)
ComPtr<ID3D12CommandQueue> RendererD3D12::CreateCommandQueue(D3D12_COMMAND_LIST_TYPE type)
{
HRESULT hr = 0;
CComPtr<ID3D12CommandQueue> pCommandQueue;
ComPtr<ID3D12CommandQueue> pCommandQueue;
D3D12_COMMAND_QUEUE_DESC desc = {};
desc.Type = type;
desc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
@ -152,30 +179,30 @@ CComPtr<ID3D12CommandQueue> RendererD3D12::CreateCommandQueue(D3D12_COMMAND_LIST
return pCommandQueue;
}
CComPtr<ID3D12CommandAllocator> RendererD3D12::CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE type)
ComPtr<ID3D12CommandAllocator> RendererD3D12::CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE type)
{
HRESULT hr = 0;
CComPtr<ID3D12CommandAllocator> pCommandAllocator;
ComPtr<ID3D12CommandAllocator> pCommandAllocator;
if (FAILED(hr = _pDevice->CreateCommandAllocator(type, IID_PPV_ARGS(&pCommandAllocator))))
throw VERUS_RUNTIME_ERROR << "CreateCommandAllocator(), hr=" << VERUS_HR(hr);
return pCommandAllocator;
}
CComPtr<ID3D12GraphicsCommandList> RendererD3D12::CreateCommandList(D3D12_COMMAND_LIST_TYPE type, CComPtr<ID3D12CommandAllocator> pCommandAllocator)
ComPtr<ID3D12GraphicsCommandList> RendererD3D12::CreateCommandList(D3D12_COMMAND_LIST_TYPE type, ComPtr<ID3D12CommandAllocator> pCommandAllocator)
{
HRESULT hr = 0;
CComPtr<ID3D12GraphicsCommandList> pGraphicsCommandList;
if (FAILED(hr = _pDevice->CreateCommandList(0, type, pCommandAllocator, nullptr, IID_PPV_ARGS(&pGraphicsCommandList))))
ComPtr<ID3D12GraphicsCommandList> pGraphicsCommandList;
if (FAILED(hr = _pDevice->CreateCommandList(0, type, pCommandAllocator.Get(), nullptr, IID_PPV_ARGS(&pGraphicsCommandList))))
throw VERUS_RUNTIME_ERROR << "CreateCommandList(), hr=" << VERUS_HR(hr);
if (FAILED(hr = pGraphicsCommandList->Close()))
throw VERUS_RUNTIME_ERROR << "Close(), hr=" << VERUS_HR(hr);
return pGraphicsCommandList;
}
CComPtr<ID3D12DescriptorHeap> RendererD3D12::CreateDescriptorHeap(D3D12_DESCRIPTOR_HEAP_TYPE type, UINT num)
ComPtr<ID3D12DescriptorHeap> RendererD3D12::CreateDescriptorHeap(D3D12_DESCRIPTOR_HEAP_TYPE type, UINT num)
{
HRESULT hr = 0;
CComPtr<ID3D12DescriptorHeap> pDescriptorHeap;
ComPtr<ID3D12DescriptorHeap> pDescriptorHeap;
D3D12_DESCRIPTOR_HEAP_DESC desc = {};
desc.Type = type;
desc.NumDescriptors = num;
@ -184,20 +211,20 @@ CComPtr<ID3D12DescriptorHeap> RendererD3D12::CreateDescriptorHeap(D3D12_DESCRIPT
return pDescriptorHeap;
}
CComPtr<ID3D12Fence> RendererD3D12::CreateFence()
ComPtr<ID3D12Fence> RendererD3D12::CreateFence()
{
HRESULT hr = 0;
CComPtr<ID3D12Fence> pFence;
ComPtr<ID3D12Fence> pFence;
if (FAILED(hr = _pDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&pFence))))
throw VERUS_RUNTIME_ERROR << "CreateFence(), hr=" << VERUS_HR(hr);
return pFence;
}
UINT64 RendererD3D12::Signal()
UINT64 RendererD3D12::QueueSignal()
{
HRESULT hr = 0;
const UINT64 value = ++_fenceValue;
if (FAILED(hr = _pCommandQueue->Signal(_pFence, value)))
const UINT64 value = _nextFenceValue++;
if (FAILED(hr = _pCommandQueue->Signal(_pFence.Get(), value)))
throw VERUS_RUNTIME_ERROR << "Signal(), hr=" << VERUS_HR(hr);
return value;
}
@ -213,9 +240,9 @@ void RendererD3D12::WaitForFenceValue(UINT64 value)
}
}
void RendererD3D12::Flush()
void RendererD3D12::QueueWaitIdle()
{
const UINT64 value = Signal();
const UINT64 value = QueueSignal();
WaitForFenceValue(value);
}
@ -231,29 +258,39 @@ D3D12_RESOURCE_BARRIER RendererD3D12::MakeResourceBarrierTransition(ID3D12Resour
return rb;
}
void RendererD3D12::PrepareDraw()
void RendererD3D12::BeginFrame()
{
auto pBackBuffer = _vSwapChainBuffers[_currentBackBufferIndex];
auto pCommandAllocator = _vCommandAllocators[_currentBackBufferIndex];
HRESULT hr = 0;
pCommandAllocator->Reset();
_pCommandList->Reset(pCommandAllocator, nullptr);
WaitForFenceValue(_fenceValues[_ringBufferIndex]);
const auto rb = MakeResourceBarrierTransition(pBackBuffer, D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
_pCommandList->ResourceBarrier(1, &rb);
_swapChainBufferIndex = _pSwapChain->GetCurrentBackBufferIndex();
auto pCommandAllocator = _mapCommandAllocators[_ringBufferIndex][std::this_thread::get_id()];
if (FAILED(hr = pCommandAllocator->Reset()))
throw VERUS_RUNTIME_ERROR << "Reset(), hr=" << VERUS_HR(hr);
if (FAILED(hr = _pCommandLists[_ringBufferIndex]->Reset(pCommandAllocator.Get(), nullptr)))
throw VERUS_RUNTIME_ERROR << "Reset(), hr=" << VERUS_HR(hr);
auto pBackBuffer = _vSwapChainBuffers[_swapChainBufferIndex];
const auto rb = MakeResourceBarrierTransition(pBackBuffer.Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
_pCommandLists[_ringBufferIndex]->ResourceBarrier(1, &rb);
}
void RendererD3D12::Clear(UINT32 flags)
void RendererD3D12::EndFrame()
{
static float x = 0;
x += 0.0001f;
x = fmod(x, 1.f);
FLOAT clearColor[] = { x, 0.5f, 0.25f, 1.0f };
HRESULT hr = 0;
auto dh = _swapChainBuffersRTVs->GetCPUDescriptorHandleForHeapStart();
dh.ptr += _currentBackBufferIndex * _descHandleIncSizeRTV;
auto pBackBuffer = _vSwapChainBuffers[_swapChainBufferIndex];
const auto rb = MakeResourceBarrierTransition(pBackBuffer.Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
_pCommandLists[_ringBufferIndex]->ResourceBarrier(1, &rb);
_pCommandList->ClearRenderTargetView(dh, clearColor, 0, nullptr);
if (FAILED(hr = _pCommandLists[_ringBufferIndex]->Close()))
throw VERUS_RUNTIME_ERROR << "Close(), hr=" << VERUS_HR(hr);
ID3D12CommandList* ppCommandLists[] = { _pCommandLists[_ringBufferIndex].Get() };
_pCommandQueue->ExecuteCommandLists(VERUS_ARRAY_LENGTH(ppCommandLists), ppCommandLists);
_fenceValues[_ringBufferIndex] = QueueSignal();
}
void RendererD3D12::Present()
@ -263,23 +300,20 @@ void RendererD3D12::Present()
bool g_VSync = false;
bool g_TearingSupported = false;
auto pBackBuffer = _vSwapChainBuffers[_currentBackBufferIndex];
const auto rb = MakeResourceBarrierTransition(pBackBuffer, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
_pCommandList->ResourceBarrier(1, &rb);
if (FAILED(hr = _pCommandList->Close()))
throw VERUS_RUNTIME_ERROR << "Close(), hr=" << VERUS_HR(hr);
ID3D12CommandList* ppCommandLists[] = { _pCommandList };
_pCommandQueue->ExecuteCommandLists(VERUS_ARRAY_LENGTH(ppCommandLists), ppCommandLists);
_vFenceValues[_currentBackBufferIndex] = Signal();
UINT syncInterval = g_VSync ? 1 : 0;
UINT flags = g_TearingSupported && !g_VSync ? DXGI_PRESENT_ALLOW_TEARING : 0;
const UINT syncInterval = g_VSync ? 1 : 0;
const UINT flags = g_TearingSupported && !g_VSync ? DXGI_PRESENT_ALLOW_TEARING : 0;
if (FAILED(hr = _pSwapChain->Present(syncInterval, flags)))
throw VERUS_RUNTIME_ERROR << "Present(), hr=" << VERUS_HR(hr);
_currentBackBufferIndex = _pSwapChain->GetCurrentBackBufferIndex();
WaitForFenceValue(_vFenceValues[_currentBackBufferIndex]);
_ringBufferIndex = (_ringBufferIndex + 1) % ringBufferSize;
}
void RendererD3D12::Clear(UINT32 flags)
{
VERUS_QREF_RENDERER;
auto dh = _dSwapChainBuffersRTVs->GetCPUDescriptorHandleForHeapStart();
dh.ptr += _swapChainBufferIndex * _descHandleIncSizeRTV;
_pCommandLists[_ringBufferIndex]->ClearRenderTargetView(dh, renderer.GetClearColor().ToPointer(), 0, nullptr);
}

View File

@ -6,20 +6,21 @@ namespace verus
{
class RendererD3D12 : public Singleton<RendererD3D12>, public BaseRenderer
{
CComPtr<IDXGISwapChain4> _pSwapChain;
CComPtr<ID3D12Device3> _pDevice;
CComPtr<ID3D12CommandQueue> _pCommandQueue;
CComPtr<ID3D12Fence> _pFence;
CComPtr<ID3D12DescriptorHeap> _swapChainBuffersRTVs;
Vector<CComPtr<ID3D12Resource>> _vSwapChainBuffers;
Vector<CComPtr<ID3D12CommandAllocator>> _vCommandAllocators;
Vector<UINT64> _vFenceValues;
CComPtr<ID3D12GraphicsCommandList> _pCommandList;
DXGI_SWAP_CHAIN_DESC1 _swapChainDesc = {};
HANDLE _hFence = 0;
UINT64 _fenceValue = 0;
UINT _descHandleIncSizeRTV = 0;
UINT _currentBackBufferIndex = 0;
typedef Map<std::thread::id, ComPtr<ID3D12CommandAllocator>> TMapCommandAllocators;
ComPtr<ID3D12Device3> _pDevice;
ComPtr<ID3D12CommandQueue> _pCommandQueue;
ComPtr<IDXGISwapChain4> _pSwapChain;
Vector<ComPtr<ID3D12Resource>> _vSwapChainBuffers;
ComPtr<ID3D12DescriptorHeap> _dSwapChainBuffersRTVs;
TMapCommandAllocators _mapCommandAllocators[ringBufferSize];
ComPtr<ID3D12GraphicsCommandList> _pCommandLists[ringBufferSize];
ComPtr<ID3D12Fence> _pFence;
HANDLE _hFence = INVALID_HANDLE_VALUE;
UINT64 _nextFenceValue = 1;
UINT64 _fenceValues[ringBufferSize];
UINT _descHandleIncSizeRTV = 0;
DXGI_SWAP_CHAIN_DESC1 _swapChainDesc = {};
public:
RendererD3D12();
@ -30,29 +31,34 @@ namespace verus
void Init();
void Done();
VERUS_P(static void EnableDebugLayer());
VERUS_P(static CComPtr<IDXGIFactory7> CreateDXGIFactory());
VERUS_P(static CComPtr<IDXGIAdapter4> GetAdapter(CComPtr<IDXGIFactory7> pFactory));
VERUS_P(static bool CheckFeatureSupportAllowTearing(CComPtr<IDXGIFactory7> pFactory));
VERUS_P(void CreateSwapChainBuffersRTVs());
VERUS_P(void InitD3D());
private:
static void EnableDebugLayer();
static ComPtr<IDXGIFactory6> CreateDXGIFactory();
static ComPtr<IDXGIAdapter4> GetAdapter(ComPtr<IDXGIFactory6> pFactory);
static bool CheckFeatureSupportAllowTearing(ComPtr<IDXGIFactory6> pFactory);
void CreateSwapChainBuffersRTVs();
void InitD3D();
virtual Gapi GetGapi() override { return Gapi::direct3D12; }
CComPtr<ID3D12CommandQueue> CreateCommandQueue(D3D12_COMMAND_LIST_TYPE type);
CComPtr<ID3D12CommandAllocator> CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE type);
CComPtr<ID3D12GraphicsCommandList> CreateCommandList(D3D12_COMMAND_LIST_TYPE type, CComPtr<ID3D12CommandAllocator> pCommandAllocator);
CComPtr<ID3D12DescriptorHeap> CreateDescriptorHeap(D3D12_DESCRIPTOR_HEAP_TYPE type, UINT num);
CComPtr<ID3D12Fence> CreateFence();
UINT64 Signal();
public:
ComPtr<ID3D12CommandQueue> CreateCommandQueue(D3D12_COMMAND_LIST_TYPE type);
ComPtr<ID3D12CommandAllocator> CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE type);
ComPtr<ID3D12GraphicsCommandList> CreateCommandList(D3D12_COMMAND_LIST_TYPE type, ComPtr<ID3D12CommandAllocator> pCommandAllocator);
ComPtr<ID3D12DescriptorHeap> CreateDescriptorHeap(D3D12_DESCRIPTOR_HEAP_TYPE type, UINT num);
ComPtr<ID3D12Fence> CreateFence();
UINT64 QueueSignal();
void WaitForFenceValue(UINT64 value);
void Flush();
void QueueWaitIdle();
static D3D12_RESOURCE_BARRIER MakeResourceBarrierTransition(ID3D12Resource* pResource, D3D12_RESOURCE_STATES before, D3D12_RESOURCE_STATES after);
virtual void PrepareDraw() override;
virtual void Clear(UINT32 flags) override;
// Which graphics API?
virtual Gapi GetGapi() override { return Gapi::direct3D12; }
// Frame cycle:
virtual void BeginFrame() override;
virtual void EndFrame() override;
virtual void Present() override;
virtual void Clear(UINT32 flags) override;
};
VERUS_TYPEDEFS(RendererD3D12);
}

View File

@ -0,0 +1,78 @@
#include "stdafx.h"
using namespace verus;
using namespace verus::CGI;
// ShaderInclude:
HRESULT STDMETHODCALLTYPE ShaderInclude::Open(
D3D_INCLUDE_TYPE IncludeType,
LPCSTR pFileName,
LPCVOID pParentData,
LPCVOID* ppData,
UINT* pBytes)
{
const String url = String("<Shaders>/") + pFileName;
Vector<BYTE> vData;
IO::FileSystem::LoadResource(_C(url), vData);
char* p = new char[vData.size()];
memcpy(p, vData.data(), vData.size());
*pBytes = vData.size();
*ppData = p;
return S_OK;
}
HRESULT STDMETHODCALLTYPE ShaderInclude::Close(LPCVOID pData)
{
delete[] pData;
return S_OK;
}
// ShaderD3D12:
ShaderD3D12::ShaderD3D12()
{
}
ShaderD3D12::~ShaderD3D12()
{
Done();
}
void ShaderD3D12::Init(CSZ source, CSZ* list)
{
VERUS_INIT();
HRESULT hr = 0;
const size_t len = strlen(source);
ShaderInclude inc;
String version = "5_0";
UINT flags = D3DCOMPILE_ENABLE_STRICTNESS;
#ifndef _DEBUG
flags = D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_OPTIMIZATION_LEVEL3;
#endif
ComPtr<ID3DBlob> pErrorMsgs;
Vector<D3D_SHADER_MACRO> vDefines;
vDefines.reserve(20);
while (*list)
{
String entryVS, entryHS, entryDS, entryGS, entryPS;
const String entry;
Compiled compiled;
hr = D3DCompile(source, len, 0, vDefines.data(), &inc, _C(entryVS), _C("vs_" + version), flags, 0, &compiled._pVS, &pErrorMsgs);
_mapCompiled[entry] = compiled;
list++;
}
}
void ShaderD3D12::Done()
{
VERUS_DONE(ShaderD3D12);
}

View File

@ -0,0 +1,44 @@
#pragma once
namespace verus
{
namespace CGI
{
struct ShaderInclude : public ID3DInclude
{
public:
virtual HRESULT STDMETHODCALLTYPE Open(
D3D_INCLUDE_TYPE IncludeType,
LPCSTR pFileName,
LPCVOID pParentData,
LPCVOID* ppData,
UINT* pBytes) override;
virtual HRESULT STDMETHODCALLTYPE Close(LPCVOID pData) override;
};
VERUS_TYPEDEFS(ShaderInclude);
class ShaderD3D12 : public BaseShader
{
struct Compiled
{
ComPtr<ID3DBlob> _pVS;
ComPtr<ID3DBlob> _pHS;
ComPtr<ID3DBlob> _pDS;
ComPtr<ID3DBlob> _pGS;
ComPtr<ID3DBlob> _pPS;
};
VERUS_TYPEDEFS(Compiled);
typedef Map<String, Compiled> TMapCompiled;
TMapCompiled _mapCompiled;
public:
ShaderD3D12();
virtual ~ShaderD3D12() override;
virtual void Init(CSZ source, CSZ* list) override;
virtual void Done() override;
};
VERUS_TYPEDEFS(ShaderD3D12);
}
}

View File

@ -91,9 +91,20 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\CGI\CGI.h" />
<ClInclude Include="src\CGI\CommandBufferVulkan.h" />
<ClInclude Include="src\CGI\GeometryVulkan.h" />
<ClInclude Include="src\CGI\PipelineVulkan.h" />
<ClInclude Include="src\CGI\RendererVulkan.h" />
<ClInclude Include="src\CGI\ShaderVulkan.h" />
<ClInclude Include="src\stdafx.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\CGI\CommandBufferVulkan.cpp" />
<ClCompile Include="src\CGI\GeometryVulkan.cpp" />
<ClCompile Include="src\CGI\PipelineVulkan.cpp" />
<ClCompile Include="src\CGI\RendererVulkan.cpp" />
<ClCompile Include="src\CGI\ShaderVulkan.cpp" />
<ClCompile Include="src\main.cpp" />
<ClCompile Include="src\stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>

View File

@ -16,11 +16,32 @@
<Filter Include="src">
<UniqueIdentifier>{836b7e96-dc7f-4278-832a-6305a03b69e4}</UniqueIdentifier>
</Filter>
<Filter Include="src\CGI">
<UniqueIdentifier>{4abdc4ba-6c11-4cdc-b578-2101f063b0c6}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\stdafx.h">
<Filter>src</Filter>
</ClInclude>
<ClInclude Include="src\CGI\CGI.h">
<Filter>src\CGI</Filter>
</ClInclude>
<ClInclude Include="src\CGI\RendererVulkan.h">
<Filter>src\CGI</Filter>
</ClInclude>
<ClInclude Include="src\CGI\CommandBufferVulkan.h">
<Filter>src\CGI</Filter>
</ClInclude>
<ClInclude Include="src\CGI\GeometryVulkan.h">
<Filter>src\CGI</Filter>
</ClInclude>
<ClInclude Include="src\CGI\PipelineVulkan.h">
<Filter>src\CGI</Filter>
</ClInclude>
<ClInclude Include="src\CGI\ShaderVulkan.h">
<Filter>src\CGI</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\main.cpp">
@ -29,5 +50,20 @@
<ClCompile Include="src\stdafx.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="src\CGI\RendererVulkan.cpp">
<Filter>src\CGI</Filter>
</ClCompile>
<ClCompile Include="src\CGI\CommandBufferVulkan.cpp">
<Filter>src\CGI</Filter>
</ClCompile>
<ClCompile Include="src\CGI\GeometryVulkan.cpp">
<Filter>src\CGI</Filter>
</ClCompile>
<ClCompile Include="src\CGI\PipelineVulkan.cpp">
<Filter>src\CGI</Filter>
</ClCompile>
<ClCompile Include="src\CGI\ShaderVulkan.cpp">
<Filter>src\CGI</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -0,0 +1,7 @@
#pragma once
#include "CommandBufferVulkan.h"
#include "GeometryVulkan.h"
#include "PipelineVulkan.h"
#include "ShaderVulkan.h"
#include "RendererVulkan.h"

View File

@ -0,0 +1,98 @@
#include "stdafx.h"
using namespace verus;
using namespace verus::CGI;
VkCommandBuffer CommandBufferVulkan::GetCommandBuffer() const
{
VERUS_QREF_RENDERER;
return _commandBuffers[renderer->GetRingBufferIndex()];
}
CommandBufferVulkan::CommandBufferVulkan()
{
}
CommandBufferVulkan::~CommandBufferVulkan()
{
Done();
}
void CommandBufferVulkan::Init()
{
VERUS_INIT();
}
void CommandBufferVulkan::Done()
{
VERUS_DONE(CommandBufferVulkan);
}
void CommandBufferVulkan::Begin()
{
VkResult res = VK_SUCCESS;
VkCommandBufferBeginInfo vkcbbi = {};
vkcbbi.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
vkcbbi.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
if (VK_SUCCESS != (res = vkBeginCommandBuffer(GetCommandBuffer(), &vkcbbi)))
throw VERUS_RUNTIME_ERROR << "vkBeginCommandBuffer(), res=" << res;
}
void CommandBufferVulkan::End()
{
VkResult res = VK_SUCCESS;
if (VK_SUCCESS != (res = vkEndCommandBuffer(GetCommandBuffer())))
throw VERUS_RUNTIME_ERROR << "vkEndCommandBuffer(), res=" << res;
}
void CommandBufferVulkan::BindVertexBuffers()
{
vkCmdBindVertexBuffers(GetCommandBuffer(), 0, 1, nullptr, nullptr);
}
void CommandBufferVulkan::BindIndexBuffer()
{
vkCmdBindIndexBuffer(GetCommandBuffer(), nullptr, 0, VK_INDEX_TYPE_UINT16);
}
void CommandBufferVulkan::SetScissor()
{
vkCmdSetScissor(GetCommandBuffer(), 0, 1, nullptr);
}
void CommandBufferVulkan::SetViewport()
{
vkCmdSetViewport(GetCommandBuffer(), 0, 1, nullptr);
}
void CommandBufferVulkan::BindPipeline()
{
vkCmdBindPipeline(GetCommandBuffer(), VK_PIPELINE_BIND_POINT_GRAPHICS, nullptr);
}
void CommandBufferVulkan::Clear(ClearFlags clearFlags)
{
VERUS_QREF_RENDERER;
if (clearFlags & ClearFlags::color)
{
VkClearColorValue clearColorValue;
memcpy(&clearColorValue, renderer.GetClearColor().ToPointer(), sizeof(clearColorValue));
VkImageSubresourceRange vkisr = {};
vkisr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
vkisr.baseMipLevel = 0;
vkisr.levelCount = 1;
vkisr.baseArrayLayer = 0;
vkisr.layerCount = 1;
vkCmdClearColorImage(GetCommandBuffer(), nullptr, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColorValue, 1, &vkisr);
}
}
void CommandBufferVulkan::Draw()
{
vkCmdDraw(GetCommandBuffer(), 0, 0, 0, 0);
}
void CommandBufferVulkan::DrawIndexed()
{
vkCmdDrawIndexed(GetCommandBuffer(), 0, 0, 0, 0, 0);
}

View File

@ -0,0 +1,35 @@
#pragma once
namespace verus
{
namespace CGI
{
class CommandBufferVulkan : public BaseCommandBuffer
{
VkCommandBuffer _commandBuffers[BaseRenderer::ringBufferSize] = { VK_NULL_HANDLE };
VkCommandBuffer GetCommandBuffer() const;
public:
CommandBufferVulkan();
virtual ~CommandBufferVulkan() override;
virtual void Init() override;
virtual void Done() override;
virtual void Begin() override;
virtual void End() override;
virtual void BindVertexBuffers() override;
virtual void BindIndexBuffer() override;
virtual void SetScissor() override;
virtual void SetViewport() override;
virtual void BindPipeline() override;
virtual void Clear(ClearFlags clearFlags) override;
virtual void Draw() override;
virtual void DrawIndexed() override;
};
}
}

View File

@ -0,0 +1,23 @@
#include "stdafx.h"
using namespace verus;
using namespace verus::CGI;
GeometryVulkan::GeometryVulkan()
{
}
GeometryVulkan::~GeometryVulkan()
{
Done();
}
void GeometryVulkan::Init(RcGeometryDesc desc)
{
VERUS_INIT();
}
void GeometryVulkan::Done()
{
VERUS_DONE(GeometryVulkan);
}

View File

@ -0,0 +1,17 @@
#pragma once
namespace verus
{
namespace CGI
{
class GeometryVulkan : public BaseGeometry
{
public:
GeometryVulkan();
virtual ~GeometryVulkan() override;
virtual void Init(RcGeometryDesc desc) override;
virtual void Done() override;
};
}
}

View File

@ -0,0 +1,23 @@
#include "stdafx.h"
using namespace verus;
using namespace verus::CGI;
PipelineVulkan::PipelineVulkan()
{
}
PipelineVulkan::~PipelineVulkan()
{
Done();
}
void PipelineVulkan::Init()
{
VERUS_INIT();
}
void PipelineVulkan::Done()
{
VERUS_DONE(PipelineVulkan);
}

View File

@ -0,0 +1,17 @@
#pragma once
namespace verus
{
namespace CGI
{
class PipelineVulkan : public BasePipeline
{
public:
PipelineVulkan();
virtual ~PipelineVulkan() override;
virtual void Init() override;
virtual void Done() override;
};
}
}

View File

@ -0,0 +1,631 @@
#include "stdafx.h"
using namespace verus;
using namespace verus::CGI;
static VkResult CreateDebugUtilsMessengerEXT(
VkInstance instance,
const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDebugUtilsMessengerEXT* pMessenger)
{
auto fn = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
if (fn)
return fn(instance, pCreateInfo, pAllocator, pMessenger);
else
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
static void DestroyDebugUtilsMessengerEXT(
VkInstance instance,
VkDebugUtilsMessengerEXT messenger,
const VkAllocationCallbacks* pAllocator)
{
auto fn = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
if (fn)
fn(instance, messenger, pAllocator);
}
// RendererVulkan:
CSZ RendererVulkan::s_requiredValidationLayers[] =
{
"VK_LAYER_LUNARG_standard_validation"
};
CSZ RendererVulkan::s_requiredDeviceExtensions[] =
{
VK_KHR_SWAPCHAIN_EXTENSION_NAME
};
RendererVulkan::RendererVulkan()
{
}
RendererVulkan::~RendererVulkan()
{
Done();
}
void RendererVulkan::ReleaseMe()
{
Free();
TestAllocCount();
}
void RendererVulkan::Init()
{
VERUS_INIT();
CreateInstance();
#if defined(_DEBUG) || defined(VERUS_DEBUG)
CreateDebugUtilsMessenger();
#endif
CreateSurface();
PickPhysicalDevice();
CreateDevice();
CreateSwapChain();
CreateImageViews();
CreateCommandPools();
CreateCommandBuffers();
CreateSyncObjects();
}
void RendererVulkan::Done()
{
if (_device)
vkDeviceWaitIdle(_device);
VERUS_FOR(i, ringBufferSize)
{
if (VK_NULL_HANDLE != _acquireNextImageSemaphores[i])
{
vkDestroySemaphore(_device, _acquireNextImageSemaphores[i], nullptr);
_acquireNextImageSemaphores[i] = VK_NULL_HANDLE;
}
if (VK_NULL_HANDLE != _queueSubmitSemaphores[i])
{
vkDestroySemaphore(_device, _queueSubmitSemaphores[i], nullptr);
_queueSubmitSemaphores[i] = VK_NULL_HANDLE;
}
if (VK_NULL_HANDLE != _queueSubmitFences[i])
{
vkDestroyFence(_device, _queueSubmitFences[i], nullptr);
_queueSubmitFences[i] = VK_NULL_HANDLE;
}
}
VERUS_FOR(i, ringBufferSize)
{
if (VK_NULL_HANDLE != _commandPools[i])
{
vkDestroyCommandPool(_device, _commandPools[i], nullptr);
_commandPools[i] = VK_NULL_HANDLE;
}
}
for (auto swapChainImageViews : _vSwapChainImageViews)
vkDestroyImageView(_device, swapChainImageViews, nullptr);
_vSwapChainImageViews.clear();
_vSwapChainImages.clear();
if (VK_NULL_HANDLE != _swapChain)
{
vkDestroySwapchainKHR(_device, _swapChain, nullptr);
_swapChain = VK_NULL_HANDLE;
}
if (VK_NULL_HANDLE != _device)
{
vkDestroyDevice(_device, nullptr);
_device = VK_NULL_HANDLE;
}
if (VK_NULL_HANDLE != _surface)
{
vkDestroySurfaceKHR(_instance, _surface, nullptr);
_surface = VK_NULL_HANDLE;
}
#if defined(_DEBUG) || defined(VERUS_DEBUG)
if (VK_NULL_HANDLE != _debugUtilsMessenger)
{
DestroyDebugUtilsMessengerEXT(_instance, _debugUtilsMessenger, nullptr);
_debugUtilsMessenger = VK_NULL_HANDLE;
}
#endif
if (VK_NULL_HANDLE != _instance)
{
vkDestroyInstance(_instance, nullptr);
_instance = VK_NULL_HANDLE;
}
VERUS_DONE(RendererVulkan);
}
VKAPI_ATTR VkBool32 VKAPI_CALL RendererVulkan::DebugUtilsMessengerCallback(
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageTypes,
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
void* pUserData)
{
D::Log::Severity severity = D::Log::Severity::error;
if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT)
severity = D::Log::Severity::debug;
if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT)
severity = D::Log::Severity::info;
if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)
severity = D::Log::Severity::warning;
if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
severity = D::Log::Severity::error;
D::Log::I().Write(pCallbackData->pMessage, std::this_thread::get_id(), __FILE__, __LINE__, severity);
return VK_FALSE;
}
bool RendererVulkan::CheckRequiredValidationLayers()
{
uint32_t propertyCount = 0;
vkEnumerateInstanceLayerProperties(&propertyCount, nullptr);
Vector<VkLayerProperties> vLayerProperties(propertyCount);
vkEnumerateInstanceLayerProperties(&propertyCount, vLayerProperties.data());
for (CSZ layerName : s_requiredValidationLayers)
{
bool layerFound = false;
for (const auto& layerProperties : vLayerProperties)
{
if (!strcmp(layerName, layerProperties.layerName))
{
layerFound = true;
break;
}
}
if (!layerFound)
return false;
}
return true;
}
Vector<CSZ> RendererVulkan::GetRequiredExtensions()
{
VERUS_QREF_RENDERER;
SDL_Window* pWnd = renderer.GetMainWindow()->GetSDL();
VERUS_RT_ASSERT(pWnd);
Vector<CSZ> vExtensions;
unsigned int count = 0;
if (!SDL_Vulkan_GetInstanceExtensions(pWnd, &count, nullptr))
throw VERUS_RUNTIME_ERROR << "SDL_Vulkan_GetInstanceExtensions(nullptr)";
vExtensions.reserve(count + 1);
vExtensions.resize(count);
if (!SDL_Vulkan_GetInstanceExtensions(pWnd, &count, vExtensions.data()))
throw VERUS_RUNTIME_ERROR << "SDL_Vulkan_GetInstanceExtensions()";
#if defined(_DEBUG) || defined(VERUS_DEBUG)
vExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
#endif
return vExtensions;
}
void RendererVulkan::CreateInstance()
{
VkResult res = VK_SUCCESS;
#if defined(_DEBUG) || defined(VERUS_DEBUG)
if (!CheckRequiredValidationLayers())
throw VERUS_RUNTIME_ERROR << "CheckRequiredValidationLayers()";
#endif
const auto vExtensions = GetRequiredExtensions();
VkApplicationInfo vkai = {};
vkai.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
vkai.pApplicationName = "Game";
vkai.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
vkai.pEngineName = "Verus";
vkai.engineVersion = VK_MAKE_VERSION(1, 0, 0);
vkai.apiVersion = VK_API_VERSION_1_0;
VkInstanceCreateInfo vkici = {};
vkici.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
vkici.pApplicationInfo = &vkai;
#if defined(_DEBUG) || defined(VERUS_DEBUG)
vkici.enabledLayerCount = VERUS_ARRAY_LENGTH(s_requiredValidationLayers);
vkici.ppEnabledLayerNames = s_requiredValidationLayers;
#endif
vkici.enabledExtensionCount = Utils::Cast32(vExtensions.size());
vkici.ppEnabledExtensionNames = vExtensions.data();
if (VK_SUCCESS != (res = vkCreateInstance(&vkici, nullptr, &_instance)))
throw VERUS_RUNTIME_ERROR << "vkCreateInstance(), res=" << res;
}
void RendererVulkan::CreateDebugUtilsMessenger()
{
VkResult res = VK_SUCCESS;
VkDebugUtilsMessengerCreateInfoEXT vkdumci = {};
vkdumci.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
vkdumci.messageSeverity =
VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
vkdumci.messageType =
VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
vkdumci.pfnUserCallback = DebugUtilsMessengerCallback;
if (VK_SUCCESS != (res = CreateDebugUtilsMessengerEXT(_instance, &vkdumci, nullptr, &_debugUtilsMessenger)))
throw VERUS_RUNTIME_ERROR << "CreateDebugUtilsMessengerEXT(), res=" << res;
}
void RendererVulkan::CreateSurface()
{
VERUS_QREF_RENDERER;
SDL_Window* pWnd = renderer.GetMainWindow()->GetSDL();
VERUS_RT_ASSERT(pWnd);
if (!SDL_Vulkan_CreateSurface(pWnd, _instance, &_surface))
throw VERUS_RUNTIME_ERROR << "SDL_Vulkan_CreateSurface()";
}
bool RendererVulkan::CheckRequiredDeviceExtensions(VkPhysicalDevice device)
{
uint32_t propertyCount = 0;
vkEnumerateDeviceExtensionProperties(device, nullptr, &propertyCount, nullptr);
Vector<VkExtensionProperties> vExtensionProperties(propertyCount);
vkEnumerateDeviceExtensionProperties(device, nullptr, &propertyCount, vExtensionProperties.data());
Set<String> setRequiredDeviceExtensions;
for (CSZ extensionName : s_requiredDeviceExtensions)
setRequiredDeviceExtensions.insert(extensionName);
for (const auto& extensionProperties : vExtensionProperties)
setRequiredDeviceExtensions.erase(extensionProperties.extensionName);
return setRequiredDeviceExtensions.empty();
}
RendererVulkan::QueueFamilyIndices RendererVulkan::FindQueueFamilyIndices(VkPhysicalDevice device)
{
QueueFamilyIndices ret;
uint32_t queueFamilyPropertyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyPropertyCount, nullptr);
Vector<VkQueueFamilyProperties> vQueueFamilyProperties(queueFamilyPropertyCount);
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyPropertyCount, vQueueFamilyProperties.data());
int i = 0;
for (const auto& queueFamilyProperties : vQueueFamilyProperties)
{
if (queueFamilyProperties.queueCount > 0 && (queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT))
ret._graphicsFamilyIndex = i;
VkBool32 supported = VK_FALSE;
vkGetPhysicalDeviceSurfaceSupportKHR(device, i, _surface, &supported);
if (queueFamilyProperties.queueCount > 0 && supported)
ret._presentFamilyIndex = i;
if (ret.IsComplete())
break;
i++;
}
return ret;
}
bool RendererVulkan::IsDeviceSuitable(VkPhysicalDevice device)
{
const QueueFamilyIndices queueFamilyIndices = FindQueueFamilyIndices(device);
if (!queueFamilyIndices.IsComplete())
return false;
const bool extensionsSupported = CheckRequiredDeviceExtensions(device);
bool swapChainOK = false;
if (extensionsSupported)
{
const SwapChainInfo swapChainInfo = GetSwapChainInfo(device);
swapChainOK = !swapChainInfo._vSurfaceFormats.empty() && !swapChainInfo._vSurfacePresentModes.empty();
}
return extensionsSupported && swapChainOK;
}
void RendererVulkan::PickPhysicalDevice()
{
uint32_t physicalDeviceCount = 0;
vkEnumeratePhysicalDevices(_instance, &physicalDeviceCount, nullptr);
if (!physicalDeviceCount)
throw VERUS_RUNTIME_ERROR << "vkEnumeratePhysicalDevices(), physicalDeviceCount=0";
Vector<VkPhysicalDevice> vPhysicalDevices(physicalDeviceCount);
vkEnumeratePhysicalDevices(_instance, &physicalDeviceCount, vPhysicalDevices.data());
for (const auto& physicalDevice : vPhysicalDevices)
{
if (IsDeviceSuitable(physicalDevice))
{
_physicalDevice = physicalDevice;
break;
}
}
if (VK_NULL_HANDLE == _physicalDevice)
throw VERUS_RUNTIME_ERROR << "PhysicalDevice not found";
}
void RendererVulkan::CreateDevice()
{
VkResult res = VK_SUCCESS;
_queueFamilyIndices = FindQueueFamilyIndices(_physicalDevice);
VERUS_RT_ASSERT(_queueFamilyIndices.IsComplete());
Set<int> setUniqueQueueFamilies = { _queueFamilyIndices._graphicsFamilyIndex, _queueFamilyIndices._presentFamilyIndex };
Vector<VkDeviceQueueCreateInfo> vDeviceQueueCreateInfos;
vDeviceQueueCreateInfos.reserve(setUniqueQueueFamilies.size());
const float queuePriorities[] = { 1.0f };
for (int queueFamilyIndex : setUniqueQueueFamilies)
{
VkDeviceQueueCreateInfo vkdqci = {};
vkdqci.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
vkdqci.queueFamilyIndex = queueFamilyIndex;
vkdqci.queueCount = 1;
vkdqci.pQueuePriorities = queuePriorities;
vDeviceQueueCreateInfos.push_back(vkdqci);
}
VkPhysicalDeviceFeatures physicalDeviceFeatures = {};
VkDeviceCreateInfo vkdci = {};
vkdci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
vkdci.queueCreateInfoCount = Utils::Cast32(vDeviceQueueCreateInfos.size());
vkdci.pQueueCreateInfos = vDeviceQueueCreateInfos.data();
#if defined(_DEBUG) || defined(VERUS_DEBUG)
vkdci.enabledLayerCount = VERUS_ARRAY_LENGTH(s_requiredValidationLayers);
vkdci.ppEnabledLayerNames = s_requiredValidationLayers;
#endif
vkdci.enabledExtensionCount = VERUS_ARRAY_LENGTH(s_requiredDeviceExtensions);
vkdci.ppEnabledExtensionNames = s_requiredDeviceExtensions;
vkdci.pEnabledFeatures = &physicalDeviceFeatures;
if (VK_SUCCESS != (res = vkCreateDevice(_physicalDevice, &vkdci, nullptr, &_device)))
throw VERUS_RUNTIME_ERROR << "vkCreateDevice(), res=" << res;
vkGetDeviceQueue(_device, _queueFamilyIndices._graphicsFamilyIndex, 0, &_graphicsQueue);
vkGetDeviceQueue(_device, _queueFamilyIndices._presentFamilyIndex, 0, &_presentQueue);
}
RendererVulkan::SwapChainInfo RendererVulkan::GetSwapChainInfo(VkPhysicalDevice device)
{
SwapChainInfo swapChainInfo;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, _surface, &swapChainInfo._surfaceCapabilities);
uint32_t surfaceFormatCount = 0;
vkGetPhysicalDeviceSurfaceFormatsKHR(device, _surface, &surfaceFormatCount, nullptr);
if (surfaceFormatCount)
{
swapChainInfo._vSurfaceFormats.resize(surfaceFormatCount);
vkGetPhysicalDeviceSurfaceFormatsKHR(device, _surface, &surfaceFormatCount, swapChainInfo._vSurfaceFormats.data());
}
uint32_t presentModeCount = 0;
vkGetPhysicalDeviceSurfacePresentModesKHR(device, _surface, &presentModeCount, nullptr);
if (presentModeCount)
{
swapChainInfo._vSurfacePresentModes.resize(presentModeCount);
vkGetPhysicalDeviceSurfacePresentModesKHR(device, _surface, &presentModeCount, swapChainInfo._vSurfacePresentModes.data());
}
return swapChainInfo;
}
void RendererVulkan::CreateSwapChain()
{
VERUS_QREF_SETTINGS;
VkResult res = VK_SUCCESS;
_numSwapChainBuffers = settings._screenVSync ? 3 : 2;
const SwapChainInfo swapChainInfo = GetSwapChainInfo(_physicalDevice);
VkSwapchainCreateInfoKHR vksci = {};
vksci.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
vksci.surface = _surface;
vksci.minImageCount = _numSwapChainBuffers;
vksci.imageFormat = VK_FORMAT_B8G8R8A8_UNORM;
vksci.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
vksci.imageExtent.width = settings._screenSizeWidth;
vksci.imageExtent.height = settings._screenSizeHeight;
vksci.imageArrayLayers = 1;
vksci.imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
vksci.preTransform = swapChainInfo._surfaceCapabilities.currentTransform;
vksci.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
vksci.presentMode = settings._screenVSync ? VK_PRESENT_MODE_MAILBOX_KHR : VK_PRESENT_MODE_FIFO_KHR;
vksci.clipped = VK_TRUE;
vksci.oldSwapchain = VK_NULL_HANDLE;
const uint32_t queueFamilyIndicesArray[] =
{
static_cast<uint32_t>(_queueFamilyIndices._graphicsFamilyIndex),
static_cast<uint32_t>(_queueFamilyIndices._presentFamilyIndex)
};
if (_queueFamilyIndices.IsSameQueue())
{
vksci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
}
else
{
vksci.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
vksci.queueFamilyIndexCount = VERUS_ARRAY_LENGTH(queueFamilyIndicesArray);
vksci.pQueueFamilyIndices = queueFamilyIndicesArray;
}
if (VK_SUCCESS != (res = vkCreateSwapchainKHR(_device, &vksci, nullptr, &_swapChain)))
throw VERUS_RUNTIME_ERROR << "vkCreateSwapchainKHR(), res=" << res;
vkGetSwapchainImagesKHR(_device, _swapChain, &_numSwapChainBuffers, nullptr);
_vSwapChainImages.resize(_numSwapChainBuffers);
vkGetSwapchainImagesKHR(_device, _swapChain, &_numSwapChainBuffers, _vSwapChainImages.data());
}
void RendererVulkan::CreateImageViews()
{
VkResult res = VK_SUCCESS;
_vSwapChainImageViews.resize(_numSwapChainBuffers);
VERUS_U_FOR(i, _numSwapChainBuffers)
{
VkImageViewCreateInfo vkivci = {};
vkivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
vkivci.image = _vSwapChainImages[i];
vkivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
vkivci.format = VK_FORMAT_B8G8R8A8_UNORM;
vkivci.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
vkivci.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
vkivci.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
vkivci.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
vkivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
vkivci.subresourceRange.baseMipLevel = 0;
vkivci.subresourceRange.levelCount = 1;
vkivci.subresourceRange.baseArrayLayer = 0;
vkivci.subresourceRange.layerCount = 1;
if (VK_SUCCESS != (res = vkCreateImageView(_device, &vkivci, nullptr, &_vSwapChainImageViews[i])))
throw VERUS_RUNTIME_ERROR << "vkCreateImageView(), res=" << res;
}
}
void RendererVulkan::CreateCommandPools()
{
VkResult res = VK_SUCCESS;
VERUS_FOR(i, ringBufferSize)
{
VkCommandPoolCreateInfo vkcpci = {};
vkcpci.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
vkcpci.queueFamilyIndex = _queueFamilyIndices._graphicsFamilyIndex;
if (VK_SUCCESS != (res = vkCreateCommandPool(_device, &vkcpci, nullptr, &_commandPools[i])))
throw VERUS_RUNTIME_ERROR << "vkCreateCommandPool(), res=" << res;
}
}
void RendererVulkan::CreateCommandBuffers()
{
VkResult res = VK_SUCCESS;
VERUS_FOR(i, ringBufferSize)
{
VkCommandBufferAllocateInfo vkcbai = {};
vkcbai.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
vkcbai.commandPool = _commandPools[i];
vkcbai.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
vkcbai.commandBufferCount = 1;
if (VK_SUCCESS != (res = vkAllocateCommandBuffers(_device, &vkcbai, &_commandBuffers[i])))
throw VERUS_RUNTIME_ERROR << "vkAllocateCommandBuffers(), res=" << res;
}
}
void RendererVulkan::CreateSyncObjects()
{
VkResult res = VK_SUCCESS;
VkSemaphoreCreateInfo vksci = {};
vksci.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
VkFenceCreateInfo vkfci = {};
vkfci.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
vkfci.flags = VK_FENCE_CREATE_SIGNALED_BIT;
VERUS_U_FOR(i, ringBufferSize)
{
if (VK_SUCCESS != (res = vkCreateSemaphore(_device, &vksci, nullptr, &_acquireNextImageSemaphores[i])))
throw VERUS_RUNTIME_ERROR << "vkCreateSemaphore(), res=" << res;
if (VK_SUCCESS != (res = vkCreateSemaphore(_device, &vksci, nullptr, &_queueSubmitSemaphores[i])))
throw VERUS_RUNTIME_ERROR << "vkCreateSemaphore(), res=" << res;
if (VK_SUCCESS != (res = vkCreateFence(_device, &vkfci, nullptr, &_queueSubmitFences[i])))
throw VERUS_RUNTIME_ERROR << "vkCreateFence(), res=" << res;
}
}
void RendererVulkan::BeginFrame()
{
VkResult res = VK_SUCCESS;
if (VK_SUCCESS != (res = vkWaitForFences(_device, 1, &_queueSubmitFences[_ringBufferIndex], VK_TRUE, UINT64_MAX)))
throw VERUS_RUNTIME_ERROR << "vkWaitForFences(), res=" << res;
if (VK_SUCCESS != (res = vkResetFences(_device, 1, &_queueSubmitFences[_ringBufferIndex])))
throw VERUS_RUNTIME_ERROR << "vkResetFences(), res=" << res;
if (VK_SUCCESS != (res = vkAcquireNextImageKHR(_device, _swapChain, UINT64_MAX, _acquireNextImageSemaphores[_ringBufferIndex], VK_NULL_HANDLE, &_swapChainBufferIndex)))
throw VERUS_RUNTIME_ERROR << "vkAcquireNextImageKHR(), res=" << res;
if (VK_SUCCESS != (res = vkResetCommandPool(_device, _commandPools[_ringBufferIndex], VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT)))
throw VERUS_RUNTIME_ERROR << "vkResetCommandPool(), res=" << res;
VkCommandBufferBeginInfo vkcbbi = {};
vkcbbi.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
vkcbbi.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
if (VK_SUCCESS != (res = vkBeginCommandBuffer(_commandBuffers[_ringBufferIndex], &vkcbbi)))
throw VERUS_RUNTIME_ERROR << "vkBeginCommandBuffer(), res=" << res;
}
void RendererVulkan::EndFrame()
{
VkResult res = VK_SUCCESS;
VkImageMemoryBarrier vkimb = {};
vkimb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
vkimb.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
vkimb.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
vkimb.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
vkimb.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
vkimb.image = _vSwapChainImages[_swapChainBufferIndex];
vkimb.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
vkimb.subresourceRange.baseMipLevel = 0;
vkimb.subresourceRange.levelCount = 1;
vkimb.subresourceRange.baseArrayLayer = 0;
vkimb.subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(_commandBuffers[_ringBufferIndex], VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &vkimb);
if (VK_SUCCESS != (res = vkEndCommandBuffer(_commandBuffers[_ringBufferIndex])))
throw VERUS_RUNTIME_ERROR << "vkEndCommandBuffer(), res=" << res;
const VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
const VkSemaphore waitSemaphores[] = { _acquireNextImageSemaphores[_ringBufferIndex] };
const VkSemaphore signalSemaphores[] = { _queueSubmitSemaphores[_ringBufferIndex] };
VkSubmitInfo vksi = {};
vksi.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
vksi.waitSemaphoreCount = VERUS_ARRAY_LENGTH(waitSemaphores);
vksi.pWaitSemaphores = waitSemaphores;
vksi.pWaitDstStageMask = waitStages;
vksi.commandBufferCount = 1;
vksi.pCommandBuffers = &_commandBuffers[_ringBufferIndex];
if (!_queueFamilyIndices.IsSameQueue())
{
vksi.signalSemaphoreCount = VERUS_ARRAY_LENGTH(signalSemaphores);
vksi.pSignalSemaphores = signalSemaphores;
}
if (VK_SUCCESS != (res = vkQueueSubmit(_graphicsQueue, 1, &vksi, _queueSubmitFences[_ringBufferIndex])))
throw VERUS_RUNTIME_ERROR << "vkQueueSubmit(), res=" << res;
}
void RendererVulkan::Present()
{
VkResult res = VK_SUCCESS;
const VkSemaphore waitSemaphores[] = { _queueSubmitSemaphores[_ringBufferIndex] };
const VkSwapchainKHR swapChains[] = { _swapChain };
VkPresentInfoKHR vkpi = {};
vkpi.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
if (!_queueFamilyIndices.IsSameQueue())
{
vkpi.waitSemaphoreCount = VERUS_ARRAY_LENGTH(waitSemaphores);
vkpi.pWaitSemaphores = waitSemaphores;
}
vkpi.swapchainCount = VERUS_ARRAY_LENGTH(swapChains);
vkpi.pSwapchains = swapChains;
vkpi.pImageIndices = &_swapChainBufferIndex;
if (VK_SUCCESS != (res = vkQueuePresentKHR(_presentQueue, &vkpi)))
throw VERUS_RUNTIME_ERROR << "vkQueuePresentKHR(), res=" << res;
_ringBufferIndex = (_ringBufferIndex + 1) % ringBufferSize;
}
void RendererVulkan::Clear(UINT32 flags)
{
VERUS_QREF_RENDERER;
VkImageMemoryBarrier vkimb = {};
vkimb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
vkimb.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
vkimb.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
vkimb.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
vkimb.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
vkimb.image = _vSwapChainImages[_swapChainBufferIndex];
vkimb.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
vkimb.subresourceRange.baseMipLevel = 0;
vkimb.subresourceRange.levelCount = 1;
vkimb.subresourceRange.baseArrayLayer = 0;
vkimb.subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(_commandBuffers[_ringBufferIndex], VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &vkimb);
VkClearColorValue clearColorValue;
memcpy(&clearColorValue, renderer.GetClearColor().ToPointer(), sizeof(clearColorValue));
VkImageSubresourceRange vkisr = {};
vkisr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
vkisr.baseMipLevel = 0;
vkisr.levelCount = 1;
vkisr.baseArrayLayer = 0;
vkisr.layerCount = 1;
vkCmdClearColorImage(_commandBuffers[_ringBufferIndex], _vSwapChainImages[_swapChainBufferIndex], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColorValue, 1, &vkisr);
}

View File

@ -0,0 +1,98 @@
#pragma once
namespace verus
{
namespace CGI
{
class RendererVulkan : public Singleton<RendererVulkan>, public BaseRenderer
{
struct QueueFamilyIndices
{
int _graphicsFamilyIndex = -1;
int _presentFamilyIndex = -1;
bool IsComplete() const
{
return _graphicsFamilyIndex >= 0 && _presentFamilyIndex >= 0;
}
bool IsSameQueue() const
{
return _graphicsFamilyIndex == _presentFamilyIndex;
}
};
struct SwapChainInfo
{
VkSurfaceCapabilitiesKHR _surfaceCapabilities = {};
Vector<VkSurfaceFormatKHR> _vSurfaceFormats;
Vector<VkPresentModeKHR> _vSurfacePresentModes;
};
static CSZ s_requiredValidationLayers[];
static CSZ s_requiredDeviceExtensions[];
VkInstance _instance = VK_NULL_HANDLE;
VkDebugUtilsMessengerEXT _debugUtilsMessenger = VK_NULL_HANDLE;
VkSurfaceKHR _surface = VK_NULL_HANDLE;
VkPhysicalDevice _physicalDevice = VK_NULL_HANDLE;
VkDevice _device = VK_NULL_HANDLE;
VkQueue _graphicsQueue = VK_NULL_HANDLE;
VkQueue _presentQueue = VK_NULL_HANDLE;
VkSwapchainKHR _swapChain = VK_NULL_HANDLE;
Vector<VkImage> _vSwapChainImages;
Vector<VkImageView> _vSwapChainImageViews;
VkCommandPool _commandPools[ringBufferSize] = { VK_NULL_HANDLE };
VkCommandBuffer _commandBuffers[ringBufferSize] = { VK_NULL_HANDLE };
VkSemaphore _acquireNextImageSemaphores[ringBufferSize] = { VK_NULL_HANDLE };
VkSemaphore _queueSubmitSemaphores[ringBufferSize] = { VK_NULL_HANDLE };
VkFence _queueSubmitFences[ringBufferSize] = { VK_NULL_HANDLE };
QueueFamilyIndices _queueFamilyIndices;
public:
RendererVulkan();
~RendererVulkan();
virtual void ReleaseMe() override;
void Init();
void Done();
private:
static VKAPI_ATTR VkBool32 VKAPI_CALL DebugUtilsMessengerCallback(
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageTypes,
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
void* pUserData);
bool CheckRequiredValidationLayers();
Vector<CSZ> GetRequiredExtensions();
void CreateInstance();
void CreateDebugUtilsMessenger();
void CreateSurface();
bool CheckRequiredDeviceExtensions(VkPhysicalDevice device);
QueueFamilyIndices FindQueueFamilyIndices(VkPhysicalDevice device);
bool IsDeviceSuitable(VkPhysicalDevice device);
void PickPhysicalDevice();
void CreateDevice();
SwapChainInfo GetSwapChainInfo(VkPhysicalDevice device);
void CreateSwapChain();
void CreateImageViews();
void CreateCommandPools();
void CreateCommandBuffers();
void CreateSyncObjects();
public:
// Which graphics API?
virtual Gapi GetGapi() override { return Gapi::vulkan; }
// Frame cycle:
virtual void BeginFrame() override;
virtual void EndFrame() override;
virtual void Present() override;
virtual void Clear(UINT32 flags) override;
};
VERUS_TYPEDEFS(RendererVulkan);
}
}
#define VERUS_QREF_RENDERER_VULKAN CGI::PRendererVulkan pRendererVulkan = CGI::RendererVulkan::P()

View File

@ -0,0 +1,23 @@
#include "stdafx.h"
using namespace verus;
using namespace verus::CGI;
ShaderVulkan::ShaderVulkan()
{
}
ShaderVulkan::~ShaderVulkan()
{
Done();
}
void ShaderVulkan::Init(CSZ source, CSZ* list)
{
VERUS_INIT();
}
void ShaderVulkan::Done()
{
VERUS_DONE(ShaderVulkan);
}

View File

@ -0,0 +1,17 @@
#pragma once
namespace verus
{
namespace CGI
{
class ShaderVulkan : public BaseShader
{
public:
ShaderVulkan();
virtual ~ShaderVulkan() override;
virtual void Init(CSZ source, CSZ* list) override;
virtual void Done() override;
};
}
}

View File

@ -18,32 +18,24 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
extern "C"
{
VERUS_DLL_EXPORT void* VerusCreateRenderer(UINT32 version, void* pDesc)
VERUS_DLL_EXPORT verus::CGI::PBaseRenderer VerusCreateRenderer(UINT32 version, verus::CGI::PBaseRendererDesc pDesc)
{
return nullptr;
#if 0
using namespace verus;
if (VERUS_SDK_VERSION != version)
{
VERUS_RT_FAIL("FAIL: wrong version");
VERUS_RT_FAIL("VerusCreateRenderer(), Wrong version");
return nullptr;
}
pDesc->_pack.Paste();
pDesc->_gvc.Paste();
CGI::RendererVulkan::Make();
VERUS_QREF_RENDERER_VULKAN;
pRendererVulkan->SetDesc(*pDesc);
if (pDesc->m_createWindow)
pRendererVulkan->InitWindow();
pRendererVulkan->Init();
return pRendererVulkan;
#endif
}
}

View File

@ -2,3 +2,5 @@
#define VERUS_INCLUDE_VULKAN
#include <verus.h>
#include "CGI/CGI.h"

View File

@ -3,8 +3,8 @@
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<IncludePath>C:\Home\Projects\Verus\verus\Verus\src;C:\Home\Middleware\bullet3-2.88\src;C:\Home\Middleware\bullet3-2.88\Extras;C:\Home\Middleware\glm-0.9.9.3\glm;C:\Home\Middleware\json-3.5.0;C:\Home\Middleware\libogg-1.3.3\include;C:\Home\Middleware\libvorbis-1.3.6\include;C:\Home\Middleware\SDL2-2.0.9\include;C:\Home\Middleware\tinyxml2-7.0.1;C:\Home\Middleware\vectormath;C:\Home\Middleware\zlib-1.2.11;C:\Program Files %28x86%29\OpenAL 1.1 SDK\include;$(IncludePath)</IncludePath>
<LibraryPath>C:\Home\Middleware\bullet3-2.88\lib\Debug;C:\Home\Middleware\libogg-1.3.3\lib;C:\Home\Middleware\libvorbis-1.3.6\lib2;C:\Home\Middleware\SDL2-2.0.9\lib\x64;C:\Home\Middleware\tinyxml2-7.0.1;C:\Home\Middleware\zlib-1.2.11;C:\Program Files %28x86%29\OpenAL 1.1 SDK\libs\Win64;$(LibraryPath)</LibraryPath>
<IncludePath>C:\Home\Projects\Verus\verus\Verus\src;C:\Home\Middleware\bullet3-2.88\src;C:\Home\Middleware\bullet3-2.88\Extras;C:\Home\Middleware\glm-0.9.9.3\glm;C:\Home\Middleware\json-3.5.0;C:\Home\Middleware\libogg-1.3.3\include;C:\Home\Middleware\libvorbis-1.3.6\include;C:\Home\Middleware\SDL2-2.0.9\include;C:\Home\Middleware\tinyxml2-7.0.1;C:\Home\Middleware\vectormath;C:\Home\Middleware\zlib-1.2.11;C:\Program Files %28x86%29\OpenAL 1.1 SDK\include;C:\VulkanSDK\1.1.101.0\Include;$(IncludePath)</IncludePath>
<LibraryPath>C:\Home\Middleware\bullet3-2.88\lib\Debug;C:\Home\Middleware\libogg-1.3.3\lib;C:\Home\Middleware\libvorbis-1.3.6\lib2;C:\Home\Middleware\SDL2-2.0.9\lib\x64;C:\Home\Middleware\tinyxml2-7.0.1;C:\Home\Middleware\zlib-1.2.11;C:\Program Files %28x86%29\OpenAL 1.1 SDK\libs\Win64;C:\VulkanSDK\1.1.101.0\Lib;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup />
<ItemGroup />

View File

@ -104,6 +104,7 @@
<ClInclude Include="src\Audio\Sound.h" />
<ClInclude Include="src\Audio\Source.h" />
<ClInclude Include="src\Audio\StreamPlayer.h" />
<ClInclude Include="src\CGI\BaseCommandBuffer.h" />
<ClInclude Include="src\CGI\BaseGeometry.h" />
<ClInclude Include="src\CGI\BasePipeline.h" />
<ClInclude Include="src\CGI\BaseRenderer.h" />
@ -204,6 +205,7 @@
<ClCompile Include="src\Audio\Sound.cpp" />
<ClCompile Include="src\Audio\Source.cpp" />
<ClCompile Include="src\Audio\StreamPlayer.cpp" />
<ClCompile Include="src\CGI\BaseCommandBuffer.cpp" />
<ClCompile Include="src\CGI\BaseGeometry.cpp" />
<ClCompile Include="src\CGI\BasePipeline.cpp" />
<ClCompile Include="src\CGI\BaseRenderer.cpp" />

View File

@ -363,6 +363,9 @@
<ClInclude Include="src\CGI\Renderer.h">
<Filter>src\CGI</Filter>
</ClInclude>
<ClInclude Include="src\CGI\BaseCommandBuffer.h">
<Filter>src\CGI</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\CGI\BaseGeometry.cpp">
@ -566,5 +569,8 @@
<ClCompile Include="src\CGI\CGI.cpp">
<Filter>src\CGI</Filter>
</ClCompile>
<ClCompile Include="src\CGI\BaseCommandBuffer.cpp">
<Filter>src\CGI</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -29,7 +29,7 @@ void Settings::Load()
Json::Load();
_quality = static_cast<Quality>(GetI("quality", +_quality));
_direct3D = GetI("direct3D", _direct3D);
_gapi = GetI("gapi", _gapi);
_gpuAnisotropyLevel = GetI("gpuAnisotropyLevel", _gpuAnisotropyLevel);
_gpuAntialiasingLevel = GetI("gpuAntialiasingLevel", _gpuAntialiasingLevel);
_gpuDepthTexture = GetI("gpuDepthTexture", _gpuDepthTexture);
@ -58,7 +58,7 @@ void Settings::Load()
void Settings::Save()
{
Set("quality", +_quality);
Set("direct3D", _direct3D);
Set("gapi", _gapi);
Set("gpuAnisotropyLevel", _gpuAnisotropyLevel);
Set("gpuAntialiasingLevel", _gpuAntialiasingLevel);
Set("gpuDepthTexture", _gpuDepthTexture);
@ -183,7 +183,6 @@ void Settings::ParseCommandLineArgs(int argc, char* argv[])
void Settings::SetQuality(Quality q)
{
_quality = q;
_direct3D = 9;
_gpuAnisotropyLevel = 0;
_gpuAntialiasingLevel = 0;
_gpuDepthTexture = 0;
@ -221,7 +220,6 @@ void Settings::SetQuality(Quality q)
_screenSizeWidth = 1024;
break;
case Quality::high:
_direct3D = 11;
_gpuAnisotropyLevel = 8;
_gpuTrilinearFilter = true;
_postProcessBloom = true;
@ -234,7 +232,6 @@ void Settings::SetQuality(Quality q)
_screenSizeWidth = 1280;
break;
case Quality::ultra:
_direct3D = 11;
_gpuAnisotropyLevel = 16;
_gpuDepthTexture = 1;
_gpuTrilinearFilter = true;
@ -257,7 +254,7 @@ void Settings::SetQuality(Quality q)
_screenWindowed = false;
# endif
#else // Linux?
_direct3D = 0;
_gapi = 0;
_gpuForcedProfile = "arb1";
#endif
}

View File

@ -33,7 +33,7 @@ namespace verus
};
Quality _quality = Quality::medium;
int _direct3D = 9;
int _gapi = 12;
int _gpuAnisotropyLevel = 4;
int _gpuAntialiasingLevel = 0;
int _gpuDepthTexture = 0;

View File

@ -27,6 +27,7 @@ Window::~Window()
void Window::Init(RcDesc descConst)
{
VERUS_INIT();
VERUS_QREF_SETTINGS;
Desc desc = descConst;
if (desc._useSettings)
@ -35,6 +36,8 @@ void Window::Init(RcDesc descConst)
Uint32 flags = 0;
if (desc._fullscreen)
flags |= SDL_WINDOW_FULLSCREEN;
if (0 == settings._gapi)
flags |= SDL_WINDOW_VULKAN;
_pWnd = SDL_CreateWindow(
desc._title ? desc._title : "",

View File

@ -26,6 +26,9 @@ namespace verus
void Init(RcDesc desc = Desc());
void Done();
SDL_Window* GetSDL() { return _pWnd; }
};
VERUS_TYPEDEFS(Window);
}
}

View File

@ -0,0 +1,4 @@
#include "verus.h"
using namespace verus;
using namespace verus::CGI;

View File

@ -0,0 +1,34 @@
#pragma once
namespace verus
{
namespace CGI
{
class BaseCommandBuffer : public Object
{
protected:
BaseCommandBuffer() = default;
virtual ~BaseCommandBuffer() = default;
public:
virtual void Init() {}
virtual void Done() {}
virtual void Begin() = 0;
virtual void End() = 0;
virtual void BindVertexBuffers() = 0;
virtual void BindIndexBuffer() = 0;
virtual void SetScissor() = 0;
virtual void SetViewport() = 0;
virtual void BindPipeline() = 0;
virtual void Clear(ClearFlags clearFlags) = 0;
virtual void Draw() = 0;
virtual void DrawIndexed() = 0;
};
VERUS_TYPEDEFS(BaseCommandBuffer);
}
}

View File

@ -4,8 +4,22 @@ namespace verus
{
namespace CGI
{
class BaseGeometry
struct GeometryDesc
{
bool _dwordIndices = false;
};
VERUS_TYPEDEFS(GeometryDesc);
class BaseGeometry : public Object
{
protected:
BaseGeometry() = default;
virtual ~BaseGeometry() = default;
public:
virtual void Init(RcGeometryDesc desc) = 0;
virtual void Done() = 0;
};
VERUS_TYPEDEFS(BaseGeometry);
}
}

View File

@ -4,8 +4,16 @@ namespace verus
{
namespace CGI
{
class BasePipeline
class BasePipeline : public Object
{
protected:
BasePipeline() = default;
virtual ~BasePipeline() = default;
public:
virtual void Init() {}
virtual void Done() {}
};
VERUS_TYPEDEFS(BasePipeline);
}
}

View File

@ -26,23 +26,47 @@ namespace verus
{
protected:
BaseRendererDesc _desc;
UINT32 _numSwapChainBuffers = 0;
UINT32 _swapChainBufferIndex = 0;
UINT32 _ringBufferIndex = 0;
BaseRenderer();
virtual ~BaseRenderer();
public:
enum { ringBufferSize = 3 };
static BaseRenderer* Load(CSZ dll, RBaseRendererDesc desc);
virtual void ReleaseMe() = 0;
void SetDesc(RBaseRendererDesc desc) { _desc = desc; }
UINT32 GetNumSwapChainBuffers() const { return _numSwapChainBuffers; }
UINT32 GetSwapChainBufferIndex() const { return _swapChainBufferIndex; }
UINT32 GetRingBufferIndex() const { return _ringBufferIndex; }
// Which graphics API?
virtual Gapi GetGapi() = 0;
virtual void PrepareDraw() {}
virtual void Clear(UINT32 flags) {}
virtual void Present() {}
// Frame cycle:
virtual void BeginFrame() = 0;
virtual void EndFrame() = 0;
virtual void Present() = 0;
virtual void Clear(UINT32 flags) = 0;
// Resources:
virtual PBaseCommandBuffer InsertCommandBuffer() { return nullptr; }
virtual PBaseGeometry InsertGeometry() { return nullptr; }
virtual PBasePipeline InsertPipeline() { return nullptr; }
virtual PBaseShader InsertShader() { return nullptr; }
virtual PBaseTexture InsertTexture() { return nullptr; }
virtual void DeleteCommandBuffer(PBaseCommandBuffer p) {}
virtual void DeleteGeometry(PBaseGeometry p) {}
virtual void DeletePipeline(PBasePipeline p) {}
virtual void DeleteShader(PBaseShader p) {}
virtual void DeleteTexture(PBaseTexture p) {}
};
VERUS_TYPEDEFS(BaseRenderer);
}

View File

@ -2,3 +2,28 @@
using namespace verus;
using namespace verus::CGI;
void BaseShader::Load(CSZ url)
{
Vector<BYTE> vData;
IO::FileSystem::LoadResource(url, vData, IO::FileSystem::LoadDesc(true));
Vector<String> v;
CSZ pText = reinterpret_cast<CSZ>(vData.data());
CSZ p = strstr(pText, "//:");
while (p)
{
const size_t span = strcspn(p, VERUS_CRNL);
const String value(p + 3, span - 3);
v.push_back(value);
p = strstr(p + span, "//:");
}
Vector<CSZ> vp;
vp.reserve(v.size() + 1);
VERUS_FOREACH_CONST(Vector<String>, v, it)
vp.push_back(_C(*it));
vp.push_back(0);
Init(reinterpret_cast<CSZ>(vData.data()), vp.data());
}

View File

@ -4,8 +4,24 @@ namespace verus
{
namespace CGI
{
class BaseShader
struct ShaderDesc
{
CSZ _source = nullptr;
};
VERUS_TYPEDEFS(ShaderDesc);
class BaseShader : public Object
{
protected:
BaseShader() = default;
virtual ~BaseShader() = default;
public:
virtual void Init(CSZ source, CSZ* list) = 0;
virtual void Done() = 0;
void Load(CSZ url);
};
VERUS_TYPEDEFS(BaseShader);
}
}

View File

@ -4,8 +4,16 @@ namespace verus
{
namespace CGI
{
class BaseTexture
class BaseTexture : public Object
{
protected:
BaseTexture() = default;
virtual ~BaseTexture() = default;
public:
virtual void Init() {}
virtual void Done() {}
};
VERUS_TYPEDEFS(BaseTexture);
}
}

View File

@ -1,9 +1,23 @@
#pragma once
namespace verus
{
namespace CGI
{
enum class ClearFlags : int
{
color = (1 << 0),
depth = (1 << 1),
stencil = (1 << 2)
};
}
}
#include "BaseGeometry.h"
#include "BasePipeline.h"
#include "BaseShader.h"
#include "BaseTexture.h"
#include "BaseCommandBuffer.h"
#include "BaseRenderer.h"
#include "Renderer.h"

View File

@ -26,14 +26,23 @@ bool Renderer::IsLoaded()
void Renderer::Init(PRendererDelegate pDelegate)
{
VERUS_INIT();
VERUS_QREF_SETTINGS;
_pRendererDelegate = pDelegate;
CSZ dll = "RendererDirect3D12.dll";
CSZ dll = "RendererVulkan.dll";
switch (settings._gapi)
{
case 12:
{
dll = "RendererDirect3D12.dll";
VERUS_LOG_INFO("Using Direct3D 12");
}
break;
default:
VERUS_LOG_INFO("Using Vulkan");
}
BaseRendererDesc desc;
_pBaseRenderer = BaseRenderer::Load(dll, desc);
_gapi = _pBaseRenderer->GetGapi();

View File

@ -15,6 +15,8 @@ namespace verus
class Renderer : public Singleton<Renderer>, public Object
{
Vector4 _clearColor = Vector4(0);
App::PWindow _pMainWindow = nullptr;
PBaseRenderer _pBaseRenderer = nullptr;
PRendererDelegate _pRendererDelegate = nullptr;
UINT64 _numFrames = 0;
@ -33,6 +35,12 @@ namespace verus
void Draw();
void Present();
App::PWindow GetMainWindow() const { return _pMainWindow; }
App::PWindow SetMainWindow(App::PWindow p) { return Utils::Swap(_pMainWindow, p); }
RcVector4 GetClearColor() const { return _clearColor; }
void SetClearColor(RcVector4 color) { _clearColor = color; }
};
VERUS_TYPEDEFS(Renderer);
}

View File

@ -13,7 +13,10 @@ struct MyRendererDelegate : CGI::RendererDelegate
virtual void Renderer_OnDraw() override
{
VERUS_QREF_RENDERER;
renderer->PrepareDraw();
VERUS_QREF_TIMER;
const float x = fmod(timer.GetTime(), 1.f);
renderer.SetClearColor(Vector4(x, 0.5f, 0.25f, 1.f));
renderer->BeginFrame();
renderer->Clear(0);
_p->BaseGame_Draw();
}
@ -26,6 +29,7 @@ struct MyRendererDelegate : CGI::RendererDelegate
virtual void Renderer_OnPresent() override
{
VERUS_QREF_RENDERER;
renderer->EndFrame();
renderer->Present();
}
@ -101,6 +105,7 @@ void BaseGame::Initialize(VERUS_MAIN_DEFAULT_ARGS)
#endif
_window.Init();
CGI::Renderer::I().SetMainWindow(&_window);
_engineInit.Init(this, new MyRendererDelegate(this));
// Configure:

Binary file not shown.

View File

@ -15,7 +15,7 @@
<ProjectGuid>{D7085182-35B9-4689-ADBA-B77087AD16BF}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>VerusTest</RootNamespace>
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">