Merge branch 'main' into SP3-14-FileSystem
This commit is contained in:
commit
7b55f7fe3b
|
@ -60,7 +60,7 @@
|
|||
<PrecompiledHeaderFile>SBpch.h</PrecompiledHeaderFile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>.;..\SHADE_Engine\src;src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\Dependencies\spdlog\include;..\SHADE_Engine\src;src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
|
@ -71,7 +71,7 @@
|
|||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EntryPointSymbol>WinMainCRTStartup</EntryPointSymbol>
|
||||
<EntryPointSymbol>wWinMainCRTStartup</EntryPointSymbol>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
@ -80,7 +80,7 @@
|
|||
<PrecompiledHeaderFile>SBpch.h</PrecompiledHeaderFile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<PreprocessorDefinitions>_RELEASE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>.;..\SHADE_Engine\src;src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\Dependencies\spdlog\include;..\SHADE_Engine\src;src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<Optimization>Full</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
|
@ -94,16 +94,20 @@
|
|||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EntryPointSymbol>WinMainCRTStartup</EntryPointSymbol>
|
||||
<EntryPointSymbol>wWinMainCRTStartup</EntryPointSymbol>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\Application\SBApplication.h" />
|
||||
<ClInclude Include="src\SBpch.h" />
|
||||
<ClInclude Include="src\Scenes\SBTestScene.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\Application\SBApplication.cpp" />
|
||||
<ClCompile Include="src\SBpch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Scenes\SBTestScene.cpp" />
|
||||
<ClCompile Include="src\WinMain.cpp" />
|
||||
</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"
|
||||
pchsource "%{prj.location}/src/SBpch.cpp"
|
||||
staticruntime "on"
|
||||
entrypoint "WinMainCRTStartup"
|
||||
entrypoint "wWinMainCRTStartup"
|
||||
system ("windows")
|
||||
|
||||
files
|
||||
|
@ -21,8 +21,7 @@ project "SHADE_Application"
|
|||
|
||||
includedirs
|
||||
{
|
||||
"%{IncludeDir.GLFW}",
|
||||
"%{IncludeDir.GLAD}",
|
||||
"%{IncludeDir.spdlog}/include",
|
||||
"../SHADE_Engine/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 <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;
|
||||
}
|
|
@ -57,8 +57,8 @@
|
|||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>SHpch.h</PrecompiledHeaderFile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<PreprocessorDefinitions>_LIB;_GLFW_INCLUDE_NONE;MSDFGEN_USE_CPP11;_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>
|
||||
<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;$(VULKAN_SDK)\Source\SPIRV-Reflect;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
|
@ -71,7 +71,7 @@
|
|||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<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>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
|
@ -80,8 +80,8 @@
|
|||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>SHpch.h</PrecompiledHeaderFile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<PreprocessorDefinitions>_LIB;_GLFW_INCLUDE_NONE;MSDFGEN_USE_CPP11;_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>
|
||||
<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;$(VULKAN_SDK)\Source\SPIRV-Reflect;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<Optimization>Full</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
|
@ -97,21 +97,169 @@
|
|||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<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>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<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\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\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>
|
||||
<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\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">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</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>
|
||||
<ProjectReference Include="..\Dependencies\yamlcpp\yaml-cpp.vcxproj">
|
||||
|
|
|
@ -4,19 +4,578 @@
|
|||
<Filter Include="Engine">
|
||||
<UniqueIdentifier>{DBC7D3B0-C769-FE86-B024-12DB9C6585D7}</UniqueIdentifier>
|
||||
</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>
|
||||
<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">
|
||||
<Filter>Engine</Filter>
|
||||
</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\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>
|
||||
<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">
|
||||
<Filter>Engine</Filter>
|
||||
</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\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>
|
||||
</Project>
|
|
@ -34,7 +34,8 @@ project "SHADE_Engine"
|
|||
"%{IncludeDir.ktx}/include",
|
||||
"%{IncludeDir.RTTR}/include",
|
||||
"%{IncludeDir.reactphysics3d}/include",
|
||||
"%{IncludeDir.VULKAN}/include"
|
||||
"%{IncludeDir.VULKAN}/include",
|
||||
"%{IncludeDir.VULKAN}/Source/SPIRV-Reflect"
|
||||
}
|
||||
|
||||
libdirs
|
||||
|
@ -56,14 +57,16 @@ project "SHADE_Engine"
|
|||
"reactphysics3d",
|
||||
"imgui",
|
||||
"spdlog",
|
||||
"vulkan-1.lib"
|
||||
"vulkan-1.lib",
|
||||
"shaderc_shared.lib"
|
||||
}
|
||||
|
||||
defines
|
||||
{
|
||||
"_LIB",
|
||||
"_GLFW_INCLUDE_NONE",
|
||||
"MSDFGEN_USE_CPP11"
|
||||
"MSDFGEN_USE_CPP11",
|
||||
"NOMINMAX"
|
||||
}
|
||||
|
||||
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 "SHEngine.h"
|
|
@ -1,9 +1,39 @@
|
|||
#pragma once
|
||||
#ifndef SH_ENGINE_H
|
||||
#define SH_ENGINE_H
|
||||
|
||||
#include <utility>
|
||||
#include "Meta/SHIsDetected.h"
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
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