Merge branch 'main' into SP3-14-FileSystem
This commit is contained in:
commit
7b55f7fe3b
|
@ -60,7 +60,7 @@
|
||||||
<PrecompiledHeaderFile>SBpch.h</PrecompiledHeaderFile>
|
<PrecompiledHeaderFile>SBpch.h</PrecompiledHeaderFile>
|
||||||
<WarningLevel>Level4</WarningLevel>
|
<WarningLevel>Level4</WarningLevel>
|
||||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<AdditionalIncludeDirectories>.;..\SHADE_Engine\src;src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\Dependencies\spdlog\include;..\SHADE_Engine\src;src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<MinimalRebuild>false</MinimalRebuild>
|
<MinimalRebuild>false</MinimalRebuild>
|
||||||
|
@ -71,7 +71,7 @@
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<EntryPointSymbol>WinMainCRTStartup</EntryPointSymbol>
|
<EntryPointSymbol>wWinMainCRTStartup</EntryPointSymbol>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
@ -80,7 +80,7 @@
|
||||||
<PrecompiledHeaderFile>SBpch.h</PrecompiledHeaderFile>
|
<PrecompiledHeaderFile>SBpch.h</PrecompiledHeaderFile>
|
||||||
<WarningLevel>Level4</WarningLevel>
|
<WarningLevel>Level4</WarningLevel>
|
||||||
<PreprocessorDefinitions>_RELEASE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>_RELEASE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<AdditionalIncludeDirectories>.;..\SHADE_Engine\src;src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\Dependencies\spdlog\include;..\SHADE_Engine\src;src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<Optimization>Full</Optimization>
|
<Optimization>Full</Optimization>
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
@ -94,16 +94,20 @@
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<EntryPointSymbol>WinMainCRTStartup</EntryPointSymbol>
|
<EntryPointSymbol>wWinMainCRTStartup</EntryPointSymbol>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="src\Application\SBApplication.h" />
|
||||||
<ClInclude Include="src\SBpch.h" />
|
<ClInclude Include="src\SBpch.h" />
|
||||||
|
<ClInclude Include="src\Scenes\SBTestScene.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="src\Application\SBApplication.cpp" />
|
||||||
<ClCompile Include="src\SBpch.cpp">
|
<ClCompile Include="src\SBpch.cpp">
|
||||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Scenes\SBTestScene.cpp" />
|
||||||
<ClCompile Include="src\WinMain.cpp" />
|
<ClCompile Include="src\WinMain.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Application">
|
||||||
|
<UniqueIdentifier>{D9DE78AF-4594-F1A4-CE88-EB7B3A3DE8A8}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Scenes">
|
||||||
|
<UniqueIdentifier>{86EEB3D0-7290-DEA6-5B4B-F2FA478C65F7}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="src\Application\SBApplication.h">
|
||||||
|
<Filter>Application</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\SBpch.h" />
|
||||||
|
<ClInclude Include="src\Scenes\SBTestScene.h">
|
||||||
|
<Filter>Scenes</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="src\Application\SBApplication.cpp">
|
||||||
|
<Filter>Application</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\SBpch.cpp" />
|
||||||
|
<ClCompile Include="src\Scenes\SBTestScene.cpp">
|
||||||
|
<Filter>Scenes</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\WinMain.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
|
@ -8,7 +8,7 @@ project "SHADE_Application"
|
||||||
pchheader "SBpch.h"
|
pchheader "SBpch.h"
|
||||||
pchsource "%{prj.location}/src/SBpch.cpp"
|
pchsource "%{prj.location}/src/SBpch.cpp"
|
||||||
staticruntime "on"
|
staticruntime "on"
|
||||||
entrypoint "WinMainCRTStartup"
|
entrypoint "wWinMainCRTStartup"
|
||||||
system ("windows")
|
system ("windows")
|
||||||
|
|
||||||
files
|
files
|
||||||
|
@ -21,8 +21,7 @@ project "SHADE_Application"
|
||||||
|
|
||||||
includedirs
|
includedirs
|
||||||
{
|
{
|
||||||
"%{IncludeDir.GLFW}",
|
"%{IncludeDir.spdlog}/include",
|
||||||
"%{IncludeDir.GLAD}",
|
|
||||||
"../SHADE_Engine/src",
|
"../SHADE_Engine/src",
|
||||||
"src"
|
"src"
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
#include "SBpch.h"
|
||||||
|
#include "SBApplication.h"
|
||||||
|
|
||||||
|
#ifdef SHEDITOR
|
||||||
|
#include "Editor/SHEditor.h"
|
||||||
|
#include "Scenes/SBEditorScene.h"
|
||||||
|
#endif // SHEDITOR
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <ratio>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
namespace Sandbox
|
||||||
|
{
|
||||||
|
bool paused = false;
|
||||||
|
void SBApplication::Initialize
|
||||||
|
(
|
||||||
|
_In_ HINSTANCE hInstance,
|
||||||
|
_In_opt_ HINSTANCE hPrevInstance,
|
||||||
|
_In_ LPWSTR lpCmdLine,
|
||||||
|
_In_ INT nCmdShow
|
||||||
|
)
|
||||||
|
{
|
||||||
|
|
||||||
|
window.Create(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
|
||||||
|
|
||||||
|
#ifdef SHEDITOR
|
||||||
|
#else
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SBApplication::Update(void)
|
||||||
|
{
|
||||||
|
//TODO: Change true to window is open
|
||||||
|
while (!window.WindowShouldClose())
|
||||||
|
{
|
||||||
|
#ifdef SHEDITOR
|
||||||
|
#else
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SBApplication::Exit(void)
|
||||||
|
{
|
||||||
|
#ifdef SHEDITOR
|
||||||
|
#else
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
#ifndef SB_APPLICATION_H
|
||||||
|
#define SB_APPLICATION_H
|
||||||
|
#include <Graphics/Windowing/SHWindow.h>
|
||||||
|
//using namespace SHADE;
|
||||||
|
|
||||||
|
namespace Sandbox
|
||||||
|
{
|
||||||
|
class SBApplication
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
SHADE::SHWindow window;
|
||||||
|
//SHAppConfig config;
|
||||||
|
public:
|
||||||
|
SBApplication() = default;
|
||||||
|
void Initialize(_In_ HINSTANCE /*hInstance*/,
|
||||||
|
_In_opt_ HINSTANCE /*hPrevInstance*/,
|
||||||
|
_In_ LPWSTR /*lpCmdLine*/,
|
||||||
|
_In_ INT /*nCmdShow*/);
|
||||||
|
void Update(void);
|
||||||
|
void Exit(void);
|
||||||
|
private:
|
||||||
|
//std::common_type_t<double> collisionSystemTime, physicsSystemTime, transformSystemTime, audioSystemTime, renderSystemTime, gameTime;
|
||||||
|
//std::chrono::high_resolution_clock::time_point audioStart, audioEnd, transformStart, transformEnd, physicsStart, physicsEnd, collisionStart, collisionEnd, renderStart, renderEnd, gameStart, gameEnd;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,48 @@
|
||||||
|
#include "SBpch.h"
|
||||||
|
#include "SBTestScene.h"
|
||||||
|
|
||||||
|
using namespace SHADE;
|
||||||
|
|
||||||
|
namespace Sandbox
|
||||||
|
{
|
||||||
|
|
||||||
|
void SBTestScene::WindowFocusFunc([[maybe_unused]]void* window, int focused)
|
||||||
|
{
|
||||||
|
if(focused)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SBTestScene::Load()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void SBTestScene::Init()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
void SBTestScene::Update(float dt)
|
||||||
|
{
|
||||||
|
(void)dt;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SBTestScene::Render()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SBTestScene::Unload()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SBTestScene::Free()
|
||||||
|
{
|
||||||
|
//SHSerialization::SerializeScene("resources/scenes/Scene01.SHADE");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Scene/SHScene.h"
|
||||||
|
#include "Scene/SHSceneManager.h"
|
||||||
|
|
||||||
|
namespace Sandbox
|
||||||
|
{
|
||||||
|
class SBTestScene : public SHADE::SHScene
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
EntityID camera;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void Load();
|
||||||
|
virtual void Init();
|
||||||
|
virtual void Update(float dt);
|
||||||
|
virtual void Render();
|
||||||
|
virtual void Free();
|
||||||
|
virtual void Unload();
|
||||||
|
|
||||||
|
//TODO: Change to new window DO IT IN CPP TOO
|
||||||
|
void WindowFocusFunc(void* window, int focused);
|
||||||
|
|
||||||
|
SBTestScene(void) = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,51 @@
|
||||||
#include "SBpch.h"
|
#include "SBpch.h"
|
||||||
|
#include <Engine/SHEngine.h>
|
||||||
|
#include <Tools/SHLogger.h>
|
||||||
|
#include <Tools/SHExceptionHandler.h>
|
||||||
|
#include "Application/SBApplication.h"
|
||||||
|
|
||||||
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
|
||||||
PSTR lpCmdLine, INT nCmdShow)
|
#define _CRTDBG_MAP_ALLOC
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <crtdbg.h>
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
|
||||||
|
// Replace _NORMAL_BLOCK with _CLIENT_BLOCK if you want the
|
||||||
|
// allocations to be of _CLIENT_BLOCK type
|
||||||
|
#else
|
||||||
|
#define DBG_NEW new
|
||||||
|
#endif
|
||||||
|
|
||||||
|
INT WINAPI wWinMain
|
||||||
|
(
|
||||||
|
_In_ HINSTANCE hInstance,
|
||||||
|
_In_opt_ HINSTANCE hPrevInstance,
|
||||||
|
_In_ LPWSTR lpCmdLine,
|
||||||
|
_In_ INT nCmdShow
|
||||||
|
)
|
||||||
{
|
{
|
||||||
|
const SHADE::SHLogger::Config LOGGER_CONFIG{ .directoryPath = "./logs/" };
|
||||||
|
SHADE::SHLogger::Initialise(LOGGER_CONFIG);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
#ifndef SHEDITOR
|
||||||
|
//ShowWindow(::GetConsoleWindow(), SW_HIDE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SHLOG_INFO("sup")
|
||||||
|
|
||||||
|
SHADE::SHEngine::Run<Sandbox::SBApplication>(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
|
||||||
|
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
SHADE::SHExceptionHandler::HandleException(std::current_exception());
|
||||||
|
SHADE::SHLogger::Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
SHADE::SHLogger::Shutdown();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
|
@ -57,8 +57,8 @@
|
||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
<PrecompiledHeaderFile>SHpch.h</PrecompiledHeaderFile>
|
<PrecompiledHeaderFile>SHpch.h</PrecompiledHeaderFile>
|
||||||
<WarningLevel>Level4</WarningLevel>
|
<WarningLevel>Level4</WarningLevel>
|
||||||
<PreprocessorDefinitions>_LIB;_GLFW_INCLUDE_NONE;MSDFGEN_USE_CPP11;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>_LIB;_GLFW_INCLUDE_NONE;MSDFGEN_USE_CPP11;NOMINMAX;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<AdditionalIncludeDirectories>src;..\Dependencies\assimp\include;..\Dependencies\imgui;..\Dependencies\imguizmo;..\Dependencies\imnodes;..\Dependencies\msdf;..\Dependencies\msdf\msdfgen;..\Dependencies\spdlog\include;..\Dependencies\tracy;..\Dependencies\VMA\include;..\Dependencies\yamlcpp\include;..\Dependencies\ktx\include;..\Dependencies\RTTR\include;..\Dependencies\reactphysics3d\include;$(VULKAN_SDK)\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>src;..\Dependencies\assimp\include;..\Dependencies\imgui;..\Dependencies\imguizmo;..\Dependencies\imnodes;..\Dependencies\msdf;..\Dependencies\msdf\msdfgen;..\Dependencies\spdlog\include;..\Dependencies\tracy;..\Dependencies\VMA\include;..\Dependencies\yamlcpp\include;..\Dependencies\ktx\include;..\Dependencies\RTTR\include;..\Dependencies\reactphysics3d\include;$(VULKAN_SDK)\include;$(VULKAN_SDK)\Source\SPIRV-Reflect;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<MinimalRebuild>false</MinimalRebuild>
|
<MinimalRebuild>false</MinimalRebuild>
|
||||||
|
@ -71,7 +71,7 @@
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
</Link>
|
</Link>
|
||||||
<Lib>
|
<Lib>
|
||||||
<AdditionalDependencies>vulkan-1.lib;assimp-vc142-mtd.lib;ktxd.lib;librttr_core_d.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>vulkan-1.lib;shaderc_shared.lib;assimp-vc142-mtd.lib;ktxd.lib;librttr_core_d.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
<AdditionalLibraryDirectories>libs;$(VULKAN_SDK)\Lib;..\Dependencies\assimp\lib\Debug;..\Dependencies\assimp\lib\Release;..\Dependencies\RTTR\lib;..\Dependencies\ktx\lib\Debug;..\Dependencies\ktx\lib\Release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
<AdditionalLibraryDirectories>libs;$(VULKAN_SDK)\Lib;..\Dependencies\assimp\lib\Debug;..\Dependencies\assimp\lib\Release;..\Dependencies\RTTR\lib;..\Dependencies\ktx\lib\Debug;..\Dependencies\ktx\lib\Release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
</Lib>
|
</Lib>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
|
@ -80,8 +80,8 @@
|
||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
<PrecompiledHeaderFile>SHpch.h</PrecompiledHeaderFile>
|
<PrecompiledHeaderFile>SHpch.h</PrecompiledHeaderFile>
|
||||||
<WarningLevel>Level4</WarningLevel>
|
<WarningLevel>Level4</WarningLevel>
|
||||||
<PreprocessorDefinitions>_LIB;_GLFW_INCLUDE_NONE;MSDFGEN_USE_CPP11;_RELEASE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>_LIB;_GLFW_INCLUDE_NONE;MSDFGEN_USE_CPP11;NOMINMAX;_RELEASE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<AdditionalIncludeDirectories>src;..\Dependencies\assimp\include;..\Dependencies\imgui;..\Dependencies\imguizmo;..\Dependencies\imnodes;..\Dependencies\msdf;..\Dependencies\msdf\msdfgen;..\Dependencies\spdlog\include;..\Dependencies\tracy;..\Dependencies\VMA\include;..\Dependencies\yamlcpp\include;..\Dependencies\ktx\include;..\Dependencies\RTTR\include;..\Dependencies\reactphysics3d\include;$(VULKAN_SDK)\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>src;..\Dependencies\assimp\include;..\Dependencies\imgui;..\Dependencies\imguizmo;..\Dependencies\imnodes;..\Dependencies\msdf;..\Dependencies\msdf\msdfgen;..\Dependencies\spdlog\include;..\Dependencies\tracy;..\Dependencies\VMA\include;..\Dependencies\yamlcpp\include;..\Dependencies\ktx\include;..\Dependencies\RTTR\include;..\Dependencies\reactphysics3d\include;$(VULKAN_SDK)\include;$(VULKAN_SDK)\Source\SPIRV-Reflect;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<Optimization>Full</Optimization>
|
<Optimization>Full</Optimization>
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
@ -97,21 +97,169 @@
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
</Link>
|
</Link>
|
||||||
<Lib>
|
<Lib>
|
||||||
<AdditionalDependencies>vulkan-1.lib;assimp-vc142-mt.lib;ktx.lib;librttr_core.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>vulkan-1.lib;shaderc_shared.lib;assimp-vc142-mt.lib;ktx.lib;librttr_core.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
<AdditionalLibraryDirectories>libs;$(VULKAN_SDK)\Lib;..\Dependencies\assimp\lib\Debug;..\Dependencies\assimp\lib\Release;..\Dependencies\RTTR\lib;..\Dependencies\ktx\lib\Debug;..\Dependencies\ktx\lib\Release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
<AdditionalLibraryDirectories>libs;$(VULKAN_SDK)\Lib;..\Dependencies\assimp\lib\Debug;..\Dependencies\assimp\lib\Release;..\Dependencies\RTTR\lib;..\Dependencies\ktx\lib\Debug;..\Dependencies\ktx\lib\Release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
</Lib>
|
</Lib>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="src\Engine\ECS_Base\Components\SHComponent.h" />
|
||||||
|
<ClInclude Include="src\Engine\ECS_Base\Components\SHComponentGroup.h" />
|
||||||
|
<ClInclude Include="src\Engine\ECS_Base\Entity\SHEntity.h" />
|
||||||
|
<ClInclude Include="src\Engine\ECS_Base\General\SHFamily.h" />
|
||||||
|
<ClInclude Include="src\Engine\ECS_Base\General\SHHandleGenerator.h" />
|
||||||
|
<ClInclude Include="src\Engine\ECS_Base\General\SHSparseBase.h" />
|
||||||
|
<ClInclude Include="src\Engine\ECS_Base\General\SHSparseSet.h" />
|
||||||
|
<ClInclude Include="src\Engine\ECS_Base\General\SHSparseSetContainer.h" />
|
||||||
|
<ClInclude Include="src\Engine\ECS_Base\SHECSMacros.h" />
|
||||||
|
<ClInclude Include="src\Engine\ECS_Base\System\SHComponentManager.h" />
|
||||||
|
<ClInclude Include="src\Engine\ECS_Base\System\SHEntityManager.h" />
|
||||||
|
<ClInclude Include="src\Engine\ECS_Base\System\SHSystem.h" />
|
||||||
|
<ClInclude Include="src\Engine\ECS_Base\System\SHSystemManager.h" />
|
||||||
<ClInclude Include="src\Engine\SHEngine.h" />
|
<ClInclude Include="src\Engine\SHEngine.h" />
|
||||||
<ClInclude Include="src\Filesystem\SHFileSystem.h" />
|
<ClInclude Include="src\Filesystem\SHFileSystem.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Buffers\SHVkBuffer.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Commands\SHCommandPoolResetMode.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Commands\SHVkCommandBuffer.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Commands\SHVkCommandPool.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Debugging\SHValidationLayersQuery.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Debugging\SHVkDebugMessenger.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Debugging\SHVulkanDebugUtil.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Descriptors\SHDescriptorPoolManager.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Descriptors\SHDescriptorPoolStorage.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Descriptors\SHVkDescriptorPool.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Descriptors\SHVkDescriptorSetGroup.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Descriptors\SHVkDescriptorSetLayout.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Devices\SHVkLogicalDevice.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Devices\SHVkPhysicalDevice.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Devices\SHVkPhysicalDeviceLibrary.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Framebuffer\SHVkFramebuffer.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Images\SHImageViewDetails.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Images\SHVkImage.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Images\SHVkImageView.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Instance\SHVkInstance.h" />
|
||||||
|
<ClInclude Include="src\Graphics\MiddleEnd\Interface\SHGraphicsSystem.h" />
|
||||||
|
<ClInclude Include="src\Graphics\MiddleEnd\Interface\SHRenderTarget.h" />
|
||||||
|
<ClInclude Include="src\Graphics\MiddleEnd\PerFrame\SHPerFrameData.h" />
|
||||||
|
<ClInclude Include="src\Graphics\MiddleEnd\PerFrame\SHRenderContext.h" />
|
||||||
|
<ClInclude Include="src\Graphics\MiddleEnd\Shaders\SHShaderModuleLibrary.h" />
|
||||||
|
<ClInclude Include="src\Graphics\MiddleEnd\Shaders\SHShaderSourceLibrary.h" />
|
||||||
|
<ClInclude Include="src\Graphics\MiddleEnd\Shaders\SHShaderType.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Pipeline\SHPipelineLayoutParams.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Pipeline\SHPipelineState.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Pipeline\SHPipelineType.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Pipeline\SHPushConstantInterface.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Pipeline\SHVkPipeline.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Pipeline\SHVkPipelineLayout.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Queues\SHVkQueue.h" />
|
||||||
|
<ClInclude Include="src\Graphics\RenderGraph\SHRenderGraph.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Renderpass\SHVkAttachDescGen.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Renderpass\SHVkAttachment.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Renderpass\SHVkRenderpass.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Renderpass\SHVkSubpassDescription.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Renderpass\SHVkSubpassParams.h" />
|
||||||
|
<ClInclude Include="src\Graphics\SHVkUtil.h" />
|
||||||
|
<ClInclude Include="src\Graphics\SHVulkanDefines.h" />
|
||||||
|
<ClInclude Include="src\Graphics\SHVulkanIncludes.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Shaders\BlockInterface\SHShaderBlockInterface.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Shaders\SHShaderReflected.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Shaders\SHVkShaderModule.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Shaders\spirv-reflect\spirv_reflect.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Swapchain\SHSwapchainParams.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Swapchain\SHVkSwapchain.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Synchronization\SHVkFence.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Synchronization\SHVkSemaphore.h" />
|
||||||
|
<ClInclude Include="src\Graphics\VertexDescriptors\SHVertexAttribute.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Windowing\SHWindow.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Windowing\SHWindowMap.h" />
|
||||||
|
<ClInclude Include="src\Graphics\Windowing\Surface\SHVkSurface.h" />
|
||||||
|
<ClInclude Include="src\Math\SHMath.h" />
|
||||||
|
<ClInclude Include="src\Math\SHMathHelpers.h" />
|
||||||
|
<ClInclude Include="src\Math\SHMatrix.h" />
|
||||||
|
<ClInclude Include="src\Math\SHQuaternion.h" />
|
||||||
|
<ClInclude Include="src\Math\Vector\SHVec2.h" />
|
||||||
|
<ClInclude Include="src\Math\Vector\SHVec3.h" />
|
||||||
|
<ClInclude Include="src\Math\Vector\SHVec4.h" />
|
||||||
|
<ClInclude Include="src\Meta\SHIsDetected.h" />
|
||||||
|
<ClInclude Include="src\Resource\Handle.h" />
|
||||||
|
<ClInclude Include="src\Resource\ResourceLibrary.h" />
|
||||||
|
<ClInclude Include="src\Resource\SparseSet.h" />
|
||||||
<ClInclude Include="src\SHpch.h" />
|
<ClInclude Include="src\SHpch.h" />
|
||||||
|
<ClInclude Include="src\Scene\SHScene.h" />
|
||||||
|
<ClInclude Include="src\Scene\SHSceneManager.h" />
|
||||||
|
<ClInclude Include="src\Tools\SHException.h" />
|
||||||
|
<ClInclude Include="src\Tools\SHExceptionHandler.h" />
|
||||||
|
<ClInclude Include="src\Tools\SHLogger.h" />
|
||||||
|
<ClInclude Include="src\Tools\SHUtilities.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="src\Engine\ECS_Base\Components\SHComponent.cpp" />
|
||||||
|
<ClCompile Include="src\Engine\ECS_Base\Components\SHComponentGroup.cpp" />
|
||||||
|
<ClCompile Include="src\Engine\ECS_Base\Entity\SHEntity.cpp" />
|
||||||
|
<ClCompile Include="src\Engine\ECS_Base\System\SHComponentManager.cpp" />
|
||||||
|
<ClCompile Include="src\Engine\ECS_Base\System\SHEntityManager.cpp" />
|
||||||
|
<ClCompile Include="src\Engine\ECS_Base\System\SHSystemManager.cpp" />
|
||||||
<ClCompile Include="src\Engine\SHEngine.cpp" />
|
<ClCompile Include="src\Engine\SHEngine.cpp" />
|
||||||
<ClCompile Include="src\Filesystem\SHFileSystem.cpp" />
|
<ClCompile Include="src\Filesystem\SHFileSystem.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Buffers\SHVkBuffer.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Commands\SHVkCommandBuffer.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Commands\SHVkCommandPool.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Debugging\SHValidationLayersQuery.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Debugging\SHVkDebugMessenger.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Debugging\SHVulkanDebugUtil.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Descriptors\SHDescriptorPoolManager.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Descriptors\SHDescriptorPoolStorage.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Descriptors\SHVkDescriptorPool.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Descriptors\SHVkDescriptorSetGroup.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Descriptors\SHVkDescriptorSetLayout.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Devices\SHVkLogicalDevice.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Devices\SHVkPhysicalDevice.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Devices\SHVkPhysicalDeviceLibrary.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Framebuffer\SHVkFramebuffer.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Images\SHVkImage.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Images\SHVkImageView.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Instance\SHVkInstance.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\MiddleEnd\Interface\SHGraphicsSystem.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\MiddleEnd\Interface\SHRenderTarget.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\MiddleEnd\PerFrame\SHPerFrameData.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\MiddleEnd\PerFrame\SHRenderContext.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\MiddleEnd\Shaders\SHShaderModuleLibrary.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\MiddleEnd\Shaders\SHShaderSourceLibrary.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Pipeline\SHPipelineState.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Pipeline\SHPushConstantInterface.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Pipeline\SHVkPipeline.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Pipeline\SHVkPipelineLayout.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Queues\SHVkQueue.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\RenderGraph\SHRenderGraph.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Renderpass\SHVkAttachDescGen.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Renderpass\SHVkRenderpass.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Renderpass\SHVkSubpassParams.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\SHVkUtil.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\SHVulkanIncludes.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Shaders\BlockInterface\SHShaderBlockInterface.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Shaders\SHShaderReflected.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Shaders\SHVkShaderModule.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Shaders\spirv-reflect\spirv_reflect.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Swapchain\SHVkSwapchain.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Synchronization\SHVkFence.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Synchronization\SHVkSemaphore.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\VertexDescriptors\SHVertexAttribute.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Windowing\SHWIndowMap.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Windowing\SHWindow.cpp" />
|
||||||
|
<ClCompile Include="src\Graphics\Windowing\Surface\SHVkSurface.cpp" />
|
||||||
|
<ClCompile Include="src\Math\SHMathHelpers.cpp" />
|
||||||
|
<ClCompile Include="src\Math\SHMatrix.cpp" />
|
||||||
|
<ClCompile Include="src\Math\SHQuaternion.cpp" />
|
||||||
|
<ClCompile Include="src\Math\Vector\SHVec2.cpp" />
|
||||||
|
<ClCompile Include="src\Math\Vector\SHVec3.cpp" />
|
||||||
|
<ClCompile Include="src\Math\Vector\SHVec4.cpp" />
|
||||||
|
<ClCompile Include="src\Resource\ResourceLibrary.cpp" />
|
||||||
<ClCompile Include="src\SHpch.cpp">
|
<ClCompile Include="src\SHpch.cpp">
|
||||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Scene\SHSceneManager.cpp" />
|
||||||
|
<ClCompile Include="src\Tools\SHException.cpp" />
|
||||||
|
<ClCompile Include="src\Tools\SHExceptionHandler.cpp" />
|
||||||
|
<ClCompile Include="src\Tools\SHLogger.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Dependencies\yamlcpp\yaml-cpp.vcxproj">
|
<ProjectReference Include="..\Dependencies\yamlcpp\yaml-cpp.vcxproj">
|
||||||
|
|
|
@ -4,19 +4,578 @@
|
||||||
<Filter Include="Engine">
|
<Filter Include="Engine">
|
||||||
<UniqueIdentifier>{DBC7D3B0-C769-FE86-B024-12DB9C6585D7}</UniqueIdentifier>
|
<UniqueIdentifier>{DBC7D3B0-C769-FE86-B024-12DB9C6585D7}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="Engine\ECS_Base">
|
||||||
|
<UniqueIdentifier>{7FF59BF8-EB80-09BD-F491-8CB1609C65BD}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Engine\ECS_Base\Components">
|
||||||
|
<UniqueIdentifier>{340D0110-201D-ADE0-89D6-11FF75059C79}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Engine\ECS_Base\Entity">
|
||||||
|
<UniqueIdentifier>{EBFC8BDC-D7F6-B42E-C063-4B3FACFC1A9B}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Engine\ECS_Base\General">
|
||||||
|
<UniqueIdentifier>{6CD692F2-D80D-DB89-E117-3FAD4DCE0183}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Engine\ECS_Base\System">
|
||||||
|
<UniqueIdentifier>{B3E3FAFD-9FDD-2350-884A-BA6074E389BC}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Filesystem">
|
||||||
|
<UniqueIdentifier>{8A8E2B37-7646-6D84-DF4D-46E0CB240875}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Graphics">
|
||||||
|
<UniqueIdentifier>{1653CE33-0220-293F-2B39-17E717655ECD}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Graphics\Buffers">
|
||||||
|
<UniqueIdentifier>{92C817CE-7EC1-3620-A7F3-1BA5934B162C}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Graphics\Commands">
|
||||||
|
<UniqueIdentifier>{17C745C0-83DD-4356-CC54-CF7738AA14DE}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Graphics\Debugging">
|
||||||
|
<UniqueIdentifier>{51443AC7-3D28-FB1C-A688-F56F928BE59E}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Graphics\Descriptors">
|
||||||
|
<UniqueIdentifier>{573A6CF2-43C9-F5BB-ECE7-09B7D8550662}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Graphics\Devices">
|
||||||
|
<UniqueIdentifier>{08DBDC43-F4D3-FB95-1D06-E11A095EDBA1}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Graphics\Framebuffer">
|
||||||
|
<UniqueIdentifier>{4AD5CA42-3664-540C-DF82-6807CBF064B2}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Graphics\Images">
|
||||||
|
<UniqueIdentifier>{FB5EE099-67EA-4D5E-70FB-D052DC05AA5E}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Graphics\Instance">
|
||||||
|
<UniqueIdentifier>{BA26540B-263D-52A1-6FB4-DDC2DB092329}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Graphics\MiddleEnd">
|
||||||
|
<UniqueIdentifier>{4B204703-3704-0859-A064-02AC8C67F2DA}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Graphics\MiddleEnd\Interface">
|
||||||
|
<UniqueIdentifier>{EBA1D3FF-D75C-C3AB-8014-3CF66CAE0D3C}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Graphics\MiddleEnd\PerFrame">
|
||||||
|
<UniqueIdentifier>{8CDBA7C9-F8E8-D5AF-81CF-D19AEDDBA166}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Graphics\MiddleEnd\Shaders">
|
||||||
|
<UniqueIdentifier>{2460C057-1070-6C28-7929-D14665585BC1}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Graphics\Pipeline">
|
||||||
|
<UniqueIdentifier>{FBD334F8-67EA-328E-B061-BEAF1CB70316}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Graphics\Queues">
|
||||||
|
<UniqueIdentifier>{1DD51CAD-8960-8A71-9271-0D66FE7BE671}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Graphics\RenderGraph">
|
||||||
|
<UniqueIdentifier>{57DAB30C-4369-3DD6-EC87-51D1D8F54D7C}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Graphics\Renderpass">
|
||||||
|
<UniqueIdentifier>{9C0DAFD9-086F-8CE7-91DC-D299FD3CC3A6}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Graphics\Shaders">
|
||||||
|
<UniqueIdentifier>{EF2D07CC-DB26-261E-0459-0BA3F0B0052A}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Graphics\Shaders\BlockInterface">
|
||||||
|
<UniqueIdentifier>{3AEF06DD-A6D2-151D-AFD5-43591B38DC6D}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Graphics\Shaders\spirv-reflect">
|
||||||
|
<UniqueIdentifier>{245F5AB0-1085-2417-F9CA-A9E2E58F49E3}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Graphics\Swapchain">
|
||||||
|
<UniqueIdentifier>{03DB39DE-EFBE-FA33-581F-F5864422E5B5}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Graphics\Synchronization">
|
||||||
|
<UniqueIdentifier>{576DF841-4392-47C2-6CDD-2C52586146E0}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Graphics\VertexDescriptors">
|
||||||
|
<UniqueIdentifier>{75F29FE5-6102-4CB6-CABB-B0D4B6EA3A4F}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Graphics\Windowing">
|
||||||
|
<UniqueIdentifier>{5BAB2A92-478F-EBE7-B0EF-E53A9CF2D569}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Graphics\Windowing\Surface">
|
||||||
|
<UniqueIdentifier>{B3B14D12-9FC1-F9E2-087B-5E01F4A9E87B}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Math">
|
||||||
|
<UniqueIdentifier>{AFF4887C-9B2B-8A0D-4418-7010302E060F}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Math\Vector">
|
||||||
|
<UniqueIdentifier>{F1B75745-5D6D-D03A-E661-CA115216C73E}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Meta">
|
||||||
|
<UniqueIdentifier>{AC05897C-983C-8A0D-4129-70102D3F060F}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Resource">
|
||||||
|
<UniqueIdentifier>{ED6CDF9B-D939-3AA7-0253-284FEE7E6F35}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Scene">
|
||||||
|
<UniqueIdentifier>{B3F7140E-1F0C-3DBF-E88D-E01E546139F0}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Tools">
|
||||||
|
<UniqueIdentifier>{16CF2D0E-82E3-55BF-4B65-F91EB73852F0}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="src\Engine\ECS_Base\Components\SHComponent.h">
|
||||||
|
<Filter>Engine\ECS_Base\Components</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Engine\ECS_Base\Components\SHComponentGroup.h">
|
||||||
|
<Filter>Engine\ECS_Base\Components</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Engine\ECS_Base\Entity\SHEntity.h">
|
||||||
|
<Filter>Engine\ECS_Base\Entity</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Engine\ECS_Base\General\SHFamily.h">
|
||||||
|
<Filter>Engine\ECS_Base\General</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Engine\ECS_Base\General\SHHandleGenerator.h">
|
||||||
|
<Filter>Engine\ECS_Base\General</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Engine\ECS_Base\General\SHSparseBase.h">
|
||||||
|
<Filter>Engine\ECS_Base\General</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Engine\ECS_Base\General\SHSparseSet.h">
|
||||||
|
<Filter>Engine\ECS_Base\General</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Engine\ECS_Base\General\SHSparseSetContainer.h">
|
||||||
|
<Filter>Engine\ECS_Base\General</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Engine\ECS_Base\SHECSMacros.h">
|
||||||
|
<Filter>Engine\ECS_Base</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Engine\ECS_Base\System\SHComponentManager.h">
|
||||||
|
<Filter>Engine\ECS_Base\System</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Engine\ECS_Base\System\SHEntityManager.h">
|
||||||
|
<Filter>Engine\ECS_Base\System</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Engine\ECS_Base\System\SHSystem.h">
|
||||||
|
<Filter>Engine\ECS_Base\System</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Engine\ECS_Base\System\SHSystemManager.h">
|
||||||
|
<Filter>Engine\ECS_Base\System</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="src\Engine\SHEngine.h">
|
<ClInclude Include="src\Engine\SHEngine.h">
|
||||||
<Filter>Engine</Filter>
|
<Filter>Engine</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Filesystem\SHFileSystem.h">
|
||||||
|
<Filter>Filesystem</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Buffers\SHVkBuffer.h">
|
||||||
|
<Filter>Graphics\Buffers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Commands\SHCommandPoolResetMode.h">
|
||||||
|
<Filter>Graphics\Commands</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Commands\SHVkCommandBuffer.h">
|
||||||
|
<Filter>Graphics\Commands</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Commands\SHVkCommandPool.h">
|
||||||
|
<Filter>Graphics\Commands</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Debugging\SHValidationLayersQuery.h">
|
||||||
|
<Filter>Graphics\Debugging</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Debugging\SHVkDebugMessenger.h">
|
||||||
|
<Filter>Graphics\Debugging</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Debugging\SHVulkanDebugUtil.h">
|
||||||
|
<Filter>Graphics\Debugging</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Descriptors\SHDescriptorPoolManager.h">
|
||||||
|
<Filter>Graphics\Descriptors</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Descriptors\SHDescriptorPoolStorage.h">
|
||||||
|
<Filter>Graphics\Descriptors</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Descriptors\SHVkDescriptorPool.h">
|
||||||
|
<Filter>Graphics\Descriptors</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Descriptors\SHVkDescriptorSetGroup.h">
|
||||||
|
<Filter>Graphics\Descriptors</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Descriptors\SHVkDescriptorSetLayout.h">
|
||||||
|
<Filter>Graphics\Descriptors</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Devices\SHVkLogicalDevice.h">
|
||||||
|
<Filter>Graphics\Devices</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Devices\SHVkPhysicalDevice.h">
|
||||||
|
<Filter>Graphics\Devices</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Devices\SHVkPhysicalDeviceLibrary.h">
|
||||||
|
<Filter>Graphics\Devices</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Framebuffer\SHVkFramebuffer.h">
|
||||||
|
<Filter>Graphics\Framebuffer</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Images\SHImageViewDetails.h">
|
||||||
|
<Filter>Graphics\Images</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Images\SHVkImage.h">
|
||||||
|
<Filter>Graphics\Images</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Images\SHVkImageView.h">
|
||||||
|
<Filter>Graphics\Images</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Instance\SHVkInstance.h">
|
||||||
|
<Filter>Graphics\Instance</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\MiddleEnd\Interface\SHGraphicsSystem.h">
|
||||||
|
<Filter>Graphics\MiddleEnd\Interface</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\MiddleEnd\Interface\SHRenderTarget.h">
|
||||||
|
<Filter>Graphics\MiddleEnd\Interface</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\MiddleEnd\PerFrame\SHPerFrameData.h">
|
||||||
|
<Filter>Graphics\MiddleEnd\PerFrame</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\MiddleEnd\PerFrame\SHRenderContext.h">
|
||||||
|
<Filter>Graphics\MiddleEnd\PerFrame</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\MiddleEnd\Shaders\SHShaderModuleLibrary.h">
|
||||||
|
<Filter>Graphics\MiddleEnd\Shaders</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\MiddleEnd\Shaders\SHShaderSourceLibrary.h">
|
||||||
|
<Filter>Graphics\MiddleEnd\Shaders</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\MiddleEnd\Shaders\SHShaderType.h">
|
||||||
|
<Filter>Graphics\MiddleEnd\Shaders</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Pipeline\SHPipelineLayoutParams.h">
|
||||||
|
<Filter>Graphics\Pipeline</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Pipeline\SHPipelineState.h">
|
||||||
|
<Filter>Graphics\Pipeline</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Pipeline\SHPipelineType.h">
|
||||||
|
<Filter>Graphics\Pipeline</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Pipeline\SHPushConstantInterface.h">
|
||||||
|
<Filter>Graphics\Pipeline</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Pipeline\SHVkPipeline.h">
|
||||||
|
<Filter>Graphics\Pipeline</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Pipeline\SHVkPipelineLayout.h">
|
||||||
|
<Filter>Graphics\Pipeline</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Queues\SHVkQueue.h">
|
||||||
|
<Filter>Graphics\Queues</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\RenderGraph\SHRenderGraph.h">
|
||||||
|
<Filter>Graphics\RenderGraph</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Renderpass\SHVkAttachDescGen.h">
|
||||||
|
<Filter>Graphics\Renderpass</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Renderpass\SHVkAttachment.h">
|
||||||
|
<Filter>Graphics\Renderpass</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Renderpass\SHVkRenderpass.h">
|
||||||
|
<Filter>Graphics\Renderpass</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Renderpass\SHVkSubpassDescription.h">
|
||||||
|
<Filter>Graphics\Renderpass</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Renderpass\SHVkSubpassParams.h">
|
||||||
|
<Filter>Graphics\Renderpass</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\SHVkUtil.h">
|
||||||
|
<Filter>Graphics</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\SHVulkanDefines.h">
|
||||||
|
<Filter>Graphics</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\SHVulkanIncludes.h">
|
||||||
|
<Filter>Graphics</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Shaders\BlockInterface\SHShaderBlockInterface.h">
|
||||||
|
<Filter>Graphics\Shaders\BlockInterface</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Shaders\SHShaderReflected.h">
|
||||||
|
<Filter>Graphics\Shaders</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Shaders\SHVkShaderModule.h">
|
||||||
|
<Filter>Graphics\Shaders</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Shaders\spirv-reflect\spirv_reflect.h">
|
||||||
|
<Filter>Graphics\Shaders\spirv-reflect</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Swapchain\SHSwapchainParams.h">
|
||||||
|
<Filter>Graphics\Swapchain</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Swapchain\SHVkSwapchain.h">
|
||||||
|
<Filter>Graphics\Swapchain</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Synchronization\SHVkFence.h">
|
||||||
|
<Filter>Graphics\Synchronization</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Synchronization\SHVkSemaphore.h">
|
||||||
|
<Filter>Graphics\Synchronization</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\VertexDescriptors\SHVertexAttribute.h">
|
||||||
|
<Filter>Graphics\VertexDescriptors</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Windowing\SHWindow.h">
|
||||||
|
<Filter>Graphics\Windowing</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Windowing\SHWindowMap.h">
|
||||||
|
<Filter>Graphics\Windowing</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Graphics\Windowing\Surface\SHVkSurface.h">
|
||||||
|
<Filter>Graphics\Windowing\Surface</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Math\SHMath.h">
|
||||||
|
<Filter>Math</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Math\SHMathHelpers.h">
|
||||||
|
<Filter>Math</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Math\SHMatrix.h">
|
||||||
|
<Filter>Math</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Math\SHQuaternion.h">
|
||||||
|
<Filter>Math</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Math\Vector\SHVec2.h">
|
||||||
|
<Filter>Math\Vector</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Math\Vector\SHVec3.h">
|
||||||
|
<Filter>Math\Vector</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Math\Vector\SHVec4.h">
|
||||||
|
<Filter>Math\Vector</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Meta\SHIsDetected.h">
|
||||||
|
<Filter>Meta</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Resource\Handle.h">
|
||||||
|
<Filter>Resource</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Resource\ResourceLibrary.h">
|
||||||
|
<Filter>Resource</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Resource\SparseSet.h">
|
||||||
|
<Filter>Resource</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="src\SHpch.h" />
|
<ClInclude Include="src\SHpch.h" />
|
||||||
<ClInclude Include="src\Filesystem\SHFileSystem.h" />
|
<ClInclude Include="src\Scene\SHScene.h">
|
||||||
|
<Filter>Scene</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Scene\SHSceneManager.h">
|
||||||
|
<Filter>Scene</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Tools\SHException.h">
|
||||||
|
<Filter>Tools</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Tools\SHExceptionHandler.h">
|
||||||
|
<Filter>Tools</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Tools\SHLogger.h">
|
||||||
|
<Filter>Tools</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Tools\SHUtilities.h">
|
||||||
|
<Filter>Tools</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="src\Engine\ECS_Base\Components\SHComponent.cpp">
|
||||||
|
<Filter>Engine\ECS_Base\Components</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Engine\ECS_Base\Components\SHComponentGroup.cpp">
|
||||||
|
<Filter>Engine\ECS_Base\Components</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Engine\ECS_Base\Entity\SHEntity.cpp">
|
||||||
|
<Filter>Engine\ECS_Base\Entity</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Engine\ECS_Base\System\SHComponentManager.cpp">
|
||||||
|
<Filter>Engine\ECS_Base\System</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Engine\ECS_Base\System\SHEntityManager.cpp">
|
||||||
|
<Filter>Engine\ECS_Base\System</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Engine\ECS_Base\System\SHSystemManager.cpp">
|
||||||
|
<Filter>Engine\ECS_Base\System</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="src\Engine\SHEngine.cpp">
|
<ClCompile Include="src\Engine\SHEngine.cpp">
|
||||||
<Filter>Engine</Filter>
|
<Filter>Engine</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Filesystem\SHFileSystem.cpp">
|
||||||
|
<Filter>Filesystem</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Buffers\SHVkBuffer.cpp">
|
||||||
|
<Filter>Graphics\Buffers</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Commands\SHVkCommandBuffer.cpp">
|
||||||
|
<Filter>Graphics\Commands</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Commands\SHVkCommandPool.cpp">
|
||||||
|
<Filter>Graphics\Commands</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Debugging\SHValidationLayersQuery.cpp">
|
||||||
|
<Filter>Graphics\Debugging</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Debugging\SHVkDebugMessenger.cpp">
|
||||||
|
<Filter>Graphics\Debugging</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Debugging\SHVulkanDebugUtil.cpp">
|
||||||
|
<Filter>Graphics\Debugging</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Descriptors\SHDescriptorPoolManager.cpp">
|
||||||
|
<Filter>Graphics\Descriptors</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Descriptors\SHDescriptorPoolStorage.cpp">
|
||||||
|
<Filter>Graphics\Descriptors</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Descriptors\SHVkDescriptorPool.cpp">
|
||||||
|
<Filter>Graphics\Descriptors</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Descriptors\SHVkDescriptorSetGroup.cpp">
|
||||||
|
<Filter>Graphics\Descriptors</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Descriptors\SHVkDescriptorSetLayout.cpp">
|
||||||
|
<Filter>Graphics\Descriptors</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Devices\SHVkLogicalDevice.cpp">
|
||||||
|
<Filter>Graphics\Devices</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Devices\SHVkPhysicalDevice.cpp">
|
||||||
|
<Filter>Graphics\Devices</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Devices\SHVkPhysicalDeviceLibrary.cpp">
|
||||||
|
<Filter>Graphics\Devices</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Framebuffer\SHVkFramebuffer.cpp">
|
||||||
|
<Filter>Graphics\Framebuffer</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Images\SHVkImage.cpp">
|
||||||
|
<Filter>Graphics\Images</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Images\SHVkImageView.cpp">
|
||||||
|
<Filter>Graphics\Images</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Instance\SHVkInstance.cpp">
|
||||||
|
<Filter>Graphics\Instance</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\MiddleEnd\Interface\SHGraphicsSystem.cpp">
|
||||||
|
<Filter>Graphics\MiddleEnd\Interface</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\MiddleEnd\Interface\SHRenderTarget.cpp">
|
||||||
|
<Filter>Graphics\MiddleEnd\Interface</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\MiddleEnd\PerFrame\SHPerFrameData.cpp">
|
||||||
|
<Filter>Graphics\MiddleEnd\PerFrame</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\MiddleEnd\PerFrame\SHRenderContext.cpp">
|
||||||
|
<Filter>Graphics\MiddleEnd\PerFrame</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\MiddleEnd\Shaders\SHShaderModuleLibrary.cpp">
|
||||||
|
<Filter>Graphics\MiddleEnd\Shaders</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\MiddleEnd\Shaders\SHShaderSourceLibrary.cpp">
|
||||||
|
<Filter>Graphics\MiddleEnd\Shaders</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Pipeline\SHPipelineState.cpp">
|
||||||
|
<Filter>Graphics\Pipeline</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Pipeline\SHPushConstantInterface.cpp">
|
||||||
|
<Filter>Graphics\Pipeline</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Pipeline\SHVkPipeline.cpp">
|
||||||
|
<Filter>Graphics\Pipeline</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Pipeline\SHVkPipelineLayout.cpp">
|
||||||
|
<Filter>Graphics\Pipeline</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Queues\SHVkQueue.cpp">
|
||||||
|
<Filter>Graphics\Queues</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\RenderGraph\SHRenderGraph.cpp">
|
||||||
|
<Filter>Graphics\RenderGraph</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Renderpass\SHVkAttachDescGen.cpp">
|
||||||
|
<Filter>Graphics\Renderpass</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Renderpass\SHVkRenderpass.cpp">
|
||||||
|
<Filter>Graphics\Renderpass</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Renderpass\SHVkSubpassParams.cpp">
|
||||||
|
<Filter>Graphics\Renderpass</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\SHVkUtil.cpp">
|
||||||
|
<Filter>Graphics</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\SHVulkanIncludes.cpp">
|
||||||
|
<Filter>Graphics</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Shaders\BlockInterface\SHShaderBlockInterface.cpp">
|
||||||
|
<Filter>Graphics\Shaders\BlockInterface</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Shaders\SHShaderReflected.cpp">
|
||||||
|
<Filter>Graphics\Shaders</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Shaders\SHVkShaderModule.cpp">
|
||||||
|
<Filter>Graphics\Shaders</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Shaders\spirv-reflect\spirv_reflect.cpp">
|
||||||
|
<Filter>Graphics\Shaders\spirv-reflect</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Swapchain\SHVkSwapchain.cpp">
|
||||||
|
<Filter>Graphics\Swapchain</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Synchronization\SHVkFence.cpp">
|
||||||
|
<Filter>Graphics\Synchronization</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Synchronization\SHVkSemaphore.cpp">
|
||||||
|
<Filter>Graphics\Synchronization</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\VertexDescriptors\SHVertexAttribute.cpp">
|
||||||
|
<Filter>Graphics\VertexDescriptors</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Windowing\SHWIndowMap.cpp">
|
||||||
|
<Filter>Graphics\Windowing</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Windowing\SHWindow.cpp">
|
||||||
|
<Filter>Graphics\Windowing</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Graphics\Windowing\Surface\SHVkSurface.cpp">
|
||||||
|
<Filter>Graphics\Windowing\Surface</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Math\SHMathHelpers.cpp">
|
||||||
|
<Filter>Math</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Math\SHMatrix.cpp">
|
||||||
|
<Filter>Math</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Math\SHQuaternion.cpp">
|
||||||
|
<Filter>Math</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Math\Vector\SHVec2.cpp">
|
||||||
|
<Filter>Math\Vector</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Math\Vector\SHVec3.cpp">
|
||||||
|
<Filter>Math\Vector</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Math\Vector\SHVec4.cpp">
|
||||||
|
<Filter>Math\Vector</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Resource\ResourceLibrary.cpp">
|
||||||
|
<Filter>Resource</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="src\SHpch.cpp" />
|
<ClCompile Include="src\SHpch.cpp" />
|
||||||
<ClCompile Include="src\Filesystem\SHFileSystem.cpp" />
|
<ClCompile Include="src\Scene\SHSceneManager.cpp">
|
||||||
|
<Filter>Scene</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Tools\SHException.cpp">
|
||||||
|
<Filter>Tools</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Tools\SHExceptionHandler.cpp">
|
||||||
|
<Filter>Tools</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Tools\SHLogger.cpp">
|
||||||
|
<Filter>Tools</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -34,7 +34,8 @@ project "SHADE_Engine"
|
||||||
"%{IncludeDir.ktx}/include",
|
"%{IncludeDir.ktx}/include",
|
||||||
"%{IncludeDir.RTTR}/include",
|
"%{IncludeDir.RTTR}/include",
|
||||||
"%{IncludeDir.reactphysics3d}/include",
|
"%{IncludeDir.reactphysics3d}/include",
|
||||||
"%{IncludeDir.VULKAN}/include"
|
"%{IncludeDir.VULKAN}/include",
|
||||||
|
"%{IncludeDir.VULKAN}/Source/SPIRV-Reflect"
|
||||||
}
|
}
|
||||||
|
|
||||||
libdirs
|
libdirs
|
||||||
|
@ -56,14 +57,16 @@ project "SHADE_Engine"
|
||||||
"reactphysics3d",
|
"reactphysics3d",
|
||||||
"imgui",
|
"imgui",
|
||||||
"spdlog",
|
"spdlog",
|
||||||
"vulkan-1.lib"
|
"vulkan-1.lib",
|
||||||
|
"shaderc_shared.lib"
|
||||||
}
|
}
|
||||||
|
|
||||||
defines
|
defines
|
||||||
{
|
{
|
||||||
"_LIB",
|
"_LIB",
|
||||||
"_GLFW_INCLUDE_NONE",
|
"_GLFW_INCLUDE_NONE",
|
||||||
"MSDFGEN_USE_CPP11"
|
"MSDFGEN_USE_CPP11",
|
||||||
|
"NOMINMAX"
|
||||||
}
|
}
|
||||||
|
|
||||||
flags
|
flags
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
#include "SHpch.h"
|
||||||
|
#include "SHComponent.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
SHComponent::~SHComponent()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,121 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \file SHComponent.h
|
||||||
|
* \author Daniel Chua Yee Chen
|
||||||
|
* \brief Declaration for the Component abstract base class.
|
||||||
|
*
|
||||||
|
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||||
|
or disclosure of this file or its contents without the prior written
|
||||||
|
consent of DigiPen Institute of Technology is prohibited.
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef SH_COMPONENT_H
|
||||||
|
#define SH_COMPONENT_H
|
||||||
|
|
||||||
|
#include "SHpch.h"
|
||||||
|
#include "../SHECSMacros.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
|
||||||
|
class SHComponentManager;
|
||||||
|
|
||||||
|
class SHComponent
|
||||||
|
{
|
||||||
|
friend SHComponentManager;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//The ID of the entity this component belongs to.
|
||||||
|
EntityID entityID;
|
||||||
|
//Whether this entity ID has been set once.
|
||||||
|
//This prevents the Set function from being able to change the entityID once it has been set
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief Construct a new SHComponent object
|
||||||
|
* Protected default constructor to make this an abstract base class.
|
||||||
|
***************************************************************************/
|
||||||
|
SHComponent()
|
||||||
|
:entityID(0),isActive(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SHComponent(SHComponent const& other)
|
||||||
|
:entityID(other.entityID), isActive(other.isActive)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
//Whether or not this component is active.
|
||||||
|
//Systems using this component should are responsible for checking the active state of the component before running their functionality.
|
||||||
|
bool isActive;
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Getter function for the entityID
|
||||||
|
* \return uint32_t
|
||||||
|
* The entityID that this component belongs to.
|
||||||
|
***************************************************************************/
|
||||||
|
uint32_t GetEID()const
|
||||||
|
{
|
||||||
|
return this->entityID;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief Destroy the SHComponent object
|
||||||
|
* Default destructor for Component Base class
|
||||||
|
***************************************************************************/
|
||||||
|
virtual ~SHComponent();
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* A function that is called when the entity changes its parent.
|
||||||
|
* This can remain empty if nothing has to be done before the parent changes.
|
||||||
|
* This does not change the component that the entity belongs to
|
||||||
|
* The old parent is not passed in here as the old parent might be the root node
|
||||||
|
* in which case there will be no parent.
|
||||||
|
* If needed, the old parent should be deduced using this entityID
|
||||||
|
* \param newParent
|
||||||
|
* EntityID of the new parent.
|
||||||
|
***************************************************************************/
|
||||||
|
virtual void ChangeParent(EntityID newParent)
|
||||||
|
{
|
||||||
|
(void)newParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* This is an overloaded function of Change parent when the entity
|
||||||
|
* changes its parent to the root node. (No parent)
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
virtual void ChangeParent()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
virtual void OnDestroy()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
virtual void OnCreate()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SHComponent& operator=(SHComponent const& other)
|
||||||
|
{
|
||||||
|
this->entityID = other.GetEID();
|
||||||
|
this->isActive = other.isActive;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,136 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \file SHComponent.h
|
||||||
|
* \author Daniel Chua Yee Chen
|
||||||
|
* \brief Implementation for the SHComponentGroup class.
|
||||||
|
* The Component Group aids the engine to sort the components to align
|
||||||
|
* different component type’s data that corresponds to a single entity
|
||||||
|
* in the same index. The component group also ensure that all components
|
||||||
|
* data belonging to the group is moved to the start of the dense array.
|
||||||
|
*
|
||||||
|
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||||
|
or disclosure of this file or its contents without the prior written
|
||||||
|
consent of DigiPen Institute of Technology is prohibited.
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#include "SHpch.h"
|
||||||
|
#include "SHComponentGroup.h"
|
||||||
|
#include "../System/SHComponentManager.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
SHComponentGroup::SHComponentGroup()
|
||||||
|
:ownershipType(OWNERSHIP_TYPE::FULL_OWNERSHIP)
|
||||||
|
{
|
||||||
|
componentTypeIDs.reserve(MAX_EID);
|
||||||
|
ownedComponentTypes.reserve(MAX_EID);
|
||||||
|
entityInGroup.reserve(MAX_EID);
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityIndex SHComponentGroup::size() noexcept
|
||||||
|
{
|
||||||
|
return (EntityIndex)entityInGroup.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHComponentGroup::IsEntityInGroup(EntityID entityID) noexcept
|
||||||
|
{
|
||||||
|
for (auto const& eid : entityInGroup)
|
||||||
|
{
|
||||||
|
if (entityID == eid)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHComponentGroup::RemoveEntity(EntityID entityID) noexcept
|
||||||
|
{
|
||||||
|
if (!IsEntityInGroup(entityID))
|
||||||
|
{
|
||||||
|
// This entity has not been added to the group. Ignore it.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//This entity is in the group.
|
||||||
|
//Move the placement of the components in all owned component types to the relevant position and remove it from the group.
|
||||||
|
for (auto const& ownedID : ownedComponentTypes)
|
||||||
|
{
|
||||||
|
if (SHComponentManager::ComponentCount_ID(ownedID) > 2)
|
||||||
|
{
|
||||||
|
// There are components that do not belong in the group. Need to swap to the last element
|
||||||
|
SHComponentManager::SwapInDenseByIndexHash_ID((EntityIndex)entityInGroup.size() - 1, entityID, ownedID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::vector<EntityID>::iterator it = entityInGroup.begin(); it != entityInGroup.end(); ++it)
|
||||||
|
{
|
||||||
|
if (*it == entityID)
|
||||||
|
{
|
||||||
|
entityInGroup.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHComponentGroup::Clear() noexcept
|
||||||
|
{
|
||||||
|
entityInGroup.clear();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHComponentGroup::AddComponentCheck(EntityID entityID, uint32_t componentTypeID) noexcept
|
||||||
|
{
|
||||||
|
if (IsEntityInGroup(entityID))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//uint32_t componentID = SHFamilyID<SHComponent>::template GetID<T>();
|
||||||
|
|
||||||
|
//Loops to check if this is one of the owned component type
|
||||||
|
for (auto const& id : componentTypeIDs)
|
||||||
|
{
|
||||||
|
//found it
|
||||||
|
if (id == componentTypeID)
|
||||||
|
{
|
||||||
|
for (auto const& typeID : componentTypeIDs)
|
||||||
|
{
|
||||||
|
if (typeID != componentTypeID && !SHComponentManager::HasComponent_ID(entityID, typeID))
|
||||||
|
{
|
||||||
|
//This entity does not contain all other component types in this group so we don't do anything yet
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//This entity contains all required component types. Add to group and swap in dense
|
||||||
|
//auto& dense = SHComponentManager::GetDense<T>();
|
||||||
|
|
||||||
|
//Loop through all the owned component and sort them.
|
||||||
|
for (auto const& ownedID : ownedComponentTypes)
|
||||||
|
{
|
||||||
|
if (SHComponentManager::ComponentCount_ID(ownedID) > entityInGroup.size() + 1)
|
||||||
|
{
|
||||||
|
// There are components that do not belong in the group. Need to swap to the last element
|
||||||
|
SHComponentManager::SwapInDenseByIndexHash_ID((EntityIndex)entityInGroup.size(), entityID, ownedID);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If dense.size() == entityInGroup.size() + 1.
|
||||||
|
// There is no component that is not in this group for this component type.
|
||||||
|
// Hence no sorting required.
|
||||||
|
|
||||||
|
//Add this entityID to group
|
||||||
|
entityInGroup.push_back(entityID);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//This component type is not in this group.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,185 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \file SHComponent.h
|
||||||
|
* \author Daniel Chua Yee Chen
|
||||||
|
* \brief Definition for the SHComponentGroup class.
|
||||||
|
* The Component Group aids the engine to sort the components to align
|
||||||
|
* different component type’s data that corresponds to a single entity
|
||||||
|
* in the same index. The component group also ensure that all components
|
||||||
|
* data belonging to the group is moved to the start of the dense array.
|
||||||
|
*
|
||||||
|
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||||
|
or disclosure of this file or its contents without the prior written
|
||||||
|
consent of DigiPen Institute of Technology is prohibited.
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef SH_COMPONENT_GROUP
|
||||||
|
#define SH_COMPONENT_GROUP
|
||||||
|
|
||||||
|
#include "../SHECSMacros.h"
|
||||||
|
#include "../General/SHFamily.h"
|
||||||
|
#include "SHComponent.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
enum class OWNERSHIP_TYPE
|
||||||
|
{
|
||||||
|
FULL_OWNERSHIP = 0,
|
||||||
|
PARTIAL_OWNERSHIP,
|
||||||
|
NON_OWNERSHIP,
|
||||||
|
OWNERSHIP_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//template<OWNERSHIP_TYPE ownership>
|
||||||
|
class SHComponentGroup
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
//This vector store the Entity IDs of all entity that belongs to this group.
|
||||||
|
std::vector<EntityID> entityInGroup;
|
||||||
|
|
||||||
|
|
||||||
|
//template<>
|
||||||
|
//bool CheckAddComponent();
|
||||||
|
SHComponentGroup();
|
||||||
|
~SHComponentGroup() = default;
|
||||||
|
|
||||||
|
//friends SHComponentManager to allow ECSCore to create componentgroups
|
||||||
|
friend class SHComponentManager;
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Get the number of entity in the group.
|
||||||
|
* \return
|
||||||
|
* Number of entity in the group.
|
||||||
|
***************************************************************************/
|
||||||
|
EntityIndex size() noexcept;
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Check if a entity is already in the group.
|
||||||
|
* \param entityID
|
||||||
|
* The entity ID of the entity
|
||||||
|
* \return
|
||||||
|
* true if the entity belongs to the group
|
||||||
|
***************************************************************************/
|
||||||
|
bool IsEntityInGroup(EntityID entityID) noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Checks whether the entity has fulfilled the requirements to be added into
|
||||||
|
* the Component Group after adding a specified Component Type.
|
||||||
|
* @tparam T
|
||||||
|
* Component type to be added
|
||||||
|
* \param entityID
|
||||||
|
* EntityID of the entity to be added
|
||||||
|
***************************************************************************/
|
||||||
|
bool AddComponentCheck(EntityID entityID, uint32_t componentTypeID) noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Check if the Component type is in the component group and if the entity is in the group
|
||||||
|
* Remove it from the group if found.
|
||||||
|
* This does not handle the removal from the dense array in the sparse set.
|
||||||
|
* @tparam T
|
||||||
|
* Component type to be removed
|
||||||
|
* \param entityID
|
||||||
|
* EntityID of the entity
|
||||||
|
***************************************************************************/
|
||||||
|
template<typename T>
|
||||||
|
std::enable_if_t<std::is_base_of_v<SHComponent, T>, bool> RemoveComponentCheck(EntityID entityID) noexcept
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!IsEntityInGroup(entityID))
|
||||||
|
{
|
||||||
|
// This entity has not been added to the group. Ignore it.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool typeFound = false;
|
||||||
|
uint32_t componentID = SHFamilyID<SHComponent>::template GetID<T>();
|
||||||
|
for (auto const& id : componentTypeIDs)
|
||||||
|
{
|
||||||
|
if (id == componentID)
|
||||||
|
{
|
||||||
|
typeFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (typeFound == false)
|
||||||
|
{
|
||||||
|
return false; //This type is not something this group needs to care about.
|
||||||
|
}
|
||||||
|
|
||||||
|
//This entity is in the group.
|
||||||
|
//Move the placement of the components in all owned component types to the relevant position and remove it from the group.
|
||||||
|
for (auto const& ownedID : ownedComponentTypes)
|
||||||
|
{
|
||||||
|
if (SHComponentManager::ComponentCount_ID(ownedID) > entityInGroup.size() + 1)
|
||||||
|
{
|
||||||
|
// There are components that do not belong in the group. Need to swap to the last element
|
||||||
|
SHComponentManager::SwapInDenseByIndexHash_ID((EntityIndex)entityInGroup.size() - 1, entityID, ownedID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::vector<EntityID>::iterator it = entityInGroup.begin(); it != entityInGroup.end(); ++it)
|
||||||
|
{
|
||||||
|
if (*it == entityID)
|
||||||
|
{
|
||||||
|
entityInGroup.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Checks if this entity is in the Component Group and remove it if found.
|
||||||
|
* This does not handle the removal from the dense array in the sparse set.
|
||||||
|
* \param entityID
|
||||||
|
* EntityID of the entity
|
||||||
|
***************************************************************************/
|
||||||
|
bool RemoveEntity(EntityID entityID) noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Resets the Component Group by clearing all entity in group.
|
||||||
|
* This will not change the Component Types that belong in the group but
|
||||||
|
* only clear the entity that belongs to the group.
|
||||||
|
* This is used for scene transition where all entities are cleared.
|
||||||
|
***************************************************************************/
|
||||||
|
void Clear() noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
OWNERSHIP_TYPE ownershipType;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
//This vector stores all IDs of all the component type that belongs to this group.
|
||||||
|
//This will be assigned when the group gets created and used by the group themselves when they for add/remove components.
|
||||||
|
std::vector<uint32_t> componentTypeIDs;
|
||||||
|
|
||||||
|
//This vector stores the IDs of all the component type that this group owns.
|
||||||
|
//Each component type can only be owned by one group.
|
||||||
|
std::vector<uint32_t> ownedComponentTypes;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \file SHEntity.cpp
|
||||||
|
* \author Daniel Chua Yee Chen
|
||||||
|
* \brief Definition of function used in SHEntity class.
|
||||||
|
*
|
||||||
|
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||||
|
or disclosure of this file or its contents without the prior written
|
||||||
|
consent of DigiPen Institute of Technology is prohibited.
|
||||||
|
*********************************************************************/
|
||||||
|
#include "SHpch.h"
|
||||||
|
#include "SHEntity.h"
|
||||||
|
#include "../System/SHEntityManager.h"
|
||||||
|
//#include "Scene/SHSceneGraph.h"
|
||||||
|
#include "../System/SHComponentManager.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
|
||||||
|
SHEntity::SHEntity()
|
||||||
|
:entityID(),isActive(true)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SHEntity::~SHEntity()
|
||||||
|
{
|
||||||
|
|
||||||
|
//SHEntityManager::RemoveEntity(this->entityID);
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityID SHEntity::GetEID() noexcept
|
||||||
|
{
|
||||||
|
return this->entityID;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHEntity::SetActive(bool active) noexcept
|
||||||
|
{
|
||||||
|
isActive = active;
|
||||||
|
SHComponentManager::SetActive(entityID, active);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void SHEntity::SetParent(SHEntity* newParent) noexcept
|
||||||
|
{
|
||||||
|
(void)newParent;
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHEntity::SetParent(EntityID newParentID) noexcept
|
||||||
|
{
|
||||||
|
(void)newParentID;
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
SHEntity* SHEntity::GetParent() noexcept
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<SHEntity*>const& SHEntity::GetChildren() noexcept
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
return std::vector<SHEntity*>{};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<EntityID>const& SHEntity::GetChildrenID() noexcept
|
||||||
|
{
|
||||||
|
return std::vector<EntityID>{};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,163 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \file SHEntity.h
|
||||||
|
* \author Daniel Chua Yee Chen
|
||||||
|
* \brief Declaration for the Entity abstract base class.
|
||||||
|
*
|
||||||
|
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||||
|
or disclosure of this file or its contents without the prior written
|
||||||
|
consent of DigiPen Institute of Technology is prohibited.
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#ifndef SH_ENTITY_H
|
||||||
|
#define SH_ENTITY_H
|
||||||
|
|
||||||
|
#include "../SHECSMacros.h"
|
||||||
|
#include "../Components/SHComponent.h"
|
||||||
|
#include "../System/SHComponentManager.h"
|
||||||
|
//#include "../../Scene/SHSceneNode.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
class SHComponentManager;
|
||||||
|
class SHEntityManager;
|
||||||
|
|
||||||
|
class SHEntity
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* Friends with SHEntityManger.
|
||||||
|
* This allows SHEntityManager to generate a unique entityID for the entity
|
||||||
|
* upon creation.
|
||||||
|
* .
|
||||||
|
***************************************************************************/
|
||||||
|
friend SHEntityManager;
|
||||||
|
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief Construct a new SHEntity object
|
||||||
|
* Default constructor for the Entity Object.
|
||||||
|
* Entities are given their entityID here.
|
||||||
|
***************************************************************************/
|
||||||
|
SHEntity();
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief Destroy the SHEntity object
|
||||||
|
* Default destructor for the Entity object.
|
||||||
|
* Removes the entityID and queue it for recycling.
|
||||||
|
***************************************************************************/
|
||||||
|
virtual ~SHEntity();
|
||||||
|
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief Get the Component object
|
||||||
|
* A templated GetComponent_s function that calls GetComponent_s from SHComponentManager.
|
||||||
|
* This is for ease of use.
|
||||||
|
* @tparam T
|
||||||
|
* The type of the Component we are trying to get.
|
||||||
|
* \return
|
||||||
|
* A pointer to the Component we are trying to get.
|
||||||
|
* Returns nullptr if the entity does not have such Component.
|
||||||
|
***************************************************************************/
|
||||||
|
template<typename T>
|
||||||
|
std::enable_if_t<std::is_base_of_v<SHComponent, T>, T*> GetComponent() noexcept
|
||||||
|
{
|
||||||
|
|
||||||
|
return SHComponentManager::GetComponent_s<T>(entityID);
|
||||||
|
//return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Getter function for the entityID
|
||||||
|
* \return uint32_t
|
||||||
|
* The entityID of this Entity object.
|
||||||
|
***************************************************************************/
|
||||||
|
EntityID GetEID() noexcept;
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief Set the Active object
|
||||||
|
* Sets the isActive of all Components in this entity.
|
||||||
|
* This is done through SHComponentManager and this function is for ease of use.
|
||||||
|
* If derived classes of Entity overloads this function, they are expected to
|
||||||
|
* call this function using SHEntity::SetActive(active) to change the active of
|
||||||
|
* all components
|
||||||
|
* \param active
|
||||||
|
* The active state to change all components in this entity.
|
||||||
|
***************************************************************************/
|
||||||
|
virtual void SetActive(bool active) noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Change the parent of the entity object in the scene graph.
|
||||||
|
* This command will be stored in a queue and only applied when
|
||||||
|
* SHSceneGraph::UpdateHierachy is called.
|
||||||
|
* \param newParent
|
||||||
|
* A pointer to the new parent entity.
|
||||||
|
* Pass a nullptr to attach this entity to the root node instead.
|
||||||
|
***************************************************************************/
|
||||||
|
void SetParent(SHEntity* newParent = nullptr) noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Change the parent of the entity object in the scene graphj.
|
||||||
|
* This command will be stored in a queue and only applied when
|
||||||
|
* SHSceneGraph::UpdateHierachy is called
|
||||||
|
* This is the overloaded version of the function that takes in a
|
||||||
|
* EntityID instead. This cannot be used to attach to the root node.
|
||||||
|
* \param newParentID
|
||||||
|
* The entityID of the new parent.
|
||||||
|
***************************************************************************/
|
||||||
|
void SetParent(EntityID newParentID) noexcept;
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Get a pointer to the parent entity.
|
||||||
|
* \return
|
||||||
|
* Returns a pointer to the parent entity.
|
||||||
|
* Returns a nullptr if the parent node is the root node.
|
||||||
|
***************************************************************************/
|
||||||
|
SHEntity* GetParent() noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Get a vector of SHEntity pointers of the children belonging to this entity.
|
||||||
|
* \return
|
||||||
|
* Return a vector of SHEntity pointers of the children belonging to this entity.
|
||||||
|
***************************************************************************/
|
||||||
|
std::vector<SHEntity*>const& GetChildren() noexcept;
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Get a vector of EntityID of the children belonging to this entity.
|
||||||
|
* \return
|
||||||
|
* return a vector of EntityID of the children belonging to this entity.
|
||||||
|
***************************************************************************/
|
||||||
|
std::vector<EntityID>const& GetChildrenID() noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
bool isActive;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
//The identifier of the entity.
|
||||||
|
//This is split into 2 x 16-bits that represents version and index respectively
|
||||||
|
//Index is used by the engine to index the entity.
|
||||||
|
//Version is used by the engine to recycle the index of the entity.
|
||||||
|
EntityID entityID;
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \file SHFamily.h
|
||||||
|
* \author Daniel Chua Yee Chen
|
||||||
|
* \brief Declaration for the SHFamily template class.
|
||||||
|
* This class is to create a unique identifier for each derived class type.
|
||||||
|
* Example: Each Component type (SHTransformComponent / SHRenderableComponent)
|
||||||
|
* will have a different identifier generated by this class.
|
||||||
|
*
|
||||||
|
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||||
|
or disclosure of this file or its contents without the prior written
|
||||||
|
consent of DigiPen Institute of Technology is prohibited.
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#ifndef SH_FAMILY_H
|
||||||
|
#define SH_FAMILY_H
|
||||||
|
|
||||||
|
#include "../SHECSMacros.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
template<typename BaseClass>
|
||||||
|
class SHFamilyID
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
//this is used to keep track of the new current ID to be assign to a new Derived class type.
|
||||||
|
static ComponentTypeID currentID;
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief Construct a new SHFamilyID object
|
||||||
|
* Private constructor.
|
||||||
|
* No objects of this type should be made.
|
||||||
|
* Only use the static functions of this class
|
||||||
|
***************************************************************************/
|
||||||
|
SHFamilyID()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief Destroy the SHFamilyID object
|
||||||
|
* Private destructor.
|
||||||
|
* No objects of this type should be made.
|
||||||
|
* Only use the static functions of this class
|
||||||
|
***************************************************************************/
|
||||||
|
virtual ~SHFamilyID()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Checks if this identifier is cuurrently in use / valid.
|
||||||
|
* \param id
|
||||||
|
* Identifier to check for.
|
||||||
|
* \return bool
|
||||||
|
* true if the identifier is currently in use.
|
||||||
|
* false if the identifier is not in use.
|
||||||
|
***************************************************************************/
|
||||||
|
static bool IsValidID(ComponentTypeID id) noexcept
|
||||||
|
{
|
||||||
|
return(id < currentID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Get the ID of a derived class type.
|
||||||
|
* Example of function call to this function should be:
|
||||||
|
* SHFamily<SHComponent>::GetID<SHTransformComponent>();
|
||||||
|
* @tparam DerivedClass
|
||||||
|
* The derived class type that we are trying to get the ID of.
|
||||||
|
***************************************************************************/
|
||||||
|
template<typename DerivedClass>
|
||||||
|
static ENABLE_IF_DERIVED(ComponentTypeID, BaseClass, DerivedClass) GetID() noexcept
|
||||||
|
{
|
||||||
|
//The first time a new derived class type call this get id, it will initialize id using the currentID from familyID class.
|
||||||
|
static ComponentTypeID id = currentID++;
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//initialize currentID as 0
|
||||||
|
template<typename BaseClass>
|
||||||
|
ComponentTypeID SHFamilyID<BaseClass>::currentID = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,305 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \file SHHandleGenerator.h
|
||||||
|
* \author Daniel Chua Yee Chen
|
||||||
|
*
|
||||||
|
* \brief Declaration for the SHHandleGenerator class.
|
||||||
|
* Generates a unique identifier/handle for objects.
|
||||||
|
* This is different from SHFamily which is meant to generate identifier for object types.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||||
|
or disclosure of this file or its contents without the prior written
|
||||||
|
consent of DigiPen Institute of Technology is prohibited.
|
||||||
|
*********************************************************************/
|
||||||
|
#ifndef SH_HANDLE_GENERATOR_H
|
||||||
|
#define SH_HANDLE_GENERATOR_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "../SHECSMacros.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/*********************************************************************
|
||||||
|
* \brief
|
||||||
|
* Generates a unique handle of HandleType type.
|
||||||
|
* The first half of the bits will be used for version. This is used for recyling the IDs.
|
||||||
|
* The second half of the bits will be used for the index, this is also used as its ID.
|
||||||
|
*
|
||||||
|
* HandleType should always be twice the size of IndexType
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
template <typename HandleType, typename IndexType>
|
||||||
|
class SHHandleGenerator
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
//List of all the handles in use. Handles that are deleted are still stored here.
|
||||||
|
std::vector<HandleType> handleList;
|
||||||
|
//The next handle to be used.
|
||||||
|
HandleType nextRecycle;
|
||||||
|
//The total number of handles that are currently deleted and waiting to be recycled.
|
||||||
|
HandleType recycleCounter;
|
||||||
|
|
||||||
|
//The Mask is variable is used to easily separate the version and index via bit masking (bitwise &).
|
||||||
|
|
||||||
|
|
||||||
|
//The index mask is used to identify the index.
|
||||||
|
//(1<<16) - 1. Shift 1 bit to the left 16 times and -1. This leaves the first 16 bits as 0 and the -1 makes the second 16 bits all 1.
|
||||||
|
static const HandleType indexMask = (1 << sizeof(IndexType) * 8) - 1;
|
||||||
|
|
||||||
|
//using the bitwise NOT, invert the index mask to get the version mask.
|
||||||
|
static const HandleType versionMask = ~indexMask;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief Construct a new SHHandleGenerator object
|
||||||
|
* default constructor for the HandleGenerator object.
|
||||||
|
***************************************************************************/
|
||||||
|
SHHandleGenerator()
|
||||||
|
:nextRecycle(0),recycleCounter(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief Destroy the SHHandleGenerator object
|
||||||
|
* Default destructor for the HandleGenerator object.
|
||||||
|
***************************************************************************/
|
||||||
|
~SHHandleGenerator() = default;
|
||||||
|
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Combines the 16-bit version and 16-bit index to make a 32-bit handle.
|
||||||
|
* \param verison
|
||||||
|
* The 16-bit version
|
||||||
|
* \param index
|
||||||
|
* The 16-bit index
|
||||||
|
* \return HandleType
|
||||||
|
* The resultant Handle
|
||||||
|
***************************************************************************/
|
||||||
|
static HandleType GetHandle(IndexType version, IndexType index) noexcept
|
||||||
|
{
|
||||||
|
return (version << sizeof(IndexType) * 8) | index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Gets the 16-bit version from the 32-bit handle
|
||||||
|
* \param handle
|
||||||
|
* The 32-bit handle
|
||||||
|
* \return IndexType
|
||||||
|
* The 16-bit version
|
||||||
|
***************************************************************************/
|
||||||
|
static IndexType GetVersion(HandleType handle) noexcept
|
||||||
|
{
|
||||||
|
return handle >> sizeof(IndexType) * 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Gets the 16-bit index from the 32-bit handle
|
||||||
|
* \param handle
|
||||||
|
* The 32-bit handle
|
||||||
|
* \return IndexType
|
||||||
|
* The 16-bit index
|
||||||
|
***************************************************************************/
|
||||||
|
static IndexType GetIndex(HandleType handle) noexcept
|
||||||
|
{
|
||||||
|
return handle & indexMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Checks if the current handle is still valid. This checks if the index
|
||||||
|
* of the handle is in use, then checks if the version of the current index
|
||||||
|
* matches the handle we are checking for.
|
||||||
|
* \param handle
|
||||||
|
* The handle to check for.
|
||||||
|
* \return bool
|
||||||
|
* True if the handle is still valid. False if the handle has been removed
|
||||||
|
* or not in use.
|
||||||
|
***************************************************************************/
|
||||||
|
bool IsValid(HandleType handle) noexcept
|
||||||
|
{
|
||||||
|
IndexType index = GetIndex(handle);
|
||||||
|
if (index >= (IndexType)handleList.size()) // handle is out of range of intialized index
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (handleList[index] == handle); // this will check if the current handle at that index has been removed.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Get the number of active handles.
|
||||||
|
* \return
|
||||||
|
* Number of active handles.
|
||||||
|
***************************************************************************/
|
||||||
|
IndexType GetActiveHandleCount() noexcept
|
||||||
|
{
|
||||||
|
return (IndexType)(handleList.size() - recycleCounter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Request the Generator for a new handle. This will provide recycled index
|
||||||
|
* if available
|
||||||
|
* \return HandleType
|
||||||
|
* The new handle.
|
||||||
|
***************************************************************************/
|
||||||
|
HandleType GetNewHandle() noexcept
|
||||||
|
{
|
||||||
|
HandleType result;
|
||||||
|
|
||||||
|
//Check if there is any index waiting to be recycled
|
||||||
|
if (recycleCounter == 0) // nothing to be recycled. Make a new one
|
||||||
|
{
|
||||||
|
result = GetHandle(0, (IndexType)handleList.size());
|
||||||
|
handleList.push_back(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
//There is a index waiting to be recycled.
|
||||||
|
result = nextRecycle;
|
||||||
|
IndexType index = GetIndex(nextRecycle);
|
||||||
|
//updates the next recycle.
|
||||||
|
nextRecycle = handleList[index];
|
||||||
|
handleList[index] = result;
|
||||||
|
--recycleCounter;
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Removes a handle and make it invalid and queue it for recycling.
|
||||||
|
* \param handle
|
||||||
|
* The handle to remove.
|
||||||
|
***************************************************************************/
|
||||||
|
void RemoveHandle(HandleType handle) noexcept
|
||||||
|
{
|
||||||
|
if (!IsValid(handle))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IndexType index = GetIndex(handle);
|
||||||
|
IndexType version = GetVersion(handle);
|
||||||
|
|
||||||
|
//set the handle at the current index to the next thing to be recycled.
|
||||||
|
handleList[index] = nextRecycle;
|
||||||
|
|
||||||
|
//set the next recycle to be the thing that was just deleted with its version incremented.
|
||||||
|
nextRecycle = GetHandle(version + 1, index);
|
||||||
|
++recycleCounter;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Clears all the handles in use and Resets the handle generation.
|
||||||
|
***************************************************************************/
|
||||||
|
void ClearAllHandles() noexcept
|
||||||
|
{
|
||||||
|
handleList.clear();
|
||||||
|
nextRecycle = 0;
|
||||||
|
recycleCounter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Attempts to claim a specified handle. If the handle is available, the
|
||||||
|
* generator will mark it as claimed and return true.
|
||||||
|
* Updates recycles accordingly when adding extra padding to the handle list.
|
||||||
|
*
|
||||||
|
* \param handle
|
||||||
|
* The handle to claim
|
||||||
|
*
|
||||||
|
* \return
|
||||||
|
* true if the handle is available to claim.
|
||||||
|
***************************************************************************/
|
||||||
|
bool ClaimHandle(HandleType handle) noexcept
|
||||||
|
{
|
||||||
|
IndexType index = GetIndex(handle);
|
||||||
|
|
||||||
|
if (handleList.size() <= index || GetIndex(handleList[index]) != index)
|
||||||
|
{
|
||||||
|
//This index is currently not in use
|
||||||
|
|
||||||
|
if (index >= handleList.size())
|
||||||
|
{
|
||||||
|
IndexType size = (IndexType)handleList.size();
|
||||||
|
|
||||||
|
for (IndexType i = 0; i < index - size; ++i)
|
||||||
|
{
|
||||||
|
handleList.push_back((IndexType)handleList.size());
|
||||||
|
|
||||||
|
HandleType back = handleList.back();
|
||||||
|
//set the handle at the current index to the next thing to be recycled.
|
||||||
|
if (recycleCounter > 0)
|
||||||
|
handleList.back() = nextRecycle;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
handleList.back() = (HandleType)-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//set the next recycle to be the thing that was just deleted with its version incremented.
|
||||||
|
nextRecycle = GetHandle(0, GetIndex(back));
|
||||||
|
++recycleCounter;
|
||||||
|
}
|
||||||
|
handleList.push_back(handle);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (index == GetIndex(nextRecycle))
|
||||||
|
{
|
||||||
|
index = GetIndex(nextRecycle);
|
||||||
|
//updates the next recycle.
|
||||||
|
nextRecycle = handleList[index];
|
||||||
|
handleList[index] = handle;
|
||||||
|
--recycleCounter;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recycleCounter > 0)
|
||||||
|
{
|
||||||
|
HandleType recycle = handleList[index];
|
||||||
|
IndexType recycleIndex = GetIndex(nextRecycle);
|
||||||
|
HandleType i = 0;
|
||||||
|
while (i < recycleCounter)
|
||||||
|
{
|
||||||
|
if (GetIndex(handleList[recycleIndex]) == index)
|
||||||
|
break;
|
||||||
|
recycleIndex = GetIndex(handleList[recycleIndex]);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
--recycleCounter;
|
||||||
|
if (recycleCounter > 0 && recycleIndex < handleList.size())
|
||||||
|
handleList[recycleIndex] = recycle;
|
||||||
|
}
|
||||||
|
handleList[index] = handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef SHHandleGenerator<EntityID, EntityIndex> EntityHandleGenerator;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \file SHSparseBase.h
|
||||||
|
* \author Daniel Chua Yee Chen
|
||||||
|
* \brief Declaration for the SHSparseBase class.
|
||||||
|
* This is an abstract class for the SHSparseSet template class.
|
||||||
|
* This allows the SHSparseSetContainer class to store SparseSet of different types.
|
||||||
|
*
|
||||||
|
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||||
|
or disclosure of this file or its contents without the prior written
|
||||||
|
consent of DigiPen Institute of Technology is prohibited.
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#ifndef SH_SPARSE_BASE_H
|
||||||
|
#define SH_SPARSE_BASE_H
|
||||||
|
|
||||||
|
#include "../SHECSMacros.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
|
||||||
|
class SHSparseBase
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
SHSparseBase() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~SHSparseBase() = default;
|
||||||
|
|
||||||
|
virtual void Remove(EntityIndex hash) { (void)hash; };
|
||||||
|
|
||||||
|
virtual void Clear() {};
|
||||||
|
|
||||||
|
virtual void Swap(EntityIndex hash1, EntityIndex hash2) { (void)hash1; (void)hash2; };
|
||||||
|
|
||||||
|
virtual void SwapIndexHash(EntityIndex index1, EntityIndex hash) { (void)index1; (void)hash; };
|
||||||
|
|
||||||
|
virtual bool Has(EntityIndex hash) = 0;
|
||||||
|
|
||||||
|
virtual void* Get(EntityIndex hash) { (void)hash; return nullptr; };
|
||||||
|
|
||||||
|
virtual void Add(EntityIndex hash) { (void)hash; };
|
||||||
|
|
||||||
|
virtual EntityIndex Count() = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,356 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \file SHSparseSet.h
|
||||||
|
* \author Daniel Chua Yee Chen
|
||||||
|
* \brief Declaration for the SHSparseSet template class
|
||||||
|
* This is a container that allows for fast iteration due to contiguous memory
|
||||||
|
* storage while having fast lookup time at the cost of memory usage.
|
||||||
|
*
|
||||||
|
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||||
|
or disclosure of this file or its contents without the prior written
|
||||||
|
consent of DigiPen Institute of Technology is prohibited.
|
||||||
|
*********************************************************************/
|
||||||
|
#ifndef SH_SPARSE_SET_H
|
||||||
|
#define SH_SPARSE_SET_H
|
||||||
|
|
||||||
|
#include "../SHECSMacros.h"
|
||||||
|
#include "../General/SHSparseBase.h"
|
||||||
|
#include "../General/SHHandleGenerator.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <array>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
template <typename T, EntityIndex MAX>
|
||||||
|
class SHSparseSet: public SHSparseBase
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
//Dense array of type T
|
||||||
|
std::vector<T> denseArray;
|
||||||
|
//This array stores the key of the corresponding element in the dense array. (eg. entity ID)
|
||||||
|
std::vector<EntityIndex> denseIndexArray;
|
||||||
|
|
||||||
|
//Sparse Array. This array helps with look up
|
||||||
|
EntityIndex sparseArray[MAX];
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief Construct a new SHSparseSet object
|
||||||
|
* Default constructor for the SparseSet class.
|
||||||
|
***************************************************************************/
|
||||||
|
SHSparseSet()
|
||||||
|
{
|
||||||
|
for (EntityIndex i = 0; i < MAX; ++i)
|
||||||
|
{
|
||||||
|
sparseArray[i] = UINT16_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
denseArray.reserve(MAX);
|
||||||
|
denseIndexArray.reserve(MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief Destroy the SHSparseSet object
|
||||||
|
* Default destructor for the SparseSet class.
|
||||||
|
***************************************************************************/
|
||||||
|
virtual ~SHSparseSet()
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Clears all elements in the current SparseSet and resets the sparseArray.
|
||||||
|
***************************************************************************/
|
||||||
|
void Clear() noexcept
|
||||||
|
{
|
||||||
|
denseArray.clear();
|
||||||
|
denseIndexArray.clear();
|
||||||
|
for (EntityIndex i = 0; i < MAX; ++i)
|
||||||
|
{
|
||||||
|
sparseArray[i] = UINT16_MAX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Check is the specified hash is in range of the sparseSet.
|
||||||
|
* \param hash
|
||||||
|
* Hash to check for.
|
||||||
|
* \return bool
|
||||||
|
* true if the specified hash is in range of the spraseSet.
|
||||||
|
***************************************************************************/
|
||||||
|
bool IsValid(EntityIndex hash) noexcept
|
||||||
|
{
|
||||||
|
return (hash < MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Checks if this sparseSet contains an element with specified hash.
|
||||||
|
* \param hash
|
||||||
|
* The hash to check for.
|
||||||
|
* \return bool
|
||||||
|
* true if the element with this hash is found. false if no such element is found.
|
||||||
|
***************************************************************************/
|
||||||
|
virtual bool Has(EntityIndex hash) noexcept
|
||||||
|
{
|
||||||
|
//Check if the hash passed in is within range.
|
||||||
|
if (!IsValid(hash) || sparseArray[hash] == UINT16_MAX)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (denseIndexArray[sparseArray[hash]] == hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Get a pointer to the element with the specified hash.
|
||||||
|
|
||||||
|
* This is the safe version which does a Has() check and return a nullptr
|
||||||
|
* if it does not have such an Element
|
||||||
|
*
|
||||||
|
* \param hash
|
||||||
|
* The hash of the element to look for.
|
||||||
|
* \return T*
|
||||||
|
* returns a pointer to the element with the specified hash if found.
|
||||||
|
* returns a nullptr if no such element is found.
|
||||||
|
***************************************************************************/
|
||||||
|
T* GetElement_s(EntityIndex hash) noexcept
|
||||||
|
{
|
||||||
|
if (!Has(hash))
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &denseArray[sparseArray[hash]];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Get a pointer to the element with the specified hash.
|
||||||
|
|
||||||
|
* This bypasses the Has() check and assumes that the hash has a Element
|
||||||
|
* in the dense array.
|
||||||
|
*
|
||||||
|
* \param hash
|
||||||
|
* The hash of the element to look for.
|
||||||
|
* \return T*
|
||||||
|
* returns a pointer to the element with the specified hash if found.
|
||||||
|
* returns a nullptr if no such element is found.
|
||||||
|
***************************************************************************/
|
||||||
|
T* GetElement(EntityIndex hash) noexcept
|
||||||
|
{
|
||||||
|
return &denseArray[sparseArray[hash]];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Operator overload for the subscript operator.
|
||||||
|
* Gets the element by reference with the hash specified in the subscript.
|
||||||
|
* This does not handle out of range exceptions.
|
||||||
|
* \param hash
|
||||||
|
* The hash of the element we are trying to get
|
||||||
|
* \return T&
|
||||||
|
* A reference to the element found.
|
||||||
|
***************************************************************************/
|
||||||
|
T& operator[](EntityIndex hash) noexcept
|
||||||
|
{
|
||||||
|
return denseArray[sparseArray[hash]];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Get the number of elements in the current SparseSet
|
||||||
|
* \return uint16_t
|
||||||
|
* The number of elements in the SparseSet.
|
||||||
|
***************************************************************************/
|
||||||
|
virtual EntityIndex Count() noexcept
|
||||||
|
{
|
||||||
|
return (EntityIndex)denseArray.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Getter function for the dense array.
|
||||||
|
* \return std::vector<T>&
|
||||||
|
* return a reference to the dense array.
|
||||||
|
***************************************************************************/
|
||||||
|
std::vector<T>& GetDense() noexcept
|
||||||
|
{
|
||||||
|
return denseArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Const getter function for the dense array.
|
||||||
|
* \return std::vector<T>&
|
||||||
|
* return a const reference to the dense array.
|
||||||
|
***************************************************************************/
|
||||||
|
const std::vector<T> GetDense() const noexcept
|
||||||
|
{
|
||||||
|
return denseArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Swaps two elements in the dense array.
|
||||||
|
* This only swaps their position in the dense array and updates their
|
||||||
|
* Sparse index reference in the sprase array accordingly.
|
||||||
|
* This DOES NOT change the hash of the elements.
|
||||||
|
* \param hash1
|
||||||
|
* Hash of the first element
|
||||||
|
* \param hash2
|
||||||
|
* Hash of the second element
|
||||||
|
***************************************************************************/
|
||||||
|
virtual void Swap(EntityIndex hash1, EntityIndex hash2) noexcept
|
||||||
|
{
|
||||||
|
if (!Has(hash1) || !Has(hash2) || hash1 == hash2)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
T tempElement = denseArray[sparseArray[hash1]];
|
||||||
|
EntityIndex tempIndex = denseIndexArray[sparseArray[hash1]];
|
||||||
|
EntityIndex tempSparse = sparseArray[hash1];
|
||||||
|
|
||||||
|
denseArray[sparseArray[hash1]] = denseArray[sparseArray[hash2]];
|
||||||
|
denseIndexArray[sparseArray[hash1]] = denseIndexArray[sparseArray[hash2]];
|
||||||
|
sparseArray[hash1] = sparseArray[hash2];
|
||||||
|
|
||||||
|
denseArray[sparseArray[hash2]] = tempElement;
|
||||||
|
denseIndexArray[sparseArray[hash2]] = tempIndex;
|
||||||
|
sparseArray[hash2] = tempSparse;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Swaps two elements in the dense array.
|
||||||
|
* This only swaps their position in the dense array and updates their
|
||||||
|
* Sparse index reference in the sprase array accordingly.
|
||||||
|
* This swaps using a index(position in the dense array) and a hash (EntityID)
|
||||||
|
* This DOES NOT change the hash of the elements.
|
||||||
|
* \param index1
|
||||||
|
* The position in the dense array of the first element
|
||||||
|
* \param hash
|
||||||
|
* Hash of the second element
|
||||||
|
***************************************************************************/
|
||||||
|
virtual void SwapIndexHash(EntityIndex index1, EntityIndex hash) noexcept
|
||||||
|
{
|
||||||
|
if (index1 >= denseArray.size() || !Has(hash))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Swap(denseIndexArray[index1], hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Adds a new element to the SparseSet.
|
||||||
|
* \param hash
|
||||||
|
* The hash of the new element.
|
||||||
|
* Nothing is added if the SparseSet already contains an element with
|
||||||
|
* the same hash.
|
||||||
|
* \param element
|
||||||
|
* A reference to the element to be added. This will be passed in as a
|
||||||
|
* copy and the default copy constructor will be used to copy the element
|
||||||
|
* into the dense array.
|
||||||
|
***************************************************************************/
|
||||||
|
void Add(EntityIndex hash, T& element) noexcept
|
||||||
|
{
|
||||||
|
if (!IsValid(hash) || Has(hash))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
denseArray.emplace_back(element);
|
||||||
|
denseIndexArray.emplace_back (hash);
|
||||||
|
sparseArray[hash] = EntityIndex(denseIndexArray.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Adds a new element to the SparseSet.
|
||||||
|
* \param hash
|
||||||
|
* The hash of the new element.
|
||||||
|
* Nothing is added if the SparseSet already contains an element with
|
||||||
|
* the same hash.
|
||||||
|
* \return
|
||||||
|
* None
|
||||||
|
***************************************************************************/
|
||||||
|
void Add(EntityIndex hash) noexcept
|
||||||
|
{
|
||||||
|
if (!IsValid(hash) || Has(hash))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
denseArray.emplace_back(T());
|
||||||
|
denseIndexArray.emplace_back(hash);
|
||||||
|
sparseArray[hash] = EntityIndex(denseIndexArray.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Removes an element from the Sparse Set
|
||||||
|
* \param hash
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
virtual void Remove(EntityIndex hash) noexcept
|
||||||
|
{
|
||||||
|
if (!Has(hash))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get the index of the item to be removed.
|
||||||
|
EntityIndex index = sparseArray[hash];
|
||||||
|
|
||||||
|
//Get the sparse index of the last element in the dense array.
|
||||||
|
EntityIndex lastSparse = denseIndexArray.back();
|
||||||
|
|
||||||
|
//Copy the contents of the last elements to the replace the element we are trying to remove
|
||||||
|
//denseArray[index] = denseArray.back();
|
||||||
|
//denseIndexArray[index] = denseIndexArray.back();
|
||||||
|
|
||||||
|
//denseArray.erase(denseArray.begin() + index);
|
||||||
|
//denseIndexArray.erase(denseIndexArray.begin() + index);
|
||||||
|
Swap(hash, lastSparse);
|
||||||
|
|
||||||
|
//update the sparse array with the new index of our last element.
|
||||||
|
sparseArray[lastSparse] = index;
|
||||||
|
sparseArray[hash] = UINT16_MAX;
|
||||||
|
|
||||||
|
//Pop out the last element since we no longer need it
|
||||||
|
denseArray.pop_back();
|
||||||
|
denseIndexArray.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Get the element specified by a hash. This will be casted to a void
|
||||||
|
* pointer
|
||||||
|
* \param hash
|
||||||
|
* The Index of the element.
|
||||||
|
* \return
|
||||||
|
* A void pointer to the element.
|
||||||
|
***************************************************************************/
|
||||||
|
virtual void* Get(EntityIndex hash) noexcept
|
||||||
|
{
|
||||||
|
if (!Has(hash))
|
||||||
|
{
|
||||||
|
//no such element in this sparse set.
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return (void*) &denseArray[sparseArray[hash]];
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,248 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \file SHSparseSetContainer.h
|
||||||
|
* \author Daniel Chua Yee Chen
|
||||||
|
* \brief Declaration for SHSparseSetContainer template class.
|
||||||
|
* This is a container for SHSparseSets meant to contain SparseSets of
|
||||||
|
* different types that are derived from a shared Base class.
|
||||||
|
*
|
||||||
|
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||||
|
or disclosure of this file or its contents without the prior written
|
||||||
|
consent of DigiPen Institute of Technology is prohibited.
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#ifndef SH_SPARSE_SET_CONTAINER_H
|
||||||
|
#define SH_SPARSE_SET_CONTAINER_H
|
||||||
|
|
||||||
|
#include "SHSparseSet.h"
|
||||||
|
#include "SHFamily.h"
|
||||||
|
#include "../Components/SHComponent.h"
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
template<typename Base>
|
||||||
|
class SHSparseSetContainer
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//The container of SparseSets.
|
||||||
|
std::vector<SHSparseBase*> container;
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Default constructor for the SHSparseSetContainer class
|
||||||
|
***************************************************************************/
|
||||||
|
SHSparseSetContainer() = default;
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Default destructor for the SHSparseSetContainer class.
|
||||||
|
***************************************************************************/
|
||||||
|
~SHSparseSetContainer()
|
||||||
|
{
|
||||||
|
for (std::vector<SHSparseBase*>::iterator it = container.begin(); it != container.end(); ++it)
|
||||||
|
{
|
||||||
|
delete (*it);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Attempts to create a SparseSet for the specified derived class.
|
||||||
|
* If a SparseSet of the same class type has already been created,
|
||||||
|
* nothing is re-created.
|
||||||
|
* @tparam Derived
|
||||||
|
* The type of the SparseSet to create.
|
||||||
|
***************************************************************************/
|
||||||
|
template<typename Derived>
|
||||||
|
ENABLE_IF_DERIVED(void, Base, Derived) CreateSparseSet() noexcept
|
||||||
|
{
|
||||||
|
EntityID typeID = SHFamilyID<Base>::template GetID<Derived>();
|
||||||
|
|
||||||
|
if (container.size() > typeID)
|
||||||
|
{
|
||||||
|
if (container[typeID] == nullptr)
|
||||||
|
{
|
||||||
|
container[typeID] = (SHSparseBase*)new SHSparseSet<Derived, MAX_EID>();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (container.size() <= typeID)
|
||||||
|
{
|
||||||
|
container.push_back(nullptr);
|
||||||
|
}
|
||||||
|
container[typeID] = (SHSparseBase*)new SHSparseSet<Derived,MAX_EID>();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Cant use ENABLE_IF_DERIVED here because the macro is defined before template is defined.
|
||||||
|
//Hence the return type that is a templated class will be an issue.
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Get the sparse set specified by a type. This converts the type to
|
||||||
|
* a type ID using SHFamilyID and use that as the index.
|
||||||
|
* This will attempt to Create a sparse set if it doesn't exist.
|
||||||
|
* \return
|
||||||
|
* The base class pointer to the sparse set.
|
||||||
|
***************************************************************************/
|
||||||
|
template<typename Derived>
|
||||||
|
std::enable_if_t< std::is_base_of_v<Base,Derived>,SHSparseSet<Derived,MAX_EID>* > GetSparseSet() noexcept
|
||||||
|
{
|
||||||
|
EntityID typeID = SHFamilyID<Base>::template GetID<Derived>();
|
||||||
|
if (container.size() <= typeID || container[typeID] == nullptr)
|
||||||
|
{
|
||||||
|
CreateSparseSet<Derived>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (SHSparseSet<Derived, MAX_EID>*)container[typeID];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Get the sparse set at the specified index.
|
||||||
|
* \param typeID
|
||||||
|
* The index of the sparse set to get.
|
||||||
|
* \return
|
||||||
|
* The base class pointer to the sparse set.
|
||||||
|
***************************************************************************/
|
||||||
|
SHSparseBase* GetSparseSet_ID(uint32_t typeID) noexcept
|
||||||
|
{
|
||||||
|
//assert(typeID >= container.size());
|
||||||
|
|
||||||
|
return container[typeID];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Get the number of elements in the specified SparseSet
|
||||||
|
* @tparam Derived
|
||||||
|
* The type of the SparseSet
|
||||||
|
***************************************************************************/
|
||||||
|
template<typename Derived>
|
||||||
|
inline ENABLE_IF_DERIVED(EntityID, Base, Derived)Count() noexcept
|
||||||
|
{
|
||||||
|
return GetSparseSet<Derived>()->Count();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Get the dense array of the specified SparseSet
|
||||||
|
* @tparam Derived
|
||||||
|
* The type of the SparseSet
|
||||||
|
* \return
|
||||||
|
* Returns a reference to the dense array of the specified SparseSet
|
||||||
|
***************************************************************************/
|
||||||
|
template<typename Derived>
|
||||||
|
inline std::enable_if_t < std::is_base_of_v<Base, Derived>, std::vector<Derived>& > GetDense() noexcept
|
||||||
|
{
|
||||||
|
return GetSparseSet<Derived>()->GetDense();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Remove all elements with the specified hash from all the SparseSets in
|
||||||
|
* the container.
|
||||||
|
* \param hash
|
||||||
|
* The hash of the elements to remove.
|
||||||
|
***************************************************************************/
|
||||||
|
void RemoveElements(EntityIndex hash) noexcept
|
||||||
|
{
|
||||||
|
for (std::vector<SHSparseBase*>::iterator it = container.begin(); it != container.end(); ++it)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (*it)
|
||||||
|
{
|
||||||
|
(*it)->Remove(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Clear all SparseSets in the container.
|
||||||
|
***************************************************************************/
|
||||||
|
void ClearAllElements() noexcept
|
||||||
|
{
|
||||||
|
for (std::vector<SHSparseBase*>::iterator it = container.begin(); it != container.end(); ++it)
|
||||||
|
{
|
||||||
|
(*it)->Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Sets the isActive variable in the elements with the specified hash
|
||||||
|
* in all the SparseSets in the container.
|
||||||
|
* This assuumes that the element types has a isActive boolean.
|
||||||
|
* \param hash
|
||||||
|
* hash of the elements
|
||||||
|
* \param active
|
||||||
|
* The active state to set to.
|
||||||
|
***************************************************************************/
|
||||||
|
void SetElementActive(EntityIndex hash, bool active) noexcept
|
||||||
|
{
|
||||||
|
(void)active;
|
||||||
|
for (std::vector<SHSparseBase*>::iterator it = container.begin(); it != container.end(); ++it)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (*it)
|
||||||
|
{
|
||||||
|
SHComponent* comp = static_cast<SHComponent*>((*it)->Get(hash));
|
||||||
|
if (comp)
|
||||||
|
{
|
||||||
|
comp->isActive = active;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Get the element of a specified hash from the Sparse set of indicated index.
|
||||||
|
* \param typeIndex
|
||||||
|
* The index of the sparse set which we are trying to get from
|
||||||
|
* \param hash
|
||||||
|
* The hash that the element belongs to.
|
||||||
|
* \return
|
||||||
|
* The address of the element casted to a void*
|
||||||
|
***************************************************************************/
|
||||||
|
void* GetElement(uint32_t typeIndex, EntityIndex hash) noexcept
|
||||||
|
{
|
||||||
|
if (typeIndex >= container.size())
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return container[typeIndex]->Get(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Get the size of the SparseSetContainer.
|
||||||
|
* \return
|
||||||
|
* The number of sparse sets in this container.
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
size_t Size() noexcept
|
||||||
|
{
|
||||||
|
return container.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef SH_MACROS_H
|
||||||
|
#define SH_MACROS_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef uint32_t EntityID;
|
||||||
|
typedef uint16_t EntityIndex;
|
||||||
|
typedef uint32_t ComponentTypeID;
|
||||||
|
|
||||||
|
|
||||||
|
const EntityIndex MAX_EID = 51000;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define ENABLE_IF_DERIVED(__RETURN__, __BASE__, __DERIVED__)\
|
||||||
|
std::enable_if_t<std::is_base_of_v<__BASE__,__DERIVED__>,__RETURN__>
|
||||||
|
|
||||||
|
|
||||||
|
#define ENABLE_IF_UINT(_TYPE, _RETURN)\
|
||||||
|
typename std::enable_if<(std::is_integral<_TYPE>::value && !std::is_signed<_TYPE>::value),_RETURN>::type
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,102 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \file SHComponentManager.cpp
|
||||||
|
* \author Daniel Chua Yee Chen
|
||||||
|
* \brief Definition of functions for the SHComponentManager class.
|
||||||
|
* This is the interface that the systems are going to use to interacte with
|
||||||
|
* the components. The SparseSetContainer of components is stored and managed
|
||||||
|
* here.
|
||||||
|
*
|
||||||
|
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||||
|
or disclosure of this file or its contents without the prior written
|
||||||
|
consent of DigiPen Institute of Technology is prohibited.
|
||||||
|
*********************************************************************/
|
||||||
|
#include "SHpch.h"
|
||||||
|
#include "SHComponentManager.h"
|
||||||
|
#include "SHEntityManager.h"
|
||||||
|
#include "SHSystemManager.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
|
||||||
|
SHSparseSetContainer<SHComponent> SHComponentManager::componentSet;
|
||||||
|
std::vector<SHComponentGroup> SHComponentManager::componentGroups;
|
||||||
|
|
||||||
|
void SHComponentManager::Exit() noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHComponentManager::RemoveComponentsOfEntity(EntityID entityID) noexcept
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!SHEntityManager::IsValidEID(entityID))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < componentSet.Size(); ++i)
|
||||||
|
{
|
||||||
|
SHComponent* comp = (SHComponent*) componentSet.GetElement(i, EntityHandleGenerator::GetIndex(entityID));
|
||||||
|
if (comp)
|
||||||
|
{
|
||||||
|
comp->OnDestroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for (auto & grp : componentGroups)
|
||||||
|
{
|
||||||
|
grp.RemoveEntity(entityID);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentSet.RemoveElements(EntityHandleGenerator::GetIndex(entityID));
|
||||||
|
|
||||||
|
//entityHandle.RemoveHandle(entityID);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool SHComponentManager::HasComponent_ID(EntityID entityID, uint32_t componentTypeID) noexcept
|
||||||
|
{
|
||||||
|
return componentSet.GetSparseSet_ID(componentTypeID)->Has(EntityHandleGenerator::GetIndex(entityID));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SHComponentManager::SetActive(EntityID entityID, bool active) noexcept
|
||||||
|
{
|
||||||
|
componentSet.SetElementActive(EntityHandleGenerator::GetIndex(entityID), active);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHComponentManager::SwapInDenseByIndexHash_ID(EntityIndex index, EntityID hash, uint32_t componentTypeID) noexcept
|
||||||
|
{
|
||||||
|
componentSet.GetSparseSet_ID(componentTypeID)->SwapIndexHash(index, EntityHandleGenerator::GetIndex(hash));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHComponentManager::ChangeParent(EntityID entity, EntityID newParent)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < (uint32_t)componentSet.Size(); ++i)
|
||||||
|
{
|
||||||
|
SHComponent* component = (SHComponent*)componentSet.GetElement(i, EntityHandleGenerator::GetIndex(entity));
|
||||||
|
if (component == nullptr)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
component->ChangeParent(newParent);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHComponentManager::ChangeParent(EntityID entity)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < (uint32_t)componentSet.Size(); ++i)
|
||||||
|
{
|
||||||
|
SHComponent* component = (SHComponent*)componentSet.GetElement(i, EntityHandleGenerator::GetIndex(entity));
|
||||||
|
if (component == nullptr)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
component->ChangeParent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,477 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \file SHComponentManager.h
|
||||||
|
* \author Daniel Chua Yee Chen
|
||||||
|
* \brief Declaration for the SHComponentManager class.
|
||||||
|
* This is the interface that the systems are going to use to interacte with
|
||||||
|
* the components.
|
||||||
|
* The SparseSetContainer of components is stored and managed
|
||||||
|
* here.
|
||||||
|
*
|
||||||
|
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||||
|
or disclosure of this file or its contents without the prior written
|
||||||
|
consent of DigiPen Institute of Technology is prohibited.
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#ifndef SH_ENGINE_H
|
||||||
|
#define SH_ENGINE_H
|
||||||
|
|
||||||
|
#include "../General/SHSparseSetContainer.h"
|
||||||
|
#include "../Components/SHComponent.h"
|
||||||
|
#include "../Components/SHComponentGroup.h"
|
||||||
|
//#include "Scene/SHSceneNode.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
class SHComponentManager
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
//The SparseSetContainer of components.
|
||||||
|
static SHSparseSetContainer<SHComponent> componentSet;
|
||||||
|
//The Container of all Componentgroups
|
||||||
|
static std::vector<SHComponentGroup> componentGroups;
|
||||||
|
|
||||||
|
friend class SHSceneNode;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* This is called by the SHSceneNode friend class to change the parent
|
||||||
|
* of an entity.
|
||||||
|
* This function is privated as it is not for general use.
|
||||||
|
* \param entity
|
||||||
|
* The entityID of the entity which to change the parent of.
|
||||||
|
* \param newParent
|
||||||
|
* The entityID of the new parent.
|
||||||
|
***************************************************************************/
|
||||||
|
static void ChangeParent(EntityID entity, EntityID newParent);
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Overloaded function of Change parent to change the parent of an entity to
|
||||||
|
* the root node.
|
||||||
|
* This is called by the SHSceneNode friend class to change the parent
|
||||||
|
* of an entity.
|
||||||
|
* This function is privated as it is not for general use.
|
||||||
|
* \param entity
|
||||||
|
* The entityID of the entity which to change the parent of.
|
||||||
|
***************************************************************************/
|
||||||
|
static void ChangeParent(EntityID entity);
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*!*************************************************************************
|
||||||
|
* This class is used as a static class.
|
||||||
|
* No objects of this type should be created
|
||||||
|
***************************************************************************/
|
||||||
|
SHComponentManager() = delete;
|
||||||
|
~SHComponentManager() = delete;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Cleans up the memory used in the Engine.
|
||||||
|
***************************************************************************/
|
||||||
|
static void Exit() noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Creates the SparseSet for the specified Component type
|
||||||
|
* @tparam T
|
||||||
|
* Component Type to create.
|
||||||
|
***************************************************************************/
|
||||||
|
template<typename T>
|
||||||
|
static void CreateComponentSparseSet() noexcept
|
||||||
|
{
|
||||||
|
componentSet.CreateSparseSet<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Getter for the dense array of a specified Component Type.
|
||||||
|
* @tparam T
|
||||||
|
* Component Type
|
||||||
|
* \return std::vector<T>&
|
||||||
|
* reference to the dense array from the SparseSet of the Component Type T.
|
||||||
|
***************************************************************************/
|
||||||
|
template<typename T>
|
||||||
|
static std::vector<T>& GetDense() noexcept
|
||||||
|
{
|
||||||
|
return componentSet.GetDense<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Gets the Component of the entity with the specified entityID
|
||||||
|
*
|
||||||
|
* This is the safe version of GetComponent_s which does a HasComponent to make
|
||||||
|
* sure that the entity has such a component and returns nullptr if it doesn't
|
||||||
|
*
|
||||||
|
* This safe version also checks if the sparse set of this component type
|
||||||
|
* has been created in SHComponentManager and creates one if it doesn't
|
||||||
|
*
|
||||||
|
* @tparam T
|
||||||
|
* Type of Component to get.
|
||||||
|
* \param entityID
|
||||||
|
* EntityID of the entity that we are trying to get the component of.
|
||||||
|
* \return
|
||||||
|
* A pointer to the component of the entity.
|
||||||
|
* Returns nullptr if the entity does not contain such a component.
|
||||||
|
***************************************************************************/
|
||||||
|
template<typename T>
|
||||||
|
static ENABLE_IF_DERIVED(T*, SHComponent, T) GetComponent_s(EntityID entityID) noexcept
|
||||||
|
{
|
||||||
|
EntityID typeID = SHFamilyID<SHComponent>::template GetID<T>();
|
||||||
|
|
||||||
|
if (componentSet.container.size() <= typeID)
|
||||||
|
{
|
||||||
|
componentSet.CreateSparseSet<T>();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return (componentSet.GetSparseSet<T>()->GetElement_s(EntityHandleGenerator::GetIndex(entityID)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Gets the Component of the entity with the specified entityID
|
||||||
|
*
|
||||||
|
* This is the faster unsafe version.
|
||||||
|
* Use only when sure that the entity has such a Component type. This could
|
||||||
|
* give garbage value or the component of a different entity if the entity
|
||||||
|
* does not have the specified component type. This is usually used with
|
||||||
|
* ComponentGroups
|
||||||
|
*
|
||||||
|
* This unsafe version bypass the HasComponent check.
|
||||||
|
*
|
||||||
|
* This unsafe version bypass the check for sparseSet creation.
|
||||||
|
*
|
||||||
|
* @tparam T
|
||||||
|
* Type of Component to get.
|
||||||
|
* \param entityID
|
||||||
|
* EntityID of the entity that we are trying to get the component of.
|
||||||
|
* \return
|
||||||
|
* A pointer to the component of the entity.
|
||||||
|
***************************************************************************/
|
||||||
|
template<typename T>
|
||||||
|
static ENABLE_IF_DERIVED(T*,SHComponent, T) GetComponent(EntityID entityID) noexcept
|
||||||
|
{
|
||||||
|
//EntityID typeID = SHFamilyID<SHComponent>::template GetID<T>();
|
||||||
|
|
||||||
|
return (componentSet.GetSparseSet<T>()->GetElement(EntityHandleGenerator::GetIndex(entityID)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Add a component to the specified entityID
|
||||||
|
* Nothing is added if the entityID already have a component of the same type.
|
||||||
|
* @tparam T
|
||||||
|
* Type of Component to be added.
|
||||||
|
* @tparam Args
|
||||||
|
* The args types to pass to the constructor of the Component
|
||||||
|
* \param entityID
|
||||||
|
* EntityID to add this component to.
|
||||||
|
* \param args
|
||||||
|
* The args to pass to the constructor of the Component
|
||||||
|
* \return
|
||||||
|
* None.
|
||||||
|
***************************************************************************/
|
||||||
|
template<typename T >
|
||||||
|
static ENABLE_IF_DERIVED(void,SHComponent,T) AddComponent(EntityID entityID) noexcept
|
||||||
|
{
|
||||||
|
T element{};
|
||||||
|
|
||||||
|
componentSet.GetSparseSet_ID(SHFamilyID<SHComponent>::GetID<T>())->Add(EntityHandleGenerator::GetIndex(entityID));
|
||||||
|
|
||||||
|
|
||||||
|
SHComponent* comp = (SHComponent*)componentSet.GetElement(SHFamilyID<SHComponent>::GetID<T>(), EntityHandleGenerator::GetIndex(entityID));
|
||||||
|
comp->entityID = entityID;
|
||||||
|
|
||||||
|
for (auto& grp : componentGroups)
|
||||||
|
{
|
||||||
|
grp.AddComponentCheck(entityID, SHFamilyID<SHComponent>::GetID<T>());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (comp)
|
||||||
|
{
|
||||||
|
comp->OnCreate();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Add Component using a component type ID. This assumes that the sparse
|
||||||
|
* set is already created for the component type ID.
|
||||||
|
* \param entityID
|
||||||
|
* The entity ID of the entity
|
||||||
|
* \param componentTypeID
|
||||||
|
* The Type ID of the Component Type.
|
||||||
|
* \return
|
||||||
|
* none
|
||||||
|
***************************************************************************/
|
||||||
|
static void AddComponent(EntityID entityID, uint32_t componentTypeID) noexcept
|
||||||
|
{
|
||||||
|
componentSet.GetSparseSet_ID(componentTypeID)->Add(EntityHandleGenerator::GetIndex(entityID));
|
||||||
|
|
||||||
|
|
||||||
|
SHComponent* comp = (SHComponent*)componentSet.GetElement(componentTypeID, EntityHandleGenerator::GetIndex(entityID));
|
||||||
|
comp->entityID = entityID;
|
||||||
|
|
||||||
|
for (auto& grp : componentGroups)
|
||||||
|
{
|
||||||
|
grp.AddComponentCheck(entityID,componentTypeID);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (comp)
|
||||||
|
{
|
||||||
|
comp->OnCreate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Checks if the specified entityID has a component of specified type.
|
||||||
|
* @tparam T
|
||||||
|
* Type of Component to check for.
|
||||||
|
* \param entityID
|
||||||
|
* EntityID to check for.
|
||||||
|
* \return bool
|
||||||
|
* True if the entity has a component of specified type.
|
||||||
|
***************************************************************************/
|
||||||
|
template<typename T>
|
||||||
|
static ENABLE_IF_DERIVED(bool, SHComponent, T) HasComponent(EntityID entityID) noexcept
|
||||||
|
{
|
||||||
|
return componentSet.GetSparseSet<T>()->Has(EntityHandleGenerator::GetIndex(entityID));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Checks if the specified entityID has a component of specified type.
|
||||||
|
* The component type is specified by a component type ID
|
||||||
|
* @tparam T
|
||||||
|
* Type of Component to check for.
|
||||||
|
* \param entityID
|
||||||
|
* EntityID to check for.
|
||||||
|
* \param componentTypeID
|
||||||
|
* The component type ID to look for
|
||||||
|
* \return bool
|
||||||
|
* True if the entity has a component of specified type.
|
||||||
|
***************************************************************************/
|
||||||
|
static bool HasComponent_ID(EntityID entityID, uint32_t componentTypeID) noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Remove the Component of specified type from the entity.
|
||||||
|
* @tparam T
|
||||||
|
* Component type to be removed
|
||||||
|
* \param entityID
|
||||||
|
* EntityID of the object to remove the component from.
|
||||||
|
***************************************************************************/
|
||||||
|
template<typename T>
|
||||||
|
static ENABLE_IF_DERIVED(void, SHComponent, T) RemoveComponent(EntityID entityID) noexcept
|
||||||
|
{
|
||||||
|
if (!HasComponent<T>(entityID))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHComponent* comp = (SHComponent*)componentSet.GetElement(SHFamilyID<SHComponent>::GetID<T>(), EntityHandleGenerator::GetIndex(entityID));
|
||||||
|
if (comp)
|
||||||
|
{
|
||||||
|
comp->OnDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& grp : componentGroups)
|
||||||
|
{
|
||||||
|
grp.RemoveComponentCheck<T>(entityID);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
componentSet.GetSparseSet<T>()->Remove(EntityHandleGenerator::GetIndex(entityID));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Swaps to positioning of two components in their dense array.
|
||||||
|
* This does not swap the entity that the components belong to
|
||||||
|
* @tparam T
|
||||||
|
* Type of the Component to swap.
|
||||||
|
* \param entityID1
|
||||||
|
* entityID of the first entity.
|
||||||
|
* \param entityID2
|
||||||
|
* entityID of the second entity.
|
||||||
|
* \return
|
||||||
|
* None.
|
||||||
|
***************************************************************************/
|
||||||
|
template<typename T>
|
||||||
|
static ENABLE_IF_DERIVED(void, SHComponent, T) SwapInDense(EntityID entityID1, EntityID entityID2) noexcept
|
||||||
|
{
|
||||||
|
componentSet.GetSparseSet<T>()->Swap(EntityHandleGenerator::GetIndex(entityID1), EntityHandleGenerator::GetIndex(entityID2));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Swaps to positioning of two components in their dense array.
|
||||||
|
* This does not swap the entity that the components belong to.
|
||||||
|
* This is the overloaded function that takes 2 Entity Index
|
||||||
|
* \param index
|
||||||
|
* The entity Index of the first entity.
|
||||||
|
* \param hash
|
||||||
|
* The entity Index of the second entity.
|
||||||
|
* \return
|
||||||
|
* none
|
||||||
|
***************************************************************************/
|
||||||
|
template<typename T>
|
||||||
|
static ENABLE_IF_DERIVED(void, SHComponent, T) SwapInDenseByIndex(EntityIndex index, EntityIndex hash) noexcept
|
||||||
|
{
|
||||||
|
componentSet.GetSparseSet<T>()->SwapIndexHash(index, EntityHandleGenerator::GetIndex(hash));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Swaps to positioning of two components in their dense array.
|
||||||
|
* This does not swap the entity that the components belong to.
|
||||||
|
* This swap using a component type ID
|
||||||
|
* \param index
|
||||||
|
* The entity Index of the first entity
|
||||||
|
* \param hash
|
||||||
|
* The entity ID of the second entity
|
||||||
|
* \param componentTypeID
|
||||||
|
* The Type ID of the component type ID
|
||||||
|
* \return
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
static void SwapInDenseByIndexHash_ID(EntityIndex index, EntityID hash, uint32_t componentTypeID) noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Removes and destroy all components tied to an entity.
|
||||||
|
* entityID
|
||||||
|
* \param entityID
|
||||||
|
* entityID of the entity to be removed.
|
||||||
|
***************************************************************************/
|
||||||
|
static void RemoveComponentsOfEntity(EntityID entityID) noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Get the number of components in a component sparse set.
|
||||||
|
* \param componentTypeID
|
||||||
|
* The type ID of the Component Type.
|
||||||
|
* \return
|
||||||
|
* The number of components in the component sparse set.
|
||||||
|
***************************************************************************/
|
||||||
|
static EntityIndex ComponentCount_ID(uint32_t componentTypeID)
|
||||||
|
{
|
||||||
|
return componentSet.GetSparseSet_ID(componentTypeID)->Count();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Set the isActive boolean of all Components that the entity has
|
||||||
|
* \param entityID
|
||||||
|
* The entityID of the entity
|
||||||
|
* \param active
|
||||||
|
* The active state to set to
|
||||||
|
***************************************************************************/
|
||||||
|
static void SetActive(EntityID entityID, bool active) noexcept;
|
||||||
|
|
||||||
|
template<typename... T>
|
||||||
|
static std::enable_if_t<(... && std::is_base_of_v<SHComponent, T>), uint32_t> CreateComponentGroup(uint32_t numOwningComponents)
|
||||||
|
{
|
||||||
|
std::vector<uint32_t> templateIDs{ (SHFamilyID<SHComponent>::GetID<T>())... };
|
||||||
|
|
||||||
|
for (auto& g : componentGroups)
|
||||||
|
{
|
||||||
|
for (auto const& oID : g.ownedComponentTypes)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < numOwningComponents; ++i)
|
||||||
|
{
|
||||||
|
if ((templateIDs[i] == oID))
|
||||||
|
{
|
||||||
|
assert("This Component is owned by another group");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SHComponentGroup grp;
|
||||||
|
for (uint32_t i = 0; i < numOwningComponents; ++i)
|
||||||
|
{
|
||||||
|
grp.ownedComponentTypes.push_back(templateIDs[i]);
|
||||||
|
}
|
||||||
|
for (uint32_t i = 0; i < templateIDs.size(); ++i)
|
||||||
|
{
|
||||||
|
grp.componentTypeIDs.push_back(templateIDs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (grp.ownedComponentTypes.size() != grp.componentTypeIDs.size())
|
||||||
|
{
|
||||||
|
if (grp.ownedComponentTypes.empty())
|
||||||
|
{
|
||||||
|
grp.ownershipType = OWNERSHIP_TYPE::NON_OWNERSHIP;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
grp.ownershipType = OWNERSHIP_TYPE::PARTIAL_OWNERSHIP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentGroups.push_back(grp);
|
||||||
|
return (uint32_t)componentGroups.size() - 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Get a reference to the component group.
|
||||||
|
* \param index
|
||||||
|
* The index of the component group
|
||||||
|
* \return
|
||||||
|
* A reference to the component group.
|
||||||
|
***************************************************************************/
|
||||||
|
static SHComponentGroup& GetComponentGroup(uint16_t index) noexcept
|
||||||
|
{
|
||||||
|
return componentGroups[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void AddScriptComponent(EntityID eid, std::string const& scriptClassName) noexcept;
|
||||||
|
|
||||||
|
static void RemoveScriptComponent(EntityID eid, std::string const& scriptClassName) noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
};// end SHComponentManager
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,232 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \file SHEntityManager.cpp
|
||||||
|
* \author Daniel Chua Yee Chen
|
||||||
|
* \brief Implementation for the SHEntityManager class.
|
||||||
|
* Entity Manager is the interface class where users of the engine
|
||||||
|
* and its systems interact with entity data in the engine. This
|
||||||
|
* includes Creation and Destruction of entities and getting Entity by
|
||||||
|
* an ID. This manager also ensures that each entity have a unique
|
||||||
|
* handle using SHHandleGenerator.
|
||||||
|
*
|
||||||
|
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||||
|
or disclosure of this file or its contents without the prior written
|
||||||
|
consent of DigiPen Institute of Technology is prohibited.
|
||||||
|
*********************************************************************/
|
||||||
|
#include "SHpch.h"
|
||||||
|
#include "SHEntityManager.h"
|
||||||
|
//#include "Scene/SHSceneGraph.h"
|
||||||
|
//#include "Serialization/SHSerialization.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
std::vector<std::unique_ptr<SHEntity>> SHEntityManager::entityVec;
|
||||||
|
EntityHandleGenerator SHEntityManager::entityHandle;
|
||||||
|
|
||||||
|
SHEntity* SHEntityManager::GetEntityByID(EntityID entityID) noexcept
|
||||||
|
{
|
||||||
|
if (!IsValidEID(entityID))
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityIndex eIndex = entityHandle.GetIndex(entityID);
|
||||||
|
return entityVec[eIndex].get();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHEntityManager::IsValidEID(EntityID entityID) noexcept
|
||||||
|
{
|
||||||
|
if (!entityHandle.IsValid(entityID))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
EntityIndex eIndex = entityHandle.GetIndex(entityID);
|
||||||
|
if (entityVec.size() <= eIndex || !entityVec[eIndex])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityIndex SHEntityManager::GetEntityIndex(EntityID entityID) noexcept
|
||||||
|
{
|
||||||
|
return entityHandle.GetIndex(entityID);
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityID SHEntityManager::CreateEntity(std::vector<uint32_t>const& componentTypeIDs, std::string const& name,EntityID parentEID)
|
||||||
|
{
|
||||||
|
EntityID eID = entityHandle.GetNewHandle();
|
||||||
|
EntityIndex eIndex = entityHandle.GetIndex(eID);
|
||||||
|
if (eIndex > entityVec.size())
|
||||||
|
{
|
||||||
|
assert("FATAL ERROR: EntityIndex out of range in Entity Creation");
|
||||||
|
}
|
||||||
|
else if (eIndex == entityVec.size())
|
||||||
|
{
|
||||||
|
entityVec.emplace_back(std::make_unique<SHEntity>());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!entityVec[eIndex])
|
||||||
|
{
|
||||||
|
//There is still an entity stored there.Something went wrong
|
||||||
|
assert("FATAL ERROR: Entity Creation error. Entity Index Conflict");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Reset it to a newly constructed entity
|
||||||
|
entityVec[eIndex].reset(new SHEntity());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
entityVec[eIndex]->entityID = eID;
|
||||||
|
entityVec[eIndex]->name = name;
|
||||||
|
for (auto& id : componentTypeIDs)
|
||||||
|
{
|
||||||
|
SHComponentManager::AddComponent(eID, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
//(SHComponentManager::AddComponent<ComponentTypes>(eID), ...);
|
||||||
|
/*if (entityHandle.IsValid(parentEID) == false)
|
||||||
|
{
|
||||||
|
entityVec[eIndex]->sceneNode.ConnectToRoot();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
entityVec[eIndex]->SetParent(parentEID);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
//TODO Link to Scene graph.
|
||||||
|
|
||||||
|
return eID;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityID SHEntityManager::CreateEntity(std::vector<uint32_t>const& componentTypeIDs, EntityID desiredEID, std::string const& name, EntityID parentEID)
|
||||||
|
{
|
||||||
|
EntityID eID ;
|
||||||
|
|
||||||
|
if (entityHandle.ClaimHandle(desiredEID) == true)
|
||||||
|
eID = desiredEID;
|
||||||
|
else
|
||||||
|
eID = entityHandle.GetNewHandle();
|
||||||
|
|
||||||
|
|
||||||
|
EntityIndex eIndex = entityHandle.GetIndex(eID);
|
||||||
|
if (eIndex > entityVec.size())
|
||||||
|
{
|
||||||
|
EntityIndex size = (EntityIndex)entityVec.size();
|
||||||
|
for (EntityIndex i = 0; i <= eIndex - size; ++i)
|
||||||
|
{
|
||||||
|
entityVec.push_back(nullptr);
|
||||||
|
|
||||||
|
}
|
||||||
|
entityVec[eIndex].reset(new SHEntity());
|
||||||
|
}
|
||||||
|
else if (eIndex == entityVec.size())
|
||||||
|
{
|
||||||
|
entityVec.emplace_back(std::make_unique<SHEntity>());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!entityVec[eIndex])
|
||||||
|
{
|
||||||
|
//There is still an entity stored there.Something went wrong
|
||||||
|
assert("FATAL ERROR: Entity Creation error. Entity Index Conflict");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Reset it to a newly constructed entity
|
||||||
|
entityVec[eIndex].reset(new SHEntity());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
entityVec[eIndex]->entityID = eID;
|
||||||
|
entityVec[eIndex]->name = name;
|
||||||
|
for (auto& id : componentTypeIDs)
|
||||||
|
{
|
||||||
|
SHComponentManager::AddComponent(eID, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
//(SHComponentManager::AddComponent<ComponentTypes>(eID), ...);
|
||||||
|
|
||||||
|
//if (entityHandle.IsValid(parentEID) == false)
|
||||||
|
//{
|
||||||
|
// entityVec[eIndex]->sceneNode.ConnectToRoot();
|
||||||
|
//}
|
||||||
|
//else
|
||||||
|
//{
|
||||||
|
// entityVec[eIndex]->SetParent(parentEID);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//TODO Link to scene graph.
|
||||||
|
|
||||||
|
|
||||||
|
return eID;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SHEntityManager::DestroyEntity(EntityID eID) noexcept
|
||||||
|
{
|
||||||
|
if (!IsValidEID(eID))
|
||||||
|
{
|
||||||
|
//Entity does not exist or already destroyed.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
EntityIndex eIndex = entityHandle.GetIndex(eID);
|
||||||
|
|
||||||
|
//Call all the children to Destroy themselves first before the parent is destroyed.
|
||||||
|
if (entityVec[eIndex])
|
||||||
|
{
|
||||||
|
//auto& children = entityVec[eIndex]->GetChildrenID();
|
||||||
|
//while(!children.empty())
|
||||||
|
//{
|
||||||
|
// DestroyEntity(children[0]);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//SHSceneNode* parentNode = entityVec[eIndex]->GetSceneNode()->GetParent();
|
||||||
|
|
||||||
|
//SHSceneGraph::RemoveChild(parentNode,entityVec[eIndex].get());
|
||||||
|
|
||||||
|
//TODO remove from parent and recursively delete child.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
SHComponentManager::RemoveComponentsOfEntity(eID);
|
||||||
|
|
||||||
|
entityHandle.RemoveHandle(eID);
|
||||||
|
|
||||||
|
entityVec[eIndex].reset(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHEntityManager::DestroyAllEntity() noexcept
|
||||||
|
{
|
||||||
|
for (auto& entity : entityVec)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (entity)
|
||||||
|
{
|
||||||
|
DestroyEntity(entity->GetEID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entityHandle.ClearAllHandles();
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityIndex SHEntityManager::GetEntityCount() noexcept
|
||||||
|
{
|
||||||
|
return entityHandle.GetActiveHandleCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*EntityID SHEntityManager::DuplicateEntity(EntityID eid) noexcept
|
||||||
|
{
|
||||||
|
if (entityHandle.IsValid(eid) == false)
|
||||||
|
return MAX_EID;
|
||||||
|
|
||||||
|
std::string data = SHSerialization::SerializeEntityToString(eid);
|
||||||
|
return SHSerialization::DeserializeEntityToSceneFromString(data);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,253 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \file SHEntityManger.h
|
||||||
|
* \author Daniel Chua Yee Chen
|
||||||
|
* \brief Definition for the SHEntityManager class.
|
||||||
|
* Entity Manager is the interface class where users of the engine
|
||||||
|
* and its systems interact with entity data in the engine. This
|
||||||
|
* includes Creation and Destruction of entities and getting Entity by
|
||||||
|
* an ID. This manager also ensures that each entity have a unique
|
||||||
|
* handle using SHHandleGenerator.
|
||||||
|
*
|
||||||
|
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||||
|
or disclosure of this file or its contents without the prior written
|
||||||
|
consent of DigiPen Institute of Technology is prohibited.
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#ifndef SH_ENTITY_MANAGER_H
|
||||||
|
#define SH_ENTITY_MANAGER_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include "../Entity/SHEntity.h"
|
||||||
|
#include "../Components/SHComponent.h"
|
||||||
|
#include "../General/SHHandleGenerator.h"
|
||||||
|
#include "../SHECSMacros.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
|
||||||
|
class SHEntityManager
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static std::vector<std::unique_ptr<SHEntity>> entityVec;
|
||||||
|
//The handle generator to generate entityIDs.
|
||||||
|
static EntityHandleGenerator entityHandle;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SHEntityManager() = delete;
|
||||||
|
~SHEntityManager() = delete;
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Get a pointer to the entity using the entityID.
|
||||||
|
* \param entityID
|
||||||
|
* The entity ID of the entity
|
||||||
|
* \return
|
||||||
|
* A pointer to the entity.
|
||||||
|
* A nullptr is returned if there is no such entity or if it is destroyed.
|
||||||
|
***************************************************************************/
|
||||||
|
static SHEntity* GetEntityByID(EntityID entityID) noexcept;
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Checks if the current Entity ID is in use and alive.
|
||||||
|
* \param entityID
|
||||||
|
* The entity ID of the entity
|
||||||
|
* \return
|
||||||
|
* true if the entity ID is in use and alive.
|
||||||
|
***************************************************************************/
|
||||||
|
static bool IsValidEID(EntityID entityID) noexcept;
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Get the index portion of the Entity ID.
|
||||||
|
* \param entityID
|
||||||
|
* The entity ID of the entity
|
||||||
|
* \return
|
||||||
|
* The index of the entity
|
||||||
|
***************************************************************************/
|
||||||
|
static EntityIndex GetEntityIndex(EntityID entityID) noexcept;
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Template function to Create a new Entity with Components specified
|
||||||
|
* by the template arguements.
|
||||||
|
* \param name
|
||||||
|
* Name of the entity (This is not unique)
|
||||||
|
* \param parentEID
|
||||||
|
* The entity ID of the parent. This does not call UpdateHierarchy hence
|
||||||
|
* the parent of the entity is not updated until UpdateHierarchy is called.
|
||||||
|
* \return
|
||||||
|
* EntityID of the new Entity
|
||||||
|
***************************************************************************/
|
||||||
|
template<typename ...ComponentTypes>
|
||||||
|
static std::enable_if_t<(... && std::is_base_of_v<SHComponent, ComponentTypes>), EntityID> CreateEntity(std::string const& name = "Default", EntityID parentEID = MAX_EID)
|
||||||
|
{
|
||||||
|
EntityID eID = entityHandle.GetNewHandle();
|
||||||
|
EntityIndex eIndex = entityHandle.GetIndex(eID);
|
||||||
|
if (eIndex > entityVec.size())
|
||||||
|
{
|
||||||
|
assert("FATAL ERROR: EntityIndex out of range in Entity Creation");
|
||||||
|
}
|
||||||
|
else if (eIndex == entityVec.size())
|
||||||
|
{
|
||||||
|
entityVec.emplace_back(std::make_unique<SHEntity>());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!entityVec[eIndex])
|
||||||
|
{
|
||||||
|
//There is still an entity stored there.Something went wrong
|
||||||
|
assert("FATAL ERROR: Entity Creation error. Entity Index Conflict");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Reset it to a newly constructed entity
|
||||||
|
entityVec[eIndex].reset(new SHEntity());
|
||||||
|
}
|
||||||
|
entityVec[eIndex]->entityID = eID;
|
||||||
|
entityVec[eIndex]->name = name;
|
||||||
|
(SHComponentManager::AddComponent<ComponentTypes>(eID),...);
|
||||||
|
|
||||||
|
/*if (entityHandle.IsValid(parentEID) == false)
|
||||||
|
{
|
||||||
|
entityVec[eIndex]->sceneNode.ConnectToRoot();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
entityVec[eIndex]->SetParent(parentEID);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
//TODO Link up with Scene graph
|
||||||
|
|
||||||
|
return eID;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ...ComponentTypes>
|
||||||
|
static std::enable_if_t<(... && std::is_base_of_v<SHComponent, ComponentTypes>), EntityID> CreateEntity(EntityID desiredEID, std::string const& name = "Default", EntityID parentEID = MAX_EID)
|
||||||
|
{
|
||||||
|
EntityID eID;
|
||||||
|
if (entityHandle.ClaimHandle(desiredEID) == true)
|
||||||
|
eID = desiredEID;
|
||||||
|
else
|
||||||
|
eID = entityHandle.GetNewHandle();
|
||||||
|
EntityIndex eIndex = entityHandle.GetIndex(eID);
|
||||||
|
if (eIndex > entityVec.size())
|
||||||
|
{
|
||||||
|
EntityIndex size = (EntityIndex)entityVec.size();
|
||||||
|
for (EntityIndex i = 0; i <= eIndex - size; ++i)
|
||||||
|
{
|
||||||
|
entityVec.push_back(nullptr);
|
||||||
|
|
||||||
|
}
|
||||||
|
entityVec[eIndex].reset(new SHEntity());
|
||||||
|
}
|
||||||
|
else if (eIndex == entityVec.size())
|
||||||
|
{
|
||||||
|
entityVec.emplace_back(std::make_unique<SHEntity>());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!entityVec[eIndex])
|
||||||
|
{
|
||||||
|
//There is still an entity stored there.Something went wrong
|
||||||
|
assert("FATAL ERROR: Entity Creation error. Entity Index Conflict");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Reset it to a newly constructed entity
|
||||||
|
entityVec[eIndex].reset(new SHEntity());
|
||||||
|
}
|
||||||
|
entityVec[eIndex]->entityID = eID;
|
||||||
|
entityVec[eIndex]->name = name;
|
||||||
|
(SHComponentManager::AddComponent<ComponentTypes>(eID), ...);
|
||||||
|
|
||||||
|
/*if (entityHandle.IsValid(parentEID) == false)
|
||||||
|
{
|
||||||
|
entityVec[eIndex]->sceneNode.ConnectToRoot();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
entityVec[eIndex]->SetParent(parentEID);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
//Link up with scene graph.
|
||||||
|
|
||||||
|
|
||||||
|
return eID;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Create Entity using a vector of ComponentTypeIDs.
|
||||||
|
* \param componentTypeIDs
|
||||||
|
* Vector of ComponentTypeIDs. This assumes that CreateSparseSet is called
|
||||||
|
* for these ComponentTypes.
|
||||||
|
* \param name
|
||||||
|
* Name of the Entity (this is not unique)
|
||||||
|
* \param parentEID
|
||||||
|
* The entity ID of the parent. This does not call UpdateHierarchy hence
|
||||||
|
* the parent of the entity is not updated until UpdateHierarchy is called.
|
||||||
|
* \return
|
||||||
|
* EntityID of the new Entity
|
||||||
|
***************************************************************************/
|
||||||
|
static EntityID CreateEntity(std::vector<ComponentTypeID>const& componentTypeIDs,std::string const& name = "Default", EntityID parentEID = MAX_EID);
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Create Entity using a vector of ComponentTypeIDs.
|
||||||
|
* \param componentTypeIDs
|
||||||
|
* Vector of ComponentTypeIDs. This assumes that CreateSparseSet is called
|
||||||
|
* for these ComponentTypes.
|
||||||
|
* \param name
|
||||||
|
* Name of the Entity (this is not unique)
|
||||||
|
* \param parentEID
|
||||||
|
* The entity ID of the parent. This does not call UpdateHierarchy hence
|
||||||
|
* the parent of the entity is not updated until UpdateHierarchy is called.
|
||||||
|
* \return
|
||||||
|
* EntityID of the new Entity
|
||||||
|
***************************************************************************/
|
||||||
|
static EntityID CreateEntity(std::vector<ComponentTypeID>const& componentTypeIDs, EntityID desiredEID, std::string const& name = "Default", EntityID parentEID = MAX_EID);
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Destroy the entity and all components tied to this entity.
|
||||||
|
* This calls Destroy Entity for all of its children as well.
|
||||||
|
* \param eID
|
||||||
|
* The entity ID of the entity
|
||||||
|
* \return
|
||||||
|
* none
|
||||||
|
***************************************************************************/
|
||||||
|
static void DestroyEntity(EntityID eID) noexcept;
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Destroy all Entities.
|
||||||
|
* \return
|
||||||
|
* none
|
||||||
|
***************************************************************************/
|
||||||
|
static void DestroyAllEntity() noexcept;
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Get the current number of entities.
|
||||||
|
* \return
|
||||||
|
* Number of entities.
|
||||||
|
***************************************************************************/
|
||||||
|
static EntityIndex GetEntityCount() noexcept;
|
||||||
|
|
||||||
|
//static EntityID DuplicateEntity(EntityID eid) noexcept;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \file SHSystem.h
|
||||||
|
* \author Daniel Chua Yee Chen
|
||||||
|
* \brief Declaration for the SHSytem abstract base class
|
||||||
|
*
|
||||||
|
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||||
|
or disclosure of this file or its contents without the prior written
|
||||||
|
consent of DigiPen Institute of Technology is prohibited.
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#ifndef SH_SYSTEM_H
|
||||||
|
#define SH_SYSTEM_H
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
class SHSystem
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Protected default constructor for SHSytem class
|
||||||
|
***************************************************************************/
|
||||||
|
SHSystem()= default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Destructor for SHSytem class
|
||||||
|
***************************************************************************/
|
||||||
|
virtual ~SHSystem() = default;
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Pure virtual Init function. Derived class must implement this
|
||||||
|
***************************************************************************/
|
||||||
|
virtual void Init() = 0;
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Pure virtual Run function. Derived class must implement this
|
||||||
|
* \param dt
|
||||||
|
* Delta time
|
||||||
|
***************************************************************************/
|
||||||
|
virtual void Run(float dt) = 0;
|
||||||
|
|
||||||
|
/*!*************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Pure virtual Exit function. Derived class must implement this
|
||||||
|
***************************************************************************/
|
||||||
|
virtual void Exit() = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \file SHSystemManager.cpp
|
||||||
|
* \author Daniel Chua Yee Chen
|
||||||
|
* \brief Implementation for the SHSystemManager class.
|
||||||
|
* SHSystemManager is the interface class where users of the engine create
|
||||||
|
* the systems that gives the components their functionality. This also
|
||||||
|
* ensures that the Init and Exit functions are ran at the appropriate time
|
||||||
|
*
|
||||||
|
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||||
|
or disclosure of this file or its contents without the prior written
|
||||||
|
consent of DigiPen Institute of Technology is prohibited.
|
||||||
|
*********************************************************************/
|
||||||
|
#include "SHpch.h"
|
||||||
|
#include "SHSystemManager.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
SHSystemManager::SystemContainer SHSystemManager::systemContainer;
|
||||||
|
|
||||||
|
|
||||||
|
SHSystem* SHSystemManager::GetSystem(std::string name)
|
||||||
|
{
|
||||||
|
if (systemContainer.find(name) == systemContainer.end())
|
||||||
|
{
|
||||||
|
assert("Get System Error: No system with such name exist.");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return systemContainer.find(name)->second.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHSystemManager::Init() noexcept
|
||||||
|
{
|
||||||
|
for (auto& system : systemContainer)
|
||||||
|
{
|
||||||
|
system.second->Init();
|
||||||
|
#ifdef _DEBUG
|
||||||
|
std::cout << system.first << " Init" << std::endl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHSystemManager::Exit() noexcept
|
||||||
|
{
|
||||||
|
for (auto& system : systemContainer)
|
||||||
|
{
|
||||||
|
system.second->Exit();
|
||||||
|
//delete system.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
systemContainer.clear();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \file SHSystemManager.h
|
||||||
|
* \author Daniel Chua Yee Chen
|
||||||
|
* \brief Declaration for the SHSystemManager class.
|
||||||
|
* SHSystemManager is the interface class where users of the engine create
|
||||||
|
* the systems that gives the components their functionality. This also ensures that the Init and Exit functions are ran at the appropriate time
|
||||||
|
*
|
||||||
|
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||||
|
or disclosure of this file or its contents without the prior written
|
||||||
|
consent of DigiPen Institute of Technology is prohibited.
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef SH_SYSTEM_MANAGER_H
|
||||||
|
#define SH_SYSTEM_MANAGER_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <cassert>
|
||||||
|
#include "../System/SHSystem.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
|
||||||
|
class SHSystemManager
|
||||||
|
{
|
||||||
|
//type definition for the container we use to store our system
|
||||||
|
using SystemContainer = std::unordered_map<std::string, std::unique_ptr<SHSystem>>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static SystemContainer systemContainer;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*!*************************************************************************
|
||||||
|
* This class is used as a static class.
|
||||||
|
* No objects of this type should be created
|
||||||
|
***************************************************************************/
|
||||||
|
SHSystemManager() = delete;
|
||||||
|
~SHSystemManager() = delete;
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Create a system of type T and map it to a name.
|
||||||
|
* throws an error if a system with the same name already exists.
|
||||||
|
* \param name
|
||||||
|
* name of the system
|
||||||
|
* \return
|
||||||
|
* none
|
||||||
|
***************************************************************************/
|
||||||
|
template<typename T>
|
||||||
|
static std::enable_if_t<std::is_base_of_v<SHSystem, T>, void> CreateSystem(std::string const& name)
|
||||||
|
{
|
||||||
|
if (systemContainer.find(name) != systemContainer.end())
|
||||||
|
{
|
||||||
|
assert("System Creation Error: System with the same name already exist.");
|
||||||
|
}
|
||||||
|
|
||||||
|
systemContainer.emplace(name, std::make_unique<T>());
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Get a pointer to the System with a specified name.
|
||||||
|
* \param name
|
||||||
|
* Name of the system in the map
|
||||||
|
* \return
|
||||||
|
* Base System pointer.
|
||||||
|
***************************************************************************/
|
||||||
|
static SHSystem* GetSystem(std::string name);
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Call the Init function of all systems.
|
||||||
|
* \return
|
||||||
|
* none
|
||||||
|
***************************************************************************/
|
||||||
|
static void Init() noexcept;
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* \brief
|
||||||
|
* Call the Exit function of all systems.
|
||||||
|
* \return
|
||||||
|
***************************************************************************/
|
||||||
|
static void Exit() noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,2 +1 @@
|
||||||
#include "SHpch.h"
|
#include "SHpch.h"
|
||||||
#include "SHEngine.h"
|
|
|
@ -1,9 +1,39 @@
|
||||||
#pragma once
|
#ifndef SH_ENGINE_H
|
||||||
|
#define SH_ENGINE_H
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
#include "Meta/SHIsDetected.h"
|
||||||
|
|
||||||
namespace SHADE
|
namespace SHADE
|
||||||
{
|
{
|
||||||
|
template <typename Application>
|
||||||
|
using GetInit_t = decltype (std::declval<Application&>().Initialize());
|
||||||
|
|
||||||
|
template <typename Application>
|
||||||
|
using GetUpdate_t = decltype (std::declval<Application&>().Update());
|
||||||
|
|
||||||
|
template <typename Application>
|
||||||
|
using GetExit_t = decltype (std::declval<Application&>().Exit());
|
||||||
|
|
||||||
|
|
||||||
class SHEngine
|
class SHEngine
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <class Application, typename ... Args>
|
||||||
|
static void Run(Args&&...args)
|
||||||
|
{
|
||||||
|
//static_assert(SHIsDetected<GetInit_t, Application>::value, "Init Not Detected");
|
||||||
|
static_assert(SHIsDetected<GetUpdate_t, Application>::value, "Update Not Detected");
|
||||||
|
static_assert(SHIsDetected<GetExit_t, Application>::value, "Exit Not Detected");
|
||||||
|
|
||||||
|
static Application application;
|
||||||
|
|
||||||
|
application.Initialize(std::forward<Args>(args)...);
|
||||||
|
application.Update();
|
||||||
|
application.Exit();
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,460 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHVkBuffer.h"
|
||||||
|
#include "Graphics/Instance/SHVkInstance.h"
|
||||||
|
#include "Graphics/Commands/SHVkCommandBuffer.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
|
||||||
|
|
||||||
|
\param data
|
||||||
|
\param sizeToWrite
|
||||||
|
\param srcOffset
|
||||||
|
\param dstOffset
|
||||||
|
\param cmdBufferHdl
|
||||||
|
|
||||||
|
\return
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkBuffer::TransferToDeviceResource(Handle<SHVkCommandBuffer> const& cmdBufferHdl) noexcept
|
||||||
|
{
|
||||||
|
if (cmdBufferHdl && (bufferUsageFlags & vk::BufferUsageFlagBits::eTransferDst))
|
||||||
|
{
|
||||||
|
vk::BufferCopy copyRegion
|
||||||
|
{
|
||||||
|
.srcOffset = 0,
|
||||||
|
.dstOffset = 0,
|
||||||
|
.size = sizeStored,
|
||||||
|
};
|
||||||
|
cmdBufferHdl->GetVkCommandBuffer().copyBuffer(stagingBuffer, vkBuffer, 1, ©Region);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::Buffer SHVkBuffer::GetVkBuffer(void) const noexcept
|
||||||
|
{
|
||||||
|
return vkBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Maps the mappedPtr member pointer.
|
||||||
|
|
||||||
|
\param vmaAllocator
|
||||||
|
Required VmaAllocator for mapping.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkBuffer::Map(void) noexcept
|
||||||
|
{
|
||||||
|
if (!boundToCoherent)
|
||||||
|
vmaMapMemory(vmaAllocator, alloc, &mappedPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Unmaps the mappedPtr member pointer. Does not work if pointer is mapped
|
||||||
|
persistently (i.e. buffer is bound to coherent memory).
|
||||||
|
|
||||||
|
\param vmaAllocator
|
||||||
|
Required VmaAllocator for unmapping.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkBuffer::Unmap(void) noexcept
|
||||||
|
{
|
||||||
|
if (!boundToCoherent)
|
||||||
|
{
|
||||||
|
vmaUnmapMemory(vmaAllocator, alloc);
|
||||||
|
mappedPtr = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Writes to the mapped pointer.
|
||||||
|
|
||||||
|
\param data
|
||||||
|
Pointer to source data.
|
||||||
|
|
||||||
|
\param sizeToWrite
|
||||||
|
Amount to write to the buffer.
|
||||||
|
|
||||||
|
\param srcOffset
|
||||||
|
byte offset into the source data.
|
||||||
|
|
||||||
|
\param dstOffset
|
||||||
|
byte offset into the destination data.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkBuffer::WriteToMemory(void* data, uint32_t sizeToWrite, uint32_t srcOffset, uint32_t dstOffset) noexcept
|
||||||
|
{
|
||||||
|
if (mappedPtr)
|
||||||
|
std::memcpy(static_cast<uint8_t*>(mappedPtr) + dstOffset, static_cast<uint8_t*>(data) + srcOffset, sizeToWrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Simply writes data to a region of memory in the buffer. Mapping and
|
||||||
|
unmapping is also done if memory the buffer is bound to is HOST_VISIBLE.
|
||||||
|
Otherwise, only the copying is carried out.
|
||||||
|
|
||||||
|
In the instance where memory is non-coherent but HOST_VISIBLE, we want to
|
||||||
|
write to data and then unmap and flush it immediately. If you want to write
|
||||||
|
to memory in random-access fashion, consider, mapping, writing a few
|
||||||
|
things, unmapping then flushing.
|
||||||
|
|
||||||
|
\param vmaAllocator
|
||||||
|
The VMA allocator object.
|
||||||
|
|
||||||
|
\param data
|
||||||
|
Pointer to source data.
|
||||||
|
|
||||||
|
\param sizeToWrite
|
||||||
|
Amount to write to the buffer.
|
||||||
|
|
||||||
|
\param srcOffset
|
||||||
|
byte offset into the source data.
|
||||||
|
|
||||||
|
\param dstOffset
|
||||||
|
byte offset into the destination data.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkBuffer::MapWriteUnmap(void* data, uint32_t sizeToWrite, uint32_t srcOffset, uint32_t dstOffset) noexcept
|
||||||
|
{
|
||||||
|
if (!boundToCoherent)
|
||||||
|
{
|
||||||
|
// map from host visible memory to pointer, do a DMA, and then unmap
|
||||||
|
Map();
|
||||||
|
WriteToMemory(data, sizeToWrite, srcOffset, dstOffset);
|
||||||
|
Unmap();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (mappedPtr)
|
||||||
|
std::memcpy(static_cast<uint8_t*>(mappedPtr) + dstOffset, static_cast<uint8_t*>(data) + srcOffset, sizeToWrite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Prepares the staging buffer. Called only during initialization when it is
|
||||||
|
known that the buffer will be a GPU only resource. We want to prep the
|
||||||
|
staging buffer in advance so that transfers later will be straightforward.
|
||||||
|
|
||||||
|
\param data
|
||||||
|
The data to write to the staging buffer.
|
||||||
|
|
||||||
|
\param srcSize
|
||||||
|
The amount of data to transfer.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkBuffer::PrepStagingBuffer(void* data, uint32_t srcSize) noexcept
|
||||||
|
{
|
||||||
|
// For creation of buffer
|
||||||
|
vk::BufferCreateInfo bufferInfo{};
|
||||||
|
|
||||||
|
// size stored same as GPU buffer
|
||||||
|
bufferInfo.size = sizeStored;
|
||||||
|
|
||||||
|
// We just want to set the transfer bit
|
||||||
|
bufferInfo.usage = vk::BufferUsageFlagBits::eTransferSrc;
|
||||||
|
|
||||||
|
// sharing mode exclusive
|
||||||
|
bufferInfo.sharingMode = vk::SharingMode::eExclusive;
|
||||||
|
|
||||||
|
// Set to auto detect bits
|
||||||
|
VmaAllocationCreateInfo allocCreateInfo{};
|
||||||
|
allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO;
|
||||||
|
|
||||||
|
// We want to just write all at once. Using random access bit could make this slow
|
||||||
|
allocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
|
||||||
|
|
||||||
|
// parameters of a vmaAllocation retrieved via vmaGetAllocationInfo
|
||||||
|
VmaAllocationInfo allocInfo;
|
||||||
|
|
||||||
|
// results of allocation
|
||||||
|
VmaAllocation stagingAlloc;
|
||||||
|
|
||||||
|
// To get around VMA's usage for C version of vulkan, create a temp first...,
|
||||||
|
VkBuffer tempBuffer{};
|
||||||
|
|
||||||
|
// Create the buffer...
|
||||||
|
vmaCreateBuffer(vmaAllocator,
|
||||||
|
&bufferInfo.operator VkBufferCreateInfo & (), // TODO: Verify if this works (can use renderdoc to check buffer variables?)
|
||||||
|
&allocCreateInfo,
|
||||||
|
&tempBuffer, &stagingAlloc, &allocInfo);
|
||||||
|
|
||||||
|
// then assign it to the hpp version
|
||||||
|
stagingBuffer = tempBuffer;
|
||||||
|
|
||||||
|
// Just map, copy then unmap
|
||||||
|
void* stagingBufferMappedPtr = nullptr;
|
||||||
|
vmaMapMemory(vmaAllocator, stagingAlloc, &stagingBufferMappedPtr);
|
||||||
|
|
||||||
|
if (stagingBufferMappedPtr)
|
||||||
|
std::memcpy(static_cast<uint8_t*>(stagingBufferMappedPtr), static_cast<uint8_t*>(data), srcSize);
|
||||||
|
|
||||||
|
const VkDeviceSize offsets = 0;
|
||||||
|
const VkDeviceSize sizes = srcSize;
|
||||||
|
vmaFlushAllocations(vmaAllocator, 1, &stagingAlloc, &offsets, &sizes);
|
||||||
|
|
||||||
|
vmaUnmapMemory(vmaAllocator, stagingAlloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Default ctor. Initializes everything to 0 or false.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHVkBuffer::SHVkBuffer(std::reference_wrapper<VmaAllocator const> allocator) noexcept
|
||||||
|
: vkBuffer{}
|
||||||
|
, stagingBuffer{}
|
||||||
|
, sizeStored{ 0 }
|
||||||
|
, mappedPtr{ nullptr }
|
||||||
|
, alloc {nullptr}
|
||||||
|
, randomAccessOptimized{false}
|
||||||
|
, boundToCoherent {false}
|
||||||
|
, vmaAllocator{allocator}
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVkBuffer::SHVkBuffer(
|
||||||
|
uint32_t inSize,
|
||||||
|
void* data,
|
||||||
|
uint32_t srcSize,
|
||||||
|
std::reference_wrapper<VmaAllocator const> allocator,
|
||||||
|
vk::BufferUsageFlags bufferUsage,
|
||||||
|
VmaMemoryUsage memUsage,
|
||||||
|
VmaAllocationCreateFlags allocFlags
|
||||||
|
) noexcept
|
||||||
|
: SHVkBuffer(allocator)
|
||||||
|
{
|
||||||
|
Init(inSize, data, srcSize, bufferUsage, memUsage, allocFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVkBuffer::SHVkBuffer(SHVkBuffer&& rhs) noexcept
|
||||||
|
: vkBuffer{std::move (rhs.vkBuffer)}
|
||||||
|
, stagingBuffer{ std::move (rhs.stagingBuffer)}
|
||||||
|
, sizeStored{ std::move (rhs.sizeStored) }
|
||||||
|
, mappedPtr{ nullptr }
|
||||||
|
, alloc{ std::move (rhs.alloc) }
|
||||||
|
, randomAccessOptimized{ rhs.randomAccessOptimized }
|
||||||
|
, boundToCoherent{ rhs.boundToCoherent}
|
||||||
|
, vmaAllocator{ rhs.vmaAllocator }
|
||||||
|
, bufferUsageFlags {rhs.bufferUsageFlags}
|
||||||
|
|
||||||
|
{
|
||||||
|
rhs.vkBuffer = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVkBuffer& SHVkBuffer::operator=(SHVkBuffer&& rhs) noexcept
|
||||||
|
{
|
||||||
|
if (&rhs == this)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
vkBuffer = std::move(rhs.vkBuffer);
|
||||||
|
stagingBuffer = std::move(rhs.stagingBuffer);
|
||||||
|
sizeStored = std::move(rhs.sizeStored);
|
||||||
|
mappedPtr = nullptr;
|
||||||
|
alloc = std::move(rhs.alloc);
|
||||||
|
randomAccessOptimized = rhs.randomAccessOptimized;
|
||||||
|
boundToCoherent = rhs.boundToCoherent;
|
||||||
|
vmaAllocator = std::move (rhs.vmaAllocator);
|
||||||
|
rhs.vkBuffer = VK_NULL_HANDLE;
|
||||||
|
bufferUsageFlags = rhs.bufferUsageFlags;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVkBuffer::~SHVkBuffer(void) noexcept
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Initialize function. Mainly creates a vulkan buffer bound to a certain
|
||||||
|
region in a VMA memory chunk based on the size passed in. What memory
|
||||||
|
chunk this buffer is bound to is also dependent on the flag.
|
||||||
|
|
||||||
|
\param inSize
|
||||||
|
The size of the buffer.
|
||||||
|
|
||||||
|
\param data
|
||||||
|
Optional data for the user to pass in to perform immediate data transfer.
|
||||||
|
|
||||||
|
\param srcSize
|
||||||
|
Amount of (optional) data to copy to the buffer.
|
||||||
|
|
||||||
|
\param vmaAllocator
|
||||||
|
VMA allocator required for allocation to occur.
|
||||||
|
|
||||||
|
\param bufferUsage
|
||||||
|
Simple and easy. Can be used as a combination
|
||||||
|
(e.g. eVertexBuffer | eTransferDst).
|
||||||
|
|
||||||
|
\param memUsage
|
||||||
|
Usually set to VMA_MEMORY_USAGE_AUTO.
|
||||||
|
|
||||||
|
\param allocFlags
|
||||||
|
Most complicated parameter. Using VMA_RANDOM_ACCESS or VMA_SEQUENTIAL
|
||||||
|
would make the buffer bind to HOST_VISIBLE memory. Using
|
||||||
|
VMA_ALLOCATION_CREATE_MAPPED_BIT will map a pointer immediately (TODO:
|
||||||
|
Need to check if this bounds the buffer to coherent virtual memory. To
|
||||||
|
make this task simple, remember to check every instance of a VMA flag,
|
||||||
|
that the Vulkan flags are set accordingly: like if with sequential,
|
||||||
|
will the coherent bit be set).
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkBuffer::Init (
|
||||||
|
uint32_t inSize,
|
||||||
|
void* data,
|
||||||
|
uint32_t srcSize,
|
||||||
|
vk::BufferUsageFlags bufferUsage,
|
||||||
|
VmaMemoryUsage memUsage,
|
||||||
|
VmaAllocationCreateFlags allocFlags
|
||||||
|
) noexcept
|
||||||
|
{
|
||||||
|
sizeStored = inSize;
|
||||||
|
|
||||||
|
// For creation of buffer
|
||||||
|
vk::BufferCreateInfo bufferInfo{};
|
||||||
|
|
||||||
|
// initialize size and usage (vertex, index, uniform, etc)
|
||||||
|
bufferInfo.size = sizeStored;
|
||||||
|
bufferInfo.usage = bufferUsage;
|
||||||
|
bufferInfo.sharingMode = vk::SharingMode::eExclusive;
|
||||||
|
|
||||||
|
// Prepare allocation parameters for call to create buffers later
|
||||||
|
VmaAllocationCreateInfo allocCreateInfo{};
|
||||||
|
allocCreateInfo.usage = memUsage;
|
||||||
|
|
||||||
|
// If vma allocation flags include dedicated bit, immediately activate dst bit
|
||||||
|
if (allocCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT)
|
||||||
|
bufferInfo.usage |= vk::BufferUsageFlagBits::eTransferDst;
|
||||||
|
|
||||||
|
allocCreateInfo.flags = allocFlags;
|
||||||
|
|
||||||
|
// parameters of a vmaAllocation retrieved via vmaGetAllocationInfo
|
||||||
|
VmaAllocationInfo allocInfo;
|
||||||
|
|
||||||
|
// To get around VMA's usage for C version of vulkan, create a temp first...,
|
||||||
|
VkBuffer tempBuffer{};
|
||||||
|
|
||||||
|
// Create the buffer...
|
||||||
|
auto result = vmaCreateBuffer(vmaAllocator,
|
||||||
|
&bufferInfo.operator VkBufferCreateInfo &(),
|
||||||
|
&allocCreateInfo,
|
||||||
|
&tempBuffer, &alloc, &allocInfo);
|
||||||
|
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
SHVulkanDebugUtil::ReportVkError(vk::Result (result), "Failed to create vulkan buffer. ");
|
||||||
|
else
|
||||||
|
SHVulkanDebugUtil::ReportVkSuccess("Successfully created buffer. ");
|
||||||
|
|
||||||
|
// ...then assign it to the hpp version
|
||||||
|
vkBuffer = tempBuffer;
|
||||||
|
|
||||||
|
// Set the buffer flags
|
||||||
|
bufferUsageFlags = bufferInfo.usage;
|
||||||
|
|
||||||
|
// This probably means that a HOST_CACHED memory type is used on allocation
|
||||||
|
if (allocFlags & VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)
|
||||||
|
randomAccessOptimized = true;
|
||||||
|
|
||||||
|
/* There are 3 instances where buffers can be a GPU only resource :
|
||||||
|
1. When its for a DEDICATED large chunk of memory that is usually not touch ever again
|
||||||
|
like images that get destroyed and recreated every time window resizes.
|
||||||
|
2. When its for a memory type that is BOTH HOST_VISIBLE and DEVICE_LOCAL. This is known
|
||||||
|
base address register (BAR). If this address space is not available (which it should be on
|
||||||
|
most machines), fall back to use DEVICE_LOCAL memory and do the usual staging buffer memory transfer to
|
||||||
|
GPU resource.
|
||||||
|
3. When the buffer is initialized with a usage dst bit.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Get the memory property flags
|
||||||
|
VkMemoryPropertyFlags memPropFlags;
|
||||||
|
vmaGetAllocationMemoryProperties(vmaAllocator, alloc, &memPropFlags);
|
||||||
|
|
||||||
|
// mainly host visible. Can be cached (need to flush/invalidate), uncached (always coherent) and coherent (virtual).
|
||||||
|
if(memPropFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
|
||||||
|
{
|
||||||
|
// If memory is marked to be coherent between CPU and GPU (no need flush/invalidate) (TODO: Verify if VMA_ALLOCATION_CREATE_MAPPED_BIT is used when VMA_MEMORY_USAGE_AUTO is set)
|
||||||
|
// TODO: also verify that coherent bit = pointer is already mapped
|
||||||
|
if (memPropFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
|
||||||
|
{
|
||||||
|
boundToCoherent = true;
|
||||||
|
mappedPtr = allocInfo.pMappedData;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mappedPtr = nullptr;
|
||||||
|
|
||||||
|
if (data)
|
||||||
|
MapWriteUnmap(data, srcSize, 0, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We can prep first so that we can do transfers later via 1 cmd buffer recording
|
||||||
|
PrepStagingBuffer(data, srcSize);
|
||||||
|
|
||||||
|
// #NoteToSelf: Command buffers used to be an optional argument to perform the transfer immediately but it was removed because we
|
||||||
|
// don't want to allow such scenarios. Ideally, we want users to be transferring data to device memory together with
|
||||||
|
// other buffers that perform similar transfers.
|
||||||
|
//if (cmdBufferHdl) // check for null handle
|
||||||
|
//{
|
||||||
|
// // case 1 and case 3
|
||||||
|
// if (bufferInfo.usage & vk::BufferUsageFlagBits::eTransferDst)
|
||||||
|
// {
|
||||||
|
// TransferToDeviceResource(cmdBufferHdl);
|
||||||
|
// }
|
||||||
|
// //case 2
|
||||||
|
// else if (allocCreateInfo.flags & VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT)
|
||||||
|
// {
|
||||||
|
// // Need to check if BAR exists, if it doesn't, fall back to DEVICE_LOCAL, and do regular explicit transfers from staging
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Destroys the buffer.
|
||||||
|
|
||||||
|
\param allocator
|
||||||
|
VMA allocator required to destroy the buffer.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkBuffer::Destroy(void) noexcept
|
||||||
|
{
|
||||||
|
vmaDestroyBuffer(vmaAllocator, vkBuffer, alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
#ifndef SH_VK_BUFFER_H
|
||||||
|
#define SH_VK_BUFFER_H
|
||||||
|
|
||||||
|
#include "Graphics/SHVulkanIncludes.h"
|
||||||
|
#include "vk_mem_alloc.h"
|
||||||
|
#include "Resource/Handle.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
// Mainly so that middle end doesn't need to call "vk::"
|
||||||
|
//using SHVkBufferUsage = vk::BufferUsageFlags;
|
||||||
|
//using SHVkBufferUsageBits = vk::BufferUsageFlagBits;
|
||||||
|
|
||||||
|
class SHVkCommandBuffer;
|
||||||
|
|
||||||
|
class SHVkBuffer
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PRIVATE MEMBER VARIABLES */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
//! Vulkan handle to a vkBuffer
|
||||||
|
vk::Buffer vkBuffer;
|
||||||
|
|
||||||
|
//! When the buffer initialized to be a GPU only resource, this buffer will
|
||||||
|
//! be necessary to perform transfer to GPU either during initialization
|
||||||
|
//! or whenever the user wants it.
|
||||||
|
vk::Buffer stagingBuffer;
|
||||||
|
|
||||||
|
//! The amount of memory this buffer is bound to in device/host memory
|
||||||
|
uint32_t sizeStored;
|
||||||
|
|
||||||
|
//! Persistently mapped pointer if applicable (will be void if buffer is
|
||||||
|
//! not created with the correct flags). Note that this is only used for
|
||||||
|
//! persistent mapping. One time updates do not use this pointer.
|
||||||
|
void* mappedPtr;
|
||||||
|
|
||||||
|
//! allocation object containing details of an allocation
|
||||||
|
VmaAllocation alloc;
|
||||||
|
|
||||||
|
//! If initialized with vma random access flag, this is true
|
||||||
|
bool randomAccessOptimized;
|
||||||
|
|
||||||
|
//! Whether or not this buffer is bound to coherent memory
|
||||||
|
bool boundToCoherent;
|
||||||
|
|
||||||
|
//! buffer usage info flags
|
||||||
|
vk::BufferUsageFlags bufferUsageFlags;
|
||||||
|
|
||||||
|
//! Reference to the allocator
|
||||||
|
//VmaAllocator const& vmaAllocator;
|
||||||
|
std::reference_wrapper<VmaAllocator const> vmaAllocator;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PRIVATE MEMBER FUNCTIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
void PrepStagingBuffer (void* data, uint32_t srcSize) noexcept;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* CTORS AND DTORS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
SHVkBuffer (void) noexcept = delete;
|
||||||
|
SHVkBuffer (std::reference_wrapper<VmaAllocator const> allocator) noexcept;
|
||||||
|
SHVkBuffer (
|
||||||
|
uint32_t inSize,
|
||||||
|
void* data,
|
||||||
|
uint32_t srcSize,
|
||||||
|
std::reference_wrapper<VmaAllocator const> allocator,
|
||||||
|
vk::BufferUsageFlags bufferUsage,
|
||||||
|
VmaMemoryUsage memUsage,
|
||||||
|
VmaAllocationCreateFlags allocFlags
|
||||||
|
) noexcept;
|
||||||
|
SHVkBuffer(SHVkBuffer&& rhs) noexcept;
|
||||||
|
SHVkBuffer& operator=(SHVkBuffer&& rhs) noexcept;
|
||||||
|
~SHVkBuffer(void) noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PUBLIC MEMBER VARIABLES */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
void Init (
|
||||||
|
uint32_t inSize,
|
||||||
|
void* data,
|
||||||
|
uint32_t srcSize,
|
||||||
|
vk::BufferUsageFlags bufferUsage,
|
||||||
|
VmaMemoryUsage memUsage,
|
||||||
|
VmaAllocationCreateFlags allocFlags
|
||||||
|
) noexcept;
|
||||||
|
void Destroy (void) noexcept;
|
||||||
|
|
||||||
|
void Map (void) noexcept;
|
||||||
|
void Unmap (void) noexcept;
|
||||||
|
void WriteToMemory (void* data, uint32_t sizeToWrite, uint32_t srcOffset, uint32_t dstOffset) noexcept;
|
||||||
|
void MapWriteUnmap (void* data, uint32_t sizeToWrite, uint32_t srcOffset, uint32_t dstOffset) noexcept;
|
||||||
|
void TransferToDeviceResource(Handle<SHVkCommandBuffer> const& cmdBufferHdl) noexcept;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* SETTERS AND GETTERS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
vk::Buffer GetVkBuffer (void) const noexcept;
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef SH_COMMAND_POOL_RESET_H
|
||||||
|
#define SH_COMMAND_POOL_RESET_H
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
enum class SH_CMD_POOL_RESET
|
||||||
|
{
|
||||||
|
POOL_BASED,
|
||||||
|
BUFFER_BASED,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,641 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHVkCommandBuffer.h"
|
||||||
|
#include "SHVkCommandPool.h"
|
||||||
|
#include "Graphics/Devices/SHVkLogicalDevice.h"
|
||||||
|
#include "SHVkCommandPool.h"
|
||||||
|
#include "Tools/SHLogger.h"
|
||||||
|
#include "Graphics/Renderpass/SHVkRenderpass.h"
|
||||||
|
#include "Graphics/Framebuffer/SHVkFramebuffer.h"
|
||||||
|
#include "Graphics/Pipeline/SHVkPipeline.h"
|
||||||
|
#include "Graphics/Buffers/SHVkBuffer.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Frees the command buffer.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHVkCommandBuffer::~SHVkCommandBuffer(void) noexcept
|
||||||
|
{
|
||||||
|
if (vkCommandBuffer)
|
||||||
|
parentPool->GetLogicalDevice()->GetVkLogicalDevice().freeCommandBuffers(parentPool->GetVkCommandPool(), commandBufferCount, &vkCommandBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Only the command buffer is allocated using
|
||||||
|
VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit, is resetting
|
||||||
|
individually permitted. Otherwise, throw exception. IMPORTANT NOTE:
|
||||||
|
the command buffer cannot be in the pending state!!!
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkCommandBuffer::Reset(void)
|
||||||
|
{
|
||||||
|
if (cmdBufferState == SH_CMD_BUFFER_STATE::PENDING)
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("Command buffer in pending state, could not reset. ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parentPool->GetPoolResetMode() != SH_CMD_POOL_RESET::BUFFER_BASED)
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("Parent Command Pool was not initialized with VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT. Cannot reset independently. ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vkCommandBuffer.reset(vk::CommandBufferResetFlagBits::eReleaseResources);
|
||||||
|
|
||||||
|
if (cmdBufferState == SH_CMD_BUFFER_STATE::RECORDING || cmdBufferState == SH_CMD_BUFFER_STATE::EXECUTABLE)
|
||||||
|
{
|
||||||
|
cmdBufferState = SH_CMD_BUFFER_STATE::INVALID;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdBufferState != SH_CMD_BUFFER_STATE::INVALID)
|
||||||
|
cmdBufferState = SH_CMD_BUFFER_STATE::INITIAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Begins the command buffer.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkCommandBuffer::BeginRecording(void) noexcept
|
||||||
|
{
|
||||||
|
// Check if command buffer is ready to record.
|
||||||
|
if (cmdBufferState != SH_CMD_BUFFER_STATE::INITIAL)
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("Command buffer not in initial state, cannot begin recording. ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Struct for recording
|
||||||
|
vk::CommandBufferBeginInfo beginInfo{};
|
||||||
|
|
||||||
|
beginInfo.flags = usageFlags;
|
||||||
|
// TODO: Allow passing in inheritance info.
|
||||||
|
|
||||||
|
// Attempt to begin recording
|
||||||
|
if (auto result = vkCommandBuffer.begin(&beginInfo); result != vk::Result::eSuccess)
|
||||||
|
{
|
||||||
|
SHVulkanDebugUtil::ReportVkError(result, "Failed to begin command buffer. ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't need to print record success
|
||||||
|
//else
|
||||||
|
// SHVulkanDebugUtil::ReportVkSuccess("Command buffer successfully begun recording... ");
|
||||||
|
|
||||||
|
// Set the state to recording if the call above succeeded.
|
||||||
|
cmdBufferState = SH_CMD_BUFFER_STATE::RECORDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
End the recording of a command buffer.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkCommandBuffer::EndRecording(void) noexcept
|
||||||
|
{
|
||||||
|
if (cmdBufferState != SH_CMD_BUFFER_STATE::RECORDING)
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("Command Buffer not in recording state, cannot end recording. ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vkCommandBuffer.end();
|
||||||
|
cmdBufferState = SH_CMD_BUFFER_STATE::EXECUTABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Begins a renderpass in the command buffer. 2 important things to note
|
||||||
|
here, the command buffer used MUST be a primary command buffer and
|
||||||
|
command buffer MUST be in a recording state.
|
||||||
|
|
||||||
|
\param renderpassHdl
|
||||||
|
Renderpass for obvious reasons.
|
||||||
|
|
||||||
|
\param framebufferHdl
|
||||||
|
Framebuffer required in the begin info.
|
||||||
|
|
||||||
|
\param offset
|
||||||
|
Offset of the render area in the framebuffer.
|
||||||
|
|
||||||
|
\param extent
|
||||||
|
Extent of the render area in the framebuffer.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkCommandBuffer::BeginRenderpass(Handle<SHVkRenderpass> const& renderpassHdl, Handle<SHVkFramebuffer> const& framebufferHdl, vk::Offset2D offset, vk::Extent2D extent) noexcept
|
||||||
|
{
|
||||||
|
// cannot begin renderpass if command buffer is primary
|
||||||
|
if (commandBufferType != SH_CMD_BUFFER_TYPE::PRIMARY)
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("Cannot begin renderpass. Command buffer is not a primary command buffer. ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cannot begin renderpass if command buffer is not recording
|
||||||
|
if (cmdBufferState != SH_CMD_BUFFER_STATE::RECORDING)
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("Command buffer must have started recording before a renderpass instance can begin. ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::Extent2D framebufferExtent{ framebufferHdl->GetWidth(), framebufferHdl->GetHeight() };
|
||||||
|
|
||||||
|
// Prepare renderpass begin
|
||||||
|
vk::RenderPassBeginInfo renderPassInfo{};
|
||||||
|
renderPassInfo.renderPass = renderpassHdl->GetVkRenderpass();
|
||||||
|
renderPassInfo.framebuffer = framebufferHdl->GetVkFramebuffer();
|
||||||
|
|
||||||
|
// If the extent passed in is 0, use the framebuffer dimensions instead.
|
||||||
|
if (extent.width == 0 && extent.height == 0)
|
||||||
|
renderPassInfo.renderArea.extent = framebufferExtent;
|
||||||
|
else
|
||||||
|
renderPassInfo.renderArea.extent = extent;
|
||||||
|
|
||||||
|
// assign offset
|
||||||
|
renderPassInfo.renderArea.offset = offset;
|
||||||
|
|
||||||
|
// prepare clear colors
|
||||||
|
auto const& clearColors = renderpassHdl->GetClearColors();
|
||||||
|
renderPassInfo.clearValueCount = static_cast<uint32_t>(clearColors.size());
|
||||||
|
renderPassInfo.pClearValues = clearColors.data();
|
||||||
|
|
||||||
|
// Check if render area is optimal
|
||||||
|
if (!IsRenderAreaOptimal(renderpassHdl, framebufferExtent, renderPassInfo.renderArea))
|
||||||
|
SHLOG_ERROR("Render area in renderpass begin info is not optimal. See Vulkan vkGetRenderAreaGranularity for details.");
|
||||||
|
|
||||||
|
// Begin the render pass
|
||||||
|
vkCommandBuffer.beginRenderPass (&renderPassInfo, vk::SubpassContents::eInline);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Ends a renderpass.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkCommandBuffer::EndRenderpass(void) noexcept
|
||||||
|
{
|
||||||
|
vkCommandBuffer.endRenderPass();
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Sets the viewport dynamically for the command buffer. #NoteToSelf:
|
||||||
|
Dynamic state will not affect pipelines that don't use dynamic state
|
||||||
|
so there isn't a need to do any checks. Also, setting dynamic state like
|
||||||
|
this only needs to happen ONCE per command buffer UNLESS a different
|
||||||
|
viewport is to be used for different drawing commands.
|
||||||
|
|
||||||
|
\param vpWidth
|
||||||
|
viewport width
|
||||||
|
|
||||||
|
\param vpHeight
|
||||||
|
viewport height
|
||||||
|
|
||||||
|
\param sWidth
|
||||||
|
Scissor extent width
|
||||||
|
|
||||||
|
\param sHeight
|
||||||
|
Scissor extent height
|
||||||
|
|
||||||
|
\param vpX
|
||||||
|
Viewport offset X.
|
||||||
|
|
||||||
|
\param vpY
|
||||||
|
Viewport offset Y.
|
||||||
|
|
||||||
|
\param sX
|
||||||
|
Scissor offset X.
|
||||||
|
|
||||||
|
\param sY
|
||||||
|
Scissor offset Y.
|
||||||
|
|
||||||
|
\param vpMinDepth
|
||||||
|
viewport minimum depth value
|
||||||
|
|
||||||
|
\param vpMaxDepth
|
||||||
|
viewport maximum depth value
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkCommandBuffer::SetviewportScissor(float vpWidth, float vpHeight, uint32_t sWidth, uint32_t sHeight, float vpX /*= 0.0f*/, float vpY /*= 0.0f*/, int32_t sX /*= 0.0f*/, int32_t sY /*= 0.0f*/, float vpMinDepth /*= 0.0f*/, float vpMaxDepth /*= 1.0f*/) noexcept
|
||||||
|
{
|
||||||
|
vk::Viewport dynamicViewport
|
||||||
|
{
|
||||||
|
.x = vpX,
|
||||||
|
.y = vpY,
|
||||||
|
.width = vpWidth,
|
||||||
|
.height = vpHeight,
|
||||||
|
.minDepth = vpMinDepth,
|
||||||
|
.maxDepth = vpMaxDepth,
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::Rect2D dynamicScissor
|
||||||
|
{
|
||||||
|
.offset = vk::Offset2D{sX, sY},
|
||||||
|
.extent = vk::Extent2D{sWidth, sHeight}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Dynamic state set viewport and scissor
|
||||||
|
vkCommandBuffer.setScissor(0, 1, &dynamicScissor);
|
||||||
|
vkCommandBuffer.setViewport(0, 1, &dynamicViewport);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Binds a pipeline object to the command buffer.
|
||||||
|
|
||||||
|
\param pipelineHdl
|
||||||
|
The pipeline to bind.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkCommandBuffer::BindPipeline(Handle<SHVkPipeline> const& pipelineHdl) noexcept
|
||||||
|
{
|
||||||
|
if (cmdBufferState != SH_CMD_BUFFER_STATE::RECORDING)
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("Command buffer must have started recording before a pipeline can be bound. ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
boundPipelineLayoutHdl = pipelineHdl->GetPipelineLayout();
|
||||||
|
vkCommandBuffer.bindPipeline(pipelineHdl->GetPipelineBindPoint(), pipelineHdl->GetVkPipeline());
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Binds a buffer to the vertex buffer binding point specified in
|
||||||
|
bindingPoint.
|
||||||
|
|
||||||
|
\param bindingPoint
|
||||||
|
The binding point to initialize a vertex
|
||||||
|
|
||||||
|
\param buffer
|
||||||
|
The buffer to bind
|
||||||
|
|
||||||
|
\param offset
|
||||||
|
The offset to start from in the buffer for the first binding point.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkCommandBuffer::BindVertexBuffer (uint32_t bindingPoint, Handle<SHVkBuffer> const& buffer, vk::DeviceSize offset) noexcept
|
||||||
|
{
|
||||||
|
if (cmdBufferState == SH_CMD_BUFFER_STATE::RECORDING)
|
||||||
|
{
|
||||||
|
auto bufferHandle = buffer->GetVkBuffer();
|
||||||
|
vkCommandBuffer.bindVertexBuffers (bindingPoint, 1, &bufferHandle, &offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Binds an index buffer to the pipeline.
|
||||||
|
|
||||||
|
\param buffer
|
||||||
|
The buffer to bind.
|
||||||
|
|
||||||
|
\param startingIndex
|
||||||
|
The starting index in the index buffer. For example, 0 would mean
|
||||||
|
starting at the beginning. 5 would mean starting at byte offset
|
||||||
|
size(uint32_t) * 5.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkCommandBuffer::BindIndexBuffer(Handle<SHVkBuffer> const& buffer, uint32_t startingIndex) const noexcept
|
||||||
|
{
|
||||||
|
if (cmdBufferState == SH_CMD_BUFFER_STATE::RECORDING)
|
||||||
|
{
|
||||||
|
auto bufferHandle = buffer->GetVkBuffer();
|
||||||
|
vkCommandBuffer.bindIndexBuffer (bufferHandle, sizeof (uint32_t) * startingIndex, vk::IndexType::eUint32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Calls vkCmdDraw.
|
||||||
|
|
||||||
|
\param vertexCount
|
||||||
|
How many vertices to draw
|
||||||
|
|
||||||
|
\param instanceCount
|
||||||
|
Number of instances to draw
|
||||||
|
|
||||||
|
\param firstVertex
|
||||||
|
First vertex in the buffer of vertices to start from
|
||||||
|
|
||||||
|
\param firstInstance
|
||||||
|
First instance to start from.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkCommandBuffer::DrawArrays(uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) const noexcept
|
||||||
|
{
|
||||||
|
if (cmdBufferState != SH_CMD_BUFFER_STATE::RECORDING)
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("Command buffer must have started recording before a pipeline can be bound. ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vkCommandBuffer.draw (vertexCount, instanceCount, firstVertex, firstInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Issues a non-instanced indexed draw call.
|
||||||
|
|
||||||
|
\param indexCount
|
||||||
|
Number of indices to draw.
|
||||||
|
|
||||||
|
\param firstIndex
|
||||||
|
Starting index. if the array was 0, 2, 5, 4, and we indicated this to be
|
||||||
|
1. The draw call would start from index 2.
|
||||||
|
|
||||||
|
\param vertexOffset
|
||||||
|
Starting vertex offset. This would indicate that vertex pulling should
|
||||||
|
start from a certain vertex. So a vertex offset of 3 (for example) would
|
||||||
|
mean an index of 0 would mean the 3rd vertex.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkCommandBuffer::DrawIndexed (uint32_t indexCount, uint32_t firstIndex, uint32_t vertexOffset) const noexcept
|
||||||
|
{
|
||||||
|
if (cmdBufferState != SH_CMD_BUFFER_STATE::RECORDING)
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("Command buffer must have started recording before a pipeline can be bound. ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// not an instanced call so we want to make the instanced related stuff hard coded
|
||||||
|
vkCommandBuffer.drawIndexed(indexCount, 1, firstIndex, vertexOffset, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Calls vkCmdPushConstants and submits data stored in command buffer.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkCommandBuffer::SubmitPushConstants(void) const noexcept
|
||||||
|
{
|
||||||
|
vkCommandBuffer.pushConstants(boundPipelineLayoutHdl->GetVkPipelineLayout(),
|
||||||
|
boundPipelineLayoutHdl->GetPushConstantInterface().GetShaderStageFlags(),
|
||||||
|
0,
|
||||||
|
boundPipelineLayoutHdl->GetPushConstantInterface().GetSize(), pushConstantData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Simply returns the command buffer handle.
|
||||||
|
|
||||||
|
\return
|
||||||
|
The command buffer handle.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
vk::CommandBuffer const& SHVkCommandBuffer::GetVkCommandBuffer(void) const noexcept
|
||||||
|
{
|
||||||
|
return vkCommandBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
See https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetRenderAreaGranularity.html
|
||||||
|
or look up vkGetRenderAreaGranularity.
|
||||||
|
|
||||||
|
\param renderpassHdl
|
||||||
|
Renderpass to get info from.
|
||||||
|
|
||||||
|
\param framebufferExtent
|
||||||
|
For the comparison. Again, look it up on the webpage.
|
||||||
|
|
||||||
|
\param renderArea
|
||||||
|
For the comparison. Again, look it up on the webpage.
|
||||||
|
|
||||||
|
\return
|
||||||
|
If optimal, true. otherwise false.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
bool SHVkCommandBuffer::IsRenderAreaOptimal(Handle<SHVkRenderpass> const& renderpassHdl, vk::Extent2D const& framebufferExtent, vk::Rect2D const& renderArea) const noexcept
|
||||||
|
{
|
||||||
|
vk::Extent2D granularity = parentPool->GetLogicalDevice()->GetVkLogicalDevice().getRenderAreaGranularity(renderpassHdl->GetVkRenderpass());
|
||||||
|
|
||||||
|
return (renderArea.offset.x % granularity.width == 0 && renderArea.offset.y % granularity.height == 0 &&
|
||||||
|
(renderArea.extent.width % granularity.width || renderArea.offset.x + renderArea.extent.width == framebufferExtent.width) &&
|
||||||
|
(renderArea.extent.height % granularity.height || renderArea.offset.y + renderArea.extent.height == framebufferExtent.height));
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Setter for the state of the command buffer.
|
||||||
|
|
||||||
|
\param state
|
||||||
|
|
||||||
|
\return
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkCommandBuffer::SetState(SH_CMD_BUFFER_STATE state) noexcept
|
||||||
|
{
|
||||||
|
cmdBufferState = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Returns the state of the command buffer.
|
||||||
|
|
||||||
|
\return
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SH_CMD_BUFFER_STATE SHVkCommandBuffer::GetState(void) const noexcept
|
||||||
|
{
|
||||||
|
return cmdBufferState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Creates a command buffer. Cmd buffer can be primary or secondary. If
|
||||||
|
secondary, flags will automatically have renderpass continue bit. Command
|
||||||
|
pool used to create this command buffer will determine whether or not
|
||||||
|
this buffer will be allocated with
|
||||||
|
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT using the reset mode.
|
||||||
|
|
||||||
|
\param logicalDevice
|
||||||
|
Need a logical device to create a buffer.
|
||||||
|
|
||||||
|
\param commandPool
|
||||||
|
Command buffer to allocate from.
|
||||||
|
|
||||||
|
\param type
|
||||||
|
Type of the command buffer; primary or secondary.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHVkCommandBuffer::SHVkCommandBuffer(Handle<SHVkCommandPool> const& commandPool, SH_CMD_BUFFER_TYPE type) noexcept
|
||||||
|
: vkCommandBuffer{ nullptr }
|
||||||
|
, cmdBufferState{ SH_CMD_BUFFER_STATE::INVALID } // Command buffer will be in initial state
|
||||||
|
, commandBufferType{ SH_CMD_BUFFER_TYPE::PRIMARY }
|
||||||
|
, parentPoolResetMode{ SH_CMD_POOL_RESET::POOL_BASED }
|
||||||
|
, usageFlags{}
|
||||||
|
, commandBufferCount{ 0 }
|
||||||
|
, parentPool{commandPool}
|
||||||
|
|
||||||
|
{
|
||||||
|
vk::CommandBufferAllocateInfo allocateInfo{};
|
||||||
|
allocateInfo.commandPool = commandPool->GetVkCommandPool();
|
||||||
|
|
||||||
|
// don't know if there are performance implications if this is set to always be 1. Could be better to create more at once
|
||||||
|
allocateInfo.commandBufferCount = 1;
|
||||||
|
|
||||||
|
// Set the type of command buffer (primary or secondary)
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case SH_CMD_BUFFER_TYPE::PRIMARY:
|
||||||
|
allocateInfo.level = vk::CommandBufferLevel::ePrimary;
|
||||||
|
break;
|
||||||
|
case SH_CMD_BUFFER_TYPE::SECONDARY:
|
||||||
|
allocateInfo.level = vk::CommandBufferLevel::eSecondary;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to allocate command buffers
|
||||||
|
if (auto result = commandPool->GetLogicalDevice()->GetVkLogicalDevice().allocateCommandBuffers(&allocateInfo, &vkCommandBuffer); result != vk::Result::eSuccess)
|
||||||
|
{
|
||||||
|
SHVulkanDebugUtil::ReportVkError(result, "Failed to create Command Buffer. ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
SHVulkanDebugUtil::ReportVkSuccess("Successfully created Command Buffer.");
|
||||||
|
|
||||||
|
// Set the state only after successfully allocating
|
||||||
|
cmdBufferState = SH_CMD_BUFFER_STATE::INITIAL;
|
||||||
|
|
||||||
|
// Parent command pool
|
||||||
|
parentPool = commandPool;
|
||||||
|
|
||||||
|
// Save some important info
|
||||||
|
parentPoolResetMode = parentPool->GetPoolResetMode();
|
||||||
|
commandBufferType = type;
|
||||||
|
commandBufferCount = allocateInfo.commandBufferCount;
|
||||||
|
|
||||||
|
if (parentPool->GetIsTransient ())
|
||||||
|
usageFlags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit;
|
||||||
|
|
||||||
|
if (commandBufferType == SH_CMD_BUFFER_TYPE::SECONDARY)
|
||||||
|
usageFlags |= vk::CommandBufferUsageFlagBits::eRenderPassContinue;
|
||||||
|
|
||||||
|
// Reset all the push constant data to 0
|
||||||
|
memset (pushConstantData, 0, PUSH_CONSTANT_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Move ctor. Invalidates Vulkan handles.
|
||||||
|
|
||||||
|
\param rhs
|
||||||
|
the other command buffer.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHVkCommandBuffer::SHVkCommandBuffer(SHVkCommandBuffer&& rhs) noexcept
|
||||||
|
: vkCommandBuffer {std::move (rhs.vkCommandBuffer)}
|
||||||
|
, cmdBufferState {rhs.cmdBufferState}
|
||||||
|
, commandBufferType {rhs.commandBufferType}
|
||||||
|
, parentPoolResetMode {rhs.parentPoolResetMode}
|
||||||
|
, usageFlags {rhs.usageFlags}
|
||||||
|
, commandBufferCount {rhs.commandBufferCount}
|
||||||
|
, parentPool {rhs.parentPool}
|
||||||
|
, boundPipelineLayoutHdl{rhs.boundPipelineLayoutHdl }
|
||||||
|
{
|
||||||
|
memcpy (pushConstantData, rhs.pushConstantData, PUSH_CONSTANT_SIZE);
|
||||||
|
|
||||||
|
rhs.vkCommandBuffer = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Move assignment operator. Invalidates Vulkan handles.
|
||||||
|
|
||||||
|
\param rhs
|
||||||
|
The other Vulkan Handle.
|
||||||
|
|
||||||
|
\return
|
||||||
|
a reference itself.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHVkCommandBuffer& SHVkCommandBuffer::operator=(SHVkCommandBuffer&& rhs) noexcept
|
||||||
|
{
|
||||||
|
if (&rhs == this)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
vkCommandBuffer = std::move(rhs.vkCommandBuffer);
|
||||||
|
cmdBufferState = rhs.cmdBufferState;
|
||||||
|
commandBufferType = rhs.commandBufferType;
|
||||||
|
parentPoolResetMode = rhs.parentPoolResetMode;
|
||||||
|
usageFlags = rhs.usageFlags;
|
||||||
|
commandBufferCount = rhs.commandBufferCount;
|
||||||
|
parentPool = rhs.parentPool;
|
||||||
|
boundPipelineLayoutHdl = rhs.boundPipelineLayoutHdl;
|
||||||
|
memcpy(pushConstantData, rhs.pushConstantData, PUSH_CONSTANT_SIZE);
|
||||||
|
|
||||||
|
rhs.vkCommandBuffer = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,134 @@
|
||||||
|
#ifndef SH_COMMAND_BUFFER_H
|
||||||
|
#define SH_COMMAND_BUFFER_H
|
||||||
|
|
||||||
|
#include "Graphics/SHVulkanIncludes.h"
|
||||||
|
#include "Graphics/SHVulkanDefines.h"
|
||||||
|
#include "SHCommandPoolResetMode.h"
|
||||||
|
#include "Resource/ResourceLibrary.h"
|
||||||
|
#include "Graphics/Pipeline/SHVkPipelineLayout.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
class SHVkCommandPool;
|
||||||
|
class SHVkLogicalDevice;
|
||||||
|
class SHVkRenderpass;
|
||||||
|
class SHVkFramebuffer;
|
||||||
|
class SHVkPipeline;
|
||||||
|
class SHVkBuffer;
|
||||||
|
|
||||||
|
enum class SH_CMD_BUFFER_TYPE
|
||||||
|
{
|
||||||
|
PRIMARY,
|
||||||
|
SECONDARY,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SH_CMD_BUFFER_STATE
|
||||||
|
{
|
||||||
|
INITIAL, // Can be moved to recording state or freed
|
||||||
|
RECORDING, // vkBeginCommandBuffer changes state from initial state to recording state.
|
||||||
|
EXECUTABLE, // Can be submitted, reset or recorded to another command buffer.
|
||||||
|
INVALID, // Enters invalid state when buffer created with ONE_TIME_SUBMIT_BIT finishes execution. Primaries also enter the invalid state when secondaries enter invalid or initial state
|
||||||
|
PENDING // Cmd buffer enters this state after being submitted to queue.
|
||||||
|
};
|
||||||
|
|
||||||
|
class SHVkCommandBuffer
|
||||||
|
{
|
||||||
|
friend class SHVkCommandPool;
|
||||||
|
friend class ResourceLibrary<SHVkCommandBuffer>;
|
||||||
|
|
||||||
|
static constexpr uint16_t PUSH_CONSTANT_SIZE = 512;
|
||||||
|
private:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PRIVATE MEMBER VARIABLES */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
//! Vulkan handle to a command buffer
|
||||||
|
vk::CommandBuffer vkCommandBuffer;
|
||||||
|
|
||||||
|
//! state of the command buffer. TODO: Test some state changes.
|
||||||
|
SH_CMD_BUFFER_STATE cmdBufferState;
|
||||||
|
|
||||||
|
//! Command buffer type
|
||||||
|
SH_CMD_BUFFER_TYPE commandBufferType;
|
||||||
|
|
||||||
|
//! Stores the reset mode of the command pool. This is so that when we
|
||||||
|
//! try to reset command buffers individually, we want to do it only when
|
||||||
|
//! the reset mode is set to COMMAND_BUFFER_RESET only.
|
||||||
|
SH_CMD_POOL_RESET parentPoolResetMode;
|
||||||
|
|
||||||
|
//! Flags of the command buffer (ONE_TIME_USE, RENDERPASS_CONTINUE, SIMULTANEOUS_USAGE)
|
||||||
|
vk::CommandBufferUsageFlags usageFlags;
|
||||||
|
|
||||||
|
//! When allocating, you can specify how many command buffers to allocate
|
||||||
|
uint32_t commandBufferCount;
|
||||||
|
|
||||||
|
//! The command pool that this command buffer belongs to
|
||||||
|
Handle<SHVkCommandPool> parentPool;
|
||||||
|
|
||||||
|
//! The currently bound pipeline
|
||||||
|
Handle<SHVkPipelineLayout> boundPipelineLayoutHdl;
|
||||||
|
|
||||||
|
//! The push constant data for the command buffer
|
||||||
|
uint8_t pushConstantData[PUSH_CONSTANT_SIZE];
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PRIVATE MEMBER FUNCTIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
bool IsRenderAreaOptimal(Handle<SHVkRenderpass> const& renderpassHdl, vk::Extent2D const& framebufferExtent, vk::Rect2D const& renderArea) const noexcept;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PRIVATE GETTERS AND SETTERS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
void SetState(SH_CMD_BUFFER_STATE state) noexcept;
|
||||||
|
SH_CMD_BUFFER_STATE GetState(void) const noexcept;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* CTORS AND DTORS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
SHVkCommandBuffer (Handle<SHVkCommandPool> const& commandPool, SH_CMD_BUFFER_TYPE type) noexcept;
|
||||||
|
SHVkCommandBuffer (SHVkCommandBuffer&& rhs) noexcept;
|
||||||
|
SHVkCommandBuffer (void) noexcept = delete;
|
||||||
|
~SHVkCommandBuffer (void) noexcept;
|
||||||
|
SHVkCommandBuffer& operator= (SHVkCommandBuffer&& rhs) noexcept;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PUBLIC MEMBER FUNCTIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
void Reset(void);
|
||||||
|
|
||||||
|
// Begins and Ends
|
||||||
|
void BeginRecording (void) noexcept;
|
||||||
|
void EndRecording (void) noexcept;
|
||||||
|
void BeginRenderpass (Handle<SHVkRenderpass> const& renderpassHdl, Handle<SHVkFramebuffer> const& framebufferHdl, vk::Offset2D offset = {0, 0}, vk::Extent2D extent = {0, 0}) noexcept;
|
||||||
|
void EndRenderpass (void) noexcept;
|
||||||
|
|
||||||
|
// Dynamic State
|
||||||
|
void SetviewportScissor (float vpWidth, float vpHeight, uint32_t sWidth, uint32_t sHeight, float vpX = 0.0f, float vpY = 0.0f, int32_t sX = 0.0f, int32_t sY = 0.0f, float vpMinDepth = 0.0f, float vpMaxDepth = 1.0f) noexcept;
|
||||||
|
|
||||||
|
// Binding Commands
|
||||||
|
void BindPipeline (Handle<SHVkPipeline> const& pipelineHdl) noexcept;
|
||||||
|
void BindVertexBuffer (uint32_t bindingPoint, Handle<SHVkBuffer> const& buffer, vk::DeviceSize offset) noexcept;
|
||||||
|
void BindIndexBuffer (Handle<SHVkBuffer> const& buffer, uint32_t startingIndex) const noexcept;
|
||||||
|
|
||||||
|
// Draw Commands
|
||||||
|
void DrawArrays (uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) const noexcept;
|
||||||
|
void DrawIndexed (uint32_t indexCount, uint32_t firstIndex, uint32_t vertexOffset) const noexcept;
|
||||||
|
|
||||||
|
// Push Constant variable setting
|
||||||
|
template <typename T>
|
||||||
|
void SetPushConstantVariable(std::string variableName, T const& data) noexcept
|
||||||
|
{
|
||||||
|
memcpy (static_cast<uint8_t*>(pushConstantData) + boundPipelineLayoutHdl->GetPushConstantInterface().GetOffset(variableName), &data, sizeof (T));
|
||||||
|
};
|
||||||
|
|
||||||
|
void SubmitPushConstants (void) const noexcept;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* GETTERS AND SETTERS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
vk::CommandBuffer const& GetVkCommandBuffer(void) const noexcept;
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,269 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHVkCommandPool.h"
|
||||||
|
#include "Graphics/Devices/SHVkLogicalDevice.h"
|
||||||
|
#include "Graphics/Instance/SHVkInstance.h"
|
||||||
|
#include "Resource/ResourceLibrary.h"
|
||||||
|
#include "Tools/SHLogger.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Simply creates a command pool. Flags passed in are also saved.
|
||||||
|
|
||||||
|
\param logicalDevice
|
||||||
|
Logical device required to create the pool
|
||||||
|
|
||||||
|
\param queueFamilyType
|
||||||
|
Every pool needs to be created from a queue family
|
||||||
|
|
||||||
|
\param inResetMode
|
||||||
|
Whether or not the reset bit that allows resetting command buffers
|
||||||
|
individually should be set or not.
|
||||||
|
|
||||||
|
\param inTransient
|
||||||
|
Whether or not buffers created from the pool are short-lived. IT IS
|
||||||
|
STRONGLY RECOMMENDED for this to be true. From "Writing an efficient
|
||||||
|
Vulkan renderer: In general approaches that pre-record command buffers for
|
||||||
|
parts of the scene are counter-productive since they can result in
|
||||||
|
excessive GPU load due to inefficient culling required to keep command
|
||||||
|
buffer workload large and can trigger inefficient code paths on some
|
||||||
|
tiled renderers, and instead applications should focus on improving the
|
||||||
|
threading and draw call submission cost on the CPU. NOTE: it is possible
|
||||||
|
to create transient command buffers from pools that are BUFFER_BASED,
|
||||||
|
hence why POOL_BASED != transient.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHVkCommandPool::SHVkCommandPool(Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl, SH_QUEUE_FAMILY_ARRAY_INDEX queueFamilyType, SH_CMD_POOL_RESET inResetMode, bool inTransient) noexcept
|
||||||
|
: vkCommandPool{ nullptr }
|
||||||
|
, queueFamilyIndex{ 0 }
|
||||||
|
, resetMode{ SH_CMD_POOL_RESET::POOL_BASED }
|
||||||
|
, primaries{}
|
||||||
|
, secondaries{}
|
||||||
|
, logicalDeviceHdl { inLogicalDeviceHdl }
|
||||||
|
, transient {false}
|
||||||
|
{
|
||||||
|
// Command pool create info
|
||||||
|
vk::CommandPoolCreateInfo poolCreateInfo{};
|
||||||
|
|
||||||
|
// Get the queue family index based on the queue family type passed in
|
||||||
|
poolCreateInfo.queueFamilyIndex = logicalDeviceHdl->GetQueueFamilyIndex(queueFamilyType);
|
||||||
|
|
||||||
|
if (inResetMode == SH_CMD_POOL_RESET::BUFFER_BASED)
|
||||||
|
poolCreateInfo.flags = vk::CommandPoolCreateFlagBits::eResetCommandBuffer;
|
||||||
|
|
||||||
|
if (inTransient)
|
||||||
|
poolCreateInfo.flags |= vk::CommandPoolCreateFlagBits::eTransient;
|
||||||
|
|
||||||
|
|
||||||
|
// Actually create the command pool and check for errors
|
||||||
|
if (auto result = logicalDeviceHdl->GetVkLogicalDevice().createCommandPool(&poolCreateInfo, nullptr, &vkCommandPool); result != vk::Result::eSuccess)
|
||||||
|
{
|
||||||
|
SHVulkanDebugUtil::ReportVkError(result, "Failed to create Command Pool! ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
SHVulkanDebugUtil::ReportVkSuccess("Successfully created Command Pool.");
|
||||||
|
|
||||||
|
// Save the queue family index
|
||||||
|
queueFamilyIndex = poolCreateInfo.queueFamilyIndex;
|
||||||
|
|
||||||
|
// Save the reset mode
|
||||||
|
resetMode = inResetMode;
|
||||||
|
transient = inTransient;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVkCommandPool::SHVkCommandPool(SHVkCommandPool&& rhs) noexcept
|
||||||
|
: ISelfHandle(rhs)
|
||||||
|
, vkCommandPool{ rhs.vkCommandPool }
|
||||||
|
, queueFamilyIndex{ rhs.queueFamilyIndex }
|
||||||
|
, resetMode{ rhs.resetMode }
|
||||||
|
, primaries{ std::move(rhs.primaries) }
|
||||||
|
, secondaries{ std::move(rhs.secondaries) }
|
||||||
|
, logicalDeviceHdl{ rhs.logicalDeviceHdl }
|
||||||
|
, transient{ rhs.transient }
|
||||||
|
{
|
||||||
|
rhs.vkCommandPool = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVkCommandPool& SHVkCommandPool::operator=(SHVkCommandPool&& rhs) noexcept
|
||||||
|
{
|
||||||
|
if (&rhs == this)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
vkCommandPool = rhs.vkCommandPool;
|
||||||
|
queueFamilyIndex = rhs.queueFamilyIndex;
|
||||||
|
resetMode = rhs.resetMode;
|
||||||
|
primaries = std::move(rhs.primaries);
|
||||||
|
secondaries = std::move(rhs.secondaries);
|
||||||
|
logicalDeviceHdl = rhs.logicalDeviceHdl;
|
||||||
|
transient = rhs.transient;
|
||||||
|
|
||||||
|
static_cast<ISelfHandle<SHVkCommandPool>&>(*this) = static_cast<ISelfHandle<SHVkCommandPool>&>(rhs);
|
||||||
|
|
||||||
|
rhs.vkCommandPool = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Destroys the command pool.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHVkCommandPool::~SHVkCommandPool(void) noexcept
|
||||||
|
{
|
||||||
|
// TODO: Destroy all command buffers first. Should implement a check for command buffers that are still recording or pending (submitted to queue)?
|
||||||
|
if (vkCommandPool)
|
||||||
|
{
|
||||||
|
|
||||||
|
for (auto& pri : primaries)
|
||||||
|
pri.Free();
|
||||||
|
for (auto& sec : secondaries)
|
||||||
|
sec.Free();
|
||||||
|
|
||||||
|
vkDestroyCommandPool(logicalDeviceHdl->GetVkLogicalDevice(), vkCommandPool, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Resets the command pool.
|
||||||
|
|
||||||
|
\param logicalDevice
|
||||||
|
Device required to reset the command pool.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkCommandPool::Reset(void) noexcept
|
||||||
|
{
|
||||||
|
// TODO: hopefully some sort of validation layer pops up here when we attempt to reset while the command buffers
|
||||||
|
// are in the pending state. Need to do a test.
|
||||||
|
logicalDeviceHdl->GetVkLogicalDevice().resetCommandPool(vkCommandPool, vk::CommandPoolResetFlagBits::eReleaseResources);
|
||||||
|
for (auto& primary : primaries)
|
||||||
|
{
|
||||||
|
if (primary->GetState() != SH_CMD_BUFFER_STATE::PENDING)
|
||||||
|
primary->SetState(SH_CMD_BUFFER_STATE::INITIAL);
|
||||||
|
else
|
||||||
|
SHLOG_ERROR("Primary command buffer in pending state, could not reset. ");
|
||||||
|
// From the spec: Any primary command buffer allocated from another VkCommandPool that is in the recording or
|
||||||
|
// executable state and has a secondary command buffer allocated from commandPool recorded into it,
|
||||||
|
// becomes invalid. TODO: Might want to check and throw exception for these conditions after making sure this actually happens using validation layers.
|
||||||
|
}
|
||||||
|
for (auto& secondary : secondaries)
|
||||||
|
{
|
||||||
|
if (secondary->GetState() != SH_CMD_BUFFER_STATE::PENDING)
|
||||||
|
secondary->SetState(SH_CMD_BUFFER_STATE::INITIAL);
|
||||||
|
else
|
||||||
|
SHLOG_ERROR("Secondary command buffer in pending state, could not reset. ");
|
||||||
|
|
||||||
|
// TODO: Ditto from TODO in primary check
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Request a command buffer from the command pool. User can choose for it
|
||||||
|
to be secondary or primary/
|
||||||
|
|
||||||
|
\param parentPool
|
||||||
|
This is solely for command buffers created to know what command pool
|
||||||
|
they originated from.
|
||||||
|
|
||||||
|
\param type
|
||||||
|
The type of the command buffer.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
Handle<SHVkCommandBuffer> SHVkCommandPool::RequestCommandBuffer(SH_CMD_BUFFER_TYPE type)
|
||||||
|
{
|
||||||
|
// If type requested for is primary
|
||||||
|
if (type == SH_CMD_BUFFER_TYPE::PRIMARY)
|
||||||
|
{
|
||||||
|
primaries.emplace_back(SHVkInstance::GetResourceManager().Create<SHVkCommandBuffer>(GetHandle(), type));
|
||||||
|
return primaries.back();
|
||||||
|
}
|
||||||
|
// If type requested for is secondary
|
||||||
|
else
|
||||||
|
{
|
||||||
|
secondaries.emplace_back(SHVkInstance::GetResourceManager().Create<SHVkCommandBuffer>(GetHandle(), type));
|
||||||
|
return secondaries.back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Get the reset mode of the command pool.
|
||||||
|
|
||||||
|
\return
|
||||||
|
Returns the reset mode of the command pool.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SH_CMD_POOL_RESET SHVkCommandPool::GetPoolResetMode(void) const noexcept
|
||||||
|
{
|
||||||
|
return resetMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Returns the vulkan command pool handle.
|
||||||
|
|
||||||
|
\return
|
||||||
|
The vulkan command pool handle.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
vk::CommandPool SHVkCommandPool::GetVkCommandPool(void) const noexcept
|
||||||
|
{
|
||||||
|
return vkCommandPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Returns the logical device handle stored in the command pool.
|
||||||
|
|
||||||
|
\return
|
||||||
|
The logical device handle.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
Handle<SHVkLogicalDevice> const& SHVkCommandPool::GetLogicalDevice(void) const noexcept
|
||||||
|
{
|
||||||
|
return logicalDeviceHdl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Returns whether or not the buffers created from this pool are
|
||||||
|
short-lived.
|
||||||
|
|
||||||
|
\return
|
||||||
|
The transient flag.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
bool SHVkCommandPool::GetIsTransient(void) const noexcept
|
||||||
|
{
|
||||||
|
return transient;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
#ifndef SH_COMMAND_POOL_H
|
||||||
|
#define SH_COMMAND_POOL_H
|
||||||
|
|
||||||
|
#include "Graphics/SHVulkanIncludes.h"
|
||||||
|
#include "Graphics/SHVulkanDefines.h"
|
||||||
|
#include "Graphics/Queues/SHVkQueue.h"
|
||||||
|
#include "SHCommandPoolResetMode.h"
|
||||||
|
#include "SHVkCommandBuffer.h"
|
||||||
|
#include "Resource/ResourceLibrary.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
class SHVkLogicalDevice;
|
||||||
|
|
||||||
|
class SHVkCommandPool : public ISelfHandle<SHVkCommandPool>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PRIVATE MEMBER VARIABLES */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
//! Vulkan handle to a command pool
|
||||||
|
vk::CommandPool vkCommandPool;
|
||||||
|
|
||||||
|
//! The queue family index that was used to initialize this pool
|
||||||
|
SHQueueFamilyIndex queueFamilyIndex;
|
||||||
|
|
||||||
|
//! The reset mode of the command buffer. For optimal usage, make the reset
|
||||||
|
//! mode POOL_BASED so that pools can recycle buffer memory all at once
|
||||||
|
//! instead of resetting 1 by 1. In general, we also want to re-record
|
||||||
|
//! buffers every frame instead of pre-recording, so resetting pools each
|
||||||
|
//! frame supports this concept.
|
||||||
|
SH_CMD_POOL_RESET resetMode;
|
||||||
|
|
||||||
|
//! primary command buffers
|
||||||
|
std::vector<Handle<SHVkCommandBuffer>> primaries;
|
||||||
|
|
||||||
|
//! secondary command buffers
|
||||||
|
std::vector<Handle<SHVkCommandBuffer>> secondaries;
|
||||||
|
|
||||||
|
//! Handle to logical device for convenience
|
||||||
|
Handle<SHVkLogicalDevice> logicalDeviceHdl;
|
||||||
|
|
||||||
|
//! Whether or not buffers created from here are to be short lived
|
||||||
|
bool transient;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* CTOR AND DTOR */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
SHVkCommandPool (Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl, SH_QUEUE_FAMILY_ARRAY_INDEX queueFamilyType, SH_CMD_POOL_RESET inResetMode, bool inTransient) noexcept;
|
||||||
|
SHVkCommandPool (void) noexcept = delete;
|
||||||
|
SHVkCommandPool(SHVkCommandPool&& rhs) noexcept;
|
||||||
|
SHVkCommandPool& operator=(SHVkCommandPool&& rhs) noexcept;
|
||||||
|
~SHVkCommandPool(void) noexcept;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PUBLIC MEMBER FUNCTIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
void Reset (void) noexcept;
|
||||||
|
Handle<SHVkCommandBuffer> RequestCommandBuffer (SH_CMD_BUFFER_TYPE type);
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* SETTERS AND GETTERS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
SH_CMD_POOL_RESET GetPoolResetMode(void) const noexcept;
|
||||||
|
vk::CommandPool GetVkCommandPool(void) const noexcept;
|
||||||
|
Handle<SHVkLogicalDevice> const& GetLogicalDevice(void) const noexcept;
|
||||||
|
bool GetIsTransient (void) const noexcept;
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,86 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHValidationLayersQuery.h"
|
||||||
|
#include "Tools/SHLogger.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
/* STATIC VARIABLE DECLARATION */
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
std::vector<vk::LayerProperties> SHValidationLayersQuery::queriedLayers;
|
||||||
|
std::vector<char const*> SHValidationLayersQuery::availableLayers;
|
||||||
|
|
||||||
|
// TODO: Not sure if necessary but it would be nice to load validation layers
|
||||||
|
// from a file.
|
||||||
|
std::vector<char const*> SHValidationLayersQuery::requiredLayers =
|
||||||
|
{
|
||||||
|
"VK_LAYER_KHRONOS_validation" // standard validation layer
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Uses the hard coded required layer above to check against the validation
|
||||||
|
layers retrieved upon querying from Vulkan. The final list of layers are
|
||||||
|
ones that are both in the required container and the queried container.
|
||||||
|
|
||||||
|
\param printInfo
|
||||||
|
If this is true, validation layer names are printed.
|
||||||
|
|
||||||
|
\param renderdocEnabled
|
||||||
|
Pushes a validation layer for renderdoc support if true.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHValidationLayersQuery::GenerateAvailableLayers(bool renderdocEnabled) noexcept
|
||||||
|
{
|
||||||
|
availableLayers.clear();
|
||||||
|
|
||||||
|
// Get the layers from vulkan
|
||||||
|
queriedLayers = vk::enumerateInstanceLayerProperties();
|
||||||
|
|
||||||
|
// Cherrypick those we want from the required list
|
||||||
|
for (char const* const requiredLayer : requiredLayers)
|
||||||
|
{
|
||||||
|
bool layerFound = false;
|
||||||
|
for (auto const& layer : queriedLayers)
|
||||||
|
{
|
||||||
|
if (strcmp (requiredLayer, layer.layerName) == 0)
|
||||||
|
{
|
||||||
|
availableLayers.push_back(requiredLayer);
|
||||||
|
layerFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!layerFound)
|
||||||
|
{
|
||||||
|
SHLOG_ERROR(std::string("validation Layer: ") + requiredLayer + std::string ("could not be found. "));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if renderdoc is requested, add to validation layer.
|
||||||
|
if (renderdocEnabled)
|
||||||
|
availableLayers.push_back("VK_LAYER_RENDERDOC_Capture");
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Gets the available layers after using QueryAvailableLayers.
|
||||||
|
|
||||||
|
\return
|
||||||
|
Returns the available layers.
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
std::vector<char const*> const& SHValidationLayersQuery::GetAvailableLayers(void) noexcept
|
||||||
|
{
|
||||||
|
return availableLayers;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
/**************************************************************************//*!
|
||||||
|
\file SHValidationLayersQuery.h
|
||||||
|
\author Brandon Mak
|
||||||
|
\par email: brandon.hao@digipen.edu
|
||||||
|
\date 17th May 2022
|
||||||
|
\brief Stores the declaration of SHValidationLayersQuery class.
|
||||||
|
|
||||||
|
Copyright (C) 2022 DigiPen Institute of Technology.
|
||||||
|
Reproduction or disclosure of this file or its contents without the prior
|
||||||
|
written consent of DigiPen Institute of Technology is prohibited.
|
||||||
|
|
||||||
|
*//***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef SH_VALIDATION_LAYERS_QUERY_H
|
||||||
|
#define SH_VALIDATION_LAYERS_QUERY_H
|
||||||
|
|
||||||
|
#include <vector> // std::vector
|
||||||
|
#include "Graphics/SHVulkanIncludes.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/*!**************************************************************************
|
||||||
|
|
||||||
|
\class SHValidationLLayersQuery
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Static class to query for validation layers. Only used during Vulkan
|
||||||
|
instance creation to enable validation layers.
|
||||||
|
|
||||||
|
***************************************************************************/
|
||||||
|
class SHValidationLayersQuery
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* STATIC VARIABLES */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
//! required validation layers
|
||||||
|
static std::vector<char const*> requiredLayers;
|
||||||
|
|
||||||
|
//! Queried layers
|
||||||
|
static std::vector<vk::LayerProperties> queriedLayers;
|
||||||
|
|
||||||
|
//! Final list that should be used to see what validation layers are available
|
||||||
|
static std::vector<char const*> availableLayers;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PUBLIC STATIC FUNCTIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
static void GenerateAvailableLayers (bool renderdocEnabled) noexcept;
|
||||||
|
static std::vector<char const*> const& GetAvailableLayers (void) noexcept;
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,84 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include "SHVkDebugMessenger.h"
|
||||||
|
#include "SHVulkanDebugUtil.h"
|
||||||
|
#include "Graphics/Instance/SHVkInstance.h"
|
||||||
|
#include "Tools/SHLogger.h"
|
||||||
|
//#include "Tools/SHLogger.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Initializes a struct for debug messenger creation.
|
||||||
|
|
||||||
|
\param[in, out] createInfo
|
||||||
|
The create info to initialize.
|
||||||
|
|
||||||
|
\param severityFlags
|
||||||
|
The severity flags we want to have for the messenger.
|
||||||
|
|
||||||
|
\param typeFlags
|
||||||
|
The type flags we want to have for the messenger.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkDebugMessenger::InitializeDebugCreateInfo(vk::DebugUtilsMessengerCreateInfoEXT& createInfo,
|
||||||
|
VkDebugUtilsMessageSeverityFlagsEXT severityFlags,
|
||||||
|
VkDebugUtilsMessageTypeFlagsEXT typeFlags) noexcept
|
||||||
|
{
|
||||||
|
createInfo.messageSeverity = vk::DebugUtilsMessageSeverityFlagsEXT (severityFlags);
|
||||||
|
createInfo.messageType = vk::DebugUtilsMessageTypeFlagsEXT (typeFlags);
|
||||||
|
createInfo.pfnUserCallback = SHVulkanDebugUtil::GenericDebugCallback;
|
||||||
|
createInfo.pNext = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Does everything required to create a debug messenger. This includes its
|
||||||
|
create info and calling the function to create a debug messenger.
|
||||||
|
|
||||||
|
\param vulkanInstance
|
||||||
|
Instance is required to create messenger.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkDebugMessenger::Initialize(void) noexcept
|
||||||
|
{
|
||||||
|
vk::DebugUtilsMessengerCreateInfoEXT debMsgCreateInfo;
|
||||||
|
InitializeDebugCreateInfo(debMsgCreateInfo,
|
||||||
|
GenMessengerSeverity(SH_DEBUG_MSG_SEV::S_VERBOSE, SH_DEBUG_MSG_SEV::S_WARNING, SH_DEBUG_MSG_SEV::S_ERROR),
|
||||||
|
GenMessengerType(SH_DEBUG_MSG_TYPE::T_GENERAL, SH_DEBUG_MSG_TYPE::T_VALIDATION, SH_DEBUG_MSG_TYPE::T_PERFORMANCE));
|
||||||
|
|
||||||
|
if (vk::Result result = SHVkInstance::GetVkInstance().createDebugUtilsMessengerEXT(&debMsgCreateInfo, nullptr, &debugMessenger); result != vk::Result::eSuccess)
|
||||||
|
{
|
||||||
|
SHVulkanDebugUtil::ReportVkError(result, "Failed to create Debug Messenger! ");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SHVulkanDebugUtil::ReportVkSuccess("Successfully created a Debug Messenger. ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Simply calls a Vulkan function to destroy the debug messenger.
|
||||||
|
|
||||||
|
\param vulkanInstance
|
||||||
|
Instance is required to destroy messenger.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkDebugMessenger::Destroy(void) noexcept
|
||||||
|
{
|
||||||
|
SHVkInstance::GetVkInstance().destroyDebugUtilsMessengerEXT(debugMessenger, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,111 @@
|
||||||
|
#ifndef SH_DEBUG_MESSENGER_H
|
||||||
|
#define SH_DEBUG_MESSENGER_H
|
||||||
|
|
||||||
|
#include "SHVulkanDebugUtil.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
enum class SH_DEBUG_MSG_SEV : VkDebugUtilsMessageSeverityFlagsEXT
|
||||||
|
{
|
||||||
|
S_VERBOSE = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
|
||||||
|
S_INFO = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
|
||||||
|
S_WARNING = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
|
||||||
|
S_ERROR = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
|
||||||
|
S_FLAG = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SH_DEBUG_MSG_TYPE : VkDebugUtilsMessageTypeFlagsEXT
|
||||||
|
{
|
||||||
|
T_GENERAL = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT,
|
||||||
|
T_VALIDATION = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT,
|
||||||
|
T_PERFORMANCE = VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
|
||||||
|
T_FLAG_BITS = VK_DEBUG_UTILS_MESSAGE_TYPE_FLAG_BITS_MAX_ENUM_EXT,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!**************************************************************************
|
||||||
|
|
||||||
|
\class SHVkDebugMessenger
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Vulkan provides debugging functionality through a messenger. This class
|
||||||
|
helps to create and initialize one.
|
||||||
|
|
||||||
|
***************************************************************************/
|
||||||
|
class SHVkDebugMessenger
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* DATA MEMBERS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
//! The vulkan debug messenger object
|
||||||
|
vk::DebugUtilsMessengerEXT debugMessenger;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PUBLIC MEMBER FUNCTIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
void Initialize(void) noexcept;
|
||||||
|
void Destroy(void) noexcept;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PUBLIC STATIC FUNCTIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
static void InitializeDebugCreateInfo(vk::DebugUtilsMessengerCreateInfoEXT& createInfo,
|
||||||
|
VkDebugUtilsMessageSeverityFlagsEXT severityFlags,
|
||||||
|
VkDebugUtilsMessageTypeFlagsEXT typeFlags) noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
When using flags to specify debug message severity, the process is
|
||||||
|
extremely cumbersome as each flag has a lengthy name. This function
|
||||||
|
along with the enum SHDebMsgSeverity helps make it more readable. Use
|
||||||
|
this function any time a VkDebugUtilsMessageSeverityFlagsEXT argument
|
||||||
|
is requested.
|
||||||
|
|
||||||
|
\param ...severities
|
||||||
|
The combined severities.
|
||||||
|
|
||||||
|
\return
|
||||||
|
Returns a bitfield indicated the debug severity flags. Gets passed to
|
||||||
|
Vulkan when created debug create info.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
template <typename... Sevs, typename = std::enable_if<(std::is_same_v<Sevs, SH_DEBUG_MSG_SEV> && ...)>>
|
||||||
|
static VkDebugUtilsMessageSeverityFlagsEXT GenMessengerSeverity(Sevs... severities)
|
||||||
|
{
|
||||||
|
return (static_cast<VkDebugUtilsMessageSeverityFlagsEXT>(severities) | ...);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
When using flags to specify debug message types, the process is
|
||||||
|
extremely cumbersome as each flag has a lengthy name. This function
|
||||||
|
along with the enum SHDebMsgType helps make it more readable. Use
|
||||||
|
this function any time a VkDebugUtilsMessageTypeFlagsEXT argument
|
||||||
|
is requested.
|
||||||
|
|
||||||
|
\param ...types
|
||||||
|
The combined types.
|
||||||
|
|
||||||
|
\return
|
||||||
|
Returns a bitfield indicated the debug severity flags. Gets passed to
|
||||||
|
Vulkan when created debug create info.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
template <typename... Types, typename = std::enable_if<(std::is_same_v<Types, SH_DEBUG_MSG_TYPE> && ...)>>
|
||||||
|
static VkDebugUtilsMessageTypeFlagsEXT GenMessengerType(Types... types)
|
||||||
|
{
|
||||||
|
return (static_cast<VkDebugUtilsMessageTypeFlagsEXT>(types) | ...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,154 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHVulkanDebugUtil.h"
|
||||||
|
#include "Tools/SHLogger.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Generic debug function callback to print error messages that are warnings
|
||||||
|
or errors.
|
||||||
|
|
||||||
|
\param messageSeverity
|
||||||
|
Severity of the message
|
||||||
|
|
||||||
|
\param messageType
|
||||||
|
Type of the message
|
||||||
|
|
||||||
|
\param pCallbackData
|
||||||
|
Vulkan object containing useful information regarding the message.
|
||||||
|
|
||||||
|
\param pUserData
|
||||||
|
A pointer to any kind of user data.
|
||||||
|
|
||||||
|
\return
|
||||||
|
returns false anyway.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
VKAPI_ATTR VkBool32 VKAPI_CALL SHVulkanDebugUtil::GenericDebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||||
|
[[maybe_unused]] VkDebugUtilsMessageSeverityFlagsEXT messageType,
|
||||||
|
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||||
|
[[maybe_unused]] void* pUserData)
|
||||||
|
{
|
||||||
|
if (messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)
|
||||||
|
ReportVkWarning(static_cast<vk::Result> (pCallbackData->messageIdNumber), pCallbackData->pMessage);
|
||||||
|
else if (messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
|
||||||
|
ReportVkError(static_cast<vk::Result> (pCallbackData->messageIdNumber), pCallbackData->pMessage);
|
||||||
|
|
||||||
|
return VK_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Prints warnings in a formatted manner. Includes vkResult.
|
||||||
|
|
||||||
|
\param vkResult
|
||||||
|
The vkResult to display.
|
||||||
|
|
||||||
|
\param message
|
||||||
|
The custom user message to display.
|
||||||
|
|
||||||
|
\param location
|
||||||
|
location contains information about the function that calls this function,
|
||||||
|
the column/row of the callsite and the filename.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVulkanDebugUtil::ReportVkWarning(vk::Result vkResult, std::string_view message, std::source_location const& location /*= std::source_location::current()*/) noexcept
|
||||||
|
{
|
||||||
|
//std::cout << location.file_name() << ": " << location.function_name() << "|" << location.line() << "|" <<
|
||||||
|
// location.column() << "|: Warning: " << SHDebugUtil::VkResultToString(vkResult) << " | " << message << std::endl;
|
||||||
|
|
||||||
|
std::string toLogger = "Vulkan Warning: " + std::string(SHVulkanDebugUtil::VkResultToString(vkResult)) + " | " + std::string(message);
|
||||||
|
|
||||||
|
SHLOGV_WARNING(toLogger);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Prints errors in a formatted manner. Includes vkResult.
|
||||||
|
|
||||||
|
\param vkResult
|
||||||
|
The vkResult to display.
|
||||||
|
|
||||||
|
\param message
|
||||||
|
The custom user message to display.
|
||||||
|
|
||||||
|
\param location
|
||||||
|
location contains information about the function that calls this function,
|
||||||
|
the column/row of the callsite and the filename.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVulkanDebugUtil::ReportVkError(vk::Result vkResult, std::string_view message, std::source_location const& location /*= std::source_location::current()*/) noexcept
|
||||||
|
{
|
||||||
|
std::string toLogger = "Vulkan Warning: " + std::string(SHVulkanDebugUtil::VkResultToString(vkResult)) + " | " + std::string(message);
|
||||||
|
|
||||||
|
SHLOGV_ERROR(toLogger);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SHVulkanDebugUtil::ReportVkSuccess(std::string_view message, std::source_location const& location /*= std::source_location::current()*/) noexcept
|
||||||
|
{
|
||||||
|
SHLOGV_INFO(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Converts a vkResult enum field to a string. Function is copied entirely
|
||||||
|
from xGPU: https://github.com/LIONant-depot/xGPU/blob/d546fc202d2acddb6beeb79947860fd437046cb3/Src/Details/Vulkan/xgpu_vulkan_instance.cpp#L19
|
||||||
|
Could not find a more straightforward way to convert enum to string.
|
||||||
|
|
||||||
|
\param vkResult
|
||||||
|
The Vulkan result to convert to string.
|
||||||
|
|
||||||
|
\return
|
||||||
|
returns a string_view that represents the vulkan result enum value.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
std::string_view SHVulkanDebugUtil::VkResultToString(vk::Result vkResult) noexcept
|
||||||
|
{
|
||||||
|
VkResult cStyleResult = static_cast<VkResult>(vkResult);
|
||||||
|
switch (cStyleResult)
|
||||||
|
{
|
||||||
|
// Macro to form the enum value using '##', and stringify the enum using '#'
|
||||||
|
#define STR(r) case VK_ ##r : return #r
|
||||||
|
STR(TIMEOUT);
|
||||||
|
STR(EVENT_SET);
|
||||||
|
STR(EVENT_RESET);
|
||||||
|
STR(INCOMPLETE);
|
||||||
|
STR(ERROR_OUT_OF_HOST_MEMORY);
|
||||||
|
STR(ERROR_OUT_OF_DEVICE_MEMORY);
|
||||||
|
STR(ERROR_INITIALIZATION_FAILED);
|
||||||
|
STR(ERROR_DEVICE_LOST);
|
||||||
|
STR(ERROR_MEMORY_MAP_FAILED);
|
||||||
|
STR(ERROR_LAYER_NOT_PRESENT);
|
||||||
|
STR(ERROR_EXTENSION_NOT_PRESENT);
|
||||||
|
STR(ERROR_FEATURE_NOT_PRESENT);
|
||||||
|
STR(ERROR_INCOMPATIBLE_DRIVER);
|
||||||
|
STR(ERROR_TOO_MANY_OBJECTS);
|
||||||
|
STR(ERROR_FORMAT_NOT_SUPPORTED);
|
||||||
|
STR(ERROR_SURFACE_LOST_KHR);
|
||||||
|
STR(ERROR_NATIVE_WINDOW_IN_USE_KHR);
|
||||||
|
STR(SUBOPTIMAL_KHR);
|
||||||
|
STR(ERROR_OUT_OF_DATE_KHR);
|
||||||
|
STR(ERROR_INCOMPATIBLE_DISPLAY_KHR);
|
||||||
|
STR(ERROR_VALIDATION_FAILED_EXT);
|
||||||
|
STR(ERROR_INVALID_SHADER_NV);
|
||||||
|
#undef STR
|
||||||
|
default:
|
||||||
|
return "UNKNOWN_ERROR";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef SH_DEBUG_UTIL_H
|
||||||
|
#define SH_DEBUG_UTIL_H
|
||||||
|
|
||||||
|
#include "Graphics/SHVulkanIncludes.h"
|
||||||
|
//#include <vulkan/vulkan_handles.hpp>
|
||||||
|
#include <source_location>
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
class SHVulkanDebugUtil
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static std::string_view VkResultToString(vk::Result vkResult) noexcept;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static VKAPI_ATTR VkBool32 VKAPI_CALL GenericDebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageSeverityFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData);
|
||||||
|
|
||||||
|
static void ReportVkWarning(vk::Result vkResult, std::string_view message, std::source_location const& location = std::source_location::current()) noexcept;
|
||||||
|
static void ReportVkError(vk::Result vkResult, std::string_view message, std::source_location const& location = std::source_location::current()) noexcept;
|
||||||
|
static void ReportVkSuccess(std::string_view message, std::source_location const& location = std::source_location::current()) noexcept;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class SHVkDebugOn
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,2 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHDescriptorPoolManager.h"
|
|
@ -0,0 +1,5 @@
|
||||||
|
#pragma once
|
||||||
|
class SHDescriptorPoolManager
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHDescriptorPoolStorage.h"
|
|
@ -0,0 +1,5 @@
|
||||||
|
#pragma once
|
||||||
|
class SHDescriptorPoolStorage
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHVkDescriptorPool.h"
|
||||||
|
|
||||||
|
#include "Graphics/Devices/SHVkLogicalDevice.h"
|
||||||
|
#include "Graphics/Instance/SHVkInstance.h"
|
||||||
|
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Constructor/Destructor */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
SHVkDescriptorPool::SHVkDescriptorPool(Handle<SHVkLogicalDevice> device, const Config& config)
|
||||||
|
: device { device }
|
||||||
|
{
|
||||||
|
// Create the Pool
|
||||||
|
const vk::DescriptorPoolCreateInfo POOL_CREATE_INFO
|
||||||
|
{
|
||||||
|
.flags = config.Flags,
|
||||||
|
.maxSets = config.MaxSets,
|
||||||
|
.poolSizeCount = static_cast<uint32_t>(config.Limits.size()),
|
||||||
|
.pPoolSizes = config.Limits.data()
|
||||||
|
};
|
||||||
|
pool = device->GetVkLogicalDevice().createDescriptorPool(POOL_CREATE_INFO);
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVkDescriptorPool::~SHVkDescriptorPool() noexcept
|
||||||
|
{
|
||||||
|
if (pool)
|
||||||
|
device->GetVkLogicalDevice().destroyDescriptorPool(pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Handle<SHVkDescriptorSetGroup>> SHVkDescriptorPool::Allocate(const std::vector<Handle<SHVkDescriptorSetLayout>>& layouts, std::vector<uint32_t> const& variableDescCounts)
|
||||||
|
{
|
||||||
|
SHVkInstance::GetResourceManager().Create<SHVkDescriptorSetGroup>(device, GetHandle(), layouts, variableDescCounts);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,114 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Project Includes
|
||||||
|
#include "Graphics/SHVulkanIncludes.h"
|
||||||
|
#include "Resource/Handle.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Forward Declarations */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
class SHVkLogicalDevice;
|
||||||
|
class SHVkDescriptorSetGroup;
|
||||||
|
class SHVkDescriptorSetLayout;
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Type Definitions */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
class SHVkDescriptorPool : public ISelfHandle<SHVkDescriptorPool>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Type Definitions */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/// <summary>
|
||||||
|
/// Configuration object for the Pool Manager.
|
||||||
|
/// </summary>
|
||||||
|
struct Config
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// <summary>
|
||||||
|
/// Describe the resource limitations of the Descriptor Pool can construct.
|
||||||
|
/// The specified type and count pairs indicate how many Descriptors will be
|
||||||
|
/// constructed in the Descriptor Pool.
|
||||||
|
/// </summary>
|
||||||
|
std::vector<vk::DescriptorPoolSize> Limits =
|
||||||
|
{
|
||||||
|
{ vk::DescriptorType::eCombinedImageSampler, 100 },
|
||||||
|
{ vk::DescriptorType::eUniformBuffer, 100 }
|
||||||
|
};
|
||||||
|
/// <summary>
|
||||||
|
/// Maximum number of descriptor sets allowed
|
||||||
|
/// </summary>
|
||||||
|
uint32_t MaxSets = 100;
|
||||||
|
/// <summary>
|
||||||
|
/// Flags used to create the DescriptorPool
|
||||||
|
/// </summary>
|
||||||
|
vk::DescriptorPoolCreateFlags Flags = vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Constructor/Destructor */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor for a Descriptor Pool.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="device">
|
||||||
|
/// The Vulkan logical device that is used to create a Descriptor Pool.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="config">
|
||||||
|
/// Configuration object that describes how to construct the Descriptor Pool.
|
||||||
|
/// </param>
|
||||||
|
SHVkDescriptorPool(Handle<SHVkLogicalDevice> device, const Config& config = {});
|
||||||
|
SHVkDescriptorPool(const SHVkDescriptorPool&) = delete;
|
||||||
|
SHVkDescriptorPool(SHVkDescriptorPool&& rhs) noexcept = default;
|
||||||
|
/// <summary>
|
||||||
|
/// Destructor which will unload and deallocate all resources for this Pool.
|
||||||
|
/// </summary>
|
||||||
|
~SHVkDescriptorPool() noexcept;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Overloaded Operators */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
SHVkDescriptorPool& operator=(const SHVkDescriptorPool&) = delete;
|
||||||
|
SHVkDescriptorPool& operator=(SHVkDescriptorPool&& rhs) noexcept = default;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Getter Functions */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the handle to the Vulkan Descriptor Pool handle.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Handle to the Vulkan Descriptor Pool.</returns>
|
||||||
|
[[nodiscard]]
|
||||||
|
inline const vk::DescriptorPool& GetVkHandle() const { return pool; }
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Usage Functions */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/// <summary>
|
||||||
|
/// Allocates multiple DescriptorSets based on the provided layouts.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="layouts">Layouts of DescriptorSets to create.</param>
|
||||||
|
/// <exception cref="std::invalid_argument">
|
||||||
|
/// Thrown if an incompatible layout was provided to this Descriptor Pool.
|
||||||
|
/// </exception>
|
||||||
|
/// <returns>
|
||||||
|
/// Handles to the created Descriptor Sets. If this DescriptorPool has run out of
|
||||||
|
/// space, lesser number of Handles will be returned.
|
||||||
|
/// </returns>
|
||||||
|
std::vector<Handle<SHVkDescriptorSetGroup>> Allocate(const std::vector<Handle<SHVkDescriptorSetLayout>>& layouts, std::vector<uint32_t> const& variableDescCounts);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Data Members */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
Handle<SHVkLogicalDevice> device;
|
||||||
|
vk::DescriptorPool pool;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHVkDescriptorSetGroup.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include "SHVkDescriptorPool.h"
|
||||||
|
#include "Graphics/Devices/SHVkLogicalDevice.h"
|
||||||
|
#include "Graphics/Descriptors/SHVkDescriptorSetLayout.h"
|
||||||
|
#include "Tools/SHLogger.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Allocates a bunch of descriptor sets based on how many layouts are
|
||||||
|
being passed in.
|
||||||
|
|
||||||
|
\param deviceHdl
|
||||||
|
Logical device required for the descriptor set creation.
|
||||||
|
|
||||||
|
|
||||||
|
\param pool
|
||||||
|
Pool to allocate from.
|
||||||
|
|
||||||
|
\param layouts
|
||||||
|
With N layouts provided, the function will allocate N descriptor sets.
|
||||||
|
All of which will be stored in this class.
|
||||||
|
|
||||||
|
\param variableDescCounts
|
||||||
|
Represents the variable descriptor count for every layout passed in.
|
||||||
|
If the binding used in the layout is not marked as using a variable count,
|
||||||
|
the value for the particular layout is ignored.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHVkDescriptorSetGroup::SHVkDescriptorSetGroup(Handle<SHVkLogicalDevice> deviceHdl, Handle<SHVkDescriptorPool> pool, std::vector<Handle<SHVkDescriptorSetLayout>> const& layouts, std::vector<uint32_t> const& variableDescCounts)
|
||||||
|
: device{deviceHdl}
|
||||||
|
, descPool {pool}
|
||||||
|
, descSets{}
|
||||||
|
{
|
||||||
|
// Create the layout for each concurrent frame
|
||||||
|
std::vector<vk::DescriptorSetLayout> vkLayouts{ layouts.size() };
|
||||||
|
for (auto& layout : layouts)
|
||||||
|
{
|
||||||
|
vkLayouts.push_back(layout->GetVkHandle());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for variable descriptor count
|
||||||
|
if (variableDescCounts.size() != layouts.size())
|
||||||
|
SHLOG_ERROR("Number of variable descriptor counts does not match number of layouts. If a layout does not use variable counts, pass in 0. ");
|
||||||
|
|
||||||
|
// Prepare variable descriptor counts
|
||||||
|
vk::DescriptorSetVariableDescriptorCountAllocateInfo variableAllocInfo{};
|
||||||
|
variableAllocInfo.descriptorSetCount = static_cast<uint32_t>(variableDescCounts.size());
|
||||||
|
variableAllocInfo.pDescriptorCounts = variableDescCounts.data();
|
||||||
|
|
||||||
|
// Prepare allocation information
|
||||||
|
const vk::DescriptorSetAllocateInfo DESC_SET_LAYOUT_CREATE_INFO
|
||||||
|
{
|
||||||
|
.pNext = &variableAllocInfo,
|
||||||
|
.descriptorPool = descPool->GetVkHandle(),
|
||||||
|
.descriptorSetCount = static_cast<uint32_t>(vkLayouts.size()),
|
||||||
|
.pSetLayouts = vkLayouts.data(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// allocate descriptor sets
|
||||||
|
descSets = device->GetVkLogicalDevice().allocateDescriptorSets(DESC_SET_LAYOUT_CREATE_INFO);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Destroys all the descriptor sets in the group.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHVkDescriptorSetGroup::~SHVkDescriptorSetGroup() noexcept
|
||||||
|
{
|
||||||
|
if (!descSets.empty())
|
||||||
|
device->GetVkLogicalDevice().freeDescriptorSets(descPool->GetVkHandle(), descSets);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Project Includes
|
||||||
|
#include "Graphics/SHVulkanIncludes.h"
|
||||||
|
#include "Resource/Handle.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Forward Declarations */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
class SHVkLogicalDevice;
|
||||||
|
class SHVkDescriptorPool;
|
||||||
|
class SHVkDescriptorSetLayout;
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Type Definitions */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
class SHVkDescriptorSetGroup
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Constructor/Destructors */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a Descriptor Set with the specified layout using the specified
|
||||||
|
/// pool meant for use with the specified surface. This Set will be created with
|
||||||
|
/// multiple Vulkan Descriptor Set objects based on the max number of concurrent
|
||||||
|
/// frames for the specified surface.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="device">Vulkan logical device used to create the Set.</param>
|
||||||
|
/// <param name="pool">Descriptor Pool used to create the Set.</param>
|
||||||
|
/// <param name="layout">Descriptor Set Layout to create the Set with.</param>
|
||||||
|
SHVkDescriptorSetGroup(Handle<SHVkLogicalDevice> deviceHdl, Handle<SHVkDescriptorPool> pool,
|
||||||
|
std::vector<Handle<SHVkDescriptorSetLayout>> const& layouts,
|
||||||
|
std::vector<uint32_t> const& variableDescCounts);
|
||||||
|
SHVkDescriptorSetGroup(const SHVkDescriptorSetGroup&) = delete;
|
||||||
|
SHVkDescriptorSetGroup(SHVkDescriptorSetGroup&& rhs) noexcept = default;
|
||||||
|
/// <summary>
|
||||||
|
/// Destructor which will unload and deallocate all resources for this Descriptor Set.
|
||||||
|
/// </summary>
|
||||||
|
~SHVkDescriptorSetGroup() noexcept;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Overloaded Operators */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
SHVkDescriptorSetGroup& operator=(const SHVkDescriptorSetGroup&) = delete;
|
||||||
|
SHVkDescriptorSetGroup& operator=(SHVkDescriptorSetGroup&& rhs) noexcept = default;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Getter Functions */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the handle to the Vulkan Descriptor Set handle.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Handle to the Vulkan Descriptor Set.</returns>
|
||||||
|
[[nodiscard]]
|
||||||
|
inline const std::vector<vk::DescriptorSet>& GetVkHandle() { return descSets; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Data Members */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
Handle<SHVkLogicalDevice> device;
|
||||||
|
Handle<SHVkDescriptorPool> descPool;
|
||||||
|
std::vector<vk::DescriptorSet> descSets;
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHVkDescriptorSetLayout.h"
|
||||||
|
#include "Graphics/Devices/SHVkLogicalDevice.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Constructor/Destructor */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
SHVkDescriptorSetLayout::SHVkDescriptorSetLayout(Handle<SHVkLogicalDevice> device, const std::vector<Binding>& bindings)
|
||||||
|
: device { device }
|
||||||
|
, layoutDesc { bindings }
|
||||||
|
{
|
||||||
|
// Check if auto-binding point calculation configuration is valid
|
||||||
|
bool autoCalc = false;
|
||||||
|
for (const auto& binding : bindings)
|
||||||
|
{
|
||||||
|
if (binding.BindPoint == Binding::AUTO_CALC_BINDING)
|
||||||
|
{
|
||||||
|
autoCalc = true;
|
||||||
|
}
|
||||||
|
else if (autoCalc)
|
||||||
|
{
|
||||||
|
throw std::invalid_argument("For auto calculation of bindings, all bindings must be set to AUTO_CALC_BINDING!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill up VK bindings with auto calculated bind points if needed
|
||||||
|
std::vector<vk::DescriptorSetLayoutBinding> layoutBindings;
|
||||||
|
layoutBindings.reserve(bindings.size());
|
||||||
|
int bindCount = 0;
|
||||||
|
for (const auto& binding : bindings)
|
||||||
|
{
|
||||||
|
const uint32_t CURR_BIND_POINT = autoCalc ? bindCount : binding.BindPoint;
|
||||||
|
const vk::DescriptorSetLayoutBinding VK_BINDING =
|
||||||
|
{
|
||||||
|
.binding = CURR_BIND_POINT,
|
||||||
|
.descriptorType = binding.Type,
|
||||||
|
.descriptorCount = binding.DescriptorCount,
|
||||||
|
.stageFlags = binding.Stage,
|
||||||
|
.pImmutableSamplers = nullptr // We will create our own samplers
|
||||||
|
};
|
||||||
|
layoutBindings.emplace_back(VK_BINDING);
|
||||||
|
|
||||||
|
// Save for future reference
|
||||||
|
layoutDesc[bindCount++].BindPoint = CURR_BIND_POINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Check layout support with physical device
|
||||||
|
|
||||||
|
// Prepare binding flags
|
||||||
|
std::vector<vk::DescriptorBindingFlags> combinedBindings(bindings.size());
|
||||||
|
for (uint32_t i = 0; i < bindings.size(); ++i)
|
||||||
|
combinedBindings[i] = bindings[i].flags;
|
||||||
|
|
||||||
|
const vk::DescriptorSetLayoutBindingFlagsCreateInfo BINDING_FLAGS_CREATE_INFO
|
||||||
|
{
|
||||||
|
.bindingCount = static_cast<uint32_t>(bindings.size()), // Number of flags = number of bindings
|
||||||
|
.pBindingFlags = combinedBindings.data(), // address to flags
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create the layout
|
||||||
|
const vk::DescriptorSetLayoutCreateInfo DESC_SET_LAYOUT_CREATE_INFO
|
||||||
|
{
|
||||||
|
.pNext = &BINDING_FLAGS_CREATE_INFO,
|
||||||
|
.flags = {},
|
||||||
|
.bindingCount = static_cast<uint32_t>(layoutBindings.size()),
|
||||||
|
.pBindings = layoutBindings.data(),
|
||||||
|
};
|
||||||
|
setLayout = device->GetVkLogicalDevice().createDescriptorSetLayout(DESC_SET_LAYOUT_CREATE_INFO);
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVkDescriptorSetLayout::SHVkDescriptorSetLayout(SHVkDescriptorSetLayout&& rhs) noexcept
|
||||||
|
: device {rhs.device}
|
||||||
|
, setLayout {rhs.setLayout}
|
||||||
|
, layoutDesc{std::move (rhs.layoutDesc)}
|
||||||
|
{
|
||||||
|
rhs.setLayout = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVkDescriptorSetLayout::~SHVkDescriptorSetLayout() noexcept
|
||||||
|
{
|
||||||
|
// Destroy layout
|
||||||
|
if (setLayout)
|
||||||
|
device->GetVkLogicalDevice().destroyDescriptorSetLayout(setLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVkDescriptorSetLayout& SHVkDescriptorSetLayout::operator=(SHVkDescriptorSetLayout&& rhs) noexcept
|
||||||
|
{
|
||||||
|
if (&rhs == this)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
device = rhs.device;
|
||||||
|
setLayout = rhs.setLayout;
|
||||||
|
layoutDesc = std::move(rhs.layoutDesc);
|
||||||
|
|
||||||
|
rhs.setLayout = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Project Includes
|
||||||
|
#include "Graphics/SHVulkanIncludes.h"
|
||||||
|
#include "Resource/Handle.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Forward Declarations */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
class SHVkLogicalDevice;
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Type Definitions */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/// <summary>
|
||||||
|
/// RAII wrapper object for a Vulkan Descriptor Set Layout object.
|
||||||
|
/// </summary>
|
||||||
|
class SHVkDescriptorSetLayout
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Type Definitions */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/// <summary>
|
||||||
|
/// Object that describes how a descriptor binding in a DescriptorSetLayout is
|
||||||
|
/// structured.
|
||||||
|
/// </summary>
|
||||||
|
struct Binding
|
||||||
|
{
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
/* Constants */
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
/// <summary>
|
||||||
|
/// If set for the "BindPoint", binding points are automatically calculated.
|
||||||
|
/// </summary>
|
||||||
|
static constexpr uint32_t AUTO_CALC_BINDING = std::numeric_limits<uint32_t>::max();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For use in Binding DescriptorCount.
|
||||||
|
/// </summary>
|
||||||
|
static constexpr uint32_t VARIABLE_DESCRIPTOR_UPPER_BOUND = 2000;
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
/* Data Members */
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
/// <summary>
|
||||||
|
/// Type of element for the descriptor.
|
||||||
|
/// </summary>
|
||||||
|
vk::DescriptorType Type = {};
|
||||||
|
/// <summary>
|
||||||
|
/// Shader stage that this binding is for.
|
||||||
|
/// </summary>
|
||||||
|
vk::ShaderStageFlags Stage = {};
|
||||||
|
/// <summary>
|
||||||
|
/// Binding point for the Descriptor within the Descriptor Set.
|
||||||
|
/// </summary>
|
||||||
|
uint32_t BindPoint = AUTO_CALC_BINDING;
|
||||||
|
/// <summary>
|
||||||
|
/// Number of elements in the binding. When VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT
|
||||||
|
/// is used in VkDescriptorBindingFlagBits, this value represents the upper bound.
|
||||||
|
/// </summary>
|
||||||
|
uint32_t DescriptorCount = 1;
|
||||||
|
|
||||||
|
vk::DescriptorBindingFlags flags = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Constructor/Destructors */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
SHVkDescriptorSetLayout() = delete;
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a DescriptorSetLayout with the specified properties and device.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="device"></param>
|
||||||
|
/// <param name="bindings"></param>
|
||||||
|
SHVkDescriptorSetLayout(Handle<SHVkLogicalDevice> device, const std::vector<Binding>& bindings);
|
||||||
|
SHVkDescriptorSetLayout(const SHVkDescriptorSetLayout&) = delete;
|
||||||
|
SHVkDescriptorSetLayout(SHVkDescriptorSetLayout&& rhs) noexcept;
|
||||||
|
/// <summary>
|
||||||
|
/// Destructor which will unload and deallocate all resources for this Set.
|
||||||
|
/// </summary>
|
||||||
|
~SHVkDescriptorSetLayout() noexcept;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Overloaded Operators */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
SHVkDescriptorSetLayout& operator=(const SHVkDescriptorSetLayout&) = delete;
|
||||||
|
SHVkDescriptorSetLayout& operator=(SHVkDescriptorSetLayout&& rhs) noexcept;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Getter Functions */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the handle to the Vulkan Descriptor Set Layout handle.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Handle to the Vulkan Descriptor Set Layout handle.</returns>
|
||||||
|
inline const vk::DescriptorSetLayout& GetVkHandle() const { return setLayout; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Data Members */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
Handle<SHVkLogicalDevice> device;
|
||||||
|
vk::DescriptorSetLayout setLayout;
|
||||||
|
std::vector<Binding> layoutDesc; // Stores description of the layout
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,637 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHVkLogicalDevice.h"
|
||||||
|
#include "SHVkPhysicalDevice.h"
|
||||||
|
#include "Graphics/Instance/SHVkInstance.h"
|
||||||
|
#include "Tools/SHLogger.h"
|
||||||
|
#include "Graphics/Windowing/Surface/SHVkSurface.h"
|
||||||
|
#include "Graphics/Swapchain/SHVkSwapchain.h"
|
||||||
|
#include "Graphics/Commands/SHVkCommandPool.h"
|
||||||
|
#include "Graphics/Buffers/SHVkBuffer.h"
|
||||||
|
#include "Graphics/Images/SHVkImage.h"
|
||||||
|
#include "Graphics/Synchronization/SHVkFence.h"
|
||||||
|
#include "Graphics/Synchronization/SHVkSemaphore.h"
|
||||||
|
#include "Graphics/Shaders/SHVkShaderModule.h"
|
||||||
|
#include "Graphics/Pipeline/SHVkPipelineLayout.h"
|
||||||
|
#include "Graphics/Pipeline/SHVkPipeline.h"
|
||||||
|
#include "Graphics/Framebuffer/SHVkFramebuffer.h"
|
||||||
|
#include "Graphics/Images/SHVkImageView.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Initializes a VMA allocator.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkLogicalDevice::InitializeVMA(void) noexcept
|
||||||
|
{
|
||||||
|
VmaVulkanFunctions vulkanFunctions = {};
|
||||||
|
vulkanFunctions.vkGetInstanceProcAddr = &vkGetInstanceProcAddr;
|
||||||
|
vulkanFunctions.vkGetDeviceProcAddr = &vkGetDeviceProcAddr;
|
||||||
|
|
||||||
|
VmaAllocatorCreateInfo vmaCreateInfo{};
|
||||||
|
vmaCreateInfo.vulkanApiVersion = VK_API_VERSION_1_3;
|
||||||
|
vmaCreateInfo.physicalDevice = parentPhysicalDeviceHdl->GetVkPhysicalDevice();
|
||||||
|
vmaCreateInfo.device = vkLogicalDevice;
|
||||||
|
vmaCreateInfo.instance = SHVkInstance::GetVkInstance();
|
||||||
|
vmaCreateInfo.pVulkanFunctions = &vulkanFunctions;
|
||||||
|
|
||||||
|
// attempt to create the vma allocator.
|
||||||
|
vmaCreateAllocator(&vmaCreateInfo, &vmaAllocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHVkLogicalDevice::InitializeQueues(std::initializer_list<SHQueueParams> queueCreateParams) noexcept
|
||||||
|
{
|
||||||
|
/* Each queue family has a set amount of queues. Before we get queues from them, we want to
|
||||||
|
* reset the queue use count to 0.
|
||||||
|
*/
|
||||||
|
for (std::size_t i = 0; i < static_cast<std::size_t>(SH_QUEUE_FAMILY_ARRAY_INDEX::MAX); ++i)
|
||||||
|
{
|
||||||
|
if (queueFamilyIndices.indices[i].has_value())
|
||||||
|
{
|
||||||
|
queueFamUseCounts[queueFamilyIndices.indices[i].value()] = 0;
|
||||||
|
queueLibrary.emplace(queueFamilyIndices.indices[i].value(), std::vector<Handle<SHVkQueue>>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// actually attempt to get queue
|
||||||
|
for (auto const& queueParams : queueCreateParams)
|
||||||
|
{
|
||||||
|
// First, check if queue family exists and get index of queue family
|
||||||
|
SHQueueFamilyIndex queueFamIndex = 0;
|
||||||
|
|
||||||
|
if (queueParams.selectionMethod == SH_QUEUE_SELECT::DEDICATED)
|
||||||
|
{
|
||||||
|
if (uint32_t arrayIndex = static_cast<uint32_t>(queueParams.arrayIndex); queueFamilyIndices.indices[arrayIndex].has_value())
|
||||||
|
queueFamIndex = queueFamilyIndices.indices[arrayIndex].value();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SHLOGV_ERROR("Failed to get queue from queue family. ");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
queueFamIndex = nonDedicatedBestIndex;
|
||||||
|
|
||||||
|
// Actually attempt to get the queue from Vulkan and increase the number of queue obtained
|
||||||
|
queueLibrary[queueFamIndex].push_back(SHVkInstance::GetResourceManager().Create<SHVkQueue>(vkLogicalDevice.getQueue(queueFamIndex, queueFamUseCounts[queueFamIndex]++), queueFamIndex, GetHandle()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Initializes a logical device and the requested queues with it. Queues
|
||||||
|
are either specified as either NON_DEDICATED_BEST or DEDICATED.
|
||||||
|
NON_DEDICATED_BEST means that the function will look for a queue family
|
||||||
|
with the highest functionality and attempt to create a queue from that.
|
||||||
|
For example, a transfer queue will select a graphics queue family, even
|
||||||
|
though the graphics aren't needed. DEDICATED means that a transfer queue
|
||||||
|
request would lead to a selection of a dedicated queue family specifically
|
||||||
|
for that queue (e.g. compute -> use compute queue family).
|
||||||
|
|
||||||
|
\param queueCreateParams
|
||||||
|
Since queues all need to be created with the logical device, the specs
|
||||||
|
of all the queues are prerequisites of the creation of the logical device.
|
||||||
|
|
||||||
|
\param inPhysicalDevice
|
||||||
|
\param queueTypes
|
||||||
|
|
||||||
|
\return
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHVkLogicalDevice::SHVkLogicalDevice(std::initializer_list<SHQueueParams> queueCreateParams, Handle<SHVkPhysicalDevice> const& inPhysicalDeviceHdl) noexcept
|
||||||
|
: vkLogicalDevice{}
|
||||||
|
, parentPhysicalDeviceHdl{ inPhysicalDeviceHdl }
|
||||||
|
, queueFamilyIndices{}
|
||||||
|
, vmaAllocator{}
|
||||||
|
{
|
||||||
|
float priority = 1.0f;
|
||||||
|
|
||||||
|
// Get all queue families
|
||||||
|
auto queueFamProps = parentPhysicalDeviceHdl->GetQueueFamilyProperties();
|
||||||
|
|
||||||
|
// Number of queue family properties
|
||||||
|
uint32_t queueFamPropsSize = static_cast<uint32_t>(queueFamProps.size());
|
||||||
|
|
||||||
|
// Will represent the first fit queue family index
|
||||||
|
nonDedicatedBestIndex = 0xFFFF;
|
||||||
|
|
||||||
|
// initialize queue family indices
|
||||||
|
for (uint32_t i = 0; i < queueFamPropsSize; ++i)
|
||||||
|
{
|
||||||
|
std::size_t index = 0;
|
||||||
|
|
||||||
|
if (queueFamProps[i].queueFlags & vk::QueueFlagBits::eGraphics)
|
||||||
|
index = static_cast<std::size_t>(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS);
|
||||||
|
else if (queueFamProps[i].queueFlags & vk::QueueFlagBits::eCompute)
|
||||||
|
index = static_cast<std::size_t>(SH_QUEUE_FAMILY_ARRAY_INDEX::COMPUTE);
|
||||||
|
else if (queueFamProps[i].queueFlags & vk::QueueFlagBits::eTransfer)
|
||||||
|
index = static_cast<std::size_t>(SH_QUEUE_FAMILY_ARRAY_INDEX::TRANSFER);
|
||||||
|
|
||||||
|
queueFamilyIndices.indices[index] = static_cast<SHQueueFamilyIndex>(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the most versatile/best queue family
|
||||||
|
nonDedicatedBestIndex = (*std::min_element(queueFamilyIndices.indices.begin(), queueFamilyIndices.indices.end())).value();
|
||||||
|
|
||||||
|
// Start producing queue create infos
|
||||||
|
std::vector<vk::DeviceQueueCreateInfo> queueCreateInfos;
|
||||||
|
for (auto const& params : queueCreateParams)
|
||||||
|
{
|
||||||
|
vk::DeviceQueueCreateInfo queueCreateInfo{};
|
||||||
|
|
||||||
|
// Check if we want the best or a dedicated queue family
|
||||||
|
if (params.selectionMethod == SH_QUEUE_SELECT::NON_DEDICATED_BEST)
|
||||||
|
queueCreateInfo.queueFamilyIndex = nonDedicatedBestIndex;
|
||||||
|
else
|
||||||
|
queueCreateInfo.queueFamilyIndex = queueFamilyIndices.indices[static_cast<std::size_t>(params.arrayIndex)].value();
|
||||||
|
|
||||||
|
queueCreateInfo.queueCount = 1;
|
||||||
|
queueCreateInfo.pQueuePriorities = &priority; // 1.0f
|
||||||
|
queueCreateInfos.push_back(queueCreateInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<const char*> requiredExtensions;
|
||||||
|
requiredExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||||
|
|
||||||
|
// Check if extensions are supported
|
||||||
|
bool extensionsSupported = parentPhysicalDeviceHdl->ExtensionsSupported(requiredExtensions);
|
||||||
|
// Log error
|
||||||
|
/*if (!extensionsSupported)
|
||||||
|
SHUtil::ReportWarning("Some of the required extensions cannot be found on the physical device. ");*/
|
||||||
|
|
||||||
|
vk::PhysicalDeviceFeatures features{}; // ADD MORE FEATURES HERE IF NEEDED
|
||||||
|
|
||||||
|
// point and lines fill mode
|
||||||
|
features.fillModeNonSolid = true;
|
||||||
|
features.samplerAnisotropy = VK_TRUE;
|
||||||
|
|
||||||
|
// for wide lines
|
||||||
|
features.wideLines = true;
|
||||||
|
|
||||||
|
// Prepare to create the device
|
||||||
|
vk::DeviceCreateInfo deviceCreateInfo
|
||||||
|
{
|
||||||
|
.pNext = nullptr,
|
||||||
|
.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size()),
|
||||||
|
.pQueueCreateInfos = queueCreateInfos.data(),
|
||||||
|
.enabledLayerCount = 0, // deprecated and ignored
|
||||||
|
.ppEnabledLayerNames = nullptr, // deprecated and ignored
|
||||||
|
.enabledExtensionCount = !extensionsSupported ? 0 : static_cast<uint32_t>(requiredExtensions.size()),
|
||||||
|
.ppEnabledExtensionNames = !extensionsSupported ? nullptr : requiredExtensions.data(),
|
||||||
|
.pEnabledFeatures = &features
|
||||||
|
};
|
||||||
|
|
||||||
|
// Actually create the device
|
||||||
|
if (auto result = parentPhysicalDeviceHdl->GetVkPhysicalDevice().createDevice(&deviceCreateInfo, nullptr, &vkLogicalDevice); result != vk::Result::eSuccess)
|
||||||
|
{
|
||||||
|
SHVulkanDebugUtil::ReportVkError(result, "Failed to create Logical Device! ");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SHVulkanDebugUtil::ReportVkSuccess("Successfully created a Logical Device. ");
|
||||||
|
}
|
||||||
|
|
||||||
|
InitializeVMA();
|
||||||
|
|
||||||
|
// TODO: Create pipeline caches
|
||||||
|
// TODO: Create Descriptor pools
|
||||||
|
//auto poolSizes = std::array
|
||||||
|
//{
|
||||||
|
// SHDescriptorPoolSize {SHDescriptorType::COMBINED_SAMPLER, 1000} // hard coded descriptor count
|
||||||
|
//};
|
||||||
|
|
||||||
|
//SHDescriptorPoolParams poolParams
|
||||||
|
//{
|
||||||
|
// .poolSizes = poolSizes,
|
||||||
|
// .maxDescriptorSets = 1000,
|
||||||
|
//};
|
||||||
|
|
||||||
|
//descriptorPool.Initialize(*this, poolParams);
|
||||||
|
//deviceStorage.Init(*this, queueFamilyIndices.indices[static_cast<uint32_t>(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS)].value());
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVkLogicalDevice::SHVkLogicalDevice(SHVkLogicalDevice&& rhs) noexcept
|
||||||
|
: vkLogicalDevice (std::move (rhs.vkLogicalDevice))
|
||||||
|
, queueFamilyIndices(std::move (rhs.queueFamilyIndices))
|
||||||
|
, vmaAllocator{rhs.vmaAllocator}
|
||||||
|
, nonDedicatedBestIndex {0}
|
||||||
|
, parentPhysicalDeviceHdl {rhs.parentPhysicalDeviceHdl}
|
||||||
|
{
|
||||||
|
rhs.vkLogicalDevice = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Destroy the logical device.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHVkLogicalDevice::~SHVkLogicalDevice(void) noexcept
|
||||||
|
{
|
||||||
|
//descriptorPool.Destroy(*this);
|
||||||
|
vkLogicalDevice.destroy(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
TODO: Not sure what this does yet LOL. see the article on efficient
|
||||||
|
Vulkan renderer.
|
||||||
|
|
||||||
|
\param alignment
|
||||||
|
|
||||||
|
\return
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
//void SHVkLogicalDevice::UpdateBufferMemoryAlignment(vk::DeviceSize alignment) noexcept
|
||||||
|
//{
|
||||||
|
// bufferMemoryAlignment = std::max(bufferMemoryAlignment, alignment);
|
||||||
|
//}
|
||||||
|
|
||||||
|
void SHVkLogicalDevice::WaitIdle(void) noexcept
|
||||||
|
{
|
||||||
|
vkLogicalDevice.waitIdle();
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Finds the memory type based on the memory type.
|
||||||
|
|
||||||
|
\param typeFilter
|
||||||
|
\param properties
|
||||||
|
|
||||||
|
\return
|
||||||
|
the index to the memory type.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
uint32_t SHVkLogicalDevice::FindMemoryType(uint32_t typeFilter, vk::MemoryPropertyFlags properties)
|
||||||
|
{
|
||||||
|
auto const& memProps = parentPhysicalDeviceHdl->GetVkPhysicalDevice().getMemoryProperties();
|
||||||
|
for (uint32_t i = 0; i < memProps.memoryTypeCount; ++i)
|
||||||
|
{
|
||||||
|
if (typeFilter & (1 << i) && (memProps.memoryTypes[i].propertyFlags & properties) == properties)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHLOGV_ERROR("Failed to find memory type. ");
|
||||||
|
return VkMemoryPropertyFlagBits::VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Creates a Surface in the resource manager and returns a handle to it.
|
||||||
|
|
||||||
|
\param windowHandle
|
||||||
|
For the surface creation.
|
||||||
|
|
||||||
|
\return
|
||||||
|
A Handle to the surface.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
Handle<SHVkSurface> SHVkLogicalDevice::CreateSurface(HWND const& windowHandle) const noexcept
|
||||||
|
{
|
||||||
|
return SHVkInstance::GetResourceManager().Create<SHVkSurface>(windowHandle, parentPhysicalDeviceHdl, GetHandle());
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Creates a swapchain in the resource manager and returns a handle to it.
|
||||||
|
|
||||||
|
\param surfaceHdl
|
||||||
|
Surface for the swapchain creation.
|
||||||
|
|
||||||
|
\param width
|
||||||
|
Width of swapchain images
|
||||||
|
|
||||||
|
\param height
|
||||||
|
height of swapchain images
|
||||||
|
|
||||||
|
\param params
|
||||||
|
swapchain creation parameters (surface format, depth format, etc).
|
||||||
|
|
||||||
|
\return
|
||||||
|
Handle to swapchain created.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
Handle<SHVkSwapchain> SHVkLogicalDevice::CreateSwapchain(Handle<SHVkSurface> const& surfaceHdl, uint32_t width, uint32_t height, SHSwapchainParams const& params) const noexcept
|
||||||
|
{
|
||||||
|
return SHVkInstance::GetResourceManager().Create<SHVkSwapchain> (parentPhysicalDeviceHdl, GetHandle(), surfaceHdl, width, height, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Creates a command pool in the resource manager and returns a handle to it.
|
||||||
|
|
||||||
|
\param queueFamilyType
|
||||||
|
What queue family type this command pool comes from.
|
||||||
|
|
||||||
|
\param inResetMode
|
||||||
|
BUFFER_BASED for individual resets, POOL_BASED for pool based resets (
|
||||||
|
good for transient command buffers).
|
||||||
|
|
||||||
|
\param inTransient
|
||||||
|
Whether or not command buffers created from this pool are short lived
|
||||||
|
or not.
|
||||||
|
|
||||||
|
\return
|
||||||
|
A handle to the command pool created.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
Handle<SHVkCommandPool> SHVkLogicalDevice::CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX queueFamilyType, SH_CMD_POOL_RESET inResetMode, bool inTransient) const noexcept
|
||||||
|
{
|
||||||
|
auto newHdl = SHVkInstance::GetResourceManager().Create<SHVkCommandPool>(GetHandle(), queueFamilyType, inResetMode, inTransient);
|
||||||
|
return newHdl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Creates a buffer in the resource manager and returns a handle to it. See
|
||||||
|
buffer init function for details on parameters.
|
||||||
|
|
||||||
|
\return
|
||||||
|
A handle to the buffer created.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
Handle<SHVkBuffer> SHVkLogicalDevice::CreateBuffer(uint32_t inSize, void* data, uint32_t srcSize, vk::BufferUsageFlags bufferUsage, VmaMemoryUsage memUsage, VmaAllocationCreateFlags allocFlags) const noexcept
|
||||||
|
{
|
||||||
|
return SHVkInstance::GetResourceManager().Create<SHVkBuffer>(inSize, data, srcSize, std::cref(vmaAllocator), bufferUsage, memUsage, allocFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Creates an image. This ctor is mainly used for constructing images that
|
||||||
|
will be used as render targets.
|
||||||
|
|
||||||
|
\param w
|
||||||
|
Width of image.
|
||||||
|
|
||||||
|
\param h
|
||||||
|
Height of image.
|
||||||
|
|
||||||
|
\param levels
|
||||||
|
Number of mip levels.
|
||||||
|
|
||||||
|
\param format
|
||||||
|
Format of the image
|
||||||
|
|
||||||
|
\param usage
|
||||||
|
Usage bits for the image.
|
||||||
|
|
||||||
|
\param create
|
||||||
|
Create bits for the image.
|
||||||
|
|
||||||
|
\return
|
||||||
|
Handle to the newly created image.
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
Handle<SHVkImage> SHVkLogicalDevice::CreateImage(uint32_t w, uint32_t h, uint8_t levels, vk::Format format, vk::ImageUsageFlags usage, vk::ImageCreateFlags create) const noexcept
|
||||||
|
{
|
||||||
|
return SHVkInstance::GetResourceManager().Create<SHVkImage>(std::cref(vmaAllocator), w, h, levels, format, usage, create);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Creates a shader module in the resource manager and returns a handle to
|
||||||
|
it.
|
||||||
|
|
||||||
|
\param binaryData
|
||||||
|
Binary data for the module's creation.
|
||||||
|
|
||||||
|
\param entryPoint
|
||||||
|
Entry point of the shader.
|
||||||
|
|
||||||
|
\param stage
|
||||||
|
Shader stage.
|
||||||
|
|
||||||
|
\return
|
||||||
|
Handle to the new shader module created.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
Handle<SHVkShaderModule> SHVkLogicalDevice::CreateShaderModule(std::vector<uint32_t> const& binaryData, std::string entryPoint, vk::ShaderStageFlagBits stage, std::string const& shaderName) noexcept
|
||||||
|
{
|
||||||
|
return SHVkInstance::GetResourceManager().Create<SHVkShaderModule>(GetHandle(), binaryData, entryPoint, stage, shaderName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Creates a pipeline layout in the resource manager and returns a handle to
|
||||||
|
it.
|
||||||
|
|
||||||
|
\param pipelineLayoutParams
|
||||||
|
|
||||||
|
\return
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
Handle<SHVkPipelineLayout> SHVkLogicalDevice::CreatePipelineLayout(SHPipelineLayoutParams& pipelineLayoutParams) noexcept
|
||||||
|
{
|
||||||
|
return SHVkInstance::GetResourceManager().Create <SHVkPipelineLayout>(GetHandle(), pipelineLayoutParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Creates a pipeline in the resource manager and returns a handle to it.
|
||||||
|
|
||||||
|
\param pipelineLayoutHdl
|
||||||
|
|
||||||
|
|
||||||
|
\param state
|
||||||
|
\param type
|
||||||
|
|
||||||
|
\return
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
Handle<SHVkPipeline> SHVkLogicalDevice::CreatePipeline(Handle<SHVkPipelineLayout> const& pipelineLayoutHdl, SHVkPipelineState const* const state, Handle<SHVkRenderpass> const& renderpassHdl, uint32_t subpass, SH_PIPELINE_TYPE type) noexcept
|
||||||
|
{
|
||||||
|
return SHVkInstance::GetResourceManager().Create <SHVkPipeline>(GetHandle(), pipelineLayoutHdl, state, renderpassHdl, subpass, type);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle<SHVkRenderpass> SHVkLogicalDevice::CreateRenderpass(std::span<vk::AttachmentDescription> const vkDescriptions, std::vector<SHVkSubpassParams> const& subpasses) noexcept
|
||||||
|
{
|
||||||
|
return SHVkInstance::GetResourceManager().Create <SHVkRenderpass>(GetHandle(), vkDescriptions, subpasses);
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle<SHVkRenderpass> SHVkLogicalDevice::CreateRenderpass(std::span<vk::AttachmentDescription> const vkDescriptions, std::span<vk::SubpassDescription> const spDescs, std::span<vk::SubpassDependency> const spDeps) noexcept
|
||||||
|
{
|
||||||
|
return SHVkInstance::GetResourceManager().Create <SHVkRenderpass>(GetHandle(), vkDescriptions, spDescs, spDeps);
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle<SHVkFramebuffer> SHVkLogicalDevice::CreateFramebuffer(Handle<SHVkRenderpass> const& renderpassHdl, std::vector<Handle<SHVkImageView>> const& attachments, uint32_t inWidth, uint32_t inHeight) noexcept
|
||||||
|
{
|
||||||
|
return SHVkInstance::GetResourceManager().Create <SHVkFramebuffer>(GetHandle(), renderpassHdl, attachments, inWidth, inHeight);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle<SHVkDescriptorSetLayout> SHVkLogicalDevice::CreateDescriptorSetLayout(std::vector<SHVkDescriptorSetLayout::Binding> const& bindings) noexcept
|
||||||
|
{
|
||||||
|
return SHVkInstance::GetResourceManager().Create <SHVkDescriptorSetLayout>(GetHandle(), bindings);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Creates a fence in the resource manager and returns a handle to it.
|
||||||
|
|
||||||
|
\return
|
||||||
|
A handle to the fence created.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
Handle<SHVkFence> SHVkLogicalDevice::CreateFence(void) const noexcept
|
||||||
|
{
|
||||||
|
return SHVkInstance::GetResourceManager().Create<SHVkFence>(GetHandle());
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Creates a semaphore in the resource manager and returns a handle to it.
|
||||||
|
|
||||||
|
\return
|
||||||
|
A handle to the semaphore created.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
Handle<SHVkSemaphore> SHVkLogicalDevice::CreateSemaphore(void) const noexcept
|
||||||
|
{
|
||||||
|
return SHVkInstance::GetResourceManager().Create<SHVkSemaphore>(GetHandle());
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Returns the vulkan logical device.
|
||||||
|
|
||||||
|
\return
|
||||||
|
The vulkan logical device.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
vk::Device const& SHVkLogicalDevice::GetVkLogicalDevice(void) const noexcept
|
||||||
|
{
|
||||||
|
return vkLogicalDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Returns a handle to a queue given an index and given a queue family array
|
||||||
|
index.
|
||||||
|
|
||||||
|
\param index
|
||||||
|
|
||||||
|
|
||||||
|
\param queueIndex
|
||||||
|
|
||||||
|
\return
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
Handle<SHVkQueue> const& SHVkLogicalDevice::GetQueue(SH_Q_FAM queueFamArrayIndex, uint8_t queueIndex) const
|
||||||
|
{
|
||||||
|
if (queueFamilyIndices.indices[static_cast<SHQueueFamilyIndex>(queueFamArrayIndex)].has_value())
|
||||||
|
{
|
||||||
|
SHQueueFamilyIndex queueFamIndex = queueFamilyIndices.indices[static_cast<SHQueueFamilyIndex>(queueFamArrayIndex)].value();
|
||||||
|
if (queueIndex < queueFamUseCounts.at(queueFamIndex))
|
||||||
|
{
|
||||||
|
return queueLibrary.at(queueFamIndex)[queueIndex];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw std::invalid_argument("Attempting to index for a queue that is out of range. Try requesting for more queues on device creation or request for a valid queue index. ");
|
||||||
|
}
|
||||||
|
throw std::invalid_argument("Queue family doesn't exist. ");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Getter for buffer alignment.
|
||||||
|
|
||||||
|
\return
|
||||||
|
The member buffer alignment variable.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
//vk::DeviceSize SHVkLogicalDevice::GetBufferAlignment(void) const noexcept
|
||||||
|
//{
|
||||||
|
// return bufferMemoryAlignment;
|
||||||
|
//}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Getter for VMA Allocator.
|
||||||
|
|
||||||
|
\return
|
||||||
|
VmaAllocator handle.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
VmaAllocator const& SHVkLogicalDevice::GetVMAAllocator(void) noexcept
|
||||||
|
{
|
||||||
|
return vmaAllocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHQueueFamilyIndex SHVkLogicalDevice::GetQueueFamilyIndex(SH_Q_FAM family) const noexcept
|
||||||
|
{
|
||||||
|
if (queueFamilyIndices.indices[static_cast<uint32_t>(family)].has_value())
|
||||||
|
return queueFamilyIndices.indices[static_cast<uint32_t>(family)].value();
|
||||||
|
else
|
||||||
|
return static_cast<SHQueueFamilyIndex>(SH_Q_FAM::INVALID);
|
||||||
|
}
|
||||||
|
|
||||||
|
//SHDescriptorPool const& SHLogicalDevice::GetDescriptorPool(void) const noexcept
|
||||||
|
//{
|
||||||
|
// return descriptorPool;
|
||||||
|
//}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,186 @@
|
||||||
|
#ifndef SH_LOGICAL_DEVICE_H
|
||||||
|
#define SH_LOGICAL_DEVICE_H
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <array>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include "Graphics/SHVulkanIncludes.h"
|
||||||
|
#include "Graphics/Devices/SHVkPhysicalDevice.h"
|
||||||
|
#include "Graphics/Queues/SHVkQueue.h"
|
||||||
|
#include "Resource/Handle.h"
|
||||||
|
#include "Resource/ResourceLibrary.h"
|
||||||
|
#include "Graphics/Swapchain/SHSwapchainParams.h"
|
||||||
|
#include "Graphics/Commands/SHCommandPoolResetMode.h"
|
||||||
|
#include "Graphics/Commands/SHVkCommandPool.h"
|
||||||
|
#include "Graphics/Pipeline/SHPipelineLayoutParams.h"
|
||||||
|
#include "Graphics/Pipeline/SHPipelineState.h"
|
||||||
|
#include "Graphics/Pipeline/SHPipelineType.h"
|
||||||
|
#include "vk_mem_alloc.h"
|
||||||
|
//#include "Graphics/DescriptorSets/SHDescriptorPool.h"
|
||||||
|
#include "Graphics/Descriptors/SHVkDescriptorSetLayout.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* FORWARD DECLARATIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
class SHVkInstance;
|
||||||
|
class SHVkSurface;
|
||||||
|
class SHVkSwapchain;
|
||||||
|
class SHVkBuffer;
|
||||||
|
class SHVkImage;
|
||||||
|
class SHVkFence;
|
||||||
|
class SHVkSemaphore;
|
||||||
|
class SHVkShaderModule;
|
||||||
|
class SHVkPipelineLayout;
|
||||||
|
class SHVkPipeline;
|
||||||
|
class SHVkFramebuffer;
|
||||||
|
class SHVkImageView;
|
||||||
|
class SHShaderBlockInterface;
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\struct SHQueueFamilyIndices
|
||||||
|
Stores Vulkan queue family indices of each queue family.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
struct SHQueueFamilyIndices
|
||||||
|
{
|
||||||
|
std::array<std::optional<SHQueueFamilyIndex>, static_cast<std::size_t>(SH_QUEUE_FAMILY_ARRAY_INDEX::MAX)> indices;
|
||||||
|
};
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\class SHVkLogicalDevice
|
||||||
|
Stores a Vulkan logical device.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
class SHVkLogicalDevice : public ISelfHandle<SHVkLogicalDevice>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PRIVATE MEMBER VARIABLES */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
//vk::DeviceSize bufferMemoryAlignment{ 64 };
|
||||||
|
|
||||||
|
//! Vulkan handle
|
||||||
|
vk::Device vkLogicalDevice;
|
||||||
|
|
||||||
|
//! Handle to the physical device this logical device was created from
|
||||||
|
Handle<SHVkPhysicalDevice> parentPhysicalDeviceHdl;
|
||||||
|
|
||||||
|
//! The array of queue family array indices
|
||||||
|
SHQueueFamilyIndices queueFamilyIndices{};
|
||||||
|
|
||||||
|
//! If the user chooses a non-dedicated queue, the device will initialize this to the best queue family index
|
||||||
|
uint32_t nonDedicatedBestIndex;
|
||||||
|
|
||||||
|
//std::vector<Handle<SHVkQueue>> queueHdls;
|
||||||
|
std::unordered_map<SHQueueFamilyIndex, std::vector<Handle<SHVkQueue>>> queueLibrary;
|
||||||
|
|
||||||
|
//! For use on tracking how many queues are retrieved
|
||||||
|
std::unordered_map<SHQueueFamilyIndex, uint32_t> queueFamUseCounts;
|
||||||
|
|
||||||
|
//! main VMA allocator of this instance
|
||||||
|
VmaAllocator vmaAllocator;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PRIVATE MEMBER FUNCTIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
void InitializeVMA (void) noexcept;
|
||||||
|
void InitializeQueues (std::initializer_list<SHQueueParams> queueCreateParams) noexcept;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* CTOR AND DTOR */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
SHVkLogicalDevice (std::initializer_list<SHQueueParams> queueCreateParams, Handle<SHVkPhysicalDevice> const& inPhysicalDeviceHdl) noexcept;
|
||||||
|
SHVkLogicalDevice (SHVkLogicalDevice const& rhs) = default;
|
||||||
|
SHVkLogicalDevice (SHVkLogicalDevice&& rhs) noexcept;
|
||||||
|
~SHVkLogicalDevice (void) noexcept;
|
||||||
|
|
||||||
|
SHVkLogicalDevice& operator= (SHVkLogicalDevice const& rhs) noexcept = default;
|
||||||
|
SHVkLogicalDevice& operator= (SHVkLogicalDevice&& rhs) noexcept = default;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PUBLIC MEMBER VARIABLES */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
void WaitIdle (void) noexcept;
|
||||||
|
uint32_t FindMemoryType (uint32_t typeFilter, vk::MemoryPropertyFlags properties);
|
||||||
|
|
||||||
|
Handle<SHVkSurface> CreateSurface (HWND const& windowHandle) const noexcept;
|
||||||
|
Handle<SHVkSwapchain> CreateSwapchain (
|
||||||
|
Handle<SHVkSurface> const& surfaceHdl,
|
||||||
|
uint32_t width,
|
||||||
|
uint32_t height,
|
||||||
|
SHSwapchainParams const& params
|
||||||
|
) const noexcept;
|
||||||
|
|
||||||
|
Handle<SHVkCommandPool> CreateCommandPool (
|
||||||
|
SH_QUEUE_FAMILY_ARRAY_INDEX queueFamilyType,
|
||||||
|
SH_CMD_POOL_RESET inResetMode,
|
||||||
|
bool inTransient
|
||||||
|
) const noexcept;
|
||||||
|
|
||||||
|
Handle<SHVkBuffer> CreateBuffer (
|
||||||
|
uint32_t inSize,
|
||||||
|
void* data,
|
||||||
|
uint32_t srcSize,
|
||||||
|
vk::BufferUsageFlags bufferUsage,
|
||||||
|
VmaMemoryUsage memUsage,
|
||||||
|
VmaAllocationCreateFlags allocFlags
|
||||||
|
) const noexcept;
|
||||||
|
|
||||||
|
Handle<SHVkImage> CreateImage (
|
||||||
|
uint32_t w,
|
||||||
|
uint32_t h,
|
||||||
|
uint8_t levels,
|
||||||
|
vk::Format format,
|
||||||
|
vk::ImageUsageFlags usage,
|
||||||
|
vk::ImageCreateFlags create
|
||||||
|
) const noexcept;
|
||||||
|
|
||||||
|
Handle<SHVkShaderModule> CreateShaderModule (
|
||||||
|
std::vector<uint32_t> const& binaryData,
|
||||||
|
std::string entryPoint,
|
||||||
|
vk::ShaderStageFlagBits stage,
|
||||||
|
std::string const& shaderName
|
||||||
|
) noexcept;
|
||||||
|
|
||||||
|
Handle<SHVkPipeline> CreatePipeline (
|
||||||
|
Handle<SHVkPipelineLayout> const& pipelineLayoutHdl,
|
||||||
|
SHVkPipelineState const* const state,
|
||||||
|
Handle<SHVkRenderpass> const& renderpassHdl,
|
||||||
|
uint32_t subpass,
|
||||||
|
SH_PIPELINE_TYPE type
|
||||||
|
) noexcept;
|
||||||
|
|
||||||
|
Handle<SHVkRenderpass> CreateRenderpass (std::span<vk::AttachmentDescription> const vkDescriptions, std::vector<SHVkSubpassParams> const& subpasses) noexcept;
|
||||||
|
Handle<SHVkRenderpass> CreateRenderpass (std::span<vk::AttachmentDescription> const vkDescriptions, std::span<vk::SubpassDescription> const spDescs, std::span<vk::SubpassDependency> const spDeps) noexcept;
|
||||||
|
Handle<SHVkFramebuffer> CreateFramebuffer (Handle<SHVkRenderpass> const& renderpassHdl, std::vector<Handle<SHVkImageView>> const& attachments, uint32_t inWidth, uint32_t inHeight) noexcept;
|
||||||
|
Handle<SHVkDescriptorSetLayout> CreateDescriptorSetLayout (std::vector<SHVkDescriptorSetLayout::Binding> const& bindings) noexcept;
|
||||||
|
Handle<SHVkPipelineLayout> CreatePipelineLayout (SHPipelineLayoutParams& pipelineLayoutParams) noexcept;
|
||||||
|
Handle<SHVkFence> CreateFence (void) const noexcept;
|
||||||
|
Handle<SHVkSemaphore> CreateSemaphore (void) const noexcept;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* SETTERS AND GETTERS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
vk::Device const& GetVkLogicalDevice (void) const noexcept;
|
||||||
|
Handle<SHVkQueue> const& GetQueue (SH_Q_FAM queueFamArrayIndex, uint8_t queueIndex) const;
|
||||||
|
VmaAllocator const& GetVMAAllocator (void) noexcept;
|
||||||
|
SHQueueFamilyIndex GetQueueFamilyIndex (SH_Q_FAM family) const noexcept;
|
||||||
|
//vk::DeviceSize GetBufferAlignment (void) const noexcept;
|
||||||
|
//SHDescriptorPool const& GetDescriptorPool(void) const noexcept;
|
||||||
|
|
||||||
|
friend class SHVkInstance;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,96 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHVkPhysicalDevice.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
|
#include "Tools/SHLogger.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
SHVkPhysicalDevice::SHVkPhysicalDevice (vk::PhysicalDevice inDevice) noexcept
|
||||||
|
: vkPhysicalDevice{nullptr}
|
||||||
|
, deviceProperties{ }
|
||||||
|
, memoryProperties{ }
|
||||||
|
, queueFamilyProperties{ }
|
||||||
|
{
|
||||||
|
if (!inDevice)
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("Trying to initialize a physical device but device passed in is nullptr! ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vkPhysicalDevice = inDevice;
|
||||||
|
|
||||||
|
vkPhysicalDevice.getProperties(&deviceProperties);
|
||||||
|
vkPhysicalDevice.getMemoryProperties(&memoryProperties);
|
||||||
|
|
||||||
|
queueFamilyProperties = vkPhysicalDevice.getQueueFamilyProperties();
|
||||||
|
|
||||||
|
deviceFeatures = vkPhysicalDevice.getFeatures();
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVkPhysicalDevice::SHVkPhysicalDevice(SHVkPhysicalDevice&& rhs) noexcept
|
||||||
|
: deviceProperties {rhs.deviceProperties}
|
||||||
|
, memoryProperties{ rhs.memoryProperties }
|
||||||
|
, deviceFeatures{ rhs.deviceFeatures }
|
||||||
|
, queueFamilyProperties{ rhs.queueFamilyProperties }
|
||||||
|
, vkPhysicalDevice{ std::move (rhs.vkPhysicalDevice)}
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::PhysicalDeviceProperties const& SHVkPhysicalDevice::GetDeviceProperties(void) const noexcept
|
||||||
|
{
|
||||||
|
return deviceProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<vk::QueueFamilyProperties> const& SHVkPhysicalDevice::GetQueueFamilyProperties(void) const noexcept
|
||||||
|
{
|
||||||
|
return queueFamilyProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::PhysicalDeviceMemoryProperties const& SHVkPhysicalDevice::GetMemoryProperties(void) const noexcept
|
||||||
|
{
|
||||||
|
return memoryProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::DeviceSize SHVkPhysicalDevice::vkGetMaxHeapSize(void) const noexcept
|
||||||
|
{
|
||||||
|
// Get array of heaps from the properties
|
||||||
|
vk::MemoryHeap const* heapPtr = memoryProperties.memoryHeaps;
|
||||||
|
|
||||||
|
if (heapPtr == nullptr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// For looping through heaps
|
||||||
|
std::vector<vk::MemoryHeap> heapContainer(heapPtr, heapPtr + memoryProperties.memoryHeapCount);
|
||||||
|
|
||||||
|
// Calculate biggest heap size among heaps of the device
|
||||||
|
VkDeviceSize biggestDeviceHeapSize = 0;
|
||||||
|
for (auto const& heap : heapContainer)
|
||||||
|
{
|
||||||
|
if (heap.size > biggestDeviceHeapSize)
|
||||||
|
biggestDeviceHeapSize = heap.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return biggestDeviceHeapSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::PhysicalDevice SHVkPhysicalDevice::GetVkPhysicalDevice(void) const noexcept
|
||||||
|
{
|
||||||
|
return vkPhysicalDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHVkPhysicalDevice::ExtensionsSupported(std::vector<const char*> const& requiredExtensions) const noexcept
|
||||||
|
{
|
||||||
|
std::vector<vk::ExtensionProperties> availableExtensions{};
|
||||||
|
availableExtensions = vkPhysicalDevice.enumerateDeviceExtensionProperties();
|
||||||
|
|
||||||
|
std::set<std::string> missingExtensions(requiredExtensions.begin(), requiredExtensions.end());
|
||||||
|
for (auto const& extension : availableExtensions)
|
||||||
|
missingExtensions.erase(extension.extensionName);
|
||||||
|
|
||||||
|
return missingExtensions.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
#ifndef SH_PHYSICAL_DEVICE_H
|
||||||
|
#define SH_PHYSICAL_DEVICE_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include "Graphics/Debugging/SHVulkanDebugUtil.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
enum class SH_PHYSICAL_DEVICE_TYPE
|
||||||
|
{
|
||||||
|
BEST,
|
||||||
|
};
|
||||||
|
|
||||||
|
class SHVkPhysicalDevice
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
vk::PhysicalDevice vkPhysicalDevice;
|
||||||
|
|
||||||
|
vk::PhysicalDeviceProperties deviceProperties{};
|
||||||
|
vk::PhysicalDeviceMemoryProperties memoryProperties{};
|
||||||
|
vk::PhysicalDeviceFeatures deviceFeatures{};
|
||||||
|
std::vector<vk::QueueFamilyProperties> queueFamilyProperties{};
|
||||||
|
|
||||||
|
public:
|
||||||
|
SHVkPhysicalDevice(void) = delete;
|
||||||
|
SHVkPhysicalDevice(vk::PhysicalDevice inDevice) noexcept;
|
||||||
|
SHVkPhysicalDevice(SHVkPhysicalDevice const& rhs) noexcept = default;
|
||||||
|
SHVkPhysicalDevice(SHVkPhysicalDevice&& rhs) noexcept;
|
||||||
|
|
||||||
|
SHVkPhysicalDevice& operator= (SHVkPhysicalDevice const& rhs) noexcept = default;
|
||||||
|
SHVkPhysicalDevice& operator= (SHVkPhysicalDevice&& rhs) noexcept = default;
|
||||||
|
|
||||||
|
vk::PhysicalDeviceProperties const& GetDeviceProperties(void) const noexcept;
|
||||||
|
std::vector<vk::QueueFamilyProperties> const& GetQueueFamilyProperties (void) const noexcept;
|
||||||
|
vk::PhysicalDeviceMemoryProperties const& GetMemoryProperties(void) const noexcept;
|
||||||
|
vk::DeviceSize vkGetMaxHeapSize(void) const noexcept;
|
||||||
|
vk::PhysicalDevice GetVkPhysicalDevice(void) const noexcept;
|
||||||
|
bool ExtensionsSupported(std::vector<const char*> const& requiredExtensions) const noexcept;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,189 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include "SHVkPhysicalDeviceLibrary.h"
|
||||||
|
#include "Graphics/Instance/SHVkInstance.h"
|
||||||
|
#include "Tools/SHLogger.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
std::vector<vk::PhysicalDevice> SHVkPhysicalDeviceLibrary::physicalDevices;
|
||||||
|
bool SHVkPhysicalDeviceLibrary::queried = false;
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Returns a c string that represents the physical device type passed in.
|
||||||
|
|
||||||
|
\param type
|
||||||
|
Type of the physical device.
|
||||||
|
|
||||||
|
\return
|
||||||
|
Returns a c string of the type.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
char const* const SHVkPhysicalDeviceLibrary::GetDeviceTypeName(vk::PhysicalDeviceType type) noexcept
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case vk::PhysicalDeviceType::eDiscreteGpu:
|
||||||
|
return "Discrete Device";
|
||||||
|
case vk::PhysicalDeviceType::eIntegratedGpu:
|
||||||
|
return "Integrated Device";
|
||||||
|
default:
|
||||||
|
return "Unsupported Device";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Fills up physical device container.
|
||||||
|
|
||||||
|
\param renderingInstance
|
||||||
|
Rendering Instance required to get physical devices.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkPhysicalDeviceLibrary::QueryPhysicalDevices(bool printInfo /*= true*/) noexcept
|
||||||
|
{
|
||||||
|
physicalDevices = SHVkInstance::GetVkInstance().enumeratePhysicalDevices();
|
||||||
|
if (physicalDevices.size() == 0)
|
||||||
|
{
|
||||||
|
SHLOGV_ERROR("Failed to detect physical devices. ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (printInfo)
|
||||||
|
PrintAllPhysicalDevices();
|
||||||
|
|
||||||
|
// Set flag to indicate devices are queried and saved
|
||||||
|
queried = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Attempts to get physical devices from the device library based on the
|
||||||
|
type passed in.
|
||||||
|
|
||||||
|
\param gpuType
|
||||||
|
The type of physical device we want to get.
|
||||||
|
|
||||||
|
\return
|
||||||
|
A subset of the queried physical devices that are of type gpuType.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
//std::vector<std::shared_ptr<SHPhysicalDevice>> SHPhysicalDeviceLibrary::GetDevicesByType(VkPhysicalDeviceType gpuType, SHVulkanAPIVersion apiVersion) noexcept
|
||||||
|
//{
|
||||||
|
// // If the application has not queried a physical device yet, don't return anything
|
||||||
|
// if (!queried)
|
||||||
|
// {
|
||||||
|
// SHUtil::ReportWarning("Cannot get any physical devices. Query the physical devices first. ");
|
||||||
|
// return {};
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Prep a container to store devices
|
||||||
|
// std::vector<std::shared_ptr<SHPhysicalDevice>> devices;
|
||||||
|
|
||||||
|
// // For all the devices queried, find ones that match the type passed in
|
||||||
|
// for (auto const& device : physicalDevices)
|
||||||
|
// {
|
||||||
|
// // Check for API version and device type
|
||||||
|
// if (device->GetDeviceProperties().apiVersion == static_cast<uint32_t>(apiVersion) && device->GetDeviceProperties().deviceType == gpuType)
|
||||||
|
// {
|
||||||
|
// devices.push_back(device);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Return list of devices (can be empty, meaning no devices have the type passed in)
|
||||||
|
// return devices;
|
||||||
|
//}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Of all the discrete devices, get the best one. Right now, this just
|
||||||
|
checks the physical device heap size and uses the one with the highest.
|
||||||
|
|
||||||
|
\param apiVersion
|
||||||
|
The API version that the device has the support.
|
||||||
|
|
||||||
|
\return
|
||||||
|
The best physical device.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
vk::PhysicalDevice SHVkPhysicalDeviceLibrary::GetBestDevice(uint32_t apiVersion /*= SHVulkanAPIVersion::V_1_2*/)
|
||||||
|
{
|
||||||
|
if (!queried || physicalDevices.empty())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
vk::PhysicalDevice bestDevice = nullptr;
|
||||||
|
VkDeviceSize biggestHeapSize = 0;
|
||||||
|
for (auto const& device : physicalDevices)
|
||||||
|
{
|
||||||
|
// Check for API version and device type. Ignore if queried device doesn't support version passed in
|
||||||
|
if (device.getProperties().apiVersion < static_cast<uint32_t>(apiVersion))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//VkDeviceSize biggestDeviceHeapSize = device.getMemoryProperties().;
|
||||||
|
|
||||||
|
// Get array of heaps from the properties
|
||||||
|
vk::MemoryHeap const* heapPtr = device.getMemoryProperties().memoryHeaps;
|
||||||
|
|
||||||
|
if (heapPtr == nullptr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// For looping through heaps
|
||||||
|
std::vector<vk::MemoryHeap> heapContainer(heapPtr, heapPtr + device.getMemoryProperties().memoryHeapCount);
|
||||||
|
|
||||||
|
// Calculate biggest heap size among heaps of the device
|
||||||
|
VkDeviceSize biggestDeviceHeapSize = 0;
|
||||||
|
for (auto const& heap : heapContainer)
|
||||||
|
{
|
||||||
|
if (heap.size > biggestDeviceHeapSize)
|
||||||
|
biggestDeviceHeapSize = heap.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the device contains a heap that is bigger than other cards calculated before
|
||||||
|
if (biggestDeviceHeapSize > biggestHeapSize)
|
||||||
|
{
|
||||||
|
// Make that device the best device
|
||||||
|
biggestHeapSize = biggestDeviceHeapSize;
|
||||||
|
bestDevice = device;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bestDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Prints all of the physical devices queried. Private function. For
|
||||||
|
internal use only.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkPhysicalDeviceLibrary::PrintAllPhysicalDevices(void) noexcept
|
||||||
|
{
|
||||||
|
if (physicalDevices.empty())
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("No physical devices queried. Nothing to print. ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHLOG_ERROR("Successfully queried Physical Devices:");
|
||||||
|
for (auto const& device : physicalDevices)
|
||||||
|
{
|
||||||
|
SHLOG_ERROR(std::string_view (std::string("\t-") + GetDeviceTypeName(device.getProperties().deviceType) + device.getProperties().deviceName.operator std::string()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef SH_PHYSICAL_DEVICE_LIBRARY_H
|
||||||
|
#define SH_PHYSICAL_DEVICE_LIBRARY_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include "Graphics/Debugging/SHVulkanDebugUtil.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
// Rendering instance forward declaration
|
||||||
|
class SHVkInstance;
|
||||||
|
|
||||||
|
class SHVkPhysicalDeviceLibrary
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
//! Stores all the available GPUs (discrete + non-discrete)
|
||||||
|
static std::vector<vk::PhysicalDevice> physicalDevices;
|
||||||
|
|
||||||
|
//! If devices have been queried, this will be false
|
||||||
|
static bool queried;
|
||||||
|
|
||||||
|
static char const* const GetDeviceTypeName(vk::PhysicalDeviceType type) noexcept;
|
||||||
|
static void PrintAllPhysicalDevices(void) noexcept;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void QueryPhysicalDevices(bool printInfo) noexcept;
|
||||||
|
//static std::vector<std::shared_ptr<SHPhysicalDevice>> GetDevicesByType(VkPhysicalDeviceType gpuType, SHVulkanAPIVersion apiVersion = SHVulkanAPIVersion::V_1_2) noexcept;
|
||||||
|
static vk::PhysicalDevice GetBestDevice(uint32_t apiVersion = VK_API_VERSION_1_3);
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,163 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHVkFramebuffer.h"
|
||||||
|
#include "Graphics/Images/SHVkImageView.h"
|
||||||
|
#include "Graphics/Images/SHVkImage.h"
|
||||||
|
#include "Graphics/Renderpass/SHVkRenderpass.h"
|
||||||
|
#include "Tools/SHLogger.h"
|
||||||
|
#include "Graphics/Devices/SHVkLogicalDevice.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Non-default ctor. Initializes a framebuffer with attachments.
|
||||||
|
|
||||||
|
\param logicalDevice
|
||||||
|
Required for framebuffer creation and destruction
|
||||||
|
|
||||||
|
\param renderpass
|
||||||
|
Renderpass that the framebuffer will be compatible with.
|
||||||
|
|
||||||
|
\param attachments
|
||||||
|
Attachments to be attached to the framebuffer.
|
||||||
|
|
||||||
|
\return
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHVkFramebuffer::SHVkFramebuffer(Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl, Handle<SHVkRenderpass> const& renderpassHdl, std::vector<Handle<SHVkImageView>> const& attachments, uint32_t inWidth, uint32_t inHeight) noexcept
|
||||||
|
: logicalDeviceHdl{inLogicalDeviceHdl}
|
||||||
|
, width {inWidth}
|
||||||
|
, height {inHeight}
|
||||||
|
{
|
||||||
|
// TODO: Verify if a check needs to be done to see if image dimensions are the same as the dimensions passed in
|
||||||
|
|
||||||
|
for (auto& attachment : attachments)
|
||||||
|
{
|
||||||
|
// Not sure if its an error to pass in diff dimension images.
|
||||||
|
if (attachment->GetParentImage()->GetWidth() != (*attachments.begin())->GetParentImage()->GetWidth() || attachment->GetParentImage()->GetHeight() != (*attachments.begin())->GetParentImage()->GetHeight())
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("Dimensions of images not same as each other. Cannot create framebuffer.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<vk::ImageView> vkAttachments(attachments.size());
|
||||||
|
|
||||||
|
uint32_t i = 0;
|
||||||
|
for(auto const& attachment : attachments)
|
||||||
|
{
|
||||||
|
vkAttachments[i] = attachment->GetImageView();
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::FramebufferCreateInfo createInfo
|
||||||
|
{
|
||||||
|
.renderPass = renderpassHdl->GetVkRenderpass(),
|
||||||
|
.attachmentCount = static_cast<uint32_t>(vkAttachments.size()),
|
||||||
|
.pAttachments = vkAttachments.data(),
|
||||||
|
.width = width,
|
||||||
|
.height = height,
|
||||||
|
.layers = 1 // TODO: Find out why this is 1
|
||||||
|
};
|
||||||
|
|
||||||
|
if (auto result = logicalDeviceHdl->GetVkLogicalDevice().createFramebuffer(&createInfo, nullptr, &vkFramebuffer); result != vk::Result::eSuccess)
|
||||||
|
{
|
||||||
|
SHVulkanDebugUtil::ReportVkError(result, "Failed to create framebuffer. ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SHVulkanDebugUtil::ReportVkSuccess("Successfully created framebuffer. ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVkFramebuffer::SHVkFramebuffer(SHVkFramebuffer&& rhs) noexcept
|
||||||
|
: vkFramebuffer{rhs.vkFramebuffer}
|
||||||
|
, logicalDeviceHdl {rhs.logicalDeviceHdl}
|
||||||
|
, width {rhs.width}
|
||||||
|
, height {rhs.height}
|
||||||
|
{
|
||||||
|
rhs.vkFramebuffer = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVkFramebuffer& SHVkFramebuffer::operator=(SHVkFramebuffer&& rhs) noexcept
|
||||||
|
{
|
||||||
|
if (&rhs == this)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
vkFramebuffer = rhs.vkFramebuffer;
|
||||||
|
logicalDeviceHdl = rhs.logicalDeviceHdl;
|
||||||
|
width = rhs.width;
|
||||||
|
height = rhs.height;
|
||||||
|
|
||||||
|
rhs.vkFramebuffer = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Getter for the vulkan framebuffer handle.
|
||||||
|
|
||||||
|
\return
|
||||||
|
The framebuffer handle.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
vk::Framebuffer SHVkFramebuffer::GetVkFramebuffer(void) const noexcept
|
||||||
|
{
|
||||||
|
return vkFramebuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Returns the framebuffer width.
|
||||||
|
|
||||||
|
\return
|
||||||
|
The framebuffer width.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
uint32_t SHVkFramebuffer::GetWidth(void) const noexcept
|
||||||
|
{
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Returns the framebuffer height.
|
||||||
|
|
||||||
|
\return
|
||||||
|
The framebuffer height.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
uint32_t SHVkFramebuffer::GetHeight(void) const noexcept
|
||||||
|
{
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Destroys the framebuffer.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHVkFramebuffer::~SHVkFramebuffer(void) noexcept
|
||||||
|
{
|
||||||
|
if (vkFramebuffer)
|
||||||
|
logicalDeviceHdl->GetVkLogicalDevice().destroyFramebuffer(vkFramebuffer, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
#ifndef SH_VK_FRAMEBUFFER_H
|
||||||
|
#define SH_VK_FRAMEBUFFER_H
|
||||||
|
|
||||||
|
#include "Graphics/SHVulkanIncludes.h"
|
||||||
|
#include "Resource/Handle.h"
|
||||||
|
#include <span>
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
class SHVkLogicalDevice;
|
||||||
|
class SHVkRenderpass;
|
||||||
|
class SHVkImageView;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Renderpasses are really only meant to hold attachments. What writes are reads from it are determined by
|
||||||
|
attachments references in subpasses.
|
||||||
|
*/
|
||||||
|
class SHVkFramebuffer
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
//! The vulkan framebuffer handle
|
||||||
|
vk::Framebuffer vkFramebuffer;
|
||||||
|
|
||||||
|
//! Logical device for destruction later on
|
||||||
|
Handle<SHVkLogicalDevice> logicalDeviceHdl;
|
||||||
|
|
||||||
|
//! Width of the images in the framebuffer
|
||||||
|
uint32_t width;
|
||||||
|
|
||||||
|
//! Height of the images in the framebuffer
|
||||||
|
uint32_t height;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SHVkFramebuffer(Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl, Handle<SHVkRenderpass> const& renderpassHdl, std::vector<Handle<SHVkImageView>> const& attachments, uint32_t inWidth, uint32_t inHeight) noexcept;
|
||||||
|
~SHVkFramebuffer(void) noexcept;
|
||||||
|
|
||||||
|
SHVkFramebuffer(SHVkFramebuffer&& rhs) noexcept;
|
||||||
|
SHVkFramebuffer& operator=(SHVkFramebuffer&& rhs) noexcept;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* SETTERS AND GETTERS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
vk::Framebuffer GetVkFramebuffer(void) const noexcept;
|
||||||
|
uint32_t GetWidth (void) const noexcept;
|
||||||
|
uint32_t GetHeight (void) const noexcept;
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,44 @@
|
||||||
|
#ifndef SH_IMAGE_VIEW_DETAILS_H
|
||||||
|
#define SH_IMAGE_VIEW_DETAILS_H
|
||||||
|
|
||||||
|
#include "Graphics/SHVulkanIncludes.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
struct SHImageViewDetails
|
||||||
|
{
|
||||||
|
//! Image view type
|
||||||
|
vk::ImageViewType viewType;
|
||||||
|
|
||||||
|
//! If the image is created with VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT bit, this format can be different from parent image
|
||||||
|
vk::Format format;
|
||||||
|
|
||||||
|
//! The subresource mask of the image view
|
||||||
|
//! NOTE: It seems that from the specification, the image view does not have the agency to choose its own subresource aspect mask.
|
||||||
|
//! For simple use cases, the image formats corresponds to the aspect mask required : color to color, depth to depth, stencil to stencil.
|
||||||
|
//! However, because there are simply too many formats to prevent users from passing in the wrong arguments, we are letting them do it anyway.
|
||||||
|
//! Just keep this in mind.
|
||||||
|
vk::ImageAspectFlags imageAspectFlags;
|
||||||
|
|
||||||
|
//! base mip level
|
||||||
|
uint32_t baseMipLevel;
|
||||||
|
|
||||||
|
//! How many mips the image view has access to
|
||||||
|
uint32_t mipLevelCount;
|
||||||
|
|
||||||
|
//! Base array layer (layer is the array index)
|
||||||
|
uint32_t baseArrayLayer;
|
||||||
|
|
||||||
|
//! How many layers the image view has access to
|
||||||
|
uint32_t layerCount;
|
||||||
|
|
||||||
|
//SHImageViewDetails(void) noexcept = default;
|
||||||
|
|
||||||
|
//SHImageViewDetails(SHImageViewDetails const& rhs) noexcept = default;
|
||||||
|
//SHImageViewDetails& operator=(SHImageViewDetails const& rhs) noexcept = default;
|
||||||
|
|
||||||
|
//SHImageViewDetails(SHImageViewDetails&& rhs) noexcept = default;
|
||||||
|
//SHImageViewDetails& operator=(SHImageViewDetails&& rhs) noexcept = default;
|
||||||
|
}; }
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,260 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHVkImage.h"
|
||||||
|
#include "Graphics/Devices/SHVkLogicalDevice.h"
|
||||||
|
#include "Graphics/Debugging/SHVulkanDebugUtil.h"
|
||||||
|
#include "Tools/SHLogger.h"
|
||||||
|
#include "SHVkImageView.h"
|
||||||
|
#include "Graphics/Instance/SHVkInstance.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
SHVkImage::SHVkImage(
|
||||||
|
VmaAllocator const& vmaAllocator,
|
||||||
|
SHImageCreateParams const& imageDetails,
|
||||||
|
VmaMemoryUsage memUsage,
|
||||||
|
VmaAllocationCreateFlags allocFlags
|
||||||
|
) noexcept
|
||||||
|
: imageType { imageDetails.imageType }
|
||||||
|
, width{ imageDetails.width }
|
||||||
|
, height{ imageDetails.height }
|
||||||
|
, depth{ imageDetails.depth }
|
||||||
|
, mipLevelCount{ imageDetails.levels }
|
||||||
|
, layerCount{ imageDetails.arrayLayers }
|
||||||
|
, imageFormat{ imageDetails.imageFormat }
|
||||||
|
, usageFlags{}
|
||||||
|
, createFlags{}
|
||||||
|
{
|
||||||
|
for (auto& bit : imageDetails.usageBits)
|
||||||
|
usageFlags |= bit;
|
||||||
|
|
||||||
|
for (auto& bit : imageDetails.createBits)
|
||||||
|
createFlags |= bit;
|
||||||
|
|
||||||
|
// If marked as 2D array compatible, image type MUST be 3D
|
||||||
|
if (createFlags & vk::ImageCreateFlagBits::e2DArrayCompatible)
|
||||||
|
{
|
||||||
|
if (imageType != vk::ImageType::e3D)
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("Image is marked to be 2D Array compatible. Image type MUST hence be 3D. ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::ImageCreateInfo imageCreateInfo{};
|
||||||
|
imageCreateInfo.imageType = imageType;
|
||||||
|
imageCreateInfo.extent.width = width;
|
||||||
|
imageCreateInfo.extent.height = height;
|
||||||
|
imageCreateInfo.extent.depth = 1;
|
||||||
|
imageCreateInfo.mipLevels = mipLevelCount;
|
||||||
|
imageCreateInfo.arrayLayers = layerCount;
|
||||||
|
imageCreateInfo.format = imageFormat;
|
||||||
|
imageCreateInfo.tiling = vk::ImageTiling::eOptimal;
|
||||||
|
imageCreateInfo.initialLayout = vk::ImageLayout::eUndefined;
|
||||||
|
imageCreateInfo.usage = usageFlags;
|
||||||
|
imageCreateInfo.sharingMode = vk::SharingMode::eExclusive;
|
||||||
|
imageCreateInfo.samples = vk::SampleCountFlagBits::e1;
|
||||||
|
imageCreateInfo.flags = createFlags;
|
||||||
|
|
||||||
|
|
||||||
|
// Prepare allocation parameters for call to create images later
|
||||||
|
VmaAllocationCreateInfo allocCreateInfo{};
|
||||||
|
allocCreateInfo.usage = memUsage;
|
||||||
|
allocCreateInfo.flags = allocFlags;
|
||||||
|
|
||||||
|
VmaAllocationInfo allocInfo{};
|
||||||
|
|
||||||
|
VkImage tempImage;
|
||||||
|
vmaCreateImage(vmaAllocator, &imageCreateInfo.operator VkImageCreateInfo&(), &allocCreateInfo, &tempImage, &alloc, &allocInfo);
|
||||||
|
vkImage = tempImage;
|
||||||
|
|
||||||
|
//if (allocFlags & )
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
This is mainly used for images that aren't created internally because
|
||||||
|
they cannot be created in the traditional way (e.g. swapchain images).
|
||||||
|
|
||||||
|
\param inVkImage
|
||||||
|
Image already created outside
|
||||||
|
|
||||||
|
\param width
|
||||||
|
Width of the image
|
||||||
|
|
||||||
|
\param height
|
||||||
|
Height of the image
|
||||||
|
|
||||||
|
\param depth
|
||||||
|
Depth of the image
|
||||||
|
|
||||||
|
\param levels
|
||||||
|
Number of levels in the image
|
||||||
|
|
||||||
|
\param arrayLayers
|
||||||
|
if the image is an array, this value will be > 1.
|
||||||
|
|
||||||
|
\param imageFormat
|
||||||
|
Format of the image
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHVkImage::SHVkImage(vk::Image inVkImage, vk::ImageType type, uint32_t inWidth, uint32_t inHeight, uint32_t inDepth, uint32_t arrayLayers, uint8_t levels, vk::Format format, vk::ImageUsageFlags flags) noexcept
|
||||||
|
: vkImage (inVkImage)
|
||||||
|
, width{ inWidth }
|
||||||
|
, height{ inHeight }
|
||||||
|
, depth{ inDepth }
|
||||||
|
, mipLevelCount{ levels }
|
||||||
|
, layerCount{ arrayLayers }
|
||||||
|
, imageFormat{ format }
|
||||||
|
, usageFlags{flags}
|
||||||
|
, alloc{}
|
||||||
|
, imageType{type}
|
||||||
|
, createFlags{}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVkImage::SHVkImage(VmaAllocator const& vmaAllocator, uint32_t w, uint32_t h, uint8_t levels, vk::Format format, vk::ImageUsageFlags usage, vk::ImageCreateFlags create) noexcept
|
||||||
|
: width {w}
|
||||||
|
, height{h}
|
||||||
|
, depth {1}
|
||||||
|
, layerCount{1}
|
||||||
|
, mipLevelCount{levels}
|
||||||
|
, imageFormat{format}
|
||||||
|
, usageFlags{usage}
|
||||||
|
, createFlags {create}
|
||||||
|
{
|
||||||
|
vk::ImageCreateInfo imageCreateInfo{};
|
||||||
|
imageCreateInfo.imageType = vk::ImageType::e2D;
|
||||||
|
imageCreateInfo.extent.width = width;
|
||||||
|
imageCreateInfo.extent.height = height;
|
||||||
|
imageCreateInfo.extent.depth = depth;
|
||||||
|
imageCreateInfo.mipLevels = mipLevelCount;
|
||||||
|
imageCreateInfo.arrayLayers = layerCount;
|
||||||
|
imageCreateInfo.format = imageFormat;
|
||||||
|
imageCreateInfo.tiling = vk::ImageTiling::eOptimal;
|
||||||
|
imageCreateInfo.initialLayout = vk::ImageLayout::eUndefined;
|
||||||
|
imageCreateInfo.usage = usageFlags;
|
||||||
|
imageCreateInfo.sharingMode = vk::SharingMode::eExclusive;
|
||||||
|
imageCreateInfo.samples = vk::SampleCountFlagBits::e1;
|
||||||
|
imageCreateInfo.flags = createFlags;
|
||||||
|
|
||||||
|
|
||||||
|
// Prepare allocation parameters for call to create images later
|
||||||
|
VmaAllocationCreateInfo allocCreateInfo{};
|
||||||
|
allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO;
|
||||||
|
allocCreateInfo.flags = {}; // TODO: Make sure the vk::MemoryPropertyFlags returned from vmaGetAllocationMemoryProperties has the device local bit set
|
||||||
|
|
||||||
|
VmaAllocationInfo allocInfo{};
|
||||||
|
|
||||||
|
VkImage tempImage;
|
||||||
|
auto result = vmaCreateImage(vmaAllocator, &imageCreateInfo.operator VkImageCreateInfo & (), &allocCreateInfo, &tempImage, &alloc, &allocInfo);
|
||||||
|
vkImage = tempImage;
|
||||||
|
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
SHVulkanDebugUtil::ReportVkError(vk::Result(result), "Failed to create vulkan image. ");
|
||||||
|
else
|
||||||
|
SHVulkanDebugUtil::ReportVkSuccess("Successfully created image. ");
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle<SHVkImageView> SHVkImage::CreateImageView(Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl, Handle<SHVkImage> const& parent, SHImageViewDetails const& createParams) const noexcept
|
||||||
|
{
|
||||||
|
return SHVkInstance::GetResourceManager().Create<SHVkImageView>(inLogicalDeviceHdl, parent, createParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHVkImage::LinkWithExteriorImage(vk::Image inVkImage, vk::ImageType type, uint32_t inWidth, uint32_t inHeight, uint32_t inDepth, uint32_t layers, uint8_t levels, vk::Format format, vk::ImageUsageFlags flags) noexcept
|
||||||
|
{
|
||||||
|
vkImage = inVkImage;
|
||||||
|
width = inWidth;
|
||||||
|
height = inHeight;
|
||||||
|
depth = inDepth;
|
||||||
|
mipLevelCount = levels;
|
||||||
|
layerCount = layers;
|
||||||
|
imageFormat = format;
|
||||||
|
usageFlags = flags;
|
||||||
|
imageType = type;
|
||||||
|
imageFormat = format;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Getter for vulkan image handle.
|
||||||
|
|
||||||
|
\return
|
||||||
|
the vulkan image handle.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
vk::Image SHVkImage::GetVkImage(void) const noexcept
|
||||||
|
{
|
||||||
|
return vkImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Getter for vulkan image create flags.
|
||||||
|
|
||||||
|
\return
|
||||||
|
The bitwise combination of create flag bits.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
vk::ImageCreateFlags SHVkImage::GetImageeCreateFlags(void) const noexcept
|
||||||
|
{
|
||||||
|
return createFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Getter for vulkan image format.
|
||||||
|
|
||||||
|
\return
|
||||||
|
The image format.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
vk::Format SHVkImage::GetImageFormat(void) const noexcept
|
||||||
|
{
|
||||||
|
return imageFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Getter for image width.
|
||||||
|
|
||||||
|
\return
|
||||||
|
The image width.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
uint32_t SHVkImage::GetWidth(void) const noexcept
|
||||||
|
{
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Getter for image height
|
||||||
|
|
||||||
|
\return
|
||||||
|
The image height.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
uint32_t SHVkImage::GetHeight(void) const noexcept
|
||||||
|
{
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
#ifndef SH_VK_IMAGE_H
|
||||||
|
#define SH_VK_IMAGE_H
|
||||||
|
|
||||||
|
#include "SHImageViewDetails.h"
|
||||||
|
#include "Graphics/SHVulkanDefines.h"
|
||||||
|
#include "Resource/ResourceLibrary.h"
|
||||||
|
#include "vk_mem_alloc.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
class SHVkLogicalDevice;
|
||||||
|
class SHVkImageView;
|
||||||
|
|
||||||
|
struct SHImageCreateParams
|
||||||
|
{
|
||||||
|
//! 1D, 2D or 3D
|
||||||
|
vk::ImageType imageType;
|
||||||
|
|
||||||
|
//! Width of the image
|
||||||
|
uint32_t width;
|
||||||
|
|
||||||
|
//! Height of the image
|
||||||
|
uint32_t height;
|
||||||
|
|
||||||
|
//! Depth of the image
|
||||||
|
uint32_t depth;
|
||||||
|
|
||||||
|
//! Number of mipmaps
|
||||||
|
uint8_t levels;
|
||||||
|
|
||||||
|
//! If image is standalone, this will be 0.
|
||||||
|
uint32_t arrayLayers = 0;
|
||||||
|
|
||||||
|
//! format of the image
|
||||||
|
vk::Format imageFormat;
|
||||||
|
|
||||||
|
//! Image usage bits
|
||||||
|
std::span<vk::ImageUsageFlagBits> usageBits;
|
||||||
|
|
||||||
|
//! Image create flags
|
||||||
|
std::span<vk::ImageCreateFlagBits> createBits;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SHVkImage
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PRIVATE MEMBER VARIABLES */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
//! 1D, 2D or 3D
|
||||||
|
vk::ImageType imageType = vk::ImageType::e2D;
|
||||||
|
|
||||||
|
//! Width of the image
|
||||||
|
uint32_t width{ 0 };
|
||||||
|
|
||||||
|
//! Height of the image
|
||||||
|
uint32_t height{ 0 };
|
||||||
|
|
||||||
|
//! Depth of the image
|
||||||
|
uint32_t depth{ 0 };
|
||||||
|
|
||||||
|
//! If image is standalone, this will be 0.
|
||||||
|
uint32_t layerCount = 0;
|
||||||
|
|
||||||
|
//! Number of mipmaps
|
||||||
|
uint8_t mipLevelCount{ 1 };
|
||||||
|
|
||||||
|
//! format of the image
|
||||||
|
vk::Format imageFormat{};
|
||||||
|
|
||||||
|
//! Image usage bits
|
||||||
|
vk::ImageUsageFlags usageFlags{};
|
||||||
|
|
||||||
|
//! Image create flags
|
||||||
|
vk::ImageCreateFlags createFlags{};
|
||||||
|
|
||||||
|
//! Vulkan image handle
|
||||||
|
vk::Image vkImage{};
|
||||||
|
|
||||||
|
//! allocation object containing details of an allocation
|
||||||
|
VmaAllocation alloc{};
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* CTOR AND DTOR */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
SHVkImage(void) noexcept = default;
|
||||||
|
|
||||||
|
// TODO: Might need to add flags to parameters
|
||||||
|
SHVkImage(
|
||||||
|
VmaAllocator const& vmaAllocator,
|
||||||
|
SHImageCreateParams const& imageDetails,
|
||||||
|
VmaMemoryUsage memUsage,
|
||||||
|
VmaAllocationCreateFlags allocFlags
|
||||||
|
) noexcept;
|
||||||
|
|
||||||
|
SHVkImage(vk::Image inVkImage, vk::ImageType type, uint32_t inWidth, uint32_t inHeight, uint32_t inDepth, uint32_t arrayLayers, uint8_t levels, vk::Format format, vk::ImageUsageFlags flags) noexcept;
|
||||||
|
SHVkImage(VmaAllocator const& vmaAllocator, uint32_t w, uint32_t h, uint8_t levels, vk::Format format, vk::ImageUsageFlags usage, vk::ImageCreateFlags create) noexcept;
|
||||||
|
|
||||||
|
SHVkImage(SHVkImage&& rhs) noexcept = default;
|
||||||
|
SHVkImage& operator=(SHVkImage && rhs) noexcept = default;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PUBLIC MEMBER FUNCTIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
Handle<SHVkImageView> CreateImageView(Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl, Handle<SHVkImage> const& parent, SHImageViewDetails const& createParams) const noexcept;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* GETTERS AND SETTERS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
void LinkWithExteriorImage(vk::Image inVkImage, vk::ImageType type, uint32_t inWidth, uint32_t inHeight, uint32_t inDepth, uint32_t arrayLayers, uint8_t levels, vk::Format format, vk::ImageUsageFlags flags) noexcept;
|
||||||
|
|
||||||
|
vk::Image GetVkImage (void) const noexcept;
|
||||||
|
vk::ImageCreateFlags GetImageeCreateFlags (void) const noexcept;
|
||||||
|
vk::Format GetImageFormat (void) const noexcept;
|
||||||
|
uint32_t GetWidth (void) const noexcept;
|
||||||
|
uint32_t GetHeight (void) const noexcept;
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,128 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHVkImageView.h"
|
||||||
|
#include "SHVkImage.h"
|
||||||
|
#include "Graphics/Devices/SHVkLogicalDevice.h"
|
||||||
|
#include "Tools/SHLogger.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Non-default ctor. Initializes image view with image that it is a view of.
|
||||||
|
|
||||||
|
\param parent
|
||||||
|
Parent image the view is a view of.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHVkImageView::SHVkImageView(Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl, Handle<SHVkImage> const& parent, SHImageViewDetails const& createParams) noexcept
|
||||||
|
: parentImage{ }
|
||||||
|
, vkImageView{}
|
||||||
|
, imageViewDetails{}
|
||||||
|
, logicalDeviceHdl {inLogicalDeviceHdl}
|
||||||
|
{
|
||||||
|
auto parentImageCreateFlags = parent->GetImageeCreateFlags();
|
||||||
|
|
||||||
|
// 2D array image type means parent image must be 2D array compatible
|
||||||
|
if (createParams.viewType == vk::ImageViewType::e2DArray)
|
||||||
|
{
|
||||||
|
if (!(parentImageCreateFlags & vk::ImageCreateFlagBits::e2DArrayCompatible))
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("Failed to create image view. Parent image not 2D array compatible. ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if its possible for the image view to have different format than parent image
|
||||||
|
if (createParams.format != parent->GetImageFormat())
|
||||||
|
{
|
||||||
|
if (!(parentImageCreateFlags & vk::ImageCreateFlagBits::eMutableFormat))
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("Failed to create image view. Format for image view not same as image but image not initialized with mutable format bit. ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
vk::ImageViewCreateInfo viewCreateInfo
|
||||||
|
{
|
||||||
|
.pNext = nullptr, // Can be used to override with a VkImageViewUsageCreateInfo to override usage. See Vulkan spec page 877 for more information
|
||||||
|
.image = parent->GetVkImage(),
|
||||||
|
.viewType = createParams.viewType,
|
||||||
|
.format = createParams.format,
|
||||||
|
.components
|
||||||
|
{
|
||||||
|
.r = vk::ComponentSwizzle::eR,
|
||||||
|
.g = vk::ComponentSwizzle::eG,
|
||||||
|
.b = vk::ComponentSwizzle::eB,
|
||||||
|
.a = vk::ComponentSwizzle::eA,
|
||||||
|
},
|
||||||
|
.subresourceRange
|
||||||
|
{
|
||||||
|
.aspectMask = createParams.imageAspectFlags,
|
||||||
|
.baseMipLevel = createParams.baseMipLevel,
|
||||||
|
.levelCount = createParams.mipLevelCount,
|
||||||
|
.baseArrayLayer = createParams.baseArrayLayer,
|
||||||
|
.layerCount = createParams.layerCount,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (auto result = inLogicalDeviceHdl->GetVkLogicalDevice().createImageView(&viewCreateInfo, nullptr, &vkImageView); result != vk::Result::eSuccess)
|
||||||
|
{
|
||||||
|
SHVulkanDebugUtil::ReportVkError(result, "Failed to create image view! ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SHVulkanDebugUtil::ReportVkSuccess("Successfully created image view. ");
|
||||||
|
}
|
||||||
|
|
||||||
|
// After success, THEN assign variables
|
||||||
|
parentImage = parent;
|
||||||
|
imageViewDetails = createParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVkImageView::SHVkImageView(SHVkImageView&& rhs) noexcept
|
||||||
|
: vkImageView {std::move (rhs.vkImageView)}
|
||||||
|
, parentImage {std::move (rhs.parentImage)}
|
||||||
|
, imageViewDetails{std::move (rhs.imageViewDetails)}
|
||||||
|
, logicalDeviceHdl{ rhs.logicalDeviceHdl } // just copy doesn't matter
|
||||||
|
{
|
||||||
|
rhs.vkImageView = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Handle<SHVkImage> const& SHVkImageView::GetParentImage(void) const noexcept
|
||||||
|
{
|
||||||
|
return parentImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::ImageView SHVkImageView::GetImageView(void) const noexcept
|
||||||
|
{
|
||||||
|
return vkImageView;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVkImageView& SHVkImageView::operator=(SHVkImageView&& rhs) noexcept
|
||||||
|
{
|
||||||
|
if (&rhs == this)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
vkImageView = rhs.vkImageView;
|
||||||
|
parentImage = std::move(rhs.parentImage);
|
||||||
|
imageViewDetails = std::move(rhs.imageViewDetails);
|
||||||
|
logicalDeviceHdl = rhs.logicalDeviceHdl; // just copy doesn't matter
|
||||||
|
|
||||||
|
rhs.vkImageView = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVkImageView::~SHVkImageView(void) noexcept
|
||||||
|
{
|
||||||
|
if (vkImageView)
|
||||||
|
logicalDeviceHdl->GetVkLogicalDevice().destroyImageView(vkImageView, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
#ifndef SH_VK_IMAGE_VIEW_H
|
||||||
|
#define SH_VK_IMAGE_VIEW_H
|
||||||
|
|
||||||
|
#include "Graphics/SHVulkanIncludes.h"
|
||||||
|
#include "Resource/Handle.h"
|
||||||
|
#include "SHImageViewDetails.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
class SHVkImage;
|
||||||
|
class SHVkLogicalDevice;
|
||||||
|
|
||||||
|
class SHVkImageView
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
//! Handle to vulkan image view
|
||||||
|
vk::ImageView vkImageView;
|
||||||
|
|
||||||
|
//! We want to to keep a reference to the parent
|
||||||
|
Handle<SHVkImage> parentImage;
|
||||||
|
|
||||||
|
//! For storing image view details
|
||||||
|
SHImageViewDetails imageViewDetails;
|
||||||
|
|
||||||
|
//! Logical Device needed for creation and destruction
|
||||||
|
Handle<SHVkLogicalDevice> logicalDeviceHdl;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SHVkImageView(Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl, Handle<SHVkImage> const& parent, SHImageViewDetails const& createParams) noexcept;
|
||||||
|
~SHVkImageView(void) noexcept;
|
||||||
|
SHVkImageView(SHVkImageView&& rhs) noexcept;
|
||||||
|
SHVkImageView& operator=(SHVkImageView&& rhs) noexcept;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* GETTERS AND SETTERS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
Handle<SHVkImage> const& GetParentImage(void) const noexcept;
|
||||||
|
vk::ImageView GetImageView (void) const noexcept;
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,266 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHVkInstance.h"
|
||||||
|
#include "Graphics/Debugging/SHValidationLayersQuery.h"
|
||||||
|
#include "Graphics/Debugging/SHVkDebugMessenger.h"
|
||||||
|
#include "Graphics/Devices/SHVkPhysicalDeviceLibrary.h"
|
||||||
|
#include "Tools/SHLogger.h"
|
||||||
|
#include "Graphics/Devices/SHVkPhysicalDeviceLibrary.h"
|
||||||
|
//#include <vulkan/vulkan_win32.h>
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
|
||||||
|
bool SHVkInstance::debugOn;
|
||||||
|
bool SHVkInstance::renderdocOn;
|
||||||
|
bool SHVkInstance::validationLayersOn;
|
||||||
|
vk::Instance SHVkInstance::vkInstance;
|
||||||
|
SHVkDebugMessenger SHVkInstance::debugMessenger;
|
||||||
|
ResourceManager SHVkInstance::resourceManager;
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Returns a basic list of extensions for the instance initialization.
|
||||||
|
|
||||||
|
\return
|
||||||
|
Returns a vector of extensions.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
std::vector <const char*> SHVkInstance::GetExtensions(void) noexcept
|
||||||
|
{
|
||||||
|
// win32 will be used for windowing
|
||||||
|
std::vector<const char*> extensions
|
||||||
|
{
|
||||||
|
VK_KHR_SURFACE_EXTENSION_NAME,
|
||||||
|
VK_KHR_WIN32_SURFACE_EXTENSION_NAME
|
||||||
|
};
|
||||||
|
|
||||||
|
// If debug flag is true, push back the extension for debug messenger
|
||||||
|
if (debugOn)
|
||||||
|
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||||
|
|
||||||
|
// Returns the extensions
|
||||||
|
return extensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Private function to initialize a vulkan application info struct.
|
||||||
|
|
||||||
|
\param[in, out] appInfo
|
||||||
|
The app info struct to modify.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkInstance::InitializeAppInfo(vk::ApplicationInfo& appInfo) noexcept
|
||||||
|
{
|
||||||
|
appInfo.pApplicationName = "SHADE Engine";
|
||||||
|
appInfo.applicationVersion = 1;
|
||||||
|
appInfo.pNext = nullptr;
|
||||||
|
appInfo.pEngineName = "SHADE Engine";
|
||||||
|
appInfo.engineVersion = 1;
|
||||||
|
|
||||||
|
// default 1.3 (latest as of 24th May 2022)
|
||||||
|
appInfo.apiVersion = VK_API_VERSION_1_3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Simply calls a function from the physical device library to query for
|
||||||
|
all physical devices.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkInstance::InitializePhysicalDevices(void) noexcept
|
||||||
|
{
|
||||||
|
SHVkPhysicalDeviceLibrary::QueryPhysicalDevices(debugOn);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Does a few things:
|
||||||
|
- Initializes an instance with extensions and (depending on flag)
|
||||||
|
validation layers.
|
||||||
|
- Initializes a debug messenger
|
||||||
|
- Query physical devices
|
||||||
|
|
||||||
|
\param inDebugOn
|
||||||
|
If true, debug messenger will be created.
|
||||||
|
|
||||||
|
\param inRenderdocOn
|
||||||
|
If true, renderdoc will be added to validation layers.
|
||||||
|
|
||||||
|
\param inValidationOn
|
||||||
|
If true, validation layers will be enabled.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkInstance::Init (bool inDebugOn, bool inRenderdocOn, bool inValidationOn) noexcept
|
||||||
|
{
|
||||||
|
// Init some members
|
||||||
|
debugOn = inDebugOn;
|
||||||
|
renderdocOn = inRenderdocOn;
|
||||||
|
validationLayersOn = inValidationOn;
|
||||||
|
|
||||||
|
// Populate application info struct
|
||||||
|
vk::ApplicationInfo appInfo;
|
||||||
|
InitializeAppInfo(appInfo);
|
||||||
|
|
||||||
|
// Get extensions
|
||||||
|
const auto extensions = GetExtensions();
|
||||||
|
|
||||||
|
// Prepare for instance creation.
|
||||||
|
vk::InstanceCreateInfo instanceInfo;
|
||||||
|
instanceInfo.pApplicationInfo = &appInfo;
|
||||||
|
instanceInfo.ppEnabledExtensionNames = extensions.size() ? extensions.data() : nullptr;
|
||||||
|
instanceInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
|
||||||
|
|
||||||
|
// Load pointers to instance-independent extension functions
|
||||||
|
vk::DynamicLoader dl;
|
||||||
|
const PFN_vkGetInstanceProcAddr VK_GET_INSTANCE_PROC_ADDR = dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
|
||||||
|
VULKAN_HPP_DEFAULT_DISPATCHER.init(VK_GET_INSTANCE_PROC_ADDR);
|
||||||
|
vkGetInstanceProcAddr(nullptr, ""); // HACK: HPP extension functions break without this line, do not remove!
|
||||||
|
|
||||||
|
// If validation layers are on
|
||||||
|
if (validationLayersOn)
|
||||||
|
{
|
||||||
|
// Generate validation layers
|
||||||
|
SHValidationLayersQuery::GenerateAvailableLayers(renderdocOn);
|
||||||
|
const auto& layers = SHValidationLayersQuery::GetAvailableLayers();
|
||||||
|
|
||||||
|
instanceInfo.enabledLayerCount = static_cast<uint32_t>(layers.size());
|
||||||
|
instanceInfo.ppEnabledLayerNames = layers.size() ? layers.data() : nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
instanceInfo.enabledLayerCount = 0;
|
||||||
|
instanceInfo.ppEnabledLayerNames = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if debug is on, create debug messenger for instance creation.
|
||||||
|
if (debugOn)
|
||||||
|
{
|
||||||
|
vk::DebugUtilsMessengerCreateInfoEXT instanceDbgInfo;
|
||||||
|
SHVkDebugMessenger::InitializeDebugCreateInfo(instanceDbgInfo,
|
||||||
|
SHVkDebugMessenger::GenMessengerSeverity(SH_DEBUG_MSG_SEV::S_VERBOSE, SH_DEBUG_MSG_SEV::S_WARNING, SH_DEBUG_MSG_SEV::S_ERROR),
|
||||||
|
SHVkDebugMessenger::GenMessengerType(SH_DEBUG_MSG_TYPE::T_GENERAL, SH_DEBUG_MSG_TYPE::T_VALIDATION, SH_DEBUG_MSG_TYPE::T_PERFORMANCE));
|
||||||
|
|
||||||
|
instanceDbgInfo.pfnUserCallback = SHVulkanDebugUtil::GenericDebugCallback;
|
||||||
|
instanceInfo.pNext = static_cast<vk::DebugUtilsMessengerCreateInfoEXT*>(&instanceDbgInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally create the instance
|
||||||
|
if (vk::Result result = vk::createInstance(&instanceInfo, nullptr, &vkInstance); result != vk::Result::eSuccess)
|
||||||
|
{
|
||||||
|
SHVulkanDebugUtil::ReportVkError(result, "Failed to create Vulkan instance! ");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SHVulkanDebugUtil::ReportVkSuccess("Successfully created a Vulkan Instance. ");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load pointers to instance-specific extension functions
|
||||||
|
VULKAN_HPP_DEFAULT_DISPATCHER.init(vkInstance);
|
||||||
|
|
||||||
|
|
||||||
|
// Initialize a debug messenger
|
||||||
|
debugMessenger.Initialize();
|
||||||
|
|
||||||
|
// Query for physical devices
|
||||||
|
InitializePhysicalDevices();
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Destroys the vulkan instance.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkInstance::Destroy(void) noexcept
|
||||||
|
{
|
||||||
|
vkInstance.destroy(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Creates a physical device and returns a handle to it.
|
||||||
|
|
||||||
|
\param inPhysicalDevice
|
||||||
|
A Vulkan physical device handle.
|
||||||
|
|
||||||
|
\return
|
||||||
|
A SHADE handle object encapsulating a SHADE wrapper for a vulkan
|
||||||
|
physical device.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
Handle<SHVkPhysicalDevice> SHVkInstance::CreatePhysicalDevice(SH_PHYSICAL_DEVICE_TYPE type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case SH_PHYSICAL_DEVICE_TYPE::BEST:
|
||||||
|
return resourceManager.Create<SHVkPhysicalDevice>(SHVkPhysicalDeviceLibrary::GetBestDevice());
|
||||||
|
default:
|
||||||
|
return resourceManager.Create<SHVkPhysicalDevice>(SHVkPhysicalDeviceLibrary::GetBestDevice());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Creates a logical device and returns a handle to it.
|
||||||
|
|
||||||
|
\param queueCreateParams
|
||||||
|
The number of queues to create from the logical device.
|
||||||
|
|
||||||
|
\param physicalDevice
|
||||||
|
The physical device to create the logical device from.
|
||||||
|
|
||||||
|
\return
|
||||||
|
The newly created logical device.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
Handle<SHVkLogicalDevice> SHVkInstance::CreateLogicalDevice(std::initializer_list<SHQueueParams> queueCreateParams, Handle<SHVkPhysicalDevice> const& physicalDeviceHdl)
|
||||||
|
{
|
||||||
|
auto newHdl = resourceManager.Create<SHVkLogicalDevice>(queueCreateParams, physicalDeviceHdl);
|
||||||
|
newHdl->InitializeQueues(queueCreateParams);
|
||||||
|
return newHdl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Getter for the underlying vulkan instance.
|
||||||
|
|
||||||
|
\return
|
||||||
|
The underlying vulkan instance.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
vk::Instance const& SHVkInstance::GetVkInstance(void) noexcept
|
||||||
|
{
|
||||||
|
return vkInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceManager& SHVkInstance::GetResourceManager(void) noexcept
|
||||||
|
{
|
||||||
|
return resourceManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
/**************************************************************************//*!
|
||||||
|
\file SHVkInstance.h
|
||||||
|
\author Brandon Mak
|
||||||
|
\par email: brandon.hao@digipen.edu
|
||||||
|
\date 16th May 2022
|
||||||
|
\brief Stores the declaration of SHVkInstance class.
|
||||||
|
|
||||||
|
Copyright (C) 2022 DigiPen Institute of Technology.
|
||||||
|
Reproduction or disclosure of this file or its contents without the prior
|
||||||
|
written consent of DigiPen Institute of Technology is prohibited.
|
||||||
|
|
||||||
|
*//***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef SH_VK_INSTANCE_H
|
||||||
|
#define SH_VK_INSTANCE_H
|
||||||
|
|
||||||
|
#include <vector> // std::vector
|
||||||
|
#include "Graphics/Debugging/SHVkDebugMessenger.h"
|
||||||
|
#include "Graphics/Devices/SHVkPhysicalDevice.h"
|
||||||
|
#include "Graphics/Devices/SHVkLogicalDevice.h"
|
||||||
|
#include "Resource/ResourceLibrary.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
//class SHVkLogicalDevice;
|
||||||
|
//class SHVkPhysicalDevice;
|
||||||
|
|
||||||
|
/*!**************************************************************************
|
||||||
|
|
||||||
|
\class SHVkInstance
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Mainly used for initializing a Vulkan Instance.
|
||||||
|
|
||||||
|
***************************************************************************/
|
||||||
|
class SHVkInstance
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* DATA MEMBERS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
//! Whether or not the debug messenger is active or not
|
||||||
|
static bool debugOn;
|
||||||
|
|
||||||
|
//! Whether or not renderdoc is on or not. Changing this flag would
|
||||||
|
//! propagate a restart of the rendering system
|
||||||
|
static bool renderdocOn;
|
||||||
|
|
||||||
|
//! Whether or not validation layers are enabled.
|
||||||
|
static bool validationLayersOn;
|
||||||
|
|
||||||
|
//! Handle to the actual vulkan instance
|
||||||
|
static vk::Instance vkInstance;
|
||||||
|
|
||||||
|
//! Debug messenger (this is not a handle (or at least I feel it shouldn't
|
||||||
|
//! be) is because it is contained within the instance class and not used
|
||||||
|
//! outside. When the instance gets destroyed, the messenger is destroyed
|
||||||
|
//! together with it
|
||||||
|
static SHVkDebugMessenger debugMessenger;
|
||||||
|
|
||||||
|
//! Resource management for vulkan project
|
||||||
|
static ResourceManager resourceManager;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PRIVATE MEMBER FUNCTIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
static std::vector <const char*> GetExtensions (void) noexcept;
|
||||||
|
static void InitializeAppInfo (vk::ApplicationInfo& appInfo) noexcept;
|
||||||
|
static void InitializePhysicalDevices (void) noexcept;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PUBLIC MEMBER FUNCTIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
static void Init (bool inDebugOn, bool inRenderdocOn, bool inValidationOn) noexcept;
|
||||||
|
static void Destroy (void) noexcept;
|
||||||
|
|
||||||
|
static Handle<SHVkPhysicalDevice> CreatePhysicalDevice (SH_PHYSICAL_DEVICE_TYPE type);
|
||||||
|
static Handle<SHVkLogicalDevice> CreateLogicalDevice (std::initializer_list<SHQueueParams> queueCreateParams, Handle<SHVkPhysicalDevice> const& physicalDeviceHdl);
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Getters and Setters */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
static vk::Instance const& GetVkInstance (void) noexcept;
|
||||||
|
static ResourceManager& GetResourceManager(void) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,238 @@
|
||||||
|
/************************************************************************************//*!
|
||||||
|
\file SHGraphicsSystem.cpp
|
||||||
|
\author Tng Kah Wei, kahwei.tng, 390009620
|
||||||
|
\par email: kahwei.tng\@digipen.edu
|
||||||
|
\date Aug 21, 2022
|
||||||
|
\brief
|
||||||
|
|
||||||
|
|
||||||
|
Copyright (C) 2022 DigiPen Institute of Technology.
|
||||||
|
Reproduction or disclosure of this file or its contents without the prior written consent
|
||||||
|
of DigiPen Institute of Technology is prohibited.
|
||||||
|
*//*************************************************************************************/
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHGraphicsSystem.h"
|
||||||
|
|
||||||
|
#include "Graphics/Instance/SHVkInstance.h"
|
||||||
|
#include "Graphics/Windowing/Surface/SHVkSurface.h"
|
||||||
|
#include "Graphics/Swapchain/SHVkSwapchain.h"
|
||||||
|
//#include "SHRenderer.h"
|
||||||
|
#include "Graphics/Windowing/SHWindow.h"
|
||||||
|
#include "Graphics/MiddleEnd/PerFrame/SHPerFrameData.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Constructor/Destructors */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
SHGraphicsSystem::SHGraphicsSystem(SHWindow& window)
|
||||||
|
{
|
||||||
|
// Save the SHWindow
|
||||||
|
this->window = &window;
|
||||||
|
|
||||||
|
// Set Up Instance
|
||||||
|
SHVkInstance::Init(true, true, true);
|
||||||
|
|
||||||
|
// Get Physical Device and Construct Logical Device
|
||||||
|
// TODO: Provide configuration for these options
|
||||||
|
physicalDevice = SHVkInstance::CreatePhysicalDevice(SH_PHYSICAL_DEVICE_TYPE::BEST);
|
||||||
|
device = SHVkInstance::CreateLogicalDevice({ SHQueueParams(SH_Q_FAM::GRAPHICS, SH_QUEUE_SELECT::DEDICATED), SHQueueParams(SH_Q_FAM::TRANSFER, SH_QUEUE_SELECT::DEDICATED) }, physicalDevice);
|
||||||
|
|
||||||
|
// Construct surface
|
||||||
|
surface = device->CreateSurface(window.GetHWND());
|
||||||
|
|
||||||
|
// Construct Swapchain
|
||||||
|
auto windowDims = window.GetWindowSize();
|
||||||
|
swapchain = device->CreateSwapchain(surface, windowDims.first, windowDims.second, SHSwapchainParams
|
||||||
|
{
|
||||||
|
.surfaceImageFormats {vk::Format::eB8G8R8A8Unorm, vk::Format::eR8G8B8A8Unorm, vk::Format::eB8G8R8Unorm, vk::Format::eR8G8B8Unorm},
|
||||||
|
.depthFormats {vk::Format::eD32Sfloat, vk::Format::eD32SfloatS8Uint, vk::Format::eD24UnormS8Uint},
|
||||||
|
.presentModes {vk::PresentModeKHR::eFifo, vk::PresentModeKHR::eMailbox, vk::PresentModeKHR::eImmediate},
|
||||||
|
.vsyncOn = false, // TODO: Set to true when shipping game
|
||||||
|
});
|
||||||
|
|
||||||
|
window.RegisterWindowSizeCallback([&]([[maybe_unused]] uint32_t width, [[maybe_unused]] uint32_t height)
|
||||||
|
{
|
||||||
|
renderContext.SetIsResized(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create graphics queue
|
||||||
|
queue = device->GetQueue(SH_Q_FAM::GRAPHICS, 0);
|
||||||
|
|
||||||
|
|
||||||
|
// Create Render Context
|
||||||
|
renderContext.Init
|
||||||
|
(
|
||||||
|
device,
|
||||||
|
SHPerFrameDataParams
|
||||||
|
{
|
||||||
|
.swapchainHdl = swapchain,
|
||||||
|
.numThreads = 1,
|
||||||
|
.cmdPoolQueueFamilyType = SH_Q_FAM::GRAPHICS,
|
||||||
|
.cmdPoolResetMode = SH_CMD_POOL_RESET::POOL_BASED,
|
||||||
|
.cmdBufferTransient = true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create Frame and Command Buffers
|
||||||
|
for (int i = 0; i < NUM_FRAME_BUFFERS; ++i)
|
||||||
|
{
|
||||||
|
//frameBuffers[i] = device->CreateFramebuffer(renderPass, { renderContext.GetFrameData(i).swapchainImageViewHdl }, windowDims[0], windowDims[1]);
|
||||||
|
SHPerFrameData& frameData = renderContext.GetFrameData(i);
|
||||||
|
|
||||||
|
if (frameData.cmdPoolHdls.empty())
|
||||||
|
throw std::runtime_error("No command pools available!");
|
||||||
|
|
||||||
|
Handle<SHVkCommandPool> commandPool = frameData.cmdPoolHdls[0];
|
||||||
|
//commandBuffers[i] = commandPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY); // works
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* RENDERGRAPH TESTING */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
renderGraph.Init(device, swapchain);
|
||||||
|
renderGraph.AddResource("Position", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eR16G16B16A16Sfloat);
|
||||||
|
renderGraph.AddResource("Normals", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eR16G16B16A16Sfloat);
|
||||||
|
renderGraph.AddResource("Composite", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eR16G16B16A16Sfloat);
|
||||||
|
renderGraph.AddResource("Downscale", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eR16G16B16A16Sfloat);
|
||||||
|
renderGraph.AddResource("Present", SH_ATT_DESC_TYPE::COLOR_PRESENT, windowDims.first, windowDims.second);
|
||||||
|
auto node = renderGraph.AddNode("G-Buffer", { "Position", "Normals", "Composite" }, {}); // no predecessors
|
||||||
|
|
||||||
|
// First subpass to write to G-Buffer
|
||||||
|
auto writeSubpass = node->AddSubpass("G-Buffer Write");
|
||||||
|
writeSubpass->AddColorOutput("Position");
|
||||||
|
writeSubpass->AddColorOutput("Normals");
|
||||||
|
|
||||||
|
// Second subpass to read from G-Buffer
|
||||||
|
auto compositeSubpass = node->AddSubpass("G-Buffer Composite");
|
||||||
|
compositeSubpass->AddColorOutput("Composite");
|
||||||
|
compositeSubpass->AddInput("Normals");
|
||||||
|
compositeSubpass->AddInput("Position");
|
||||||
|
|
||||||
|
auto compositeNode = renderGraph.AddNode("Bloom", { "Composite", "Downscale", "Present"}, {"G-Buffer"});
|
||||||
|
auto bloomSubpass = compositeNode->AddSubpass("Downsample");
|
||||||
|
bloomSubpass->AddInput("Composite");
|
||||||
|
bloomSubpass->AddColorOutput("Downscale");
|
||||||
|
bloomSubpass->AddColorOutput("Present");
|
||||||
|
|
||||||
|
renderGraph.Generate();
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* RENDERGRAPH END TESTING */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
}
|
||||||
|
SHGraphicsSystem::~SHGraphicsSystem()
|
||||||
|
{
|
||||||
|
//renderPass.Free();
|
||||||
|
renderContext.Destroy();
|
||||||
|
queue.Free();
|
||||||
|
swapchain.Free();
|
||||||
|
surface.Free();
|
||||||
|
device.Free();
|
||||||
|
|
||||||
|
SHVkInstance::Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Lifecycle Functions */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Checks for window resize and acquire next image in swapchain.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHGraphicsSystem::BeginRender()
|
||||||
|
{
|
||||||
|
auto windowDims = window->GetWindowSize();
|
||||||
|
if (renderContext.GetResizeAndReset())
|
||||||
|
{
|
||||||
|
device->WaitIdle();
|
||||||
|
|
||||||
|
// Resize the swapchain
|
||||||
|
swapchain->Resize(surface, windowDims.first, windowDims.second);
|
||||||
|
|
||||||
|
renderContext.HandleResize();
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t CURR_FRAME_IDX = renderContext.GetCurrentFrame();
|
||||||
|
|
||||||
|
// #BackEndTest: For for the fence initialized by queue submit
|
||||||
|
renderContext.WaitForFence();
|
||||||
|
|
||||||
|
// #BackEndTest: Acquire the next image in the swapchain available
|
||||||
|
renderContext.AcquireNextIamge();
|
||||||
|
|
||||||
|
// #BackEndTest: Get the current frame from frame manager
|
||||||
|
auto& currFrameData = renderContext.GetCurrentFrameData();
|
||||||
|
|
||||||
|
// #BackEndTest: Reset command pool
|
||||||
|
if (currFrameData.cmdPoolHdls.empty())
|
||||||
|
throw std::runtime_error("No command pools available!");
|
||||||
|
currFrameData.cmdPoolHdls[0]->Reset();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Check if need to resize and advance the frame in the render context.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHGraphicsSystem::EndRender()
|
||||||
|
{
|
||||||
|
const uint32_t CURR_FRAME_IDX = renderContext.GetCurrentFrame();
|
||||||
|
auto& currFrameData = renderContext.GetCurrentFrameData();
|
||||||
|
|
||||||
|
// #BackEndTest: Prepare to present current image
|
||||||
|
vk::PresentInfoKHR presentInfo{};
|
||||||
|
presentInfo.waitSemaphoreCount = 1;
|
||||||
|
presentInfo.pWaitSemaphores = &currFrameData.semRenderFinishHdl->GetVkSem();
|
||||||
|
presentInfo.swapchainCount = 1;
|
||||||
|
presentInfo.pSwapchains = &swapchain->GetVkSwapchain();
|
||||||
|
presentInfo.pImageIndices = &CURR_FRAME_IDX;
|
||||||
|
|
||||||
|
// #BackEndTest: queues an image for presentation
|
||||||
|
if (auto result = device->GetQueue(SH_Q_FAM::GRAPHICS, 0)->GetVkQueue().presentKHR(&presentInfo); result != vk::Result::eSuccess)
|
||||||
|
{
|
||||||
|
// If swapchain is incompatible/outdated
|
||||||
|
if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR)
|
||||||
|
{
|
||||||
|
auto windowDims = window->GetWindowSize();
|
||||||
|
swapchain->Resize(surface, windowDims.first, windowDims.second);
|
||||||
|
|
||||||
|
renderContext.HandleResize();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// #BackEndTest: Cycle frame count
|
||||||
|
renderContext.AdvanceFrame();
|
||||||
|
}
|
||||||
|
//Handle<SHRenderer> SHGraphicsSystem::AddRenderer()
|
||||||
|
//{
|
||||||
|
// return Handle<SHRenderer>();
|
||||||
|
//}
|
||||||
|
//void SHGraphicsSystem::RemoveRenderer(Handle<SHRenderer> renderer)
|
||||||
|
//{
|
||||||
|
//}
|
||||||
|
Handle<SHScreenSegment> SHGraphicsSystem::AddSegment(const VkViewport& viewport, Handle<SHVkImage> imageToUse)
|
||||||
|
{
|
||||||
|
return Handle<SHScreenSegment>();
|
||||||
|
}
|
||||||
|
void SHGraphicsSystem::RemoveSegment(Handle<SHScreenSegment> segment)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,129 @@
|
||||||
|
/************************************************************************************//*!
|
||||||
|
\file SHGraphicsSystem.h
|
||||||
|
\author Tng Kah Wei, kahwei.tng, 390009620
|
||||||
|
\par email: kahwei.tng\@digipen.edu
|
||||||
|
\date Aug 21, 2022
|
||||||
|
\brief
|
||||||
|
|
||||||
|
|
||||||
|
Copyright (C) 2022 DigiPen Institute of Technology.
|
||||||
|
Reproduction or disclosure of this file or its contents without the prior written consent
|
||||||
|
of DigiPen Institute of Technology is prohibited.
|
||||||
|
*//*************************************************************************************/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// STL Includes
|
||||||
|
#include <vector>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
// Project Includes
|
||||||
|
#include "Resource/Handle.h"
|
||||||
|
#include "Graphics/SHVulkanIncludes.h"
|
||||||
|
#include "Graphics/MiddleEnd/PerFrame/SHRenderContext.h"
|
||||||
|
#include "Graphics/RenderGraph/SHRenderGraph.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Forward Declarations */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
class SHVkPhysicalDevice;
|
||||||
|
class SHVkLogicalDevice;
|
||||||
|
class SHVkSurface;
|
||||||
|
class SHVkSwapchain;
|
||||||
|
class SHScreenSegment;
|
||||||
|
//class SHRenderer;
|
||||||
|
class SHWindow;
|
||||||
|
class SHVkImage;
|
||||||
|
class SHVkFramebuffer;
|
||||||
|
class SHVkCommandBuffer;
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Type Definitions */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/***********************************************************************************/
|
||||||
|
/*!
|
||||||
|
\brief
|
||||||
|
Represents an axis aligned box on the screen to render to along with the
|
||||||
|
specified Image to render to that spot.
|
||||||
|
*/
|
||||||
|
/***********************************************************************************/
|
||||||
|
struct SHScreenSegment
|
||||||
|
{
|
||||||
|
VkViewport Viewport;
|
||||||
|
Handle<SHVkImage> ImageToUse;
|
||||||
|
};
|
||||||
|
|
||||||
|
/***********************************************************************************/
|
||||||
|
/*!
|
||||||
|
\brief
|
||||||
|
Manages the lifecycle and provides an interface for rendering multiple objects to
|
||||||
|
portions of the screen.
|
||||||
|
*/
|
||||||
|
/***********************************************************************************/
|
||||||
|
class SHGraphicsSystem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Constants */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
static constexpr int NUM_FRAME_BUFFERS = 3;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Constructor/Destructors */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
SHGraphicsSystem(SHWindow& window);
|
||||||
|
~SHGraphicsSystem();
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Lifecycle Functions */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
void BeginRender();
|
||||||
|
void EndRender();
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Renderers Registration Functions */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
//Handle<SHRenderer> AddRenderer();
|
||||||
|
//void RemoveRenderer(Handle<SHRenderer> renderer);
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Viewport Registration Functions */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
Handle<SHScreenSegment> AddSegment(const VkViewport& viewport, Handle<SHVkImage> imageToUse);
|
||||||
|
void RemoveSegment(Handle<SHScreenSegment> segment);
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Getters (Temporary) */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
Handle<SHVkLogicalDevice> GetDevice() const { return device; }
|
||||||
|
Handle<SHVkSwapchain> GetSwapchain() const { return swapchain; }
|
||||||
|
Handle<SHVkSurface> GetSurface() const { return surface; }
|
||||||
|
//Handle<SHVkRenderpass> GetRenderPass() const { return renderPass; }
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Data Members */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
// Owned Resources
|
||||||
|
Handle<SHVkPhysicalDevice> physicalDevice;
|
||||||
|
Handle<SHVkLogicalDevice> device;
|
||||||
|
Handle<SHVkSurface> surface;
|
||||||
|
Handle<SHVkSwapchain> swapchain;
|
||||||
|
Handle<SHVkQueue> queue;
|
||||||
|
//Handle<SHVkRenderpass> renderPass; // Potentially bring out?
|
||||||
|
std::vector<SHScreenSegment> screenSegments;
|
||||||
|
SHRenderContext renderContext;
|
||||||
|
//std::array<Handle<SHVkFramebuffer>, NUM_FRAME_BUFFERS> frameBuffers;
|
||||||
|
//std::array<Handle<SHVkCommandBuffer>, NUM_FRAME_BUFFERS> commandBuffers;
|
||||||
|
// Not Owned Resources
|
||||||
|
SHWindow* window;
|
||||||
|
// Renderers
|
||||||
|
//Handle<SHRenderer> debugWorldRenderer;
|
||||||
|
//Handle<SHRenderer> debugScreenRenderer;
|
||||||
|
//std::vector<SHRenderer> renderers;
|
||||||
|
SHRenderGraph renderGraph;
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHRenderTarget.h"
|
|
@ -0,0 +1,37 @@
|
||||||
|
/************************************************************************************//*!
|
||||||
|
\file SHRenderTarget.h
|
||||||
|
\author Tng Kah Wei, kahwei.tng, 390009620
|
||||||
|
\par email: kahwei.tng\@digipen.edu
|
||||||
|
\date Aug 21, 2022
|
||||||
|
\brief
|
||||||
|
|
||||||
|
|
||||||
|
Copyright (C) 2022 DigiPen Institute of Technology.
|
||||||
|
Reproduction or disclosure of this file or its contents without the prior written consent
|
||||||
|
of DigiPen Institute of Technology is prohibited.
|
||||||
|
*//*************************************************************************************/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/***********************************************************************************/
|
||||||
|
/*!
|
||||||
|
\brief
|
||||||
|
Represents an object that rendering operations can be outputted to. These are
|
||||||
|
images in general but could be a separate texture or even a swapchain image.
|
||||||
|
*/
|
||||||
|
/***********************************************************************************/
|
||||||
|
class SHRenderTarget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Constructor/Destructors */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Data Members */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHPerFrameData.h"
|
||||||
|
#include "Graphics/Swapchain/SHVkSwapchain.h"
|
||||||
|
#include "Graphics/Devices/SHVkLogicalDevice.h"
|
||||||
|
#include "Graphics/Instance/SHVkInstance.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Initializes frame data. Everything here is created brand new from
|
||||||
|
the logical device except for the swapchain images (which are retrieved
|
||||||
|
from the swapchain).
|
||||||
|
|
||||||
|
\param logicalDeviceHdl
|
||||||
|
Required to create objects
|
||||||
|
|
||||||
|
\param params
|
||||||
|
Stores information required to initialize frame data like the swapchain
|
||||||
|
used and command pool parameters.
|
||||||
|
|
||||||
|
\param inFrameIndex
|
||||||
|
Every frame will have an index.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHPerFrameData::Recreate(Handle<SHVkLogicalDevice> const& logicalDeviceHdl) noexcept
|
||||||
|
{
|
||||||
|
// Swapchain recreation means the images are just relinked to SHVkImages. Handles will remain the same. There is no need for this line.
|
||||||
|
//swapchainImageHdl = params.swapchainHdl->GetSwapchainImage(frameIndex);
|
||||||
|
|
||||||
|
SHImageViewDetails viewDetails
|
||||||
|
{
|
||||||
|
.viewType = vk::ImageViewType::e2D,
|
||||||
|
.format = swapchainImageHdl->GetImageFormat(),
|
||||||
|
.imageAspectFlags = vk::ImageAspectFlagBits::eColor,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.mipLevelCount = 1,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create image views for the swapchain
|
||||||
|
swapchainImageViewHdl = swapchainImageHdl->CreateImageView(logicalDeviceHdl, swapchainImageHdl, viewDetails);
|
||||||
|
|
||||||
|
// Create a fence
|
||||||
|
fenceHdl = logicalDeviceHdl->CreateFence();
|
||||||
|
|
||||||
|
// scope makes it easier to navigate
|
||||||
|
semImgAvailableHdl = logicalDeviceHdl->SHVkLogicalDevice::CreateSemaphore();
|
||||||
|
semRenderFinishHdl = logicalDeviceHdl->SHVkLogicalDevice::CreateSemaphore();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Destroys frame data.
|
||||||
|
|
||||||
|
\param logicalDeviceHdl
|
||||||
|
Required for destruction.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHPerFrameData::Destroy(void)
|
||||||
|
{
|
||||||
|
// swapchainImageHdl is non-owning, so we don't destroy that here
|
||||||
|
|
||||||
|
// TODO: Non very user friendly to have objects created from the logical device but destroyed from the resource manager. Can perhaps refactor.
|
||||||
|
SHVkInstance::GetResourceManager().Free(swapchainImageViewHdl);
|
||||||
|
|
||||||
|
// Destroy all the synchronization objects
|
||||||
|
fenceHdl.Free();
|
||||||
|
semImgAvailableHdl.Free();
|
||||||
|
semRenderFinishHdl.Free();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
#ifndef SH_PER_FRAME_DATA_H
|
||||||
|
#define SH_PER_FRAME_DATA_H
|
||||||
|
|
||||||
|
#include "Graphics/Images/SHVkImage.h"
|
||||||
|
#include "Graphics/Images/SHVkImageView.h"
|
||||||
|
#include "Graphics/Commands/SHVkCommandBuffer.h"
|
||||||
|
#include "Graphics/Commands/SHVkCommandPool.h"
|
||||||
|
#include "Graphics/Synchronization/SHVkFence.h"
|
||||||
|
#include "Graphics/Synchronization/SHVkSemaphore.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
class SHVkLogicalDevice;
|
||||||
|
class SHVkSwapchain;
|
||||||
|
|
||||||
|
struct SHPerFrameDataParams
|
||||||
|
{
|
||||||
|
//! Swapchain to get image data
|
||||||
|
Handle<SHVkSwapchain> swapchainHdl{};
|
||||||
|
|
||||||
|
//! Number of threads will dictate how many command pools we will have
|
||||||
|
uint32_t numThreads = 0;
|
||||||
|
|
||||||
|
//! Queue family index for command pool creation
|
||||||
|
SH_Q_FAM cmdPoolQueueFamilyType{};
|
||||||
|
|
||||||
|
//! Reset mode for the command pool
|
||||||
|
SH_CMD_POOL_RESET cmdPoolResetMode = SH_CMD_POOL_RESET::POOL_BASED;
|
||||||
|
|
||||||
|
// whether or not cmd buffers from command pool should be transient
|
||||||
|
bool cmdBufferTransient = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! While there are other things that could also be shared between frames, there are certain things like command buffers that fit into more than 1 contexts.
|
||||||
|
//! The data here should only consists of data that is handled in a straightforward manner.
|
||||||
|
struct SHPerFrameData
|
||||||
|
{
|
||||||
|
|
||||||
|
//! The actual swapchain image for the frame
|
||||||
|
Handle<SHVkImage> swapchainImageHdl;
|
||||||
|
|
||||||
|
//! The image view of the image above
|
||||||
|
Handle<SHVkImageView> swapchainImageViewHdl;
|
||||||
|
|
||||||
|
//! Command pools for the frame. We need it this way because we don't want to reset a command pool when the GPU is using it. We want a container because
|
||||||
|
//! we want 1 for each thread. // TODO: Need to verify this.
|
||||||
|
std::vector<Handle<SHVkCommandPool>> cmdPoolHdls;
|
||||||
|
|
||||||
|
//! Every frame needs a fence
|
||||||
|
Handle<SHVkFence> fenceHdl;
|
||||||
|
|
||||||
|
//! Semaphore for the GPU to signal when an image is available
|
||||||
|
Handle<SHVkSemaphore> semImgAvailableHdl;
|
||||||
|
|
||||||
|
//! Semaphore for the GPU to signal when rendering to an image has finished (used for signal sem in vkSubmitInfo and wait sem in VkPresentInfo)
|
||||||
|
Handle<SHVkSemaphore> semRenderFinishHdl;
|
||||||
|
|
||||||
|
//! Every index will have a frame index
|
||||||
|
uint32_t frameIndex{ 0 };
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PRIVATE MEMBER FUNCTIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
// These are made into functions (instead of ctor and dtor) because we want to call these functions again when we resize the window
|
||||||
|
void Recreate (Handle<SHVkLogicalDevice> const& logicalDeviceHdl) noexcept;
|
||||||
|
void Destroy (void);
|
||||||
|
|
||||||
|
friend class SHRenderContext;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,207 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHRenderContext.h"
|
||||||
|
#include "Tools/SHLogger.h"
|
||||||
|
#include "Graphics/Devices/SHVkLogicalDevice.h"
|
||||||
|
#include "Graphics/Swapchain/SHVkSwapchain.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Frame manager ctor. Initializes the data for all frames.
|
||||||
|
|
||||||
|
\param inLogicalDeviceHdl
|
||||||
|
Logical device required for frame initialization.
|
||||||
|
|
||||||
|
\param params
|
||||||
|
params used for frame data creation.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHRenderContext::Init(Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl, SHPerFrameDataParams const& params) noexcept
|
||||||
|
{
|
||||||
|
perFrameDataParams = params;
|
||||||
|
|
||||||
|
logicalDeviceHdl = inLogicalDeviceHdl;
|
||||||
|
numThreads = params.numThreads;
|
||||||
|
currentFrame = 0;
|
||||||
|
|
||||||
|
// initialize number of threads to 1 if user passes in 0
|
||||||
|
if (params.numThreads == 0)
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("Number of threads is 0. Using 1 thread instead. ");
|
||||||
|
numThreads = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const numImages = params.swapchainHdl->GetNumImages();
|
||||||
|
|
||||||
|
// Once the amount of frame data is reinitialized, we don't need to touch it anymore because swapchain recreation only necessitates
|
||||||
|
// reinitializing the data, not recreating.
|
||||||
|
frameData.resize(numImages);
|
||||||
|
for (uint32_t i = 0; i < numImages; ++i)
|
||||||
|
{
|
||||||
|
// assign a set non-changing frame index
|
||||||
|
frameData[i].frameIndex = i;
|
||||||
|
|
||||||
|
// Initialize the swapchain image handle. See first line of recreation function in frame data.
|
||||||
|
frameData[i].swapchainImageHdl = params.swapchainHdl->GetSwapchainImage(i);
|
||||||
|
|
||||||
|
for (uint32_t j = 0; j < params.numThreads; ++j)
|
||||||
|
{
|
||||||
|
frameData[i].cmdPoolHdls.push_back(logicalDeviceHdl->CreateCommandPool(params.cmdPoolQueueFamilyType, params.cmdPoolResetMode, params.cmdBufferTransient));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize all the info.
|
||||||
|
for (auto& frame : frameData)
|
||||||
|
frame.Recreate(logicalDeviceHdl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHRenderContext::Destroy(void) noexcept
|
||||||
|
{
|
||||||
|
for (auto& data : frameData)
|
||||||
|
{
|
||||||
|
for (auto& hdl : data.cmdPoolHdls)
|
||||||
|
hdl.Free();
|
||||||
|
|
||||||
|
data.cmdPoolHdls.clear();
|
||||||
|
|
||||||
|
data.Destroy();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
frameData.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
SHRenderContext::SHRenderContext(void) noexcept
|
||||||
|
: numThreads {1}
|
||||||
|
, currentFrame{0}
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SHRenderContext::~SHRenderContext(void) noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
When the window resizes, the swapchain needs to be recreated. When that
|
||||||
|
happens, the swapchain images are also new, hence necessitating the need
|
||||||
|
to update the frame data image handles.
|
||||||
|
|
||||||
|
|
||||||
|
\return
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHRenderContext::HandleResize(void) noexcept
|
||||||
|
{
|
||||||
|
// Destroy the frame data
|
||||||
|
for (auto& frame : frameData)
|
||||||
|
frame.Destroy();
|
||||||
|
|
||||||
|
for (auto& frame : frameData)
|
||||||
|
frame.Recreate(logicalDeviceHdl);
|
||||||
|
|
||||||
|
currentFrame = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Acquire the index of the next image in the swapchain. Do note that this
|
||||||
|
function is non-blocking but it takes in a semaphore that will be
|
||||||
|
signaled when the image becomes available. We want to use this together
|
||||||
|
with AdvanceFrame because this engine trusts the implementation
|
||||||
|
to return swapchain images IN ORDER. When that happens the correct
|
||||||
|
behavior would be that currentFrame will end up being the same as the
|
||||||
|
what returns from vkAcquireNextImageKHR.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHRenderContext::AcquireNextIamge(void) noexcept
|
||||||
|
{
|
||||||
|
uint32_t frameIndex = 0;
|
||||||
|
logicalDeviceHdl->GetVkLogicalDevice().acquireNextImageKHR(perFrameDataParams.swapchainHdl->GetVkSwapchain(), std::numeric_limits<uint64_t>::max(), frameData[currentFrame].semImgAvailableHdl->GetVkSem(), VK_NULL_HANDLE, &frameIndex);
|
||||||
|
if (frameIndex != currentFrame)
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("Frame index retrieved from vkAcquireNextImageKHR is not the same as currentFrame.");
|
||||||
|
}
|
||||||
|
currentFrame = frameIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Waits for a fence to be signaled.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
bool SHRenderContext::WaitForFence(void) noexcept
|
||||||
|
{
|
||||||
|
return frameData[currentFrame].fenceHdl->Wait(true, std::numeric_limits<uint64_t>::max());
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Resets a fence.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHRenderContext::ResetFence(void) noexcept
|
||||||
|
{
|
||||||
|
frameData[currentFrame].fenceHdl->Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHRenderContext::SetIsResized(bool resized) noexcept
|
||||||
|
{
|
||||||
|
isResized = resized;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Advances the frame. The correct frame to use can also be returned by
|
||||||
|
vkAcquireNextImageKHR so this is just an aiternative.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHRenderContext::AdvanceFrame(void) noexcept
|
||||||
|
{
|
||||||
|
currentFrame = (currentFrame + 1u) % frameData.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
SHPerFrameData& SHRenderContext::GetCurrentFrameData(void) noexcept
|
||||||
|
{
|
||||||
|
return frameData[currentFrame];
|
||||||
|
}
|
||||||
|
|
||||||
|
SHPerFrameData& SHRenderContext::GetFrameData(uint32_t index) noexcept
|
||||||
|
{
|
||||||
|
return frameData[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t SHRenderContext::GetCurrentFrame(void) const noexcept
|
||||||
|
{
|
||||||
|
return currentFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHRenderContext::GetResizeAndReset(void) noexcept
|
||||||
|
{
|
||||||
|
bool b = isResized;
|
||||||
|
isResized = false;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
#ifndef SH_RENDER_CONTEXT_H
|
||||||
|
#define SH_RENDER_CONTEXT_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include "SHPerFrameData.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
class SHVkSwapchain;
|
||||||
|
class SHVkLogicalDevice;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//! Think of a render context like the context in OpenGL. When you call draw calls, the drivers are calling
|
||||||
|
//! queue submissions and presenting functions at the back. Frame swapping is also done there. The only difference a
|
||||||
|
//! render context in SHADE engine has is that it requires users to call these explicitly in the middle end. While there
|
||||||
|
//! is little reason the flow of the render context should deviate from its intended usage, we want to leave it up to
|
||||||
|
//! users to explicitly call functions from here so we don't risk losing opportunities for different usage.
|
||||||
|
class SHRenderContext
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
//! container of frame data. Note that the manager owns the data, but the frame data themselves do not own anything.
|
||||||
|
std::vector<SHPerFrameData> frameData;
|
||||||
|
|
||||||
|
//! Logical Device for creation and deletion
|
||||||
|
Handle<SHVkLogicalDevice> logicalDeviceHdl;
|
||||||
|
|
||||||
|
//! We want to save this to handle resizing without passing in arguments.
|
||||||
|
SHPerFrameDataParams perFrameDataParams;
|
||||||
|
|
||||||
|
//! Number of threads
|
||||||
|
uint32_t numThreads;
|
||||||
|
|
||||||
|
//! current frame being used
|
||||||
|
uint32_t currentFrame;
|
||||||
|
|
||||||
|
bool isResized{ false };
|
||||||
|
|
||||||
|
public:
|
||||||
|
SHRenderContext(void) noexcept;
|
||||||
|
~SHRenderContext(void) noexcept;
|
||||||
|
|
||||||
|
void Init (Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl, SHPerFrameDataParams const& params) noexcept;
|
||||||
|
void Destroy (void) noexcept;
|
||||||
|
void HandleResize (void) noexcept;
|
||||||
|
|
||||||
|
void AcquireNextIamge (void) noexcept;
|
||||||
|
void AdvanceFrame (void) noexcept;
|
||||||
|
|
||||||
|
bool WaitForFence (void) noexcept;
|
||||||
|
void ResetFence (void) noexcept;
|
||||||
|
|
||||||
|
void SetIsResized (bool resized) noexcept;
|
||||||
|
|
||||||
|
SHPerFrameData& GetCurrentFrameData(void) noexcept;
|
||||||
|
SHPerFrameData& GetFrameData (uint32_t index) noexcept;
|
||||||
|
uint32_t GetCurrentFrame (void) const noexcept;
|
||||||
|
bool GetResizeAndReset (void) noexcept;
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,69 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHShaderModuleLibrary.h"
|
||||||
|
#include "Graphics/Devices/SHVkLogicalDevice.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Imports all shader binaries from the source library.
|
||||||
|
|
||||||
|
\param logicalDeviceHdl
|
||||||
|
For creating shader modules.
|
||||||
|
|
||||||
|
\param sourceLib
|
||||||
|
The source library class that stores the container of shader binary data.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHShaderModuleLibrary::ImportFromSourceLibrary(Handle<SHVkLogicalDevice>& logicalDeviceHdl, SHShaderSourceLibrary const& sourceLib) noexcept
|
||||||
|
{
|
||||||
|
auto const& sources = sourceLib.GetSourceLibrary();
|
||||||
|
for (auto const& source : sources)
|
||||||
|
{
|
||||||
|
vk::ShaderStageFlagBits shaderType{};
|
||||||
|
switch (source.shaderType)
|
||||||
|
{
|
||||||
|
case SH_SHADER_TYPE::VERTEX:
|
||||||
|
shaderType = vk::ShaderStageFlagBits::eVertex;
|
||||||
|
break;
|
||||||
|
case SH_SHADER_TYPE::FRAGMENT:
|
||||||
|
shaderType = vk::ShaderStageFlagBits::eFragment;
|
||||||
|
break;
|
||||||
|
case SH_SHADER_TYPE::COMPUTE:
|
||||||
|
shaderType = vk::ShaderStageFlagBits::eCompute;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
shaderType = vk::ShaderStageFlagBits::eVertex;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle<SHVkShaderModule> newShaderModule = logicalDeviceHdl->CreateShaderModule(source.spirvBinary, "main", shaderType, source.name);
|
||||||
|
shaderModules.emplace(source.id, newShaderModule);
|
||||||
|
stringToID.emplace(source.name, source.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Gets the shader module based on module name.
|
||||||
|
|
||||||
|
\param shaderName
|
||||||
|
|
||||||
|
\return
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
Handle<SHVkShaderModule> SHShaderModuleLibrary::GetShaderModule(std::string shaderName) const noexcept
|
||||||
|
{
|
||||||
|
if (stringToID.contains(shaderName))
|
||||||
|
return shaderModules.at(stringToID.at(shaderName));
|
||||||
|
else
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
#ifndef SH_SHADER_MODULE_LIBRARY_H
|
||||||
|
#define SH_SHADER_MODULE_LIBRARY_H
|
||||||
|
|
||||||
|
#include "Graphics/Shaders/SHVkShaderModule.h"
|
||||||
|
#include "SHShaderSourceLibrary.h"
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
class SHVkLogicalDevice;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The purpose of this shader module library is to be separate from the source library. The source library contains
|
||||||
|
* pure shader binary data that contains no vulkan related objects. Every time we load on unload a scene/level,
|
||||||
|
* this class and the source library class is cleared of its modules and recreated.
|
||||||
|
*/
|
||||||
|
class SHShaderModuleLibrary
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PRIVATE MEMBER VARIABLES */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
//! Stored shader modules
|
||||||
|
std::unordered_map<uint32_t, Handle<SHVkShaderModule>> shaderModules;
|
||||||
|
|
||||||
|
//! We want some sort of interface with strings, instead of ints
|
||||||
|
std::map<std::string, uint32_t> stringToID;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PUBLIC MEMBER FUNCTIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
void ImportFromSourceLibrary(Handle<SHVkLogicalDevice>& logicalDeviceHdl, SHShaderSourceLibrary const& sourceLib) noexcept;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* SETTERS AND GETTERS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
Handle<SHVkShaderModule> GetShaderModule(std::string shaderName) const noexcept;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,272 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include "SHShaderSourceLibrary.h"
|
||||||
|
#include "Tools/SHLogger.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Initializes the directory to take assets from. TODO: Only temporary until
|
||||||
|
the resource manager is implemented.
|
||||||
|
|
||||||
|
\param directory
|
||||||
|
|
||||||
|
\return
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHShaderSourceLibrary::Init (std::string directory) noexcept
|
||||||
|
{
|
||||||
|
shaderDirectory = directory;
|
||||||
|
if (shaderDirectory.back() != '/')
|
||||||
|
{
|
||||||
|
shaderDirectory += '/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Private member function to compile a shader STRING source to binary and
|
||||||
|
returns a vector of 4 bytes.
|
||||||
|
|
||||||
|
\param glslSource
|
||||||
|
The GLSL string source.
|
||||||
|
|
||||||
|
\param type
|
||||||
|
Type of the shader: vertex, fragment, compute, etc.
|
||||||
|
|
||||||
|
\param opLevel
|
||||||
|
Optimization level.
|
||||||
|
|
||||||
|
\return
|
||||||
|
Returns a vector of the binary data.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
std::vector<uint32_t> SHShaderSourceLibrary::CompileToBinary(std::string const& glslSource, char const* const spirvFilename, SH_SHADER_TYPE type, shaderc_optimization_level opLevel /*= shaderc_optimization_level_zero*/)
|
||||||
|
{
|
||||||
|
// shaderc compiler
|
||||||
|
shaderc::Compiler compiler;
|
||||||
|
shaderc::CompileOptions options;
|
||||||
|
|
||||||
|
options.AddMacroDefinition("MY_DEFINE", "1");
|
||||||
|
|
||||||
|
// Set optimization levels
|
||||||
|
if (opLevel != shaderc_optimization_level_zero)
|
||||||
|
options.SetOptimizationLevel(opLevel);
|
||||||
|
|
||||||
|
// Attempt to get the shaderc equivalent shader stage
|
||||||
|
shaderc_shader_kind shaderKind;
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case SH_SHADER_TYPE::VERTEX:
|
||||||
|
shaderKind = shaderc_shader_kind::shaderc_glsl_vertex_shader;
|
||||||
|
break;
|
||||||
|
case SH_SHADER_TYPE::FRAGMENT:
|
||||||
|
shaderKind = shaderc_shader_kind::shaderc_glsl_fragment_shader;
|
||||||
|
break;
|
||||||
|
case SH_SHADER_TYPE::COMPUTE:
|
||||||
|
shaderKind = shaderc_shader_kind::shaderc_glsl_compute_shader;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
shaderKind = shaderc_shader_kind::shaderc_glsl_vertex_shader;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile the shader and get the result
|
||||||
|
shaderc::SpvCompilationResult compileResult = compiler.CompileGlslToSpv(glslSource, shaderKind, spirvFilename, options);
|
||||||
|
|
||||||
|
if (compileResult.GetCompilationStatus() != shaderc_compilation_status_success)
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("Shaderc failed to compile GLSL shader to binary | " + compileResult.GetErrorMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return { compileResult.begin(), compileResult.end() };
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
TODO: Delete after file IO is implemented. Loads a shader from disk.
|
||||||
|
|
||||||
|
\param filePath
|
||||||
|
file path to the shader in the asset directory.
|
||||||
|
|
||||||
|
\return
|
||||||
|
Returns the data in the file in string form.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
std::string SHShaderSourceLibrary::GetStringFromFile(char const* filePath) noexcept
|
||||||
|
{
|
||||||
|
// Retrieve contents from filePath
|
||||||
|
// Ensure ifstream objects can throw exceptions
|
||||||
|
std::ifstream iFile;
|
||||||
|
iFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||||
|
std::string fileContent = "";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Open file
|
||||||
|
// Read file's buffer contents into streams
|
||||||
|
iFile.open(filePath);
|
||||||
|
std::stringstream fileStream;
|
||||||
|
fileStream << iFile.rdbuf();
|
||||||
|
|
||||||
|
fileContent = fileStream.str();
|
||||||
|
|
||||||
|
// Close file handler
|
||||||
|
iFile.close();
|
||||||
|
}
|
||||||
|
catch (std::ifstream::failure e)
|
||||||
|
{
|
||||||
|
std::cerr << "File was not successfully read" << filePath << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileContent;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Load a shader into the library.
|
||||||
|
|
||||||
|
\param filePath
|
||||||
|
file path to the shader in the asset directory.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
bool SHShaderSourceLibrary::LoadShader (uint32_t id, std::string glslFile, SH_SHADER_TYPE type, bool checkSpirvOutdated/* = true*/, bool recompileAnyway /*= false*/) noexcept
|
||||||
|
{
|
||||||
|
//if (sourceLibrary.contains(id))
|
||||||
|
//{
|
||||||
|
// SHLOG_ERROR("Shader with ID passed in already exists. Use a different ID");
|
||||||
|
// return false;
|
||||||
|
//}
|
||||||
|
|
||||||
|
std::string fullGLSLPath = shaderDirectory + glslFile;
|
||||||
|
auto path = std::filesystem::path(fullGLSLPath);
|
||||||
|
|
||||||
|
if (path.extension() != ".glsl")
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("Shader is not GLSL file, failed to load shader. ");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string spirvFilepath = path.replace_extension("spv").string();
|
||||||
|
|
||||||
|
SHShaderData newShaderData{};
|
||||||
|
newShaderData.shaderType = type;
|
||||||
|
|
||||||
|
// spirv file
|
||||||
|
std::ifstream spirvFile(spirvFilepath, std::ios::ate | std::ios::binary);
|
||||||
|
|
||||||
|
// If we disable spirv validation, file is not checked
|
||||||
|
if (!recompileAnyway &&
|
||||||
|
spirvFile.is_open() &&
|
||||||
|
(checkSpirvOutdated ? (std::filesystem::last_write_time(spirvFilepath) > std::filesystem::last_write_time(fullGLSLPath)) : true))
|
||||||
|
{
|
||||||
|
// Get file size of binary
|
||||||
|
uint32_t fileSize = static_cast<uint32_t>(spirvFile.tellg());
|
||||||
|
|
||||||
|
// resize container to store binary
|
||||||
|
newShaderData.spirvBinary.resize(fileSize / sizeof(uint32_t));
|
||||||
|
|
||||||
|
// Read data from binary file to container
|
||||||
|
spirvFile.seekg(0);
|
||||||
|
spirvFile.read(reinterpret_cast<char*>(newShaderData.spirvBinary.data()), fileSize);
|
||||||
|
|
||||||
|
// close file
|
||||||
|
spirvFile.close();
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Use glslc to generate spirv file
|
||||||
|
newShaderData.spirvBinary = CompileToBinary(GetStringFromFile(fullGLSLPath.c_str()), spirvFilepath.c_str(), type);
|
||||||
|
|
||||||
|
std::ofstream binaryFile(spirvFilepath, std::ios::binary);
|
||||||
|
|
||||||
|
if (binaryFile.is_open())
|
||||||
|
{
|
||||||
|
// write all data to binary file
|
||||||
|
binaryFile.write(reinterpret_cast<const char*>(newShaderData.spirvBinary.data()), newShaderData.spirvBinary.size() * sizeof(uint32_t));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("Failed to modify spirv file. ");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newShaderData.name = glslFile;
|
||||||
|
newShaderData.id = id;
|
||||||
|
|
||||||
|
sourceLibrary.emplace_back(std::move (newShaderData));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Gets the entire source library.
|
||||||
|
|
||||||
|
\return
|
||||||
|
The container of binary data.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
std::vector<SHShaderData> const& SHShaderSourceLibrary::GetSourceLibrary(void) const noexcept
|
||||||
|
{
|
||||||
|
return sourceLibrary;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Move ctor for shader data.
|
||||||
|
|
||||||
|
\param rhs
|
||||||
|
The other shader data
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHShaderData::SHShaderData(SHShaderData&& rhs) noexcept
|
||||||
|
: spirvBinary{ std::move (rhs.spirvBinary)}
|
||||||
|
, shaderType{std::move (rhs.shaderType)}
|
||||||
|
, name{ std::move (rhs.name)}
|
||||||
|
, id {std::move (rhs.id)}
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Default ctor for shader data. Does nothing.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHShaderData::SHShaderData(void) noexcept
|
||||||
|
: spirvBinary{}
|
||||||
|
, shaderType{SH_SHADER_TYPE::VERTEX}
|
||||||
|
, name{ }
|
||||||
|
, id{ }
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
#ifndef SH_SHADER_SOURCE_LIBRARY_H
|
||||||
|
#define SH_SHADER_SOURCE_LIBRARY_H
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include "SHShaderType.h"
|
||||||
|
#include "shaderc/shaderc.hpp"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
struct SHShaderData
|
||||||
|
{
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* MEMBER VARIABLES */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
//! container storing the spirv binary
|
||||||
|
std::vector<uint32_t> spirvBinary;
|
||||||
|
|
||||||
|
//! For the compilation of the shader. Vulkan backend will use it too
|
||||||
|
SH_SHADER_TYPE shaderType;
|
||||||
|
|
||||||
|
//! Name of the shader file (without parent path)
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
//! id of the shader
|
||||||
|
uint32_t id;
|
||||||
|
|
||||||
|
SHShaderData(void) noexcept;
|
||||||
|
SHShaderData(SHShaderData&& rhs) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: This class is purely temporary and will be converted/changed when XQ implements his resource manager
|
||||||
|
class SHShaderSourceLibrary
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PRIVATE MEMBER VARIABLES */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
//! Stores all the source data. Take note that the source here is GLSL source and NOT binary data.
|
||||||
|
//! Binary data gets passed to the backend to convert to spirv.
|
||||||
|
std::vector<SHShaderData> sourceLibrary;
|
||||||
|
|
||||||
|
//! The directory where the shaders are located.
|
||||||
|
std::string shaderDirectory;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PRIVATE MEMBER FUNCTIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
std::vector<uint32_t> CompileToBinary(std::string const& glslSource, char const* const spirvFilename, SH_SHADER_TYPE type, shaderc_optimization_level opLevel = shaderc_optimization_level_zero);
|
||||||
|
|
||||||
|
// TODO: Delete after file IO is implemented
|
||||||
|
std::string GetStringFromFile(char const* filePath) noexcept;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PUBLIC MEMBER FUNCTIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
void Init (std::string directory) noexcept;
|
||||||
|
bool LoadShader (uint32_t id, std::string glslFile, SH_SHADER_TYPE type, bool checkSpirvOutdated = true, bool recompileAnyway = false) noexcept;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* SETTERS AND GETTERS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
std::vector<SHShaderData> const& GetSourceLibrary(void) const noexcept;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef SH_SHADER_TYPE_H
|
||||||
|
#define SH_SHADER_TYPE_H
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
enum class SH_SHADER_TYPE
|
||||||
|
{
|
||||||
|
VERTEX,
|
||||||
|
FRAGMENT,
|
||||||
|
COMPUTE
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef SH_PIPELINE_LAYOUT_PARAMS_H
|
||||||
|
#define SH_PIPELINE_LAYOUT_PARAMS_H
|
||||||
|
|
||||||
|
#include "Graphics/SHVulkanIncludes.h"
|
||||||
|
#include "Resource/Handle.h"
|
||||||
|
#include "Graphics/Descriptors/SHVkDescriptorSetLayout.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
class SHVkShaderModule;
|
||||||
|
|
||||||
|
struct SHPipelineLayoutParams
|
||||||
|
{
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* MEMBER VARIABLES */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
//! Shader modules for pipeline creation. See pipeline layout for details.
|
||||||
|
//! Note that this will be moved to pipeline layout.
|
||||||
|
std::vector<Handle<SHVkShaderModule>> shaderModules;
|
||||||
|
|
||||||
|
//! There's a huge chance that there is going to be a layout for a descriptor
|
||||||
|
//! set that is to be used for many shaders (i.e. a global descriptor set
|
||||||
|
//! used just for textures or lights for example). In that case, we still
|
||||||
|
//! want to use the layout to initialize the pipeline layout but we do not
|
||||||
|
//! want to use it for allocating descriptor sets.
|
||||||
|
std::vector<Handle<SHVkDescriptorSetLayout>> globalDescSetLayouts = {};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,238 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHPipelineState.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
|
||||||
|
void SHVkPipelineState::AddDefaultColorBlendAttachment(void) noexcept
|
||||||
|
{
|
||||||
|
vk::PipelineColorBlendAttachmentState colorBlendAttachment{};
|
||||||
|
colorBlendAttachment.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA;
|
||||||
|
colorBlendAttachment.blendEnable = true;
|
||||||
|
colorBlendAttachment.srcColorBlendFactor = vk::BlendFactor::eSrcAlpha;
|
||||||
|
colorBlendAttachment.dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha;
|
||||||
|
colorBlendAttachment.colorBlendOp = vk::BlendOp::eAdd;
|
||||||
|
colorBlendAttachment.srcAlphaBlendFactor = vk::BlendFactor::eOne;
|
||||||
|
colorBlendAttachment.dstAlphaBlendFactor = vk::BlendFactor::eZero;
|
||||||
|
colorBlendAttachment.alphaBlendOp = vk::BlendOp::eAdd;
|
||||||
|
|
||||||
|
colorBlendState.attachments.push_back(colorBlendAttachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHVkPipelineState::SetInputAssemblyState(SHInputAssemblyState const& state) noexcept
|
||||||
|
{
|
||||||
|
dirty = true;
|
||||||
|
inputAssemblyState = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHVkPipelineState::SetRasterizationState(SHRasterizationState const& state) noexcept
|
||||||
|
{
|
||||||
|
dirty = true;
|
||||||
|
rasterizationState = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHVkPipelineState::SetViewportState(SHViewportState const& state) noexcept
|
||||||
|
{
|
||||||
|
dirty = true;
|
||||||
|
viewportState = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHVkPipelineState::SetMultiSampleState(SHMultisampleState const& state) noexcept
|
||||||
|
{
|
||||||
|
dirty = true;
|
||||||
|
multisampleState = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHVkPipelineState::SetDepthStencilState(SHDepthStencilState const& state) noexcept
|
||||||
|
{
|
||||||
|
dirty = true;
|
||||||
|
depthStencilState = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHVkPipelineState::SetColorBlenState(SHColorBlendState const& state) noexcept
|
||||||
|
{
|
||||||
|
dirty = true;
|
||||||
|
colorBlendState = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHVkPipelineState::SetRenderpass(Handle<SHVkRenderpass> const& inRenderpassHdl) noexcept
|
||||||
|
{
|
||||||
|
dirty = true;
|
||||||
|
renderpassHdl = inRenderpassHdl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHVkPipelineState::SetSubpassIndex(uint32_t index) noexcept
|
||||||
|
{
|
||||||
|
dirty = true;
|
||||||
|
subpassIndex = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVertexInputState const& SHVkPipelineState::GetVertexInputState(void) const noexcept
|
||||||
|
{
|
||||||
|
return vertexInputState;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHInputAssemblyState const& SHVkPipelineState::GetInputAssemblyState(void) const noexcept
|
||||||
|
{
|
||||||
|
return inputAssemblyState;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHRasterizationState const& SHVkPipelineState::GetRasterizationState(void) const noexcept
|
||||||
|
{
|
||||||
|
return rasterizationState;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHViewportState const& SHVkPipelineState::GetViewportState(void) const noexcept
|
||||||
|
{
|
||||||
|
return viewportState;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHMultisampleState const& SHVkPipelineState::GetMultisampleState(void) const noexcept
|
||||||
|
{
|
||||||
|
return multisampleState;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHDepthStencilState const& SHVkPipelineState::GetDepthStencilState(void) const noexcept
|
||||||
|
{
|
||||||
|
return depthStencilState;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHColorBlendState const& SHVkPipelineState::GetColorBlenState(void) const noexcept
|
||||||
|
{
|
||||||
|
return colorBlendState;
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle<SHVkRenderpass> const& SHVkPipelineState::GetRenderpass(void) const noexcept
|
||||||
|
{
|
||||||
|
return renderpassHdl;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t SHVkPipelineState::GetSubpassIndex(void) const noexcept
|
||||||
|
{
|
||||||
|
return subpassIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHVkPipelineState::SetDirty(bool isDirty) noexcept
|
||||||
|
{
|
||||||
|
dirty = isDirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<uint32_t, uint32_t, vk::Format> SHVertexInputState::GetInfoFromAttribFormat(SHAttribFormat attribFormat) const noexcept
|
||||||
|
{
|
||||||
|
switch (attribFormat)
|
||||||
|
{
|
||||||
|
case SHAttribFormat::FLOAT_1D:
|
||||||
|
return std::make_tuple(1, 4, vk::Format::eR32Sfloat);
|
||||||
|
case SHAttribFormat::FLOAT_2D:
|
||||||
|
return std::make_tuple(1, 8, vk::Format::eR32G32Sfloat);
|
||||||
|
case SHAttribFormat::FLOAT_3D:
|
||||||
|
return std::make_tuple(1, 12, vk::Format::eR32G32B32Sfloat);
|
||||||
|
case SHAttribFormat::FLOAT_4D:
|
||||||
|
return std::make_tuple(1, 16, vk::Format::eR32G32B32A32Sfloat);
|
||||||
|
|
||||||
|
// Matrix formats onwards all return less than actual bytes required but the numSlots will adjust offsets accordingly
|
||||||
|
case SHAttribFormat::MAT_2D:
|
||||||
|
return std::make_tuple(2, 8, vk::Format::eR32G32Sfloat);
|
||||||
|
case SHAttribFormat::MAT_3D:
|
||||||
|
return std::make_tuple(3, 12, vk::Format::eR32G32B32Sfloat);
|
||||||
|
case SHAttribFormat::MAT_4D:
|
||||||
|
return std::make_tuple(4, 16, vk::Format::eR32G32B32A32Sfloat);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return std::make_tuple(0, 0, vk::Format::eR32Sfloat);
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVertexInputState::SHVertexInputState(void) noexcept
|
||||||
|
: bindings{}
|
||||||
|
, attributes{}
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVertexInputState::SHVertexInputState(SHVertexInputState const& rhs) noexcept
|
||||||
|
: bindings{rhs.bindings}
|
||||||
|
, attributes{rhs.attributes}
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVertexInputState::SHVertexInputState(SHVertexInputState&& rhs) noexcept
|
||||||
|
: bindings{ std::move (rhs.bindings) }
|
||||||
|
, attributes{ std::move (rhs.attributes) }
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVertexInputState& SHVertexInputState::operator=(SHVertexInputState const& rhs) noexcept
|
||||||
|
{
|
||||||
|
if (&rhs == this)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
bindings = rhs.bindings;
|
||||||
|
attributes = rhs.attributes;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVertexInputState& SHVertexInputState::operator=(SHVertexInputState&& rhs) noexcept
|
||||||
|
{
|
||||||
|
if (&rhs == this)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
bindings = std::move(rhs.bindings);
|
||||||
|
attributes = std::move(rhs.attributes);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHVertexInputState::AddBinding(bool instanced, bool calcOffset, std::initializer_list<SHVertexAttribute> inAttribs) noexcept
|
||||||
|
{
|
||||||
|
// add a binding and get ref to it
|
||||||
|
bindings.emplace_back();
|
||||||
|
auto& binding = bindings.back();
|
||||||
|
|
||||||
|
// if binding is instanced, attributes are per instance, if not attributes here are per vertex
|
||||||
|
if (instanced)
|
||||||
|
binding.inputRate = vk::VertexInputRate::eInstance;
|
||||||
|
else
|
||||||
|
binding.inputRate = vk::VertexInputRate::eVertex;
|
||||||
|
|
||||||
|
// Offset is 0 at first (for first element)
|
||||||
|
uint32_t offset = 0;
|
||||||
|
|
||||||
|
// for every attribute passed in
|
||||||
|
for (auto const& attrib : inAttribs)
|
||||||
|
{
|
||||||
|
// Get number of slots needed, the bytes required and format of the attribute
|
||||||
|
auto const& [slots, bytes, format] = GetInfoFromAttribFormat(attrib.attribFormat);
|
||||||
|
|
||||||
|
// For each attribute slot the attribute needs
|
||||||
|
for (uint32_t i = 0; i < slots; ++i)
|
||||||
|
{
|
||||||
|
// Add an attribute description
|
||||||
|
attributes.emplace_back();
|
||||||
|
auto& vertexAttrib = attributes.back();
|
||||||
|
|
||||||
|
// The binding for that attribute description is index of the new binding created earlier in this function
|
||||||
|
vertexAttrib.binding = static_cast<uint32_t>(bindings.size() - 1);
|
||||||
|
|
||||||
|
// Attribute location. New index is simply + 1 of the previous. Starts from 0 obviously
|
||||||
|
vertexAttrib.location = static_cast<uint32_t>(attributes.size () - 1);
|
||||||
|
|
||||||
|
// Get the vkFormat associated with the SHAttribFormat
|
||||||
|
vertexAttrib.format = format;
|
||||||
|
|
||||||
|
// if calcOffset is false, we want to use the calcuated one. If not, use the attribute's offset passed in.
|
||||||
|
vertexAttrib.offset = calcOffset ? offset : attrib.offset;
|
||||||
|
|
||||||
|
// For when we want to use calculated offset and for the stride.
|
||||||
|
offset += bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stride is always all the offsets added together (Unless of course under special conditions which this class doesn't cover).
|
||||||
|
binding.stride = offset;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,225 @@
|
||||||
|
#ifndef SH_PIPELINE_STATE_H
|
||||||
|
#define SH_PIPELINE_STATE_H
|
||||||
|
|
||||||
|
#include "Graphics/SHVulkanIncludes.h"
|
||||||
|
#include "Graphics/Renderpass/SHVkRenderpass.h"
|
||||||
|
#include "Graphics/VertexDescriptors/SHVertexAttribute.h"
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
// This is mainly for non-interleaved attributes where we have a separate buffer for
|
||||||
|
// each vertex attribute.
|
||||||
|
struct SHVertexInputState
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
using numAttribSlots = uint32_t;
|
||||||
|
using bytesRequired = uint32_t;
|
||||||
|
|
||||||
|
//! Vertex attribute bindings
|
||||||
|
std::vector<vk::VertexInputBindingDescription> bindings;
|
||||||
|
|
||||||
|
//! Vertex attributes
|
||||||
|
std::vector<vk::VertexInputAttributeDescription> attributes;
|
||||||
|
|
||||||
|
std::tuple<numAttribSlots, bytesRequired, vk::Format> GetInfoFromAttribFormat(SHAttribFormat attribFormat) const noexcept;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SHVertexInputState(void) noexcept;
|
||||||
|
SHVertexInputState(SHVertexInputState const& rhs) noexcept;
|
||||||
|
SHVertexInputState(SHVertexInputState&& rhs) noexcept;
|
||||||
|
|
||||||
|
SHVertexInputState& operator= (SHVertexInputState const& rhs) noexcept;
|
||||||
|
SHVertexInputState& operator= (SHVertexInputState&& rhs) noexcept;
|
||||||
|
|
||||||
|
void AddBinding(bool instanced, bool calcOffset, std::initializer_list<SHVertexAttribute> inAttribs) noexcept;
|
||||||
|
|
||||||
|
friend class SHVkPipelineState;
|
||||||
|
friend class SHVkPipeline;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SHInputAssemblyState
|
||||||
|
{
|
||||||
|
//! Primitive topology
|
||||||
|
vk::PrimitiveTopology topology{ vk::PrimitiveTopology::eTriangleList };
|
||||||
|
|
||||||
|
//! For drawElements this will enable primitive restarting
|
||||||
|
bool primitiveRestart{ VK_FALSE };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SHRasterizationState
|
||||||
|
{
|
||||||
|
//! is depth clamping enabled
|
||||||
|
bool depthClamp{ VK_FALSE };
|
||||||
|
|
||||||
|
//! Rasterizer discard
|
||||||
|
bool rasterizerDiscard{ VK_FALSE };
|
||||||
|
|
||||||
|
//! Fill, line, point
|
||||||
|
vk::PolygonMode polygonMode{ vk::PolygonMode::eFill};
|
||||||
|
|
||||||
|
//! cull front, back or both faces
|
||||||
|
vk::CullModeFlags cull_mode{ vk::CullModeFlagBits::eBack };
|
||||||
|
|
||||||
|
//! CW or CCW
|
||||||
|
vk::FrontFace frontFacingOrientation{ vk::FrontFace::eCounterClockwise };
|
||||||
|
|
||||||
|
bool depthBias{ VK_FALSE };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SHViewportState
|
||||||
|
{
|
||||||
|
//! Number of viewports
|
||||||
|
uint32_t viewportCount{ 1 };
|
||||||
|
|
||||||
|
//! number of scissors
|
||||||
|
uint32_t scissorCount{ 1 };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SHMultisampleState
|
||||||
|
{
|
||||||
|
//! number of rasterization samples
|
||||||
|
vk::SampleCountFlagBits rasterizationSamples{ vk::SampleCountFlagBits::e1 };
|
||||||
|
|
||||||
|
//! Sample shading
|
||||||
|
bool sampleShading{ false };
|
||||||
|
|
||||||
|
// Minimum sample shading
|
||||||
|
float minSampleShading{ 1.0f };
|
||||||
|
|
||||||
|
//! Sample mask
|
||||||
|
vk::SampleMask sampleMask{ 0 };
|
||||||
|
|
||||||
|
//! Alpha to coverage
|
||||||
|
bool alphaToCoverage{ false };
|
||||||
|
|
||||||
|
//! Alpha to one
|
||||||
|
bool alphaToOne{ false };
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct SHStencilOpState
|
||||||
|
{
|
||||||
|
//! When stencil test fails
|
||||||
|
vk::StencilOp failOp { vk::StencilOp::eReplace};
|
||||||
|
|
||||||
|
//! When stencil test passes
|
||||||
|
vk::StencilOp passOp{ vk::StencilOp::eReplace };
|
||||||
|
|
||||||
|
//! When stencil test passes
|
||||||
|
vk::StencilOp depthFailOp{ vk::StencilOp::eReplace };
|
||||||
|
|
||||||
|
//! The compare function for stencil tests
|
||||||
|
vk::CompareOp compareOp{ vk::CompareOp::eNever};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SHDepthStencilState
|
||||||
|
{
|
||||||
|
bool depthTest{ VK_TRUE };
|
||||||
|
|
||||||
|
bool depthWrite{ VK_TRUE };
|
||||||
|
|
||||||
|
// Note: Using Reversed depth-buffer for increased precision, so Greater depth values are kept
|
||||||
|
vk::CompareOp depthCompare{ vk::CompareOp::eGreater };
|
||||||
|
|
||||||
|
bool depthBounds{ VK_FALSE };
|
||||||
|
|
||||||
|
bool stencilTest{ VK_FALSE };
|
||||||
|
|
||||||
|
SHStencilOpState front{};
|
||||||
|
|
||||||
|
SHStencilOpState back{};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SHColorBlendState
|
||||||
|
{
|
||||||
|
VkBool32 logic_op_enable{ VK_TRUE };
|
||||||
|
|
||||||
|
vk::LogicOp logic_op{ VK_LOGIC_OP_COPY };
|
||||||
|
|
||||||
|
std::vector<vk::PipelineColorBlendAttachmentState> attachments;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Specialization constants
|
||||||
|
|
||||||
|
class SHVkPipelineState
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PRIVATE MEMBER VARIABLES */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
//! If any of the pipeline states change, set to true
|
||||||
|
bool dirty{ false };
|
||||||
|
|
||||||
|
//! Vertex input state
|
||||||
|
SHVertexInputState vertexInputState;
|
||||||
|
|
||||||
|
//! Input assembly
|
||||||
|
SHInputAssemblyState inputAssemblyState;
|
||||||
|
|
||||||
|
//! Rasterization state
|
||||||
|
SHRasterizationState rasterizationState;
|
||||||
|
|
||||||
|
//! Viewport state
|
||||||
|
SHViewportState viewportState;
|
||||||
|
|
||||||
|
//! Multisample state
|
||||||
|
SHMultisampleState multisampleState;
|
||||||
|
|
||||||
|
//! Depth Stencil state
|
||||||
|
SHDepthStencilState depthStencilState;
|
||||||
|
|
||||||
|
//! Color blend state
|
||||||
|
SHColorBlendState colorBlendState;
|
||||||
|
|
||||||
|
//! Renderpass that is compatible with the pipeline
|
||||||
|
Handle<SHVkRenderpass> renderpassHdl;
|
||||||
|
|
||||||
|
//! Subpass index
|
||||||
|
uint32_t subpassIndex;
|
||||||
|
|
||||||
|
friend class SHVkPipeline;
|
||||||
|
public:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PUBLIC MEMBER FUNCTIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
void AddDefaultColorBlendAttachment (void) noexcept;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* SETTERS AND GETTERS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
template <typename T, typename = std::enable_if_t <std::is_same_v<std::remove_reference_t<T>, SHVertexInputState>>>
|
||||||
|
void SetVertexInputState (T&& state) noexcept;
|
||||||
|
void SetInputAssemblyState(SHInputAssemblyState const& state) noexcept;
|
||||||
|
void SetRasterizationState(SHRasterizationState const& state) noexcept;
|
||||||
|
void SetViewportState (SHViewportState const& state) noexcept;
|
||||||
|
void SetMultiSampleState (SHMultisampleState const& state) noexcept;
|
||||||
|
void SetDepthStencilState (SHDepthStencilState const& state) noexcept;
|
||||||
|
void SetColorBlenState (SHColorBlendState const& state) noexcept;
|
||||||
|
void SetRenderpass (Handle<SHVkRenderpass> const& inRenderpassHdl) noexcept;
|
||||||
|
void SetSubpassIndex (uint32_t index) noexcept;
|
||||||
|
|
||||||
|
SHVertexInputState const& GetVertexInputState (void) const noexcept;
|
||||||
|
SHInputAssemblyState const& GetInputAssemblyState (void) const noexcept;
|
||||||
|
SHRasterizationState const& GetRasterizationState (void) const noexcept;
|
||||||
|
SHViewportState const& GetViewportState (void) const noexcept;
|
||||||
|
SHMultisampleState const& GetMultisampleState (void) const noexcept;
|
||||||
|
SHDepthStencilState const& GetDepthStencilState (void) const noexcept;
|
||||||
|
SHColorBlendState const& GetColorBlenState (void) const noexcept;
|
||||||
|
Handle<SHVkRenderpass> const& GetRenderpass (void) const noexcept;
|
||||||
|
uint32_t GetSubpassIndex (void) const noexcept;
|
||||||
|
|
||||||
|
void SetDirty(bool isDirty) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename Enable>
|
||||||
|
void SHVkPipelineState::SetVertexInputState(T&& state) noexcept
|
||||||
|
{
|
||||||
|
//static_assert(std::is_same_v<std::remove_reference_t<T>, SHVertexInputState>);
|
||||||
|
vertexInputState = std::forward<T>(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef SH_PIPELINE_TYPE_H
|
||||||
|
#define SH_PIPELINE_TYPE_H
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
enum class SH_PIPELINE_TYPE
|
||||||
|
{
|
||||||
|
GRAPHICS,
|
||||||
|
COMPUTE,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,91 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHPushConstantInterface.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Adds a variable and its offset to the interface.
|
||||||
|
|
||||||
|
\param variableName
|
||||||
|
The push constant variable's name.
|
||||||
|
|
||||||
|
\param offset
|
||||||
|
The push constant variable's offset.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHPushConstantInterface::AddOffset(std::string variableName, uint32_t offset) noexcept
|
||||||
|
{
|
||||||
|
offsets.try_emplace(std::move (variableName), offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHPushConstantInterface::Reset(void) noexcept
|
||||||
|
{
|
||||||
|
offsets.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Sets the size of the push constant interface.
|
||||||
|
|
||||||
|
\param inSize
|
||||||
|
Size to set to.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHPushConstantInterface::SetSize(uint32_t inSize) noexcept
|
||||||
|
{
|
||||||
|
size = inSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHPushConstantInterface::SetShaderStageFlags(vk::ShaderStageFlags flags) noexcept
|
||||||
|
{
|
||||||
|
shaderStages = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Retrieves an offset given a variable name.
|
||||||
|
|
||||||
|
\param variableName
|
||||||
|
The variable's offset we want to retrieve.
|
||||||
|
|
||||||
|
\return
|
||||||
|
The variable's offset.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
uint32_t SHPushConstantInterface::GetOffset(std::string const& variableName) const noexcept
|
||||||
|
{
|
||||||
|
return offsets.at (variableName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Getter for the size.
|
||||||
|
|
||||||
|
\return
|
||||||
|
The size required for the push constant memory.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
uint32_t SHPushConstantInterface::GetSize(void) const noexcept
|
||||||
|
{
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::ShaderStageFlags SHPushConstantInterface::GetShaderStageFlags(void) const noexcept
|
||||||
|
{
|
||||||
|
return shaderStages;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
#ifndef SH_PUSH_CONSTANT_INTERFACE_H
|
||||||
|
#define SH_PUSH_CONSTANT_INTERFACE_H
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
#include "Graphics/Shaders/SHShaderReflected.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\class SHPushConstantInterface
|
||||||
|
When we want to send data into the push constant memory in command
|
||||||
|
buffers, the middle end usage is very raw. Vulkan API mainly expects
|
||||||
|
the offset and data. This class will store the offsets and they can
|
||||||
|
be accessed via this class.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
class SHPushConstantInterface
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PRIVATE MEMBER VARIABLES */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
//! Stores the offset to variables in push constant structs
|
||||||
|
std::unordered_map<std::string, uint32_t> offsets;
|
||||||
|
|
||||||
|
//! The size in bytes the push constant requires
|
||||||
|
uint32_t size{ 0 };
|
||||||
|
|
||||||
|
vk::ShaderStageFlags shaderStages;
|
||||||
|
public:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PUBLIC MEMBER FUNCTIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
void AddOffset (std::string variableName, uint32_t offset) noexcept;
|
||||||
|
void Reset (void) noexcept;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* SETTERS AND GETTERS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
void SetSize (uint32_t inSize) noexcept;
|
||||||
|
void SetShaderStageFlags (vk::ShaderStageFlags flags) noexcept;
|
||||||
|
|
||||||
|
uint32_t GetOffset (std::string const& variableName) const noexcept;
|
||||||
|
uint32_t GetSize (void) const noexcept;
|
||||||
|
vk::ShaderStageFlags GetShaderStageFlags (void) const noexcept;
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,427 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHVkPipeline.h"
|
||||||
|
#include "Graphics/Devices/SHVkLogicalDevice.h"
|
||||||
|
#include "Graphics/Shaders/SHVkShaderModule.h"
|
||||||
|
#include "Graphics/Debugging/SHVulkanDebugUtil.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Creates a graphics pipeline from the pipeline state.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkPipeline::CreateGraphicsPipeline(void) noexcept
|
||||||
|
{
|
||||||
|
// Alot of the code is here is just boilerplate assignment. It may look
|
||||||
|
// like alot but the code is self explanatory.
|
||||||
|
|
||||||
|
vk::GraphicsPipelineCreateInfo gpCreateInfo{};
|
||||||
|
|
||||||
|
auto const& shaderModules = pipelineLayout->GetShaderModules();
|
||||||
|
|
||||||
|
std::vector<vk::PipelineShaderStageCreateInfo> shaderPipelineInfos{shaderModules.size()};
|
||||||
|
uint32_t numShaderModules = static_cast<uint32_t>(shaderPipelineInfos.size());
|
||||||
|
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < numShaderModules; ++i)
|
||||||
|
{
|
||||||
|
auto& info = shaderPipelineInfos[i];
|
||||||
|
info.stage = shaderModules[i]->GetShaderStageFlagBits();
|
||||||
|
info.pName = shaderModules[i]->GetEntryPoint().c_str();
|
||||||
|
info.module = shaderModules[i]->GetVkShaderModule();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: specialization info
|
||||||
|
|
||||||
|
gpCreateInfo.stageCount = numShaderModules;
|
||||||
|
gpCreateInfo.pStages = shaderPipelineInfos.data();
|
||||||
|
|
||||||
|
vk::PipelineVertexInputStateCreateInfo vertexInputState{};
|
||||||
|
auto const& viState = pipelineState.GetVertexInputState();
|
||||||
|
vertexInputState.pVertexBindingDescriptions = viState.bindings.data();
|
||||||
|
vertexInputState.vertexBindingDescriptionCount = static_cast<uint32_t>(viState.bindings.size());
|
||||||
|
vertexInputState.pVertexAttributeDescriptions = viState.attributes.data();
|
||||||
|
vertexInputState.vertexAttributeDescriptionCount = static_cast<uint32_t>(viState.attributes.size());
|
||||||
|
|
||||||
|
vk::PipelineInputAssemblyStateCreateInfo inputAssemblyState{};
|
||||||
|
auto const& iaState = pipelineState.GetInputAssemblyState();
|
||||||
|
inputAssemblyState.topology = iaState.topology;
|
||||||
|
inputAssemblyState.primitiveRestartEnable = iaState.primitiveRestart;
|
||||||
|
|
||||||
|
vk::PipelineRasterizationStateCreateInfo rasterizationState{};
|
||||||
|
auto const& rasterState = pipelineState.GetRasterizationState();
|
||||||
|
rasterizationState.depthClampEnable = rasterState.depthClamp;
|
||||||
|
rasterizationState.rasterizerDiscardEnable = rasterState.rasterizerDiscard;
|
||||||
|
rasterizationState.polygonMode = rasterState.polygonMode;
|
||||||
|
rasterizationState.cullMode = rasterState.cull_mode;
|
||||||
|
rasterizationState.frontFace = rasterState.frontFacingOrientation;
|
||||||
|
rasterizationState.depthBiasEnable = rasterState.depthBias;
|
||||||
|
rasterizationState.depthBiasClamp = 1.0f;
|
||||||
|
rasterizationState.depthBiasSlopeFactor = 1.0f;
|
||||||
|
rasterizationState.lineWidth = 1.0f;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
vk::PipelineViewportStateCreateInfo viewportState{};
|
||||||
|
auto const& vpState = pipelineState.GetViewportState();
|
||||||
|
viewportState.viewportCount = vpState.viewportCount;
|
||||||
|
viewportState.scissorCount = vpState.scissorCount;
|
||||||
|
|
||||||
|
vk::PipelineDepthStencilStateCreateInfo depthStencilState{};
|
||||||
|
auto const& dsState = pipelineState.GetDepthStencilState();
|
||||||
|
depthStencilState.depthTestEnable = dsState.depthTest;
|
||||||
|
depthStencilState.depthWriteEnable = dsState.depthWrite;
|
||||||
|
depthStencilState.depthCompareOp = dsState.depthCompare;
|
||||||
|
depthStencilState.depthBoundsTestEnable = dsState.depthBounds;
|
||||||
|
depthStencilState.stencilTestEnable = dsState.stencilTest;
|
||||||
|
depthStencilState.front.failOp = dsState.front.failOp;
|
||||||
|
depthStencilState.front.passOp = dsState.front.passOp;
|
||||||
|
depthStencilState.front.depthFailOp = dsState.front.depthFailOp;
|
||||||
|
depthStencilState.front.compareOp = dsState.front.compareOp;
|
||||||
|
depthStencilState.front.compareMask = ~0U;
|
||||||
|
depthStencilState.front.writeMask = ~0U;
|
||||||
|
depthStencilState.front.reference = ~0U;
|
||||||
|
depthStencilState.back.failOp = dsState.back.failOp;
|
||||||
|
depthStencilState.back.passOp = dsState.back.passOp;
|
||||||
|
depthStencilState.back.depthFailOp = dsState.back.depthFailOp;
|
||||||
|
depthStencilState.back.compareOp = dsState.back.compareOp;
|
||||||
|
depthStencilState.back.compareMask = ~0U;
|
||||||
|
depthStencilState.back.writeMask = ~0U;
|
||||||
|
depthStencilState.back.reference = ~0U;
|
||||||
|
|
||||||
|
|
||||||
|
vk::PipelineColorBlendStateCreateInfo colorBlendState{};
|
||||||
|
auto const& cbState = pipelineState.colorBlendState;
|
||||||
|
|
||||||
|
colorBlendState.logicOpEnable = cbState.logic_op_enable;
|
||||||
|
colorBlendState.logicOp = cbState.logic_op;
|
||||||
|
|
||||||
|
colorBlendState.attachmentCount = static_cast<uint32_t>(cbState.attachments.size());
|
||||||
|
colorBlendState.pAttachments = reinterpret_cast<const vk::PipelineColorBlendAttachmentState*>(cbState.attachments.data());
|
||||||
|
|
||||||
|
colorBlendState.blendConstants[0] = 1.0f;
|
||||||
|
colorBlendState.blendConstants[1] = 1.0f;
|
||||||
|
colorBlendState.blendConstants[2] = 1.0f;
|
||||||
|
colorBlendState.blendConstants[3] = 1.0f;
|
||||||
|
|
||||||
|
std::array dynamicStates =
|
||||||
|
{
|
||||||
|
vk::DynamicState::eViewport,
|
||||||
|
vk::DynamicState::eScissor,
|
||||||
|
vk::DynamicState::eLineWidth,
|
||||||
|
vk::DynamicState::eDepthBias,
|
||||||
|
vk::DynamicState::eBlendConstants,
|
||||||
|
vk::DynamicState::eDepthBounds,
|
||||||
|
vk::DynamicState::eStencilCompareMask,
|
||||||
|
vk::DynamicState::eStencilWriteMask,
|
||||||
|
vk::DynamicState::eStencilReference,
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::PipelineDynamicStateCreateInfo dynamicStateCreateInfo
|
||||||
|
{
|
||||||
|
.pNext = nullptr,
|
||||||
|
.flags{},
|
||||||
|
.dynamicStateCount = static_cast<uint32_t>(dynamicStates.size()),
|
||||||
|
.pDynamicStates = dynamicStates.data()
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::PipelineMultisampleStateCreateInfo multisamplingCreateInfo{};
|
||||||
|
auto const& msState = pipelineState.multisampleState;
|
||||||
|
|
||||||
|
multisamplingCreateInfo.sampleShadingEnable = msState.sampleShading;
|
||||||
|
multisamplingCreateInfo.rasterizationSamples = msState.rasterizationSamples;
|
||||||
|
multisamplingCreateInfo.minSampleShading = msState.minSampleShading;
|
||||||
|
|
||||||
|
if (msState.sampleMask != 0)
|
||||||
|
multisamplingCreateInfo.pSampleMask = &msState.sampleMask;
|
||||||
|
|
||||||
|
multisamplingCreateInfo.alphaToCoverageEnable = msState.alphaToCoverage;
|
||||||
|
multisamplingCreateInfo.alphaToOneEnable = msState.alphaToOne;
|
||||||
|
|
||||||
|
|
||||||
|
gpCreateInfo.pVertexInputState = &vertexInputState;
|
||||||
|
gpCreateInfo.pInputAssemblyState = &inputAssemblyState;
|
||||||
|
gpCreateInfo.pMultisampleState = &multisamplingCreateInfo;
|
||||||
|
gpCreateInfo.pRasterizationState = &rasterizationState;
|
||||||
|
gpCreateInfo.pViewportState = &viewportState;
|
||||||
|
gpCreateInfo.pDepthStencilState = &depthStencilState;
|
||||||
|
gpCreateInfo.pColorBlendState = &colorBlendState;
|
||||||
|
gpCreateInfo.pDynamicState = &dynamicStateCreateInfo;
|
||||||
|
gpCreateInfo.layout = pipelineLayout->GetVkPipelineLayout();
|
||||||
|
|
||||||
|
gpCreateInfo.renderPass = pipelineState.GetRenderpass()->GetVkRenderpass();
|
||||||
|
gpCreateInfo.subpass = pipelineState.GetSubpassIndex();
|
||||||
|
|
||||||
|
gpCreateInfo.basePipelineHandle = VK_NULL_HANDLE;
|
||||||
|
gpCreateInfo.basePipelineIndex = -1;
|
||||||
|
|
||||||
|
if (auto result = logicalDeviceHdl->GetVkLogicalDevice().createGraphicsPipelines(VK_NULL_HANDLE, 1, &gpCreateInfo, nullptr, &vkPipeline); result != vk::Result::eSuccess)
|
||||||
|
SHVulkanDebugUtil::ReportVkError(result, "Failed to create Graphics Pipeline. ");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SHVulkanDebugUtil::ReportVkSuccess("Successfully created a Graphics Pipeline. ");
|
||||||
|
created = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHVkPipeline::CreateComputePipeline(void) noexcept
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Non-default ctor.
|
||||||
|
|
||||||
|
\param inLogicalDeviceHdl
|
||||||
|
Needed for creation and destruction.
|
||||||
|
|
||||||
|
\param inPipelineLayout
|
||||||
|
The pipeline layout to use.
|
||||||
|
|
||||||
|
\param state
|
||||||
|
The pipeline state to copy from. This can be nullptr, in which case the
|
||||||
|
default constructed pipeline state will be used and initialized with
|
||||||
|
the renderpass and subpass passed in.
|
||||||
|
|
||||||
|
\param renderpassHdl
|
||||||
|
The renderpass that this pipeline will be used in. If state is not
|
||||||
|
nullptr, this parameter is ignored.
|
||||||
|
|
||||||
|
\param subpass
|
||||||
|
The subpass that this pipeline will be used in. If state is not
|
||||||
|
nullptr, this parameter is ignored.
|
||||||
|
|
||||||
|
\param type
|
||||||
|
The type of the pipeline.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHVkPipeline::SHVkPipeline(Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl, Handle<SHVkPipelineLayout> const& inPipelineLayout, SHVkPipelineState const* const state, Handle<SHVkRenderpass> const& renderpassHdl, uint32_t subpass, SH_PIPELINE_TYPE type) noexcept
|
||||||
|
: pipelineState{ } // copy the pipeline state
|
||||||
|
, pipelineType {type}
|
||||||
|
, vkPipeline {VK_NULL_HANDLE}
|
||||||
|
, logicalDeviceHdl{ inLogicalDeviceHdl }
|
||||||
|
, pipelineLayout { inPipelineLayout }
|
||||||
|
, created {false}
|
||||||
|
{
|
||||||
|
// We want to create a pipeline
|
||||||
|
if (state != nullptr)
|
||||||
|
{
|
||||||
|
pipelineState = *state;
|
||||||
|
|
||||||
|
// Creates a pipeline based on type
|
||||||
|
ConstructPipeline();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pipelineState.SetRenderpass(renderpassHdl);
|
||||||
|
pipelineState.SetSubpassIndex(subpass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Move ctor.
|
||||||
|
|
||||||
|
\param rhs
|
||||||
|
The other SHVkPipeline
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHVkPipeline::SHVkPipeline(SHVkPipeline&& rhs) noexcept
|
||||||
|
: vkPipeline {rhs.vkPipeline}
|
||||||
|
, pipelineState {rhs.pipelineState}
|
||||||
|
, pipelineType {rhs.pipelineType}
|
||||||
|
, created {rhs.created}
|
||||||
|
, logicalDeviceHdl{ rhs.logicalDeviceHdl }
|
||||||
|
, pipelineLayout { rhs.pipelineLayout }
|
||||||
|
{
|
||||||
|
vkPipeline = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Destructor. Destroys the pipeline.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHVkPipeline::~SHVkPipeline(void) noexcept
|
||||||
|
{
|
||||||
|
logicalDeviceHdl->GetVkLogicalDevice().destroyPipeline(vkPipeline, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
move assignment operator overload.
|
||||||
|
|
||||||
|
\param rhs
|
||||||
|
The other pipeline.
|
||||||
|
|
||||||
|
\return
|
||||||
|
The reference to the pipeline.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHVkPipeline& SHVkPipeline::operator=(SHVkPipeline&& rhs) noexcept
|
||||||
|
{
|
||||||
|
if (&rhs == this)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
vkPipeline = rhs.vkPipeline;
|
||||||
|
pipelineState = rhs.pipelineState;
|
||||||
|
pipelineType = rhs.pipelineType;
|
||||||
|
created = rhs.created;
|
||||||
|
logicalDeviceHdl = rhs.logicalDeviceHdl;
|
||||||
|
|
||||||
|
vkPipeline = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
For users to call when they created the pipeline with the default
|
||||||
|
constructor.
|
||||||
|
|
||||||
|
\param type
|
||||||
|
The type of the pipeline (graphics, compute, etc).
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkPipeline::ConstructPipeline(void) noexcept
|
||||||
|
{
|
||||||
|
// if it was created before, destroy it
|
||||||
|
if (created)
|
||||||
|
logicalDeviceHdl->GetVkLogicalDevice().destroyPipeline(vkPipeline, nullptr);
|
||||||
|
|
||||||
|
// Set to false again. If creation succeeds after this, this will be true
|
||||||
|
created = false;
|
||||||
|
|
||||||
|
// Create pipeline based on type
|
||||||
|
switch (pipelineType)
|
||||||
|
{
|
||||||
|
case SH_PIPELINE_TYPE::GRAPHICS:
|
||||||
|
CreateGraphicsPipeline();
|
||||||
|
break;
|
||||||
|
case SH_PIPELINE_TYPE::COMPUTE:
|
||||||
|
CreateComputePipeline();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Sets the pipeline type.
|
||||||
|
|
||||||
|
\param type
|
||||||
|
The pipeline type.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkPipeline::SetPipelineType(SH_PIPELINE_TYPE type) noexcept
|
||||||
|
{
|
||||||
|
pipelineState.SetDirty(true);
|
||||||
|
pipelineType = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Returns a reference to the pipeline state. Not a const reference because
|
||||||
|
we want to be able to modify the pipeline state.
|
||||||
|
|
||||||
|
\return
|
||||||
|
Reference to the stored pipeline state.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHVkPipelineState& SHVkPipeline::GetPipelineState(void) noexcept
|
||||||
|
{
|
||||||
|
return pipelineState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Derives a pipeline bind point from the type of the pipeline and returns
|
||||||
|
it.
|
||||||
|
|
||||||
|
\return
|
||||||
|
The derived bind point type.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
vk::PipelineBindPoint SHVkPipeline::GetPipelineBindPoint(void) const noexcept
|
||||||
|
{
|
||||||
|
switch (pipelineType)
|
||||||
|
{
|
||||||
|
case SH_PIPELINE_TYPE::GRAPHICS:
|
||||||
|
return vk::PipelineBindPoint::eGraphics;
|
||||||
|
case SH_PIPELINE_TYPE::COMPUTE:
|
||||||
|
return vk::PipelineBindPoint::eCompute;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return vk::PipelineBindPoint::eGraphics;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Gets the vulkan pipeline handle.
|
||||||
|
|
||||||
|
\return
|
||||||
|
The vulkan pipeline handle.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
vk::Pipeline SHVkPipeline::GetVkPipeline(void) const noexcept
|
||||||
|
{
|
||||||
|
return vkPipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Returns whether or not the pipeline has been created.
|
||||||
|
|
||||||
|
|
||||||
|
\return
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
bool SHVkPipeline::GetIsCreated(void) const noexcept
|
||||||
|
{
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle<SHVkPipelineLayout> SHVkPipeline::GetPipelineLayout(void) const noexcept
|
||||||
|
{
|
||||||
|
return pipelineLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
#ifndef SH_VK_PIPELINE_H
|
||||||
|
#define SH_VK_PIPELINE_H
|
||||||
|
|
||||||
|
#include "SHPipelineState.h"
|
||||||
|
#include "SHPipelineType.h"
|
||||||
|
#include "Resource/Handle.h"
|
||||||
|
#include "Graphics/Pipeline/SHVkPipelineLayout.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
class SHVkLogicalDevice;
|
||||||
|
|
||||||
|
class SHVkPipeline
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PRIVATE MEMBER VARIABLES */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
//! Vulkan pipeline handle
|
||||||
|
vk::Pipeline vkPipeline;
|
||||||
|
|
||||||
|
//! pipeline state
|
||||||
|
SHVkPipelineState pipelineState;
|
||||||
|
|
||||||
|
//! The type of the pipeline (affects creation)
|
||||||
|
SH_PIPELINE_TYPE pipelineType;
|
||||||
|
|
||||||
|
//! Logical device needed for creation and destruction of pipeline
|
||||||
|
Handle<SHVkLogicalDevice> logicalDeviceHdl;
|
||||||
|
|
||||||
|
//! Pipeline Layout used for the pipeline
|
||||||
|
Handle<SHVkPipelineLayout> pipelineLayout;
|
||||||
|
|
||||||
|
//! Sometimes we want to modify some state values before we create the
|
||||||
|
//! pipeline. This boolean just helps to identify if the pipeline has
|
||||||
|
//! already been created or not
|
||||||
|
bool created;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PRIVATE MEMBER FUNCTIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
void CreateGraphicsPipeline(void) noexcept;
|
||||||
|
void CreateComputePipeline (void) noexcept;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* CTORS AND DTORS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
SHVkPipeline (Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl,
|
||||||
|
Handle<SHVkPipelineLayout> const& inPipelineLayout,
|
||||||
|
SHVkPipelineState const* const state,
|
||||||
|
Handle<SHVkRenderpass> const& renderpassHdl,
|
||||||
|
uint32_t subpass,
|
||||||
|
SH_PIPELINE_TYPE type) noexcept;
|
||||||
|
|
||||||
|
SHVkPipeline (SHVkPipeline&& rhs) noexcept;
|
||||||
|
~SHVkPipeline (void) noexcept;
|
||||||
|
|
||||||
|
SHVkPipeline& operator= (SHVkPipeline&& rhs) noexcept;
|
||||||
|
// TODO: move ctors
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PUBLIC MEMBER FUNCTIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
void ConstructPipeline(void) noexcept;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* SETTERS AND GETTERS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
void SetPipelineType (SH_PIPELINE_TYPE type) noexcept;
|
||||||
|
|
||||||
|
SHVkPipelineState& GetPipelineState (void) noexcept;
|
||||||
|
vk::PipelineBindPoint GetPipelineBindPoint (void) const noexcept;
|
||||||
|
vk::Pipeline GetVkPipeline (void) const noexcept;
|
||||||
|
bool GetIsCreated (void) const noexcept;
|
||||||
|
Handle<SHVkPipelineLayout> GetPipelineLayout (void) const noexcept;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,424 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHVkPipelineLayout.h"
|
||||||
|
#include "Graphics/Devices/SHVkLogicalDevice.h"
|
||||||
|
#include "Graphics/Shaders/SHVkShaderModule.h"
|
||||||
|
#include "Tools/SHLogger.h"
|
||||||
|
#include "Graphics/Instance/SHVkInstance.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
|
||||||
|
void SHVkPipelineLayout::PreparePushConstantInterface (void) noexcept
|
||||||
|
{
|
||||||
|
// The starting of every push constant block, will get updated later.
|
||||||
|
uint32_t startOffset = 0;
|
||||||
|
|
||||||
|
// To check for duplicates
|
||||||
|
std::vector<SHShaderPushConstantInfo const*> pcInfos;
|
||||||
|
vk::ShaderStageFlags stageFlags;
|
||||||
|
|
||||||
|
for (auto& shaderModule : shaderModules)
|
||||||
|
{
|
||||||
|
// References for convenience
|
||||||
|
auto const& reflectedData = shaderModule->GetReflectedData();
|
||||||
|
auto const& pcInfo = reflectedData.GetPushConstantInfo();
|
||||||
|
|
||||||
|
// If a push constant block exists for the shader module
|
||||||
|
if (pcInfo.memberCount != 0)
|
||||||
|
{
|
||||||
|
bool exists = false;
|
||||||
|
|
||||||
|
// Check if push constant block already exists
|
||||||
|
for (uint32_t i = 0; i < pcInfos.size(); ++i)
|
||||||
|
{
|
||||||
|
// If there is a block with the same name, member count and size
|
||||||
|
if (std::strcmp(pcInfos[i]->name, pcInfo.name) == 0 && pcInfos[i]->memberCount == pcInfo.memberCount && pcInfos[i]->size == pcInfo.size)
|
||||||
|
{
|
||||||
|
// We just take the existing pc range we built earlier, and allow it to be accessed in potentially other shader stages
|
||||||
|
vkPcRanges[i].stageFlags |= shaderModule->GetShaderStageFlagBits();
|
||||||
|
|
||||||
|
// Set flag and stop checking
|
||||||
|
exists = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the block doesn't exist yet
|
||||||
|
if (!exists)
|
||||||
|
{
|
||||||
|
// Loop through all member variables of the new push constant block
|
||||||
|
for (uint32_t i = 0; i < pcInfo.memberCount; ++i)
|
||||||
|
{
|
||||||
|
std::string variableName;
|
||||||
|
variableName.reserve(50);
|
||||||
|
variableName += pcInfo.name;
|
||||||
|
variableName += ".";
|
||||||
|
variableName += pcInfo.members[i].name;
|
||||||
|
|
||||||
|
// Add the variable's offset info to the interface
|
||||||
|
pushConstantInterface.AddOffset(std::move(variableName), startOffset + pcInfo.members[i].offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// New push constant range
|
||||||
|
vk::PushConstantRange newRange;
|
||||||
|
|
||||||
|
// set offset and size
|
||||||
|
newRange.offset = startOffset;
|
||||||
|
newRange.size = pcInfo.size;
|
||||||
|
|
||||||
|
// Stage flags will be whatever shader stage of the shader that contains the push constant block
|
||||||
|
newRange.stageFlags = shaderModule->GetShaderStageFlagBits();
|
||||||
|
|
||||||
|
// Add to the list foe checking later
|
||||||
|
pcInfos.push_back(&pcInfo);
|
||||||
|
|
||||||
|
// For pipeline layout to consume
|
||||||
|
vkPcRanges.push_back(newRange);
|
||||||
|
|
||||||
|
// Next push constant block will start next to the previous push constant block
|
||||||
|
startOffset += pcInfo.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
stageFlags |= shaderModule->GetShaderStageFlagBits();
|
||||||
|
}
|
||||||
|
|
||||||
|
// After all the sizes of the push constant blocks have been added, record the size in the interface
|
||||||
|
pushConstantInterface.SetSize(startOffset);
|
||||||
|
pushConstantInterface.SetShaderStageFlags(stageFlags);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHVkPipelineLayout::PrepareDescriptorLayout(void) noexcept
|
||||||
|
{
|
||||||
|
enum class PARSE_RESULT
|
||||||
|
{
|
||||||
|
STAGE_APPENDED,
|
||||||
|
REJECTED,
|
||||||
|
DOES_NOT_EXIST,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function that attempts to take a binding and see if it already exists.
|
||||||
|
auto TryParseExistingBinding = [](std::vector<SHVkDescriptorSetLayout::Binding>& bindings, vk::DescriptorType type, uint32_t bindPoint, vk::ShaderStageFlagBits stage)
|
||||||
|
{
|
||||||
|
for (auto& binding : bindings)
|
||||||
|
{
|
||||||
|
// If some existing binding is detected...
|
||||||
|
if (bindPoint == binding.BindPoint)
|
||||||
|
{
|
||||||
|
// ...and the existing binding has the same descriptor type
|
||||||
|
if (type == binding.Type)
|
||||||
|
{
|
||||||
|
// Append shader stage since it exists in more than 1 shader
|
||||||
|
binding.Stage |= stage;
|
||||||
|
return PARSE_RESULT::STAGE_APPENDED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("Binding Set pair already parsed with a different descriptor type and therefore unavailable. ");
|
||||||
|
return PARSE_RESULT::REJECTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PARSE_RESULT::DOES_NOT_EXIST;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// KEY is set index, VALUE is vector of bindings (perfect for descriptor set layout construction). We
|
||||||
|
// want this to be map because we want to add the descriptor layouts IN ORDER.
|
||||||
|
std::map<uint32_t, std::vector<SHVkDescriptorSetLayout::Binding>> setsWithBindings;
|
||||||
|
|
||||||
|
//! Now we take descriptor set info from all shaders and prepare some bindings for the descriptor set
|
||||||
|
for (auto& shaderModule : shaderModules)
|
||||||
|
{
|
||||||
|
auto const& descBindingInfo = shaderModule->GetReflectedData().GetDescriptorBindingInfo();
|
||||||
|
auto const& reflectedSets = descBindingInfo.GetReflectedSets();
|
||||||
|
|
||||||
|
// If there are no descriptor sets for the shader module, just skip to the next one
|
||||||
|
if (reflectedSets.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// For every descriptor set
|
||||||
|
for (auto const* const set : reflectedSets)
|
||||||
|
{
|
||||||
|
// For descriptor sets that are found in the shader that are meant to be global descriptors, don't parse them
|
||||||
|
if (set->set < descriptorSetLayoutsGlobal.size())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Convenient variable for the current descriptor set index
|
||||||
|
uint32_t const CURRENT_SET = set->set;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < set->binding_count; ++i)
|
||||||
|
{
|
||||||
|
// for convenience
|
||||||
|
SpvReflectDescriptorBinding const* const reflectedBinding = set->bindings[i];
|
||||||
|
|
||||||
|
// If same set binding pair is found
|
||||||
|
if (TryParseExistingBinding(setsWithBindings[CURRENT_SET], SHShaderDescriptorBindingInfo::ConvertFromReflectDescType (reflectedBinding->descriptor_type), reflectedBinding->binding, shaderModule->GetShaderStageFlagBits()) == PARSE_RESULT::DOES_NOT_EXIST)
|
||||||
|
{
|
||||||
|
// New binding for the set binding pair number above
|
||||||
|
SHVkDescriptorSetLayout::Binding newBinding;
|
||||||
|
|
||||||
|
// Straightforward stuff.
|
||||||
|
newBinding.BindPoint = reflectedBinding->binding;
|
||||||
|
newBinding.Stage = shaderModule->GetShaderStageFlagBits();
|
||||||
|
newBinding.Type = descBindingInfo.ConvertFromReflectDescType(reflectedBinding->descriptor_type);
|
||||||
|
|
||||||
|
// In reality, the check for variable descriptor sets do not exists in spirv-reflect. Fortunately, when a shader
|
||||||
|
// defines a boundless descriptor binding in the shader, the information reflected makes the array dimensions
|
||||||
|
// contain a 1 element of value 1. Knowing that having an array [1] doesn't make sense, we can use this to
|
||||||
|
// signify a variable sized binding.
|
||||||
|
if (reflectedBinding->array.dims[0] == 1)
|
||||||
|
{
|
||||||
|
// variable binding has to be the last in the set
|
||||||
|
if (i == set->binding_count - 1)
|
||||||
|
{
|
||||||
|
// Set to predefined upper bound. this probably doesn't do any allocations yet. It just tells Vulkan this is the maximum allowed
|
||||||
|
newBinding.DescriptorCount = SHVkDescriptorSetLayout::Binding::VARIABLE_DESCRIPTOR_UPPER_BOUND;
|
||||||
|
|
||||||
|
// Set the flags for variable bindings
|
||||||
|
newBinding.flags = vk::DescriptorBindingFlagBits::eVariableDescriptorCount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
SHLOG_ERROR("Variable size binding is detected, but the binding is not the last binding of the set and is therefore invalid. ");
|
||||||
|
}
|
||||||
|
|
||||||
|
setsWithBindings[CURRENT_SET].emplace_back(newBinding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // for reflected descriptor set
|
||||||
|
} // for shader module
|
||||||
|
|
||||||
|
|
||||||
|
// Now we want to create a container to contain all the required descriptor set for both allocation and pipelines
|
||||||
|
descriptorSetLayoutsAllocate.reserve(setsWithBindings.size());
|
||||||
|
|
||||||
|
// Create the descriptor set layouts here for each set in setWithBindings. Essentially you would have
|
||||||
|
// 1 descriptor set layout for every descriptor set detected.
|
||||||
|
for (auto const& set : setsWithBindings)
|
||||||
|
{
|
||||||
|
auto newDescriptorSetLayout = logicalDeviceHdl->CreateDescriptorSetLayout(set.second);
|
||||||
|
descriptorSetLayoutsAllocate.push_back(newDescriptorSetLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare the vulkan layouts for pipeline layout creation
|
||||||
|
PrepareVkDescriptorSetLayouts();
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Prepares the vulkan descriptor set layout for pipeline layout consumption.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkPipelineLayout::PrepareVkDescriptorSetLayouts(void) noexcept
|
||||||
|
{
|
||||||
|
// Settle allocate layouts first
|
||||||
|
vkDescriptorSetLayoutsAllocate.reserve(descriptorSetLayoutsAllocate.size());
|
||||||
|
for (auto const& layout : descriptorSetLayoutsAllocate)
|
||||||
|
{
|
||||||
|
vkDescriptorSetLayoutsAllocate.emplace_back(layout->GetVkHandle());
|
||||||
|
}
|
||||||
|
|
||||||
|
// pipeline layouts contain global layouts first, then layouts for allocation
|
||||||
|
vkDescriptorSetLayoutsPipeline.reserve(descriptorSetLayoutsAllocate.size() + descriptorSetLayoutsGlobal.size());
|
||||||
|
|
||||||
|
// First we insert the global layouts
|
||||||
|
for (auto const& layout : descriptorSetLayoutsGlobal)
|
||||||
|
vkDescriptorSetLayoutsPipeline.emplace_back(layout->GetVkHandle());
|
||||||
|
|
||||||
|
// Then we append layouts for allocation at the back of the vector
|
||||||
|
std::copy(vkDescriptorSetLayoutsAllocate.begin(), vkDescriptorSetLayoutsAllocate.end(), std::back_inserter(vkDescriptorSetLayoutsPipeline));
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Destroys the pipeline layout and descriptor layouts used.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHVkPipelineLayout::Destroy(void) noexcept
|
||||||
|
{
|
||||||
|
// Kill the pipeline layout if required
|
||||||
|
if (vkPipelineLayout)
|
||||||
|
logicalDeviceHdl->GetVkLogicalDevice().destroyPipelineLayout(vkPipelineLayout, nullptr);
|
||||||
|
|
||||||
|
// Reset push constant interface before reflecting
|
||||||
|
pushConstantInterface.Reset();
|
||||||
|
|
||||||
|
// Clear pc ranges
|
||||||
|
vkPcRanges.clear();
|
||||||
|
|
||||||
|
// Kill all descriptor set layouts
|
||||||
|
for (auto& layout : descriptorSetLayoutsGlobal)
|
||||||
|
SHVkInstance::GetResourceManager().Free(layout);
|
||||||
|
|
||||||
|
descriptorSetLayoutsGlobal.clear();
|
||||||
|
|
||||||
|
for (auto& layout : descriptorSetLayoutsAllocate)
|
||||||
|
SHVkInstance::GetResourceManager().Free(layout);
|
||||||
|
|
||||||
|
descriptorSetLayoutsAllocate.clear();
|
||||||
|
|
||||||
|
// We don't need to use vulkan to destroy descriptor sets here since they are just owned by the container with handles
|
||||||
|
vkDescriptorSetLayoutsAllocate.clear();
|
||||||
|
vkDescriptorSetLayoutsPipeline.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Non-default ctor. Initializes shader modules used for the pipeline.
|
||||||
|
|
||||||
|
\param inLogicalDeviceHdl
|
||||||
|
logical device required for creation and destruction
|
||||||
|
|
||||||
|
\param shaderModules
|
||||||
|
Shader modules that will be used in pipeline (not pipeline layout)
|
||||||
|
creation.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHVkPipelineLayout::SHVkPipelineLayout(Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl, SHPipelineLayoutParams& pipelineLayoutParams) noexcept
|
||||||
|
: vkPipelineLayout {VK_NULL_HANDLE}
|
||||||
|
, shaderModules{std::move (pipelineLayoutParams.shaderModules)}
|
||||||
|
, logicalDeviceHdl {inLogicalDeviceHdl}
|
||||||
|
, pushConstantInterface{}
|
||||||
|
, vkPcRanges{}
|
||||||
|
, descriptorSetLayoutsGlobal{pipelineLayoutParams.globalDescSetLayouts } // do a copy, some other pipeline layout might need this
|
||||||
|
, descriptorSetLayoutsAllocate{}
|
||||||
|
, vkDescriptorSetLayoutsAllocate{}
|
||||||
|
, vkDescriptorSetLayoutsPipeline{}
|
||||||
|
{
|
||||||
|
for (auto& mod : shaderModules)
|
||||||
|
{
|
||||||
|
mod->AddCallback([this]()
|
||||||
|
{
|
||||||
|
RecreateIfNeeded();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
RecreateIfNeeded ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Move ctor. Does what it says.
|
||||||
|
|
||||||
|
\param rhs
|
||||||
|
The other pipeline layout to move from.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHVkPipelineLayout::SHVkPipelineLayout(SHVkPipelineLayout&& rhs) noexcept
|
||||||
|
: logicalDeviceHdl {rhs.logicalDeviceHdl}
|
||||||
|
, vkPipelineLayout {rhs.vkPipelineLayout}
|
||||||
|
, shaderModules {std::move (rhs.shaderModules)}
|
||||||
|
, pushConstantInterface {std::move (rhs.pushConstantInterface)}
|
||||||
|
, vkPcRanges {std::move (rhs.vkPcRanges)}
|
||||||
|
, descriptorSetLayoutsGlobal {std::move (rhs.descriptorSetLayoutsGlobal)}
|
||||||
|
, descriptorSetLayoutsAllocate {std::move (rhs.descriptorSetLayoutsAllocate)}
|
||||||
|
, vkDescriptorSetLayoutsAllocate{std::move (rhs.vkDescriptorSetLayoutsAllocate)}
|
||||||
|
, vkDescriptorSetLayoutsPipeline{std::move (rhs.vkDescriptorSetLayoutsAllocate)}
|
||||||
|
{
|
||||||
|
rhs.vkPipelineLayout = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Destructor for the pipeline layout.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHVkPipelineLayout::~SHVkPipelineLayout(void) noexcept
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHVkPipelineLayout::RecreateIfNeeded(void) noexcept
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
|
||||||
|
vk::PipelineLayoutCreateInfo plCreateInfo{};
|
||||||
|
|
||||||
|
// Prepare push constant information
|
||||||
|
PreparePushConstantInterface();
|
||||||
|
|
||||||
|
// This takes the reflection information from all the shader modules used in the pipeline and creates descriptor set layouts
|
||||||
|
// for the pipeline
|
||||||
|
PrepareDescriptorLayout();
|
||||||
|
|
||||||
|
// Set push constant data to pipeline layout
|
||||||
|
plCreateInfo.pushConstantRangeCount = static_cast<uint32_t>(vkPcRanges.size());
|
||||||
|
plCreateInfo.pPushConstantRanges = vkPcRanges.data();
|
||||||
|
|
||||||
|
// To initialize the descriptor set layouts for the pipeline layout.
|
||||||
|
plCreateInfo.setLayoutCount = static_cast<uint32_t>(vkDescriptorSetLayoutsPipeline.size());
|
||||||
|
plCreateInfo.pSetLayouts = vkDescriptorSetLayoutsPipeline.data();
|
||||||
|
|
||||||
|
if (auto const RESULT = logicalDeviceHdl->GetVkLogicalDevice().createPipelineLayout(&plCreateInfo, nullptr, &vkPipelineLayout); RESULT != vk::Result::eSuccess)
|
||||||
|
{
|
||||||
|
SHVulkanDebugUtil::ReportVkError(RESULT, "Failed to create Pipeline Layout. ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
SHVulkanDebugUtil::ReportVkSuccess("Successfully created Pipeline Layout. ");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Handle<SHVkShaderModule>> const& SHVkPipelineLayout::GetShaderModules(void) const noexcept
|
||||||
|
{
|
||||||
|
return shaderModules;
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::PipelineLayout SHVkPipelineLayout::GetVkPipelineLayout(void) const noexcept
|
||||||
|
{
|
||||||
|
return vkPipelineLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHPushConstantInterface const& SHVkPipelineLayout::GetPushConstantInterface(void) const noexcept
|
||||||
|
{
|
||||||
|
return pushConstantInterface;
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle<SHShaderBlockInterface> SHVkPipelineLayout::GetShaderBlockInterface(uint32_t set, uint32_t binding, vk::ShaderStageFlagBits shaderStage) const noexcept
|
||||||
|
{
|
||||||
|
for (auto& shader : shaderModules)
|
||||||
|
{
|
||||||
|
if (shader->GetShaderStageFlagBits() == shaderStage)
|
||||||
|
return shader->GetReflectedData().GetDescriptorBindingInfo().GetShaderBlockInterface(set, binding);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVkPipelineLayout& SHVkPipelineLayout::operator=(SHVkPipelineLayout&& rhs) noexcept
|
||||||
|
{
|
||||||
|
if (&rhs == this)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
logicalDeviceHdl = rhs.logicalDeviceHdl;
|
||||||
|
vkPipelineLayout = rhs.vkPipelineLayout;
|
||||||
|
shaderModules = std::move(rhs.shaderModules);
|
||||||
|
pushConstantInterface = std::move(rhs.pushConstantInterface);
|
||||||
|
vkPcRanges = std::move(rhs.vkPcRanges);
|
||||||
|
descriptorSetLayoutsGlobal = std::move(rhs.descriptorSetLayoutsGlobal);
|
||||||
|
descriptorSetLayoutsAllocate = std::move(rhs.descriptorSetLayoutsAllocate);
|
||||||
|
vkDescriptorSetLayoutsAllocate = std::move(rhs.vkDescriptorSetLayoutsAllocate);
|
||||||
|
vkDescriptorSetLayoutsPipeline = std::move(rhs.vkDescriptorSetLayoutsAllocate);
|
||||||
|
|
||||||
|
rhs.vkPipelineLayout = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
#ifndef SH_VK_PIPELINE_LAYOUT_H
|
||||||
|
#define SH_VK_PIPELINE_LAYOUT_H
|
||||||
|
|
||||||
|
#include "SHPipelineLayoutParams.h"
|
||||||
|
#include "SHPushConstantInterface.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
class SHVkLogicalDevice;
|
||||||
|
|
||||||
|
class SHVkPipelineLayout
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PRIVATE MEMBER VARIABLES */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
//! Logical device used for creation and destruction.
|
||||||
|
Handle<SHVkLogicalDevice> logicalDeviceHdl;
|
||||||
|
|
||||||
|
//! The Vulkan handle to a pipeline layout
|
||||||
|
vk::PipelineLayout vkPipelineLayout;
|
||||||
|
|
||||||
|
//! Shader modules used by the pipeline. Note that these modules themselves
|
||||||
|
//! are not used in pipeline layout creation. We mainly have it here so that
|
||||||
|
//! pipelines can simply take in this class and the shader modules would
|
||||||
|
//! be included.
|
||||||
|
std::vector<Handle<SHVkShaderModule>> shaderModules;
|
||||||
|
|
||||||
|
//! Push constant interface
|
||||||
|
SHPushConstantInterface pushConstantInterface;
|
||||||
|
|
||||||
|
//! Push constant ranges
|
||||||
|
std::vector<vk::PushConstantRange> vkPcRanges;
|
||||||
|
|
||||||
|
//! List of global set layouts
|
||||||
|
std::vector<Handle<SHVkDescriptorSetLayout>> descriptorSetLayoutsGlobal;
|
||||||
|
|
||||||
|
//! List of set layouts to allocate descriptor sets for. Set indices here should
|
||||||
|
//! also be smaller than the global ones passed in.
|
||||||
|
std::vector<Handle<SHVkDescriptorSetLayout>> descriptorSetLayoutsAllocate;
|
||||||
|
|
||||||
|
//! We want to store this also because we need to allocate later
|
||||||
|
std::vector<vk::DescriptorSetLayout> vkDescriptorSetLayoutsAllocate;
|
||||||
|
|
||||||
|
//! Store for pipeline layout recreation
|
||||||
|
std::vector<vk::DescriptorSetLayout> vkDescriptorSetLayoutsPipeline;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PRIVATE MEMBER FUNCTIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
void PreparePushConstantInterface (void) noexcept;
|
||||||
|
void PrepareDescriptorLayout (void) noexcept;
|
||||||
|
void PrepareVkDescriptorSetLayouts(void) noexcept;
|
||||||
|
void Destroy (void) noexcept;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* CTORS AND DTORS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
SHVkPipelineLayout (Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl, SHPipelineLayoutParams& pipelineLayoutParams) noexcept;
|
||||||
|
SHVkPipelineLayout (SHVkPipelineLayout&& rhs) noexcept;
|
||||||
|
~SHVkPipelineLayout (void) noexcept;
|
||||||
|
SHVkPipelineLayout& operator= (SHVkPipelineLayout&& rhs) noexcept;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PUBLIC MEMBER FUNCTIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
void RecreateIfNeeded (void) noexcept;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* SETTERS AND GETTERS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
std::vector<Handle<SHVkShaderModule>> const& GetShaderModules (void) const noexcept;
|
||||||
|
vk::PipelineLayout GetVkPipelineLayout (void) const noexcept;
|
||||||
|
SHPushConstantInterface const& GetPushConstantInterface (void) const noexcept;
|
||||||
|
Handle<SHShaderBlockInterface> GetShaderBlockInterface (uint32_t set, uint32_t binding, vk::ShaderStageFlagBits shaderStage) const noexcept;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,86 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHVkQueue.h"
|
||||||
|
#include "Tools/SHLogger.h"
|
||||||
|
#include "Graphics/Devices/SHVkLogicalDevice.h"
|
||||||
|
#include "Graphics/Synchronization/SHVkSemaphore.h"
|
||||||
|
#include "Graphics/Synchronization/SHVkFence.h"
|
||||||
|
#include "Graphics/Commands/SHVkCommandBuffer.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Non default ctor to initialize variables.
|
||||||
|
|
||||||
|
\param inVkQueue
|
||||||
|
The vulkan queue handle to initialize this class with.
|
||||||
|
|
||||||
|
\param parent
|
||||||
|
The queue family this queue originated from.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHVkQueue::SHVkQueue(vk::Queue inVkQueue, SHQueueFamilyIndex parent, Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl) noexcept
|
||||||
|
: vkQueue{ inVkQueue }
|
||||||
|
, parentFamily{ parent }
|
||||||
|
, logicalDeviceHdl{ inLogicalDeviceHdl }
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::Queue SHVkQueue::GetVkQueue(void) const noexcept
|
||||||
|
{
|
||||||
|
return vkQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHVkQueue::SubmitCommandBuffer(std::initializer_list<Handle<SHVkCommandBuffer>> cmdBuffers, std::initializer_list<Handle<SHVkSemaphore>> signalSems /*= {}*/, std::initializer_list<Handle<SHVkSemaphore>> waitSems /*= {}*/, vk::PipelineStageFlagBits waitDstStageMask /*= {}*/, Handle<SHVkFence> const& optionalFence /*= {}*/) noexcept
|
||||||
|
{
|
||||||
|
std::vector<vk::Semaphore> vkWaitSems{ waitSems.size() };
|
||||||
|
uint32_t i = 0;
|
||||||
|
for (auto& sem : waitSems)
|
||||||
|
{
|
||||||
|
vkWaitSems[i] = sem->GetVkSem();
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<vk::Semaphore> vkSignalSems{ signalSems.size() };
|
||||||
|
i = 0;
|
||||||
|
for (auto& sem : signalSems)
|
||||||
|
{
|
||||||
|
vkSignalSems[i] = sem->GetVkSem();
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<vk::CommandBuffer> vkCmdBuffers{ cmdBuffers.size() };
|
||||||
|
i = 0;
|
||||||
|
for (auto& cmdBuffer : cmdBuffers)
|
||||||
|
{
|
||||||
|
vkCmdBuffers[i] = cmdBuffer->GetVkCommandBuffer();
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::PipelineStageFlags mask = waitDstStageMask;
|
||||||
|
|
||||||
|
vk::SubmitInfo submitInfo
|
||||||
|
{
|
||||||
|
.waitSemaphoreCount = static_cast<uint32_t>(vkWaitSems.size()),
|
||||||
|
.pWaitSemaphores = vkWaitSems.data(),
|
||||||
|
.pWaitDstStageMask = &mask,
|
||||||
|
.commandBufferCount = static_cast<uint32_t>(vkCmdBuffers.size()),
|
||||||
|
.pCommandBuffers = vkCmdBuffers.data(),
|
||||||
|
.signalSemaphoreCount = static_cast<uint32_t>(vkSignalSems.size()),
|
||||||
|
.pSignalSemaphores = vkSignalSems.data(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// #BackEndTest: Submit the queue
|
||||||
|
if (auto result = vkQueue.submit(1, &submitInfo, (optionalFence) ? optionalFence->GetVkFence() : nullptr); result != vk::Result::eSuccess)
|
||||||
|
{
|
||||||
|
SHVulkanDebugUtil::ReportVkError(result, "Failed to submit command buffer. ");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
#ifndef SH_QUEUE_H
|
||||||
|
#define SH_QUEUE_H
|
||||||
|
|
||||||
|
#include "Graphics/SHVulkanIncludes.h"
|
||||||
|
#include "Graphics/SHVulkanDefines.h"
|
||||||
|
#include "Resource/Handle.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
class SHVkLogicalDevice;
|
||||||
|
class SHVkCommandBuffer;
|
||||||
|
class SHVkFence;
|
||||||
|
class SHVkSemaphore;
|
||||||
|
|
||||||
|
enum class SH_QUEUE_FAMILY_ARRAY_INDEX : std::size_t
|
||||||
|
{
|
||||||
|
GRAPHICS = 0,
|
||||||
|
COMPUTE = 1,
|
||||||
|
TRANSFER = 2,
|
||||||
|
MAX = 3,
|
||||||
|
INVALID = 0xFFFF,
|
||||||
|
};
|
||||||
|
|
||||||
|
using SH_Q_FAM = SH_QUEUE_FAMILY_ARRAY_INDEX;
|
||||||
|
|
||||||
|
enum class SH_QUEUE_SELECT
|
||||||
|
{
|
||||||
|
DEDICATED,
|
||||||
|
NON_DEDICATED_BEST // First fit means attempting to select the most versatile queue family
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SHQueueParams
|
||||||
|
{
|
||||||
|
SH_QUEUE_FAMILY_ARRAY_INDEX arrayIndex;
|
||||||
|
SH_QUEUE_SELECT selectionMethod;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SHVkQueue
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
vk::Queue vkQueue;
|
||||||
|
SHQueueFamilyIndex parentFamily;
|
||||||
|
Handle<SHVkLogicalDevice> logicalDeviceHdl;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SHVkQueue(vk::Queue inVkQueue, SHQueueFamilyIndex parent, Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl) noexcept;
|
||||||
|
vk::Queue GetVkQueue(void) const noexcept;
|
||||||
|
|
||||||
|
void SubmitCommandBuffer(std::initializer_list<Handle<SHVkCommandBuffer>> cmdBuffers, std::initializer_list<Handle<SHVkSemaphore>> signalSems = {}, std::initializer_list<Handle<SHVkSemaphore>> waitSems = {}, vk::PipelineStageFlagBits waitDstStageMask = {}, Handle<SHVkFence> const& fence = {}) noexcept;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,941 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHRenderGraph.h"
|
||||||
|
#include "Graphics/Swapchain/SHVkSwapchain.h"
|
||||||
|
#include "Graphics/Framebuffer/SHVkFramebuffer.h"
|
||||||
|
#include "Graphics/Devices/SHVkLogicalDevice.h"
|
||||||
|
#include "Graphics/Images/SHVkImage.h"
|
||||||
|
#include "Graphics/Images/SHVkImageView.h"
|
||||||
|
#include "Graphics/Framebuffer/SHVkFramebuffer.h"
|
||||||
|
#include "Tools/SHLogger.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Non-default ctor for the resource. Using the type of the resource, we
|
||||||
|
decide whether or not we create a resource or link with a swapchain
|
||||||
|
resource (image).
|
||||||
|
|
||||||
|
\param logicalDevice
|
||||||
|
Logical device required to create an image resource if the type is NOT
|
||||||
|
SH_ATT_DESC_TYPE::COLOR_PRESENT.
|
||||||
|
|
||||||
|
\param swapchain
|
||||||
|
Swapchain required to get swapchain image if the type IS
|
||||||
|
SH_ATT_DESC_TYPE::COLOR_PRESENT.
|
||||||
|
|
||||||
|
\param type
|
||||||
|
Type of the image resource.
|
||||||
|
|
||||||
|
\param format
|
||||||
|
Format of the image resource.
|
||||||
|
|
||||||
|
\param w
|
||||||
|
Width of the image resource.
|
||||||
|
|
||||||
|
\param h
|
||||||
|
Height of the image resource.
|
||||||
|
|
||||||
|
\param levels
|
||||||
|
Number of mipmap levels of the image resource.
|
||||||
|
|
||||||
|
\param createFlags
|
||||||
|
Create flags used when an image resource needs to be created.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHRenderGraphResource::SHRenderGraphResource(Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, std::string const& name, SH_ATT_DESC_TYPE type, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageCreateFlagBits createFlags) noexcept
|
||||||
|
: resourceType{ type }
|
||||||
|
, resourceFormat{ format }
|
||||||
|
, images{}
|
||||||
|
, imageViews{}
|
||||||
|
, width{ w }
|
||||||
|
, height{ h }
|
||||||
|
, mipLevels{ levels }
|
||||||
|
, resourceName{ name }
|
||||||
|
{
|
||||||
|
// If the resource type is an arbitrary image and not swapchain image
|
||||||
|
if (type != SH_ATT_DESC_TYPE::COLOR_PRESENT)
|
||||||
|
{
|
||||||
|
vk::ImageAspectFlags imageAspectFlags;
|
||||||
|
vk::ImageUsageFlags usage = {};
|
||||||
|
|
||||||
|
// Check the resource type and set image usage flags and image aspect flags accordingly
|
||||||
|
switch (resourceType)
|
||||||
|
{
|
||||||
|
case SH_ATT_DESC_TYPE::COLOR:
|
||||||
|
usage |= vk::ImageUsageFlagBits::eColorAttachment;
|
||||||
|
imageAspectFlags |= vk::ImageAspectFlagBits::eColor;
|
||||||
|
break;
|
||||||
|
case SH_ATT_DESC_TYPE::DEPTH:
|
||||||
|
usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment;
|
||||||
|
imageAspectFlags |= vk::ImageAspectFlagBits::eDepth;
|
||||||
|
break;
|
||||||
|
case SH_ATT_DESC_TYPE::STENCIL:
|
||||||
|
usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment;
|
||||||
|
imageAspectFlags |= vk::ImageAspectFlagBits::eStencil;
|
||||||
|
break;
|
||||||
|
case SH_ATT_DESC_TYPE::DEPTH_STENCIL:
|
||||||
|
usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment;
|
||||||
|
imageAspectFlags |= vk::ImageAspectFlagBits::eStencil | vk::ImageAspectFlagBits::eDepth;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The resource is not a swapchain image, just use the first slot of the vector
|
||||||
|
images.push_back(logicalDevice->CreateImage(width, height, mipLevels, resourceFormat, usage, createFlags));
|
||||||
|
|
||||||
|
// prepare image view details
|
||||||
|
SHImageViewDetails viewDetails
|
||||||
|
{
|
||||||
|
.viewType = vk::ImageViewType::e2D,
|
||||||
|
.format = images[0]->GetImageFormat(),
|
||||||
|
.imageAspectFlags = imageAspectFlags,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.mipLevelCount = mipLevels,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
// just 1 image view created
|
||||||
|
imageViews.push_back(images[0]->CreateImageView(logicalDevice, images[0], viewDetails));
|
||||||
|
}
|
||||||
|
else // if swapchain image resource
|
||||||
|
{
|
||||||
|
// Prepare image view details
|
||||||
|
SHImageViewDetails viewDetails
|
||||||
|
{
|
||||||
|
.viewType = vk::ImageViewType::e2D,
|
||||||
|
.format = swapchain->GetSurfaceFormatKHR().format,
|
||||||
|
.imageAspectFlags = vk::ImageAspectFlagBits::eColor,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.mipLevelCount = 1,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
// We want an image handle for every swapchain image
|
||||||
|
images.resize(swapchain->GetNumImages());
|
||||||
|
imageViews.resize(swapchain->GetNumImages());
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < swapchain->GetNumImages(); ++i)
|
||||||
|
{
|
||||||
|
images[i] = swapchain->GetSwapchainImage(i);
|
||||||
|
imageViews[i] = images[i]->CreateImageView(logicalDevice, images[i], viewDetails);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Move ctor for resource.
|
||||||
|
|
||||||
|
\param rhs
|
||||||
|
The other resource.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHRenderGraphResource::SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept
|
||||||
|
: resourceName{ std::move(rhs.resourceName) }
|
||||||
|
, resourceType{ std::move(rhs.resourceType) }
|
||||||
|
, images{ std::move(rhs.images) }
|
||||||
|
, imageViews{ std::move(rhs.imageViews) }
|
||||||
|
, resourceFormat{ std::move(rhs.resourceFormat) }
|
||||||
|
, width{ rhs.width }
|
||||||
|
, height{ rhs.height }
|
||||||
|
, mipLevels{ rhs.mipLevels }
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Move assignment operator.
|
||||||
|
|
||||||
|
\param rhs
|
||||||
|
The other resource.
|
||||||
|
|
||||||
|
\return
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHRenderGraphResource& SHRenderGraphResource::operator=(SHRenderGraphResource&& rhs) noexcept
|
||||||
|
{
|
||||||
|
if (this == &rhs)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
resourceName = std::move(rhs.resourceName);
|
||||||
|
resourceType = std::move(rhs.resourceType);
|
||||||
|
images = std::move(rhs.images);
|
||||||
|
imageViews = std::move(rhs.imageViews);
|
||||||
|
resourceFormat = std::move(rhs.resourceFormat);
|
||||||
|
width = rhs.width;
|
||||||
|
height = rhs.height;
|
||||||
|
mipLevels = rhs.mipLevels;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Destructor for resource.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHRenderGraphResource::~SHRenderGraphResource(void) noexcept
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Subpass non-default constructor. Simply initializes variables.
|
||||||
|
|
||||||
|
\param mapping
|
||||||
|
Mapping from a resource handle to an attachment reference referencing
|
||||||
|
the resource.
|
||||||
|
|
||||||
|
\param resources
|
||||||
|
A mapping from string to render graph resource.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHRenderGraphNode::SHSubpass::SHSubpass(std::unordered_map<uint64_t, uint32_t> const* mapping, std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* resources) noexcept
|
||||||
|
: resourceAttachmentMapping{ mapping }
|
||||||
|
, ptrToResources{ resources }
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Move constructor for subpass.
|
||||||
|
|
||||||
|
\param rhs
|
||||||
|
The subpass the move from.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHRenderGraphNode::SHSubpass::SHSubpass(SHSubpass&& rhs) noexcept
|
||||||
|
: colorReferences{ std::move(rhs.colorReferences) }
|
||||||
|
, depthReferences{ std::move(rhs.depthReferences) }
|
||||||
|
, inputReferences{ std::move(rhs.inputReferences) }
|
||||||
|
, resourceAttachmentMapping{ rhs.resourceAttachmentMapping }
|
||||||
|
, ptrToResources{ rhs.ptrToResources }
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Move assignment operator for subpass.
|
||||||
|
|
||||||
|
\param rhs
|
||||||
|
subpass to move from.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHRenderGraphNode::SHSubpass& SHRenderGraphNode::SHSubpass::operator=(SHSubpass&& rhs) noexcept
|
||||||
|
{
|
||||||
|
if (this == &rhs)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
colorReferences = std::move(rhs.colorReferences);
|
||||||
|
depthReferences = std::move(rhs.depthReferences);
|
||||||
|
inputReferences = std::move(rhs.inputReferences);
|
||||||
|
resourceAttachmentMapping = rhs.resourceAttachmentMapping;
|
||||||
|
ptrToResources = rhs.ptrToResources;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Adds a color output to a subpass. Takes in a string and finds the
|
||||||
|
attachment index to create the vk::SubpassReference.
|
||||||
|
|
||||||
|
\param resourceToReference
|
||||||
|
Resource name to find resource to attach.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHRenderGraphNode::SHSubpass::AddColorOutput(std::string resourceToReference) noexcept
|
||||||
|
{
|
||||||
|
colorReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eColorAttachmentOptimal });
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Adds a depth output to a subpass. Takes in a string and finds the
|
||||||
|
attachment index to create the vk::SubpassReference.
|
||||||
|
|
||||||
|
\param resourceToReference
|
||||||
|
Resource name to find resource to attach.
|
||||||
|
|
||||||
|
\param attachmentDescriptionType
|
||||||
|
Depending on the type of the resource, initialize the image layout
|
||||||
|
appropriately.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHRenderGraphNode::SHSubpass::AddDepthOutput(std::string resourceToReference, SH_ATT_DESC_TYPE attachmentDescriptionType) noexcept
|
||||||
|
{
|
||||||
|
vk::ImageLayout imageLayout;
|
||||||
|
switch (attachmentDescriptionType)
|
||||||
|
{
|
||||||
|
case SH_ATT_DESC_TYPE::DEPTH:
|
||||||
|
imageLayout = vk::ImageLayout::eDepthAttachmentOptimal;
|
||||||
|
break;
|
||||||
|
case SH_ATT_DESC_TYPE::STENCIL:
|
||||||
|
imageLayout = vk::ImageLayout::eStencilAttachmentOptimal;
|
||||||
|
break;
|
||||||
|
case SH_ATT_DESC_TYPE::DEPTH_STENCIL:
|
||||||
|
imageLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//Invalid
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
depthReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), imageLayout });
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Adds a input output to a subpass. Takes in a string and finds the
|
||||||
|
attachment index to create the vk::SubpassReference.
|
||||||
|
|
||||||
|
\param resourceToReference
|
||||||
|
Resource name to find resource to attach.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHRenderGraphNode::SHSubpass::AddInput(std::string resourceToReference) noexcept
|
||||||
|
{
|
||||||
|
inputReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eShaderReadOnlyOptimal });
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Creates a renderpass for the node. Uses subpass and attachment
|
||||||
|
descriptions already configured beforehand in the render graph.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHRenderGraphNode::CreateRenderpass(void) noexcept
|
||||||
|
{
|
||||||
|
renderpass = logicalDeviceHdl->CreateRenderpass(attachmentDescriptions, spDescs, spDeps);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Creates a framebuffer from the images used in the renderpass.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHRenderGraphNode::CreateFramebuffer(void) noexcept
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < framebuffers.size(); ++i)
|
||||||
|
{
|
||||||
|
std::vector<Handle<SHVkImageView>> imageViews(attResources.size());
|
||||||
|
uint32_t fbWidth = std::numeric_limits<uint32_t>::max();
|
||||||
|
uint32_t fbHeight = std::numeric_limits<uint32_t>::max();
|
||||||
|
|
||||||
|
for (uint32_t j = 0; j < attResources.size(); ++j)
|
||||||
|
{
|
||||||
|
uint32_t imageViewIndex = (attResources[j]->resourceType == SH_ATT_DESC_TYPE::COLOR_PRESENT) ? i : 0;
|
||||||
|
imageViews[j] = attResources[j]->imageViews[imageViewIndex];
|
||||||
|
|
||||||
|
// We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's
|
||||||
|
if (fbWidth > attResources[j]->width)
|
||||||
|
fbWidth = attResources[j]->width;
|
||||||
|
if (fbHeight > attResources[j]->height)
|
||||||
|
fbHeight = attResources[j]->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
framebuffers[i] = logicalDeviceHdl->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Render Graph node constructor. Note that we do not create the renderpass
|
||||||
|
yet. This is because layouts of attachment descriptions facilitate image
|
||||||
|
transitions and we cannot know guarantee layouts until we've seen all
|
||||||
|
renderpasses and their subpasses in the graph.
|
||||||
|
|
||||||
|
\param swapchain
|
||||||
|
Swapchain required to query number of images as parameters for number
|
||||||
|
of framebuffers to create.
|
||||||
|
|
||||||
|
\param attachmentDescriptionTypes
|
||||||
|
|
||||||
|
|
||||||
|
\return
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHRenderGraphNode::SHRenderGraphNode(ResourceManager& rm, Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, std::vector<Handle<SHRenderGraphResource>> attRes, std::vector<Handle<SHRenderGraphNode>> predecessors, std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* resources) noexcept
|
||||||
|
: logicalDeviceHdl{ logicalDevice }
|
||||||
|
, renderpass{}
|
||||||
|
, framebuffers{}
|
||||||
|
, prereqNodes{ std::move(predecessors) }
|
||||||
|
, attachmentDescriptions{}
|
||||||
|
, resourceAttachmentMapping{}
|
||||||
|
, attResources{ std::move(attRes) }
|
||||||
|
, subpasses{}
|
||||||
|
, executed{ false }
|
||||||
|
, configured{ false }
|
||||||
|
, resourceManager{ rm }
|
||||||
|
, ptrToResources{ resources }
|
||||||
|
{
|
||||||
|
attachmentDescriptions.resize(attResources.size());
|
||||||
|
|
||||||
|
bool containsSwapchainImage = false;
|
||||||
|
for (uint32_t i = 0; i < attResources.size(); ++i)
|
||||||
|
{
|
||||||
|
// As mentioned above we don't initialize much here because it's dependent on how other renderpasses are configured.
|
||||||
|
vk::AttachmentDescription& newDesc = attachmentDescriptions[i];
|
||||||
|
newDesc.samples = vk::SampleCountFlagBits::e1;
|
||||||
|
|
||||||
|
// We set this to clear first. If later we find out that some predecessor is writing to the same attachment,
|
||||||
|
// we set the pred's storeOp to eStore and "this" loadOp to eLoad.
|
||||||
|
newDesc.loadOp = vk::AttachmentLoadOp::eClear;
|
||||||
|
newDesc.storeOp = vk::AttachmentStoreOp::eDontCare;
|
||||||
|
|
||||||
|
newDesc.stencilLoadOp = vk::AttachmentLoadOp::eClear;
|
||||||
|
newDesc.stencilStoreOp = vk::AttachmentStoreOp::eDontCare;
|
||||||
|
|
||||||
|
newDesc.format = attResources[i]->resourceFormat;
|
||||||
|
|
||||||
|
if (attResources[i]->resourceType == SH_ATT_DESC_TYPE::COLOR_PRESENT)
|
||||||
|
containsSwapchainImage = true;
|
||||||
|
|
||||||
|
resourceAttachmentMapping.try_emplace(attResources[i].GetId().Raw, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!containsSwapchainImage)
|
||||||
|
framebuffers.resize(1);
|
||||||
|
else
|
||||||
|
framebuffers.resize(swapchain->GetNumImages());
|
||||||
|
|
||||||
|
// At this point, we could configure framebuffers if we had the renderpass object but we don't so their creation has to be
|
||||||
|
// deferred to when renderpasses are also created.
|
||||||
|
}
|
||||||
|
|
||||||
|
SHRenderGraphNode::SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept
|
||||||
|
: resourceManager{ rhs.resourceManager }
|
||||||
|
, logicalDeviceHdl{ rhs.logicalDeviceHdl }
|
||||||
|
, renderpass{ rhs.renderpass }
|
||||||
|
, framebuffers{ std::move(rhs.framebuffers) }
|
||||||
|
, prereqNodes{ std::move(rhs.prereqNodes) }
|
||||||
|
, attachmentDescriptions{ std::move(rhs.attachmentDescriptions) }
|
||||||
|
, attResources{ std::move(rhs.attResources) }
|
||||||
|
, subpasses{ std::move(rhs.subpasses) }
|
||||||
|
, resourceAttachmentMapping{ std::move(rhs.resourceAttachmentMapping) }
|
||||||
|
, subpassIndexing{ std::move(rhs.subpassIndexing) }
|
||||||
|
, configured{ rhs.configured }
|
||||||
|
, executed{ rhs.executed }
|
||||||
|
, ptrToResources{ rhs.ptrToResources }
|
||||||
|
{
|
||||||
|
rhs.renderpass = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
SHRenderGraphNode& SHRenderGraphNode::operator=(SHRenderGraphNode&& rhs) noexcept
|
||||||
|
{
|
||||||
|
if (&rhs == this)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
resourceManager = rhs.resourceManager;
|
||||||
|
logicalDeviceHdl = rhs.logicalDeviceHdl;
|
||||||
|
renderpass = rhs.renderpass;
|
||||||
|
framebuffers = std::move(rhs.framebuffers);
|
||||||
|
prereqNodes = std::move(rhs.prereqNodes);
|
||||||
|
attachmentDescriptions = std::move(rhs.attachmentDescriptions);
|
||||||
|
attResources = std::move(rhs.attResources);
|
||||||
|
subpasses = std::move(rhs.subpasses);
|
||||||
|
resourceAttachmentMapping = std::move(rhs.resourceAttachmentMapping);
|
||||||
|
subpassIndexing = std::move(rhs.subpassIndexing);
|
||||||
|
ptrToResources = std::move(rhs.ptrToResources);
|
||||||
|
|
||||||
|
rhs.renderpass = {};
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Add subpasses to the renderpass and returns a reference to it.
|
||||||
|
|
||||||
|
\param subpassName
|
||||||
|
Name of the subpass.
|
||||||
|
|
||||||
|
\return
|
||||||
|
Handle to the new subpass.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
Handle<SHRenderGraphNode::SHSubpass> SHRenderGraphNode::AddSubpass(std::string subpassName) noexcept
|
||||||
|
{
|
||||||
|
// if subpass already exists, don't add.
|
||||||
|
if (subpassIndexing.contains(subpassName))
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("Subpass already exists.");
|
||||||
|
return{};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add subpass to container and create mapping for it
|
||||||
|
subpasses.emplace_back(resourceManager.Create<SHSubpass>(&resourceAttachmentMapping, ptrToResources));
|
||||||
|
subpassIndexing.try_emplace(subpassName, subpasses.size() - 1);
|
||||||
|
return subpasses.at(subpassIndexing[subpassName]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Attempts to add a resource that will be used globally in the render graph.
|
||||||
|
|
||||||
|
\param resourceName
|
||||||
|
Name of the resource.
|
||||||
|
|
||||||
|
\param type
|
||||||
|
The type of the resource.
|
||||||
|
|
||||||
|
\param w
|
||||||
|
Width of the resource. If set to uint32_t(-1), use swapchain image dims.
|
||||||
|
|
||||||
|
\param h
|
||||||
|
Height of the resource. If set to uint32_t(-1), use swapchain image dims.
|
||||||
|
|
||||||
|
\param format
|
||||||
|
The format that the resource is using. If w and h are set to uint32_t(-1),
|
||||||
|
use swapchain image format.
|
||||||
|
|
||||||
|
\param levels
|
||||||
|
Number of mipmap levels of the resource.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHRenderGraph::AddResource(std::string resourceName, SH_ATT_DESC_TYPE type, uint32_t w /*= static_cast<uint32_t>(-1)*/, uint32_t h /*= static_cast<uint32_t>(-1)*/, vk::Format format/* = vk::Format::eB8G8R8A8Unorm*/, uint32_t levels /*= 1*/, vk::ImageCreateFlagBits createFlags /*= {}*/)
|
||||||
|
{
|
||||||
|
// If we set to
|
||||||
|
if (w == static_cast<uint32_t>(-1) && h == static_cast<uint32_t>(-1))
|
||||||
|
{
|
||||||
|
w = swapchainHdl->GetSwapchainImage(0)->GetWidth();
|
||||||
|
w = swapchainHdl->GetSwapchainImage(0)->GetHeight();
|
||||||
|
format = swapchainHdl->GetSurfaceFormatKHR().format;
|
||||||
|
}
|
||||||
|
|
||||||
|
graphResources.try_emplace(resourceName, resourceManager.Create<SHRenderGraphResource>(logicalDeviceHdl, swapchainHdl, resourceName, type, format, w, h, levels, createFlags));
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Loops through all nodes and configures their attachment descriptions.
|
||||||
|
|
||||||
|
\return
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHRenderGraph::ConfigureAttachmentDescriptions(void) noexcept
|
||||||
|
{
|
||||||
|
// First we want to take all the attachment descriptions and initialize the
|
||||||
|
// finalLayout to whatever layout is specified in the last subpass that references the attachment.
|
||||||
|
|
||||||
|
for (auto& node : nodes)
|
||||||
|
{
|
||||||
|
// key is handle ID, value is pair (first is initial layout, second is final layout).
|
||||||
|
std::unordered_map<uint32_t, vk::ImageLayout> resourceAttLayouts;
|
||||||
|
if (node->subpasses.empty())
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("Node does not contain a subpass. Cannot configure attachment descriptions as a result. ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& subpass : node->subpasses)
|
||||||
|
{
|
||||||
|
for (auto& color : subpass->colorReferences)
|
||||||
|
{
|
||||||
|
if (node->attResources[color.attachment]->resourceType == SH_ATT_DESC_TYPE::COLOR_PRESENT)
|
||||||
|
resourceAttLayouts[color.attachment] = vk::ImageLayout::ePresentSrcKHR;
|
||||||
|
else
|
||||||
|
resourceAttLayouts[color.attachment] = color.layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& depth : subpass->depthReferences)
|
||||||
|
resourceAttLayouts[depth.attachment] = depth.layout;
|
||||||
|
|
||||||
|
for (auto& input : subpass->inputReferences)
|
||||||
|
resourceAttLayouts[input.attachment] = input.layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < node->attachmentDescriptions.size(); ++i)
|
||||||
|
{
|
||||||
|
auto& att = node->attachmentDescriptions[i];
|
||||||
|
att.initialLayout = vk::ImageLayout::eUndefined;
|
||||||
|
att.finalLayout = resourceAttLayouts[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// at this point all attachment descs will have their final layouts initialized as if they were standalone and did
|
||||||
|
// not have any predecessor nodes
|
||||||
|
|
||||||
|
// Now we use the predecessor attachment description and first subpass to configure the current node's attachment descriptions.
|
||||||
|
// This is so that we minimize image layout transitions.
|
||||||
|
for (auto& node : nodes)
|
||||||
|
{
|
||||||
|
for (auto& prereq : node->prereqNodes)
|
||||||
|
{
|
||||||
|
// Look through all resources used by this node
|
||||||
|
for (auto& predResource : prereq->attResources)
|
||||||
|
{
|
||||||
|
// if a predecessor's resource is used by this node, we want to copy the final layout from the pred to the initial of this node
|
||||||
|
if (uint64_t resourceID = predResource.GetId().Raw; node->resourceAttachmentMapping.contains(resourceID))
|
||||||
|
{
|
||||||
|
// Get the resource's attachment index in BOTH the predecessor and the current node
|
||||||
|
uint32_t prereqResourceAttIndex = prereq->resourceAttachmentMapping[resourceID];
|
||||||
|
uint32_t resourceAttIndex = node->resourceAttachmentMapping[resourceID];
|
||||||
|
|
||||||
|
// Use the resource attachment index to get the attachment description in the renderpass
|
||||||
|
auto& attDesc = node->attachmentDescriptions[resourceAttIndex];
|
||||||
|
auto& predAttDesc = prereq->attachmentDescriptions[prereqResourceAttIndex];
|
||||||
|
|
||||||
|
// We want the predecessor to preserve the attachment and we want this node to load the attachment
|
||||||
|
attDesc.loadOp = vk::AttachmentLoadOp::eLoad;
|
||||||
|
predAttDesc.storeOp = vk::AttachmentStoreOp::eStore;
|
||||||
|
|
||||||
|
// TODO: Stecil load and store
|
||||||
|
|
||||||
|
// When an image is done being used in a renderpass, the image layout will end up being the finalLayout
|
||||||
|
// value of the attachment description. We want this to carry over to the next renderpass; specifically
|
||||||
|
// to have the initialLayout of the attachment description in the next renderpass match the finalLayout in the previous.
|
||||||
|
attDesc.initialLayout = predAttDesc.finalLayout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Configures the supasses; mainly the subpass descriptions and the
|
||||||
|
subpass dependencies involved between subpasses.
|
||||||
|
|
||||||
|
|
||||||
|
\return
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHRenderGraph::ConfigureSubpasses(void) noexcept
|
||||||
|
{
|
||||||
|
// For all nodes
|
||||||
|
for (auto& node : nodes)
|
||||||
|
{
|
||||||
|
// Create subpass description and dependencies based on number of subpasses
|
||||||
|
node->spDescs.resize(node->subpasses.size());
|
||||||
|
node->spDeps.resize(node->subpasses.size());
|
||||||
|
|
||||||
|
// Now we want to loop through all attachments in all subpasses in the node and query
|
||||||
|
// the resources being used. For each resource we want to query the type and record it
|
||||||
|
// in bit fields (1 bit for each subpass).
|
||||||
|
uint32_t colorRead = 0, colorWrite = 0, depthRead = 0, depthWrite = 0, inputDependencies = 0;
|
||||||
|
|
||||||
|
uint32_t i = 0;
|
||||||
|
|
||||||
|
// For all subpasses (see above description about bit field for this).
|
||||||
|
for (auto& subpass : node->subpasses)
|
||||||
|
{
|
||||||
|
// Configure subpass description
|
||||||
|
auto& desc = node->spDescs[i];
|
||||||
|
desc.pColorAttachments = subpass->colorReferences.data();
|
||||||
|
desc.colorAttachmentCount = static_cast<uint32_t>(subpass->colorReferences.size());
|
||||||
|
desc.pInputAttachments = subpass->inputReferences.data();
|
||||||
|
desc.inputAttachmentCount = static_cast<uint32_t>(subpass->inputReferences.size());
|
||||||
|
desc.pDepthStencilAttachment = subpass->depthReferences.data();
|
||||||
|
desc.pipelineBindPoint = vk::PipelineBindPoint::eGraphics; // TODO: Just graphics for now. See if its possible to allow user defined params.
|
||||||
|
|
||||||
|
// Get reference to subpass description
|
||||||
|
auto& dep = node->spDeps[i];
|
||||||
|
|
||||||
|
// Configure subpass index for dependencies
|
||||||
|
dep.srcSubpass = (i == 0) ? VK_SUBPASS_EXTERNAL : i - 1;
|
||||||
|
dep.dstSubpass = i;
|
||||||
|
|
||||||
|
// First we want to see if the subpass has color, depth or input attachments and set bit field accordingly
|
||||||
|
if (subpass->colorReferences.size())
|
||||||
|
{
|
||||||
|
colorRead |= (1 << i);
|
||||||
|
colorWrite |= (1 << i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same thing for depth
|
||||||
|
if (subpass->depthReferences.size())
|
||||||
|
{
|
||||||
|
depthRead |= (1 << i);
|
||||||
|
depthWrite |= (1 << i);
|
||||||
|
}
|
||||||
|
if (subpass->inputReferences.size())
|
||||||
|
inputDependencies |= (1 << i);
|
||||||
|
|
||||||
|
// Input attachments can be any type, so we need to check what type it is
|
||||||
|
for (auto& inputAtt : subpass->inputReferences)
|
||||||
|
{
|
||||||
|
auto resource = node->attResources[inputAtt.attachment];
|
||||||
|
if (resource->resourceType == SH_ATT_DESC_TYPE::COLOR)
|
||||||
|
colorRead |= (1 << i);
|
||||||
|
else if (resource->resourceType == SH_ATT_DESC_TYPE::DEPTH_STENCIL)
|
||||||
|
depthRead |= (1 << i);
|
||||||
|
}
|
||||||
|
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through all subpasses again but this time we use the bit field to initialize
|
||||||
|
// the dependencies.
|
||||||
|
for (i = 0; i < node->subpasses.size(); ++i)
|
||||||
|
{
|
||||||
|
vk::PipelineStageFlags srcStage;
|
||||||
|
vk::PipelineStageFlags dstStage;
|
||||||
|
vk::AccessFlags srcAccess;
|
||||||
|
vk::AccessFlags dstAccess;
|
||||||
|
auto& dep = node->spDeps[i];
|
||||||
|
|
||||||
|
if (colorRead & (1 << i))
|
||||||
|
{
|
||||||
|
srcStage |= vk::PipelineStageFlagBits::eColorAttachmentOutput;
|
||||||
|
dstStage |= vk::PipelineStageFlagBits::eColorAttachmentOutput;
|
||||||
|
srcAccess |= vk::AccessFlagBits::eColorAttachmentWrite;
|
||||||
|
dstAccess |= vk::AccessFlagBits::eColorAttachmentRead;
|
||||||
|
}
|
||||||
|
if (colorWrite & (1 << i))
|
||||||
|
{
|
||||||
|
srcStage |= vk::PipelineStageFlagBits::eColorAttachmentOutput;
|
||||||
|
dstStage |= vk::PipelineStageFlagBits::eColorAttachmentOutput;
|
||||||
|
srcAccess |= vk::AccessFlagBits::eColorAttachmentWrite;
|
||||||
|
dstAccess |= vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eColorAttachmentRead;
|
||||||
|
}
|
||||||
|
if (depthRead & (1 << i))
|
||||||
|
{
|
||||||
|
srcStage |= vk::PipelineStageFlagBits::eEarlyFragmentTests;
|
||||||
|
dstStage |= vk::PipelineStageFlagBits::eEarlyFragmentTests | vk::PipelineStageFlagBits::eLateFragmentTests;
|
||||||
|
srcAccess |= vk::AccessFlagBits::eDepthStencilAttachmentWrite;
|
||||||
|
dstAccess |= vk::AccessFlagBits::eDepthStencilAttachmentRead;
|
||||||
|
}
|
||||||
|
if (depthWrite & (1 << i))
|
||||||
|
{
|
||||||
|
srcStage |= vk::PipelineStageFlagBits::eEarlyFragmentTests;
|
||||||
|
dstStage |= vk::PipelineStageFlagBits::eEarlyFragmentTests | vk::PipelineStageFlagBits::eLateFragmentTests;
|
||||||
|
srcAccess |= vk::AccessFlagBits::eDepthStencilAttachmentWrite;
|
||||||
|
dstAccess |= vk::AccessFlagBits::eDepthStencilAttachmentRead | vk::AccessFlagBits::eDepthStencilAttachmentWrite;
|
||||||
|
}
|
||||||
|
if (inputDependencies & (1 << i))
|
||||||
|
{
|
||||||
|
dstStage |= vk::PipelineStageFlagBits::eFragmentShader;
|
||||||
|
dstAccess |= vk::AccessFlagBits::eInputAttachmentRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
//// If subpass of first renderpass, stage flag should be bottom of pipe
|
||||||
|
//if (&node == &nodes.front() && i == 0)
|
||||||
|
// srcStage = vk::PipelineStageFlagBits::eBottomOfPipe;
|
||||||
|
|
||||||
|
//// If subpass of last renderpass, stage flag should be bottom of pipe
|
||||||
|
//if (&node == &nodes.back() && i == node->subpasses.size() - 1)
|
||||||
|
// dstStage = vk::PipelineStageFlagBits::eTopOfPipe;
|
||||||
|
|
||||||
|
dep.srcStageMask = srcStage;
|
||||||
|
dep.dstStageMask = dstStage;
|
||||||
|
dep.srcAccessMask = srcAccess;
|
||||||
|
dep.dstAccessMask = dstAccess;
|
||||||
|
|
||||||
|
dep.srcStageMask = srcStage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Simply loops through all nodes and create renderpasses.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHRenderGraph::ConfigureRenderpasses(void) noexcept
|
||||||
|
{
|
||||||
|
for (auto& node : nodes)
|
||||||
|
{
|
||||||
|
node->CreateRenderpass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Simply loops through all nodes and create framebuffers.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHRenderGraph::ConfigureFramebuffers(void) noexcept
|
||||||
|
{
|
||||||
|
for (auto& node : nodes)
|
||||||
|
{
|
||||||
|
node->CreateFramebuffer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Init function. Doesn't do much except initialize device and swapchain
|
||||||
|
handle. Graph should start out empty.
|
||||||
|
|
||||||
|
\param swapchain
|
||||||
|
Used for querying number of images later.
|
||||||
|
|
||||||
|
\param logicalDevice
|
||||||
|
Used for initializing logicalDeviceHdl.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHRenderGraph::Init(Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain) noexcept
|
||||||
|
{
|
||||||
|
logicalDeviceHdl = logicalDevice;
|
||||||
|
swapchainHdl = swapchain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Default ctor, doesn't do much.
|
||||||
|
|
||||||
|
|
||||||
|
\return
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
SHRenderGraph::SHRenderGraph(void) noexcept
|
||||||
|
: logicalDeviceHdl{ }
|
||||||
|
, swapchainHdl{ }
|
||||||
|
, nodes{}
|
||||||
|
, graphResources{}
|
||||||
|
, resourceManager{}
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Adds a renderpass to the graph.
|
||||||
|
|
||||||
|
\param nodeName
|
||||||
|
The name of the renderpass
|
||||||
|
|
||||||
|
\param attachmentDescriptions
|
||||||
|
The attachment description types for the node. See SHRenderGraphNode
|
||||||
|
ctor for more details.
|
||||||
|
|
||||||
|
\return
|
||||||
|
Reference to the node.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
Handle<SHRenderGraphNode> SHRenderGraph::AddNode(std::string nodeName, std::initializer_list<std::string> resourceNames, std::initializer_list<std::string> predecessorNodes) noexcept
|
||||||
|
{
|
||||||
|
if (nodeIndexing.contains(nodeName))
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("Node already exists, cannot add node. ");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Handle<SHRenderGraphResource>> resources;
|
||||||
|
for (auto const& name : resourceNames)
|
||||||
|
{
|
||||||
|
// If the resource that the new node is requesting for exists, allow the graph to reference it
|
||||||
|
if (graphResources.contains(name))
|
||||||
|
resources.push_back(graphResources.at(name));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("Resource doesn't exist in graph yet. Cannot create new node.");
|
||||||
|
return{};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Predecessor nodes for this node
|
||||||
|
std::vector<Handle<SHRenderGraphNode>> predecessors;
|
||||||
|
for (auto& pred : predecessorNodes)
|
||||||
|
{
|
||||||
|
// If predecessor exists, allow new node to reference it
|
||||||
|
if (nodeIndexing.contains(pred))
|
||||||
|
predecessors.push_back(nodes[nodeIndexing[pred]]);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("Predecessor doesn't exist in graph yet. Cannot create new node.");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nodes.emplace_back(resourceManager.Create<SHRenderGraphNode>(resourceManager, logicalDeviceHdl, swapchainHdl, std::move(resources), std::move(predecessors), &graphResources));
|
||||||
|
nodeIndexing.emplace(nodeName, nodes.size() - 1);
|
||||||
|
return nodes.at(nodeIndexing[nodeName]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/*!
|
||||||
|
|
||||||
|
\brief
|
||||||
|
Generates and configures all renderpass nodes.
|
||||||
|
Does a few things.
|
||||||
|
1. Using predecessors and subpasses, configure attachment descriptions.
|
||||||
|
2. Using predecessors, configure subpass description and dependencies.
|
||||||
|
3. Create Renderpasses in nodes.
|
||||||
|
4. Create framebuffers in nodes using renderpasses.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/***************************************************************************/
|
||||||
|
void SHRenderGraph::Generate(void) noexcept
|
||||||
|
{
|
||||||
|
ConfigureAttachmentDescriptions();
|
||||||
|
ConfigureSubpasses();
|
||||||
|
ConfigureRenderpasses();
|
||||||
|
ConfigureFramebuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,233 @@
|
||||||
|
#ifndef SH_RENDER_GRAPH_H
|
||||||
|
#define SH_RENDER_GRAPH_H
|
||||||
|
|
||||||
|
#include "Graphics/Renderpass/SHVkRenderpass.h"
|
||||||
|
#include "Resource/ResourceLibrary.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
class SHVkLogicalDevice;
|
||||||
|
class SHVkFramebuffer;
|
||||||
|
class SHVkSwapchain;
|
||||||
|
class SHVkImage;
|
||||||
|
class SHVkImageView;
|
||||||
|
class SHVkFramebuffer;
|
||||||
|
|
||||||
|
// Used for attachment description creation for renderpass node
|
||||||
|
enum class SH_ATT_DESC_TYPE
|
||||||
|
{
|
||||||
|
COLOR,
|
||||||
|
COLOR_PRESENT,
|
||||||
|
DEPTH,
|
||||||
|
STENCIL,
|
||||||
|
DEPTH_STENCIL,
|
||||||
|
};
|
||||||
|
|
||||||
|
class SHRenderGraphResource
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PRIVATE MEMBER VARIABLES */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
//! Name of the resource
|
||||||
|
std::string resourceName;
|
||||||
|
|
||||||
|
//! Used for initializing image layouts
|
||||||
|
SH_ATT_DESC_TYPE resourceType;
|
||||||
|
|
||||||
|
//! The resource itself (this is a vector because if the resource happens
|
||||||
|
//! to be a swapchain image, then we need however many frames in flight).
|
||||||
|
//! However when it's not a swapchain image, we want this container to be size 1
|
||||||
|
//! because writing to these images will not interfere with images in the previous
|
||||||
|
//! frame, unlike the swapchain image.
|
||||||
|
std::vector<Handle<SHVkImage>> images;
|
||||||
|
|
||||||
|
//! Views to resources (vector because same rationale as images. see above).
|
||||||
|
std::vector<Handle<SHVkImageView>> imageViews;
|
||||||
|
|
||||||
|
//! Image format
|
||||||
|
vk::Format resourceFormat;
|
||||||
|
|
||||||
|
//! width of the resource
|
||||||
|
uint32_t width;
|
||||||
|
|
||||||
|
//! Height of the resource
|
||||||
|
uint32_t height;
|
||||||
|
|
||||||
|
//! Number of mipmap levels
|
||||||
|
uint8_t mipLevels;
|
||||||
|
public:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* CTORS AND DTORS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
SHRenderGraphResource(Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, std::string const& name, SH_ATT_DESC_TYPE type, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageCreateFlagBits createFlags) noexcept;
|
||||||
|
SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept;
|
||||||
|
SHRenderGraphResource& operator=(SHRenderGraphResource&& rhs) noexcept;
|
||||||
|
~SHRenderGraphResource (void) noexcept;
|
||||||
|
|
||||||
|
friend class SHRenderGraphNode;
|
||||||
|
friend class SHRenderGraph;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SHRenderGraphNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
class SHSubpass
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SHSubpass(std::unordered_map<uint64_t, uint32_t> const* mapping, std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* ptrToResources) noexcept;
|
||||||
|
SHSubpass(SHSubpass&& rhs) noexcept;
|
||||||
|
SHSubpass& operator=(SHSubpass&& rhs) noexcept;
|
||||||
|
|
||||||
|
void AddColorOutput (std::string resourceToReference) noexcept;
|
||||||
|
void AddDepthOutput (std::string resourceToReference, SH_ATT_DESC_TYPE attachmentDescriptionType = SH_ATT_DESC_TYPE::DEPTH_STENCIL) noexcept;
|
||||||
|
void AddInput (std::string resourceToReference) noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*---------------------------------------------------------------------*/
|
||||||
|
/* PRIVATE MEMBER VARIABLES */
|
||||||
|
/*---------------------------------------------------------------------*/
|
||||||
|
//! Color attachments
|
||||||
|
std::vector<vk::AttachmentReference> colorReferences;
|
||||||
|
|
||||||
|
//! Depth attachments
|
||||||
|
std::vector<vk::AttachmentReference> depthReferences;
|
||||||
|
|
||||||
|
//! Input attachments
|
||||||
|
std::vector<vk::AttachmentReference> inputReferences;
|
||||||
|
|
||||||
|
//! For getting attachment reference indices using handles
|
||||||
|
std::unordered_map<uint64_t, uint32_t> const* resourceAttachmentMapping;
|
||||||
|
|
||||||
|
//! Pointer to resources in the render graph (for getting handle IDs)
|
||||||
|
std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* ptrToResources;
|
||||||
|
|
||||||
|
friend class SHRenderGraphNode;
|
||||||
|
friend class SHRenderGraph;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PRIVATE MEMBER VARIABLES */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
ResourceManager& resourceManager;
|
||||||
|
|
||||||
|
//! For Vulkan object creation
|
||||||
|
Handle<SHVkLogicalDevice> logicalDeviceHdl;
|
||||||
|
|
||||||
|
//! Each node will have a renderpass and each renderpass will have its own subpasses.
|
||||||
|
//! These subpasses will execute sequentially.
|
||||||
|
Handle<SHVkRenderpass> renderpass;
|
||||||
|
|
||||||
|
//! Framebuffers used in this renderpass. If renderpass contains usage of a swapchain image
|
||||||
|
//! used for presenting, then we cannot use just 1 framebuffer, we need to have 1 for however many frames in flight.
|
||||||
|
std::vector<Handle<SHVkFramebuffer>> framebuffers;
|
||||||
|
|
||||||
|
//! Nodes that must finish execution before this node is executed will be in this container
|
||||||
|
std::vector<Handle<SHRenderGraphNode>> prereqNodes;
|
||||||
|
|
||||||
|
//! Container of Attachment descriptions
|
||||||
|
std::vector<vk::AttachmentDescription> attachmentDescriptions;
|
||||||
|
|
||||||
|
//! Resources used in this renderpass
|
||||||
|
std::vector<Handle<SHRenderGraphResource>> attResources;
|
||||||
|
|
||||||
|
//! Vector of subpasses
|
||||||
|
std::vector<Handle<SHSubpass>> subpasses;
|
||||||
|
|
||||||
|
//! Descriptions to pass to renderpass for renderpass creation. We want to keep this here because
|
||||||
|
std::vector<vk::SubpassDescription> spDescs;
|
||||||
|
|
||||||
|
//! Subpass dependencies for renderpass creation
|
||||||
|
std::vector<vk::SubpassDependency> spDeps;
|
||||||
|
|
||||||
|
//! For indexing resources fast
|
||||||
|
std::unordered_map<uint64_t, uint32_t> resourceAttachmentMapping;
|
||||||
|
|
||||||
|
//! For indexing subpasses
|
||||||
|
std::map<std::string, uint32_t> subpassIndexing;
|
||||||
|
|
||||||
|
//! Pointer to resources in the render graph (for getting handle IDs)
|
||||||
|
std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* ptrToResources;
|
||||||
|
|
||||||
|
//! Whether or not the node has finished execution
|
||||||
|
bool executed;
|
||||||
|
|
||||||
|
//! Whether or not the node has been configured already or not
|
||||||
|
bool configured;
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PRIVATE MEMBER FUNCTIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
void CreateRenderpass (void) noexcept;
|
||||||
|
void CreateFramebuffer(void) noexcept;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* CTORS AND DTORS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
SHRenderGraphNode (ResourceManager& rm, Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, std::vector<Handle<SHRenderGraphResource>> attRes, std::vector<Handle<SHRenderGraphNode>> predecessors, std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* resources) noexcept;
|
||||||
|
SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept;
|
||||||
|
SHRenderGraphNode& operator= (SHRenderGraphNode&& rhs) noexcept;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PUBLIC MEMBER FUNCTIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
Handle<SHSubpass> AddSubpass (std::string subpassName) noexcept;
|
||||||
|
|
||||||
|
friend class SHRenderGraph;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SHRenderGraph
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PRIVATE MEMBER FUNCTIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
void ConfigureAttachmentDescriptions (void) noexcept;
|
||||||
|
void ConfigureSubpasses (void) noexcept;
|
||||||
|
void ConfigureRenderpasses (void) noexcept;
|
||||||
|
void ConfigureFramebuffers (void) noexcept;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PRIVATE MEMBER VARIABLES */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
Handle<SHVkLogicalDevice> logicalDeviceHdl;
|
||||||
|
|
||||||
|
//! swapchain used for querying image count
|
||||||
|
Handle<SHVkSwapchain> swapchainHdl;
|
||||||
|
|
||||||
|
//! For indexing render graph node container
|
||||||
|
std::map<std::string, uint32_t> nodeIndexing;
|
||||||
|
|
||||||
|
//! Render graph nodes
|
||||||
|
std::vector<Handle<SHRenderGraphNode>> nodes;
|
||||||
|
|
||||||
|
//! Resources that exist for the entire render graph
|
||||||
|
std::unordered_map<std::string, Handle<SHRenderGraphResource>> graphResources;
|
||||||
|
|
||||||
|
//! Resource library for graph handles
|
||||||
|
ResourceManager resourceManager;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* CTORS AND DTORS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
SHRenderGraph (void) noexcept;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* PUBLIC MEMBER FUNCTIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
void Init (Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain) noexcept;
|
||||||
|
void AddResource(std::string resourceName, SH_ATT_DESC_TYPE type, uint32_t w = static_cast<uint32_t>(-1), uint32_t h = static_cast<uint32_t>(-1), vk::Format format = vk::Format::eB8G8R8A8Unorm, uint32_t levels = 1, vk::ImageCreateFlagBits createFlags = {});
|
||||||
|
Handle<SHRenderGraphNode> AddNode (std::string nodeName, std::initializer_list<std::string> resourceNames, std::initializer_list<std::string> predecessorNodes) noexcept;
|
||||||
|
void Generate (void) noexcept;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,48 @@
|
||||||
|
#include "SHPch.h"
|
||||||
|
#include "SHVkAttachDescGen.h"
|
||||||
|
#include "Graphics/Swapchain/SHVkSwapchain.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
vk::AttachmentDescription SHVkAttachDescGen::GenGenericColorPresent(Handle<SHVkSwapchain> const& swapchain) noexcept
|
||||||
|
{
|
||||||
|
return vk::AttachmentDescription
|
||||||
|
{
|
||||||
|
.format = swapchain->GetSurfaceFormatKHR().format,
|
||||||
|
.samples = vk::SampleCountFlagBits::e1, // > 1 for multisampling
|
||||||
|
|
||||||
|
.loadOp = vk::AttachmentLoadOp::eClear,
|
||||||
|
.storeOp = vk::AttachmentStoreOp::eStore,
|
||||||
|
|
||||||
|
// Ditto but with stencil
|
||||||
|
.stencilLoadOp = vk::AttachmentLoadOp::eDontCare,
|
||||||
|
.stencilStoreOp = vk::AttachmentStoreOp::eDontCare,
|
||||||
|
|
||||||
|
// Layout of image when render pass begins and ends
|
||||||
|
.initialLayout = vk::ImageLayout::eUndefined,
|
||||||
|
.finalLayout = vk::ImageLayout::ePresentSrcKHR
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::AttachmentDescription SHVkAttachDescGen::GenDepthStencil(Handle<SHVkSwapchain> const& swapchain) noexcept
|
||||||
|
{
|
||||||
|
return vk::AttachmentDescription
|
||||||
|
{
|
||||||
|
.format = swapchain->GetDepthFormat(),
|
||||||
|
.samples = vk::SampleCountFlagBits::e1, // > 1 for multisampling
|
||||||
|
|
||||||
|
.loadOp = vk::AttachmentLoadOp::eClear,
|
||||||
|
.storeOp = vk::AttachmentStoreOp::eStore,
|
||||||
|
|
||||||
|
// Ditto but with stencil
|
||||||
|
.stencilLoadOp = vk::AttachmentLoadOp::eDontCare,
|
||||||
|
.stencilStoreOp = vk::AttachmentStoreOp::eDontCare,
|
||||||
|
|
||||||
|
// Layout of image when render pass begins and ends
|
||||||
|
.initialLayout = vk::ImageLayout::eUndefined,
|
||||||
|
.finalLayout = vk::ImageLayout::ePresentSrcKHR
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef SH_VK_ATTACHMENT_DESC_GEN_H
|
||||||
|
#define SH_VK_ATTACHMENT_DESC_GEN_H
|
||||||
|
|
||||||
|
#include "Graphics/SHVulkanIncludes.h"
|
||||||
|
#include "Resource/Handle.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
class SHVkSwapchain;
|
||||||
|
|
||||||
|
class SHVkAttachDescGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static vk::AttachmentDescription GenGenericColorPresent (Handle<SHVkSwapchain> const& swapchain) noexcept;
|
||||||
|
static vk::AttachmentDescription GenDepthStencil (Handle<SHVkSwapchain> const& swapchain) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,44 @@
|
||||||
|
#ifndef SH_VK_ATTACHMENT_H
|
||||||
|
#define SH_VK_ATTACHMENT_H
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
//struct SHVkAttachmentReference
|
||||||
|
//{
|
||||||
|
// //! Identifies the attachment index of in the array of attachments in renderpass
|
||||||
|
// uint32_t attachment;
|
||||||
|
|
||||||
|
// //! What layout the attachment uses during the subpass
|
||||||
|
//vk::ImageLayout imageLayout;
|
||||||
|
//};
|
||||||
|
|
||||||
|
//struct SHVkAttachmentDescription
|
||||||
|
//{
|
||||||
|
// //! Specifies that the attachment aliases the same device memory as other attachments
|
||||||
|
// bool mayAlias;
|
||||||
|
|
||||||
|
// //! specifies the format of the image that will be used for the attachment
|
||||||
|
// vk::Format format;
|
||||||
|
|
||||||
|
// //! Number of samples of the image
|
||||||
|
// uint8_t samples;
|
||||||
|
|
||||||
|
// //! How to treat contents of an attachment at the beginning of a subpass where it is FIRST used
|
||||||
|
// vk::AttachmentLoadOp loadOp;
|
||||||
|
|
||||||
|
// //! How to treat contents of an attachment at the beginning of a subpass where it is FIRST used
|
||||||
|
// vk::AttachmentStoreOp storeOp;
|
||||||
|
|
||||||
|
// // TODO: We don't really want to mess with stencils yet, so this is left out
|
||||||
|
// // stecilLoadOp
|
||||||
|
// // stecilStoreOp
|
||||||
|
|
||||||
|
// // layout that the attachment will be in when render pass instance begins
|
||||||
|
// vk::ImageLayout initialLayout;
|
||||||
|
|
||||||
|
// // layout that the attachment will be in when render pass instance ends
|
||||||
|
// vk::ImageLayout finalLayout;
|
||||||
|
//};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue