diff --git a/Assets/Audio/Master.bank b/Assets/Audio/Master.bank new file mode 100644 index 00000000..a1b4e563 Binary files /dev/null and b/Assets/Audio/Master.bank differ diff --git a/Assets/Audio/Master.strings.bank b/Assets/Audio/Master.strings.bank new file mode 100644 index 00000000..ecad89fe Binary files /dev/null and b/Assets/Audio/Master.strings.bank differ diff --git a/Assets/Audio/footsteps.bank b/Assets/Audio/footsteps.bank new file mode 100644 index 00000000..ce53111e Binary files /dev/null and b/Assets/Audio/footsteps.bank differ diff --git a/Assets/TD_Checker_Base_Color.dds b/Assets/TD_Checker_Base_Color.dds new file mode 100644 index 00000000..9dcbfeee Binary files /dev/null and b/Assets/TD_Checker_Base_Color.dds differ diff --git a/Dependencies.bat b/Dependencies.bat index e16c4267..1d4a3473 100644 --- a/Dependencies.bat +++ b/Dependencies.bat @@ -19,10 +19,11 @@ echo "L - yamlcpp" echo "M - SDL" echo "N - dotnet" echo "O - tinyddsloader" +echo "P - fmod" echo --------------------------------------------------- echo. -choice /C ABCDEFGHIJKLMNO /T 10 /D A +choice /C ABCDEFGHIJKLMNOP /T 10 /D A set _e=%ERRORLEVEL% if %_e%==1 goto VMA @@ -40,6 +41,7 @@ if %_e%==12 goto yamlcpp if %_e%==13 goto SDL if %_e%==14 goto dotnet if %_e%==15 goto tinyddsloader +if %_e%==16 goto fmod :VMA echo -----------------------VMA---------------------------- @@ -145,6 +147,12 @@ if %_e%==14 (goto :done) else (goto :tinyddsloader) echo --------------------tinyddsloader------------------------- rmdir "Dependencies/tinyddsloader" /S /Q git clone https://github.com/SHADE-DP/tinyddsloader.git "Dependencies/tinyddsloader" +if %_e%==15 (goto :done) else (goto :fmod) + +:fmod +echo --------------------fmod------------------------- +rmdir "Dependencies/fmod" /S /Q +git clone https://github.com/SHADE-DP/FMOD.git "Dependencies/fmod" :done echo DONE! diff --git a/Dependencies.lua b/Dependencies.lua index 9ae406f0..6dd7a711 100644 --- a/Dependencies.lua +++ b/Dependencies.lua @@ -15,3 +15,4 @@ IncludeDir["SDL"] = "%{wks.location}\\Dependencies\\SDL" IncludeDir["VULKAN"] = "$(VULKAN_SDK)" IncludeDir["dotnet"] = "%{wks.location}\\Dependencies\\dotnet" IncludeDir["tinyddsloader"] = "%{wks.location}\\Dependencies\\tinyddsloader" +IncludeDir["fmod"] = "%{wks.location}\\Dependencies\\fmod" \ No newline at end of file diff --git a/SHADE_Application/premake5.lua b/SHADE_Application/premake5.lua index 0e1acc05..ea6886e9 100644 --- a/SHADE_Application/premake5.lua +++ b/SHADE_Application/premake5.lua @@ -30,13 +30,14 @@ project "SHADE_Application" externalincludedirs { - "%{IncludeDir.spdlog}/include", - "%{IncludeDir.VULKAN}/include", - "%{IncludeDir.VMA}/include", - "%{IncludeDir.VULKAN}/Source/SPIRV-Reflect", - "%{IncludeDir.RTTR}/include", - "%{IncludeDir.tinyddsloader}", - "%{IncludeDir.reactphysics3d}\\include" + "%{IncludeDir.RTTR}\\include", + "%{IncludeDir.fmod}/include", + "%{IncludeDir.VULKAN}/Source/SPIRV-Reflect", + "%{IncludeDir.VMA}/include", + "%{IncludeDir.VULKAN}/include", + "%{IncludeDir.spdlog}/include", + "%{IncludeDir.tinyddsloader}", + "%{IncludeDir.reactphysics3d}\\include" } externalwarnings "Off" @@ -57,7 +58,7 @@ project "SHADE_Application" libdirs { "%{IncludeDir.spdlog}/lib", - "%{IncludeDir.SDL}/lib", + "%{IncludeDir.SDL}/lib" } defines diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index 8135a4dc..60deb78d 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -31,6 +31,7 @@ #include "Math/Transform/SHTransformSystem.h" #include "Input/SHInputManagerSystem.h" #include "FRC/SHFramerateController.h" +//#include "AudioSystem/SHAudioSystem.h" // Components #include "Graphics/MiddleEnd/Interface/SHRenderable.h" @@ -66,6 +67,7 @@ namespace Sandbox SHADE::SHSystemManager::CreateSystem(); SHADE::SHGraphicsSystem* graphicsSystem = static_cast(SHADE::SHSystemManager::GetSystem()); SHADE::SHSystemManager::CreateSystem(); + //SHADE::SHSystemManager::CreateSystem(); // Create Routines SHADE::SHSystemManager::RegisterRoutine(); @@ -86,6 +88,7 @@ namespace Sandbox SHADE::SHSystemManager::RegisterRoutine(); SHADE::SHSystemManager::RegisterRoutine(); + //SHADE::SHComponentManager::CreateComponentSparseSet(); SHADE::SHComponentManager::CreateComponentSparseSet(); SHADE::SHComponentManager::CreateComponentSparseSet(); @@ -93,8 +96,11 @@ namespace Sandbox SHADE::SHAssetManager::LoadDataTemp("../../Assets/racoon.gltf"); SHADE::SHAssetManager::LoadDataTemp("../../Assets/RaccoonBag_Color_Ver4.dds"); SHADE::SHAssetManager::LoadDataTemp("../../Assets/RaccoonPreTexturedVer1_Base9.dds"); + SHADE::SHAssetManager::LoadDataTemp("../../Assets/TD_Checker_Base_Color.dds"); //TODO: REMOVE AFTER PRESENTATION + //SHADE::SHSystemManager::RegisterRoutine(); + // Set up graphics system and windows graphicsSystem->SetWindow(&window); diff --git a/SHADE_Application/src/Scenes/SBTestScene.cpp b/SHADE_Application/src/Scenes/SBTestScene.cpp index 0f42b419..74ac4c1d 100644 --- a/SHADE_Application/src/Scenes/SBTestScene.cpp +++ b/SHADE_Application/src/Scenes/SBTestScene.cpp @@ -9,6 +9,7 @@ #include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h" #include "Scripting/SHScriptEngine.h" #include "Math/Transform/SHTransformComponent.h" +#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" #include "Assets/SHAssetManager.h" @@ -57,70 +58,103 @@ namespace Sandbox } graphicsSystem->BuildMeshBuffers(); - //Test Textures - auto textures{ SHADE::SHAssetManager::GetAllTextures() }; + // Load Textures + auto textures = SHADE::SHAssetManager::GetAllTextures(); + std::vector> texHandles; + for (const auto& tex : textures) + { + auto texture = graphicsSystem->Add(tex); + texHandles.push_back(texture); + } + graphicsSystem->BuildTextures(); // Create Materials auto matInst = graphicsSystem->AddOrGetBaseMaterialInstance(); + auto customMat = graphicsSystem->AddMaterialInstanceCopy(matInst); + customMat->SetProperty("data.color", SHVec4(0.0f, 1.0f, 1.0f, 1.0f)); + customMat->SetProperty("data.textureIndex", 1); + customMat->SetProperty("data.alpha", 0.1f); // Create Stress Test Objects - static const SHVec3 TEST_OBJ_SCALE = { 0.2f, 0.2f, 0.2f }; - constexpr int NUM_ROWS = 1; - constexpr int NUM_COLS = 1; - static const SHVec3 TEST_OBJ_SPACING = { 1.0f, 1.0f, 1.0f }; - static const SHVec3 TEST_OBJ_START_POS = { - (NUM_COLS / 2 * TEST_OBJ_SPACING.x ), 0.0f, 0.0f }; - //for (int z = 0; z < NUM_ROWS; ++z) - //for (int x = 0; x < NUM_COLS; ++x) - //{ - // auto entity = SHEntityManager::CreateEntity(); - // auto& renderable = *SHComponentManager::GetComponent_s(entity); - // auto& transform = *SHComponentManager::GetComponent_s(entity); - - // renderable.Mesh = handles.front(); - // renderable.SetMaterial(matInst); - - // // Set initial positions - // transform.SetWorldPosition(TEST_OBJ_START_POS + SHVec3{ x * TEST_OBJ_SPACING.x, 0.0f, z * TEST_OBJ_SPACING.z }); - // //transform.SetLocalScale(TEST_OBJ_SCALE); - - // stressTestObjects.emplace_back(entity); - //} + static const SHVec3 TEST_OBJ_SCALE = { 0.05f, 0.05f, 0.05f }; + constexpr int NUM_ROWS = 100; + constexpr int NUM_COLS = 100; + static const SHVec3 TEST_OBJ_SPACING = { 0.05f, 0.05f, 0.05f }; + static const SHVec3 TEST_OBJ_START_POS = { - (NUM_COLS / 2 * TEST_OBJ_SPACING.x ) + 1.0f, -2.0f, -1.0f }; + for (int y = 0; y < NUM_ROWS; ++y) + for (int x = 0; x < NUM_COLS; ++x) + { auto entity = SHEntityManager::CreateEntity(); auto& renderable = *SHComponentManager::GetComponent_s(entity); auto& transform = *SHComponentManager::GetComponent_s(entity); renderable.Mesh = handles.front(); - renderable.SetMaterial(matInst); + renderable.SetMaterial(customMat); - //transform.SetLocalScale(TEST_OBJ_SCALE); + if (y == 50) + renderable.GetModifiableMaterial()->SetProperty("data.color", SHVec4(1.0f, 0.0f, 0.0f, 1.0f)); + + //Set initial positions + transform.SetWorldPosition(TEST_OBJ_START_POS + SHVec3{ + x * TEST_OBJ_SPACING.x, + y * TEST_OBJ_SPACING.y, + 0.0f + }); + //transform.SetWorldPosition({-1.0f, -1.0f, -1.0f}); + //transform.SetWorldRotation(3.14159265f * 1.5f, -3.14159265f / 2.0f, 0.0f); + transform.SetLocalScale(TEST_OBJ_SCALE); stressTestObjects.emplace_back(entity); + } + + auto entity = SHEntityManager::CreateEntity(); + auto& renderable = *SHComponentManager::GetComponent_s(entity); + auto& transform = *SHComponentManager::GetComponent_s(entity); + + renderable.Mesh = handles.front(); + renderable.SetMaterial(customMat); + renderable.GetModifiableMaterial()->SetProperty("data.color", SHVec4(0.0f, 0.0f, 0.0f, 0.0f)); + renderable.GetModifiableMaterial()->SetProperty("data.alpha", 1.0f); + renderable.GetModifiableMaterial()->SetProperty("data.textureIndex", 1); + + transform.SetWorldPosition ({-3.0f, -1.0f, -1.0f}); + transform.SetLocalScale({5.0f, 5.0f, 5.0f}); + + //auto entity = SHEntityManager::CreateEntity(); + //auto& renderable = *SHComponentManager::GetComponent_s(entity); + //auto& transform = *SHComponentManager::GetComponent_s(entity); + + //renderable.Mesh = handles.back(); + //renderable.SetMaterial(customMat); + + //transform.SetLocalScale(TEST_OBJ_SCALE); + //transform.SetWorldPosition({-1.0f, -1.0f, -1.0f}); // Create blank entity with a script - testObj = SHADE::SHEntityManager::CreateEntity(); + //testObj = SHADE::SHEntityManager::CreateEntity(); + //auto& testObjRenderable = *SHComponentManager::GetComponent_s(testObj); + //testObjRenderable.Mesh = CUBE_MESH; + //testObjRenderable.SetMaterial(matInst); + SHADE::SHScriptEngine* scriptEngine = static_cast(SHADE::SHSystemManager::GetSystem()); scriptEngine->AddScript(testObj, "TestScript"); } void SBTestScene::Update(float dt) { - /*static float rotation = 0.0f; + static float rotation = 0.0f; - auto& transform = *SHADE::SHComponentManager::GetComponent_s(testObj); + //auto& transform = *SHADE::SHComponentManager::GetComponent_s(testObj); - transform.SetLocalRotation(rotation, 0.0f, 0.0f); - rotation += dt * 10.0f;*/ - /*static float rotation = 0.0f; - - auto& transform = *SHADE::SHComponentManager::GetComponent_s(stressTestObjects[0]); - - transform.SetWorldPosition({rotation, 0.0f, 0.0f}); - rotation += dt * 10.0f;*/ + //transform.SetWorldPosition({1.0f, 1.0f, -1.0f}); + //transform.SetWorldRotation(0.0f, 0.0f + rotation, 0.0f); + //rotation += dt * 0.2f; // Destroy entity if space is pressed if (GetKeyState(VK_SPACE) & 0x8000) { + rotation = 0.0f; SHADE::SHScriptEngine* scriptEngine = static_cast(SHADE::SHSystemManager::GetSystem()); scriptEngine->RemoveAllScripts(testObj); } @@ -128,6 +162,7 @@ namespace Sandbox void SBTestScene::Render() { + } void SBTestScene::Unload() diff --git a/SHADE_Engine/premake5.lua b/SHADE_Engine/premake5.lua index 444dad12..3015a623 100644 --- a/SHADE_Engine/premake5.lua +++ b/SHADE_Engine/premake5.lua @@ -42,7 +42,8 @@ project "SHADE_Engine" "%{IncludeDir.VULKAN}\\include", "%{IncludeDir.VULKAN}\\Source\\SPIRV-Reflect", "%{IncludeDir.dotnet}\\include", - "%{IncludeDir.tinyddsloader}" + "%{IncludeDir.tinyddsloader}", + "%{IncludeDir.fmod}\\include" } externalwarnings "Off" @@ -55,7 +56,8 @@ project "SHADE_Engine" "%{IncludeDir.assimp}/lib/Release", "%{IncludeDir.RTTR}/lib", "%{IncludeDir.SDL}/lib", - "%{IncludeDir.spdlog}/lib" + "%{IncludeDir.spdlog}/lib", + "%{IncludeDir.fmod}/lib" } links @@ -104,14 +106,32 @@ project "SHADE_Engine" { "xcopy /s /r /y /q \"%{IncludeDir.spdlog}\\bin\" \"$(OutDir)\"", "xcopy /r /y /q \"%{IncludeDir.SDL}\\lib\\SDL2.dll\" \"$(OutDir)\"", - "xcopy /s /r /y /q \"%{IncludeDir.dotnet}\\bin\" \"$(OutDir)\"" + "xcopy /s /r /y /q \"%{IncludeDir.dotnet}\\bin\" \"$(OutDir)\"" } filter "configurations:Debug" - postbuildcommands {"xcopy /r /y /q \"%{IncludeDir.assimp}\\bin\\Debug\\assimp-vc142-mtd.dll\" \"$(OutDir)\""} + postbuildcommands + { + "xcopy /r /y /q \"%{IncludeDir.assimp}\\bin\\Debug\\assimp-vc142-mtd.dll\" \"$(OutDir)\"", + "xcopy /r /y /q \"%{IncludeDir.fmod}\\lib\\fmodL.dll\" \"$(OutDir)\"", + "xcopy /r /y /q \"%{IncludeDir.fmod}\\lib\\fmodstudioL.dll\" \"$(OutDir)\"" + } filter "configurations:Release" - postbuildcommands {"xcopy /r /y /q \"%{IncludeDir.assimp}\\bin\\Release\\assimp-vc142-mt.dll\" \"$(OutDir)\""} + postbuildcommands + { + "xcopy /r /y /q \"%{IncludeDir.assimp}\\bin\\Release\\assimp-vc142-mt.dll\" \"$(OutDir)\"", + "xcopy /r /y /q \"%{IncludeDir.fmod}\\lib\\fmod.dll\" \"$(OutDir)\"", + "xcopy /r /y /q \"%{IncludeDir.fmod}\\lib\\fmodstudio.dll\" \"$(OutDir)\"" + } + + filter "configurations:Publish" + postbuildcommands + { + "xcopy /r /y /q \"%{IncludeDir.assimp}\\bin\\Release\\assimp-vc142-mt.dll\" \"$(OutDir)\"", + "xcopy /r /y /q \"%{IncludeDir.fmod}\\lib\\fmod.dll\" \"$(OutDir)\"", + "xcopy /r /y /q \"%{IncludeDir.fmod}\\lib\\fmodstudio.dll\" \"$(OutDir)\"" + } filter "configurations:Publish" postbuildcommands {"xcopy /r /y /q \"%{IncludeDir.assimp}\\bin\\Release\\assimp-vc142-mt.dll\" \"$(OutDir)\""} @@ -122,13 +142,13 @@ project "SHADE_Engine" symbols "On" defines {"_DEBUG", "SHEDITOR"} links{"assimp-vc142-mtd.lib", "librttr_core_d.lib", "spdlogd.lib"} - --links{"fmodstudioL_vc.lib", "fmodL_vc.lib"} + links{"fmodstudioL_vc.lib", "fmodL_vc.lib"} filter "configurations:Release" optimize "On" defines{"_RELEASE", "SHEDITOR"} links{"assimp-vc142-mt.lib", "librttr_core.lib", "spdlog.lib"} - --links{"fmodstudio_vc.lib", "fmod_vc.lib"} + links{"fmodstudio_vc.lib", "fmod_vc.lib"} filter "configurations:Publish" optimize "On" @@ -140,4 +160,4 @@ project "SHADE_Engine" "%{prj.location}/src/Editor/**.h", "%{prj.location}/src/Editor/**.hpp", } - --links{"fmodstudio_vc.lib", "fmod_vc.lib"} \ No newline at end of file + links{"fmodstudio_vc.lib", "fmod_vc.lib"} \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/Asset Types/SHMeshAsset.h b/SHADE_Engine/src/Assets/Asset Types/SHMeshAsset.h index b4632c2e..18674a04 100644 --- a/SHADE_Engine/src/Assets/Asset Types/SHMeshAsset.h +++ b/SHADE_Engine/src/Assets/Asset Types/SHMeshAsset.h @@ -2,16 +2,17 @@ #include #include "Math/SHMath.h" +#include "SH_API.h" namespace SHADE { - struct SHMeshAssetHeader + struct SH_API SHMeshAssetHeader { uint32_t vertexCount; uint32_t indexCount; }; - struct SHMeshAsset + struct SH_API SHMeshAsset { bool compiled; bool changed; diff --git a/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp b/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp index 33270bb6..4f510c0a 100644 --- a/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp +++ b/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp @@ -74,12 +74,12 @@ namespace SHADE for (auto i{0}; i < file.GetMipCount(); ++i) { - mipOff.push_back(totalBytes); + mipOff[i] = totalBytes; totalBytes += file.GetImageData(i, 0)->m_memSlicePitch; } SHTexture::PixelChannel* pixel = new SHTexture::PixelChannel[totalBytes]; - std::memcpy(pixel, file.GetDDSData(), totalBytes); + std::memcpy(pixel, file.GetImageData()->m_mem, totalBytes); //pixel = std::move(reinterpret_cast(file.GetDDSData())); asset.numBytes = totalBytes; diff --git a/SHADE_Engine/src/AudioSystem/SHAudioListenerComponent.cpp b/SHADE_Engine/src/AudioSystem/SHAudioListenerComponent.cpp new file mode 100644 index 00000000..988b2781 --- /dev/null +++ b/SHADE_Engine/src/AudioSystem/SHAudioListenerComponent.cpp @@ -0,0 +1,58 @@ +/********************************************************************* +* \file SHAudioListenerComponent.cpp +* \author Glence Low +* \brief Definition of the SHAudioListenerComponent 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 "SHAudioListenerComponent.h" +#include "ECS_Base/Managers/SHSystemManager.h" + +namespace SHADE +{ + const SHVec3 SHAudioListenerComponent::GetPos() const + { + return pos; + } + + const SHVec3 SHAudioListenerComponent::GetVel() const + { + return vel; + } + + const SHVec3 SHAudioListenerComponent::GetForward() const + { + return forward; + } + + const SHVec3 SHAudioListenerComponent::GetUp() const + { + return up; + } + + void SHAudioListenerComponent::SetPos(const SHVec3 p) + { + pos = p; + } + + void SHAudioListenerComponent::SetVel(const SHVec3 v) + { + vel = v; + } + + void SHAudioListenerComponent::SetForward(const SHVec3 f) + { + forward = f; + } + + void SHAudioListenerComponent::SetUp(const SHVec3 u) + { + up = u; + } + +} + diff --git a/SHADE_Engine/src/AudioSystem/SHAudioListenerComponent.h b/SHADE_Engine/src/AudioSystem/SHAudioListenerComponent.h new file mode 100644 index 00000000..e0fa8104 --- /dev/null +++ b/SHADE_Engine/src/AudioSystem/SHAudioListenerComponent.h @@ -0,0 +1,41 @@ +#pragma once +/********************************************************************* + * \file SHAudioListenerComponent.h + * \author Glence Low + * \brief Declaration of the SHAudioListenerComponent 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. +*********************************************************************/ + +#pragma once +#include "ECS_Base/Components/SHComponent.h" +#include "Math/SHMath.h" + +namespace SHADE +{ + class SHAudioListenerComponent : public SHComponent + { + friend class SHAudioSystem; + public: + + SHAudioListenerComponent() = default; + ~SHAudioListenerComponent() = default; + + const SHVec3 GetPos() const; + void SetPos(const SHVec3 p); + + const SHVec3 GetVel() const; + const SHVec3 GetForward() const; + const SHVec3 GetUp() const; + + void SetVel(const SHVec3 v); + void SetForward(const SHVec3 f); + void SetUp(const SHVec3 u); + + private: + SHVec3 pos{}, vel{}, forward{}, up{ 0.f,1.f,0.f }; + }; +}//namespace SHADE + diff --git a/SHADE_Engine/src/AudioSystem/SHAudioSourceComponent.cpp b/SHADE_Engine/src/AudioSystem/SHAudioSourceComponent.cpp new file mode 100644 index 00000000..2d623ede --- /dev/null +++ b/SHADE_Engine/src/AudioSystem/SHAudioSourceComponent.cpp @@ -0,0 +1,53 @@ +/********************************************************************* +* \file SHAudioSourceComponet.cpp +* \author Glence Low +* \brief Definition of the SHAudioSourceComponet 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 "ECS_Base/Managers/SHSystemManager.h" +#include "AudioSystem/SHAudioSystem.h" +#include "SHAudioSourceComponent.h" + +namespace SHADE +{ + /** + * @brief play the sound + * + * @param index where the sound is in the index + */ + void SHAudioSourceComponent::PlaySoundSFX(EntityID id, bool loop, bool spatial, float min , float max ) + { + SHSystemManager::GetSystem()->PlaySFX(id, GetEID(),loop,spatial, min, max); + } + + void SHAudioSourceComponent::PlaySoundBGM(EntityID id, bool loop, bool spatial, float min, float max) + { + SHSystemManager::GetSystem()->PlayBGM(id, GetEID(), loop, spatial, min, max); + } + + /** + * @brief Stop the sound + * + * @param index where the sound is in the index + */ + void SHAudioSourceComponent::StopSound(EntityID id) + { + SHSystemManager::GetSystem()->StopSound(id); + } + + /** + * @brief Mute the sound + * + * @param index where the sound is in the index + */ + void SHAudioSourceComponent::SetMute(EntityID id, bool mute) + { + SHSystemManager::GetSystem()->SetMute(id, mute); + } +} + diff --git a/SHADE_Engine/src/AudioSystem/SHAudioSourceComponent.h b/SHADE_Engine/src/AudioSystem/SHAudioSourceComponent.h new file mode 100644 index 00000000..987dc3d4 --- /dev/null +++ b/SHADE_Engine/src/AudioSystem/SHAudioSourceComponent.h @@ -0,0 +1,60 @@ +/********************************************************************* + * \file SHAudioSourceComponet.h + * \author Glence Low + * \brief Declaration of the SHAudioSourceComponet 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. +*********************************************************************/ + +#pragma once +#include "ECS_Base/Components/SHComponent.h" +#include "ECS_Base/SHECSMacros.h" + +namespace SHADE +{ + class SHAudioSourceComponent : public SHComponent + { + public: + /** + * @brief default constructor for the component + * + */ + SHAudioSourceComponent() = default; + + + /** + * @brief default destructor for the component + * + */ + ~SHAudioSourceComponent() = default; + + /** + * @brief play the sound + * + * @param index where the sound is in the index + */ + void PlaySoundSFX(EntityID id, bool loop = false, bool spatial = false, float min = 5.0f, float max = 1000.f); + + void PlaySoundBGM(EntityID id, bool loop = false, bool spatial = false, float min = 5.0f, float max = 1000.f); + + /** + * @brief Stop the sound + * + * @param index where the sound is in the index + */ + void StopSound(EntityID id); + + /** + * @brief Mute the sound + * + * @param index where the sound is in the index + */ + void SetMute(EntityID id, bool mute); + + private: + + }; +}//namespace SHADE + diff --git a/SHADE_Engine/src/AudioSystem/SHAudioSystem.cpp b/SHADE_Engine/src/AudioSystem/SHAudioSystem.cpp new file mode 100644 index 00000000..be9ee832 --- /dev/null +++ b/SHADE_Engine/src/AudioSystem/SHAudioSystem.cpp @@ -0,0 +1,557 @@ +#include "SHpch.h" +#include "SHAudioSystem.h" +#include "Scene/SHSceneManager.h" +#include "ECS_Base/Managers/SHComponentManager.h" +#include "ECS_Base/Managers/SHSystemManager.h" +#include "ECS_Base/Managers/SHEntityManager.h" + +#include + +#include "AudioSystem/SHAudioListenerComponent.h" +#include "AudioSystem/SHAudioSourceComponent.h" +#include "Math/Transform/SHTransformComponent.h" +#pragma warning(push) +#pragma warning(disable:26812) //disable warning about preference of enum class over enum as ImGuizmo uses enums +#include +#include +#include +#include + +namespace SHADE +{ + SHAudioSystem::SHAudioSystem() + : fmodStudioSystem(nullptr) + , extraDriverData(nullptr) + , soundList() + , bgmChannelGroup(nullptr) + , sfxChannelGroup(nullptr) + , masterGroup(nullptr) + , audioChannels() + , result(FMOD_RESULT_FORCEINT) + , bgmVolume(1.F) + , sfxVolume(1.F) + , masterVolume(1.0F) + , version(0) + , speakerMode(FMOD_SPEAKERMODE_5POINT1) + , paused(false) + { + result = FMOD::Studio::System::create(&fmodStudioSystem); + ErrorCheck(); + } + + SHAudioSystem::~SHAudioSystem() + { + } + + void SHADE::SHAudioSystem::Init() + { + + SHADE::SHComponentManager::CreateComponentSparseSet(); + SHADE::SHComponentManager::CreateComponentSparseSet(); + + denseListener = &SHComponentManager::GetDense(); + fmodStudioSystem->getCoreSystem(&fmodSystem); + + result = fmodStudioSystem->initialize(AUDIO_SYS_MAX_CHANNELS, AUDIO_SYS_MAX_CHANNELS, FMOD_STUDIO_INIT_NORMAL, extraDriverData); + ErrorCheck(); + + fmodSystem->setSoftwareFormat(0, speakerMode, 0); + + result = fmodSystem->createChannelGroup("SFX", &sfxChannelGroup); + ErrorCheck(); + + result = fmodSystem->createChannelGroup("BGM", &bgmChannelGroup); + ErrorCheck(); + + result = fmodSystem->getMasterChannelGroup(&masterGroup); + ErrorCheck(); + + result = masterGroup->addGroup(bgmChannelGroup); + ErrorCheck(); + + result = masterGroup->addGroup(sfxChannelGroup); + ErrorCheck(); + + bgmChannelGroup->setVolume(bgmVolume); + sfxChannelGroup->setVolume(sfxVolume); + masterGroup->setVolume(masterVolume); + + //SHResourceManager::LoadAllAudio(system, soundList); + + + LoadBank("../../Assets/Audio/Master.bank"); + LoadBank("../../Assets/Audio/Master.strings.bank"); + //LoadBank("../../Assets/Audio/Music.bank"); + LoadBank("../../Assets/Audio/footsteps.bank"); + + //auto clip = CreateAudioClip("event:/Characters/sfx_footsteps_human"); + //clip->Play(); + //PlayEventOnce("event:/Characters/sfx_footsteps_raccoon"); + //PlayEventOnce("event:/SFX/Dawn/Dawn_Attack"); + } + + void SHADE::SHAudioSystem::Run(float dt) + { + static_cast(dt); + if (GetKeyState(VK_SPACE) & 0x8000) + PlayEventOnce("event:/Characters/sfx_footsteps_raccoon"); + + fmodStudioSystem->update(); + if (!denseListener->empty()) + { + SHAudioListenerComponent& listener = denseListener->at(0); + SHTransformComponent* listenerTransform = SHComponentManager::GetComponent_s(listener.GetEID()); + if (listenerTransform) + { + listener.SetPos(listenerTransform->GetLocalPosition()); + listener.SetForward({ (listenerTransform->GetLocalScale()[0] > 0.f) ? 1.f : -1.f, 0.f, 0.f }); + FMOD_VECTOR pos = { listener.pos[0] ,listener.pos[1] ,0.f }; + FMOD_VECTOR forward = { listener.forward[0] ,listener.forward[1] ,listener.forward[2] }; + FMOD_VECTOR up = { listener.up[0] ,listener.up[1] ,listener.up[2] }; + fmodSystem->set3DListenerAttributes(0, &pos, nullptr, &forward, &up); + } + } + } + + SHAudioSystem::AudioRoutine::AudioRoutine() + : SHSystemRoutine("Audio Routine", false) {} + + void SHAudioSystem::AudioRoutine::Execute(double dt) noexcept + { + reinterpret_cast(system)->Run(dt); + } + + void SHADE::SHAudioSystem::Exit() + { + for (auto& event : eventMap) + { + result = event.second->releaseAllInstances(); + ErrorCheck(); + } + + for (auto& bank : bankMap) + { + result = bank.second->unload(); + ErrorCheck(); + } + + for (auto& sound : soundList) + { + result = sound.second->release(); + ErrorCheck(); + } + + if (bgmChannelGroup) + { + result = bgmChannelGroup->release(); + ErrorCheck(); + } + + if (sfxChannelGroup) + { + result = sfxChannelGroup->release(); + ErrorCheck(); + } + + if (fmodStudioSystem) + { + result = fmodStudioSystem->release(); + ErrorCheck(); + } + } + + void SHAudioSystem::ErrorCheck() const + { + if (result != FMOD_OK) + std::cerr << "Audio system error: " << FMOD_ErrorString(result) << std::endl; + } + + void SHAudioSystem::PlayEventOnce(const char* path, bool isSFX, EntityID eid, bool spatial) + { + if (paused) + return; + auto it = eventMap.find(path); + if (it != eventMap.end()) + { + FMOD::Studio::EventInstance* event = nullptr; + it->second->createInstance(&event); + if (event) + { + + event->setVolume(masterVolume * (isSFX ? sfxVolume : bgmVolume)); + if (spatial) + { + if (SHTransformComponent* audioTransform = SHComponentManager::GetComponent_s(eid)) + { + FMOD_3D_ATTRIBUTES attributes{ {} }; + attributes.forward.z = 1.0f; + attributes.up.y = 1.0f; + SHAudioListenerComponent& listener = denseListener->at(0); + SHTransformComponent* listenerTransform = SHComponentManager::GetComponent_s(listener.GetEID()); + if (listenerTransform) + { + attributes.position.z = listenerTransform->GetLocalPosition()[2]; + } + attributes.position.x = audioTransform->GetLocalPosition()[0]; + attributes.position.y = audioTransform->GetLocalPosition()[1]; + event->set3DAttributes(&attributes); + } + } + event->start(); + event->release(); + } + } + } + + void SHAudioSystem::PlaySFX(EntityID id, EntityID eid, const bool& loop, const bool& spatial, float min, float max) + { + SHSound sound = soundList[id]; + int index = GetAvailableChannelIndex(); + if (index >= 0) + { + unsigned int mode{}; + mode |= (loop ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF); + mode |= (spatial ? FMOD_3D : FMOD_2D); + sound->setMode(mode); + result = fmodSystem->playSound(sound, sfxChannelGroup, false, &audioChannels[index]); + if (spatial && SHComponentManager::HasComponent(eid)) + { + SHTransformComponent* audioTransform = SHComponentManager::GetComponent_s(eid); + FMOD_VECTOR fpos{ audioTransform->GetLocalPosition()[0],audioTransform->GetLocalPosition()[1] ,0.f}; + audioChannels[index]->set3DAttributes(&fpos, nullptr); + audioChannels[index]->setMode(mode); + audioChannels[index]->set3DMinMaxDistance(min, max); + } + ErrorCheck(); + } + } + + void SHAudioSystem::PlayBGM(EntityID id, EntityID eid, const bool& loop, const bool& spatial, float min, float max) + { + SHSound sound = soundList[id]; + int index = GetAvailableChannelIndex(); + if (index >= 0) + { + unsigned int mode{}; + mode |= (loop ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF); + mode |= (spatial ? FMOD_3D : FMOD_2D); + sound->setMode(mode); + result = fmodSystem->playSound(sound, bgmChannelGroup, false, &audioChannels[index]); + if (spatial && SHComponentManager::HasComponent(eid)) + { + SHTransformComponent* audioTransform = SHComponentManager::GetComponent_s(eid); + FMOD_VECTOR fpos{ audioTransform->GetLocalPosition()[0],audioTransform->GetLocalPosition()[1] ,0.f }; + audioChannels[index]->set3DAttributes(&fpos, nullptr); + audioChannels[index]->setMode(mode); + audioChannels[index]->set3DMinMaxDistance(min, max); + } + ErrorCheck(); + } + } + + void SHAudioSystem::SetMute(EntityID id, bool mute) + { + SHSound sound; + for (auto& channel : audioChannels) + { + channel->getCurrentSound(&sound); + if (soundList.find(id)->second == sound) // tbc + { + channel->setMute(mute); + } + } + } + + void SHAudioSystem::StopSound(EntityID id) + { + SHSound sound; + for (auto& channel : audioChannels) + { + channel->getCurrentSound(&sound); + if (soundList.find(id)->second == sound) // tbc + { + channel->stop(); + } + } + } + + void SHAudioSystem::StopAllSounds() + { + for (auto& channel : audioChannels) + { + bool isPlaying{ false }; + if (channel->isPlaying(&isPlaying) == FMOD_OK && isPlaying) + channel->stop(); + } + } + + std::optional SHAudioSystem::GetEventGUID(const char* path) + { + FMOD_GUID guid; + FMOD::Studio::EventDescription* event; + result = fmodStudioSystem->getEvent(path, &event); + ErrorCheck(); + if (result == FMOD_OK) + { + result = event->getID(&guid); + ErrorCheck(); + if (result == FMOD_OK) + { + return guid; + } + } + return std::nullopt; + } + + AudioClip* SHAudioSystem::CreateAudioClip(const char* path) + { + AudioClipID newID{}; + AudioClip* clip = nullptr; + auto it = eventMap.find(path); + if (it != eventMap.end()) + { + FMOD::Studio::EventInstance* event = nullptr; + it->second->createInstance(&event); + if (event) + { + //event->start(); + newID = clipID; + clipID++; + eventInstances.emplace(newID, AudioClip(newID, event)); + clip = &eventInstances[newID]; + } + } + return clip; + } + + //std::vector SHAudioSystem::GetAllEvents() + //{ + // int count{}; + // stringsBank->getEventCount(&count); + + // std::vector events(count); + // auto eventData = events.data(); + // int finalCount{}; + // stringsBank->getEventList(eventData, count, &finalCount); + // std::vector eventNames; + // std::transform(events.begin(), events.end(), std::back_inserter(eventNames), [](FMOD::Studio::EventDescription* event) + // { + // char path[256]; + // event->getPath(path, 256, nullptr); + // return path; + // }); + // return eventNames; + //} + + //void SHAudioSystem::PlayEventInstance(FMOD::Studio::EventInstance* instance, bool isSFX, EntityID eid, bool spatial) + //{ + // instance->setVolume(masterVolume * (isSFX ? sfxVolume : bgmVolume)); + // FMOD::ChannelGroup* channelGroup; + // if (spatial) + // { + // if (SHTransformComponent* audioTransform = SHComponentManager::GetComponent_s(eid)) + // { + // FMOD_3D_ATTRIBUTES attributes{ {} }; + // attributes.forward.z = 1.0f; + // attributes.up.y = 1.0f; + // SHAudioListenerComponent& listener = denseListener->at(0); + // SHTransformComponent* listenerTransform = SHComponentManager::GetComponent_s(listener.GetEID()); + // if (listenerTransform) + // { + // attributes.position.z = listenerTransform->GetTranslation()[2]; + // } + // attributes.position.x = audioTransform->GetTranslation()[0]; + // attributes.position.y = audioTransform->GetTranslation()[1]; + // instance->set3DAttributes(&attributes); + // } + // } + // instance->start(); + //} + + int SHAudioSystem::GetAvailableChannelIndex() + { + bool isPlaying = false; + for (int i = 0; i < AUDIO_SYS_MAX_CHANNELS; ++i) + { + audioChannels[i]->isPlaying(&isPlaying); + if (!isPlaying) + return i; + } + return -1; + } + + float SHAudioSystem::GetBgmVolume() + { + return bgmVolume; + } + float SHAudioSystem::GetSfxVolume() + { + return sfxVolume; + } + float SHAudioSystem::GetMasterVolume() + { + return masterVolume; + } + void SHAudioSystem::SetBgmVolume(float const bgmvol) + { + bgmChannelGroup->setVolume(bgmvol); + } + void SHAudioSystem::SetSfxVolume(float const sfxvol) + { + sfxChannelGroup->setVolume(sfxvol); + } + void SHAudioSystem::SetMasterVolume(float const mastervol) + { + masterGroup->setVolume(mastervol); + } + + void SHAudioSystem::SetPaused(bool pause) + { + paused = pause; + for (auto const& channel : audioChannels) + { + channel->setPaused(paused); + } + for (auto const& event : eventMap) + { + int instanceCount = 0; + event.second->getInstanceCount(&instanceCount); + std::vector instances(instanceCount); + event.second->getInstanceList(instances.data(), instances.size(), &instanceCount); + for (auto const& instance : instances) + { + instance->setPaused(pause); + } + } + } + + bool SHAudioSystem::GetPaused() const + { + return paused; + } + + SHVec3 SHAudioSystem::GetListenerPosition() + { + auto &listener = denseListener->at(0); + SHTransformComponent* listenerTransform = SHComponentManager::GetComponent_s(listener.GetEID()); + if (listenerTransform) + { + return listenerTransform->GetLocalPosition(); + } + return {}; + } + + void SHAudioSystem::LoadBank(const char* path) + { + FMOD::Studio::Bank* bank = nullptr; + result = fmodStudioSystem->loadBankFile(path, FMOD_STUDIO_LOAD_BANK_NORMAL, &bank); + ErrorCheck(); + if (result != FMOD_OK) + return; + bankMap.emplace(path, bank); + bank->loadSampleData(); + int numOfEvents; + bank->getEventCount(&numOfEvents); + if (numOfEvents > 0) + { + std::vector events(numOfEvents); + bank->getEventList(events.data(), numOfEvents, &numOfEvents); + char eventName[512]; + for (int i{}; i < numOfEvents; ++i) + { + FMOD::Studio::EventDescription* event = events[i]; + event->getPath(eventName, 512, nullptr); + eventMap.emplace(eventName, event); + } + } + } + + AudioClip::AudioClip(AudioClipID clipID, FMOD::Studio::EventInstance* inst) + :instance(inst), id(clipID) + { + } + + AudioClip::~AudioClip() + { + } + + void AudioClip::Play(bool isSfx) + { + if (!instance) + return; + instance->start(); + auto audioSystem = SHSystemManager::GetSystem(); + instance->setVolume(audioSystem->GetMasterVolume() * (isSfx ? audioSystem->GetSfxVolume() : audioSystem->GetBgmVolume())); + } + + void AudioClip::Play(SHVec3 position, bool isSfx) + { + if (!instance) + return; + instance->start(); + FMOD_3D_ATTRIBUTES attributes{ {} }; + attributes.forward.z = 1.0f; + attributes.up.y = 1.0f; + + auto audioSystem = SHSystemManager::GetSystem(); + SHVec3 listenerPos = audioSystem->GetListenerPosition(); + attributes.position.x = position[0]; + attributes.position.y = position[1]; + attributes.position.z = listenerPos[2]; + instance->set3DAttributes(&attributes); + instance->setVolume(audioSystem->GetMasterVolume() * (isSfx ? audioSystem->GetSfxVolume() : audioSystem->GetBgmVolume())); + } + + void AudioClip::Stop(bool fadeOut) + { + if (!instance) + return; + instance->stop(fadeOut ? FMOD_STUDIO_STOP_ALLOWFADEOUT : FMOD_STUDIO_STOP_IMMEDIATE); + } + + void AudioClip::SetPause(bool pause) + { + if (!instance) + return; + instance->setPaused(pause); + } + + bool AudioClip::IsPaused() + { + if (!instance) + return true; + + bool paused{}; + instance->getPaused(&paused); + return paused; + } + + + void AudioClip::SetParameter(const char* paramName, float value) + { + if (!instance) + return; + instance->setParameterByName(paramName, value); + } + + void AudioClip::SetParameterLabel(const char* paramName, const char* label) + { + if (!instance) + return; + instance->setParameterByNameWithLabel(paramName, label); + } + + float AudioClip::GetParameterValue(const char* paramName) + { + if (!instance) + return {}; + float value{}; + instance->getParameterByName(paramName, &value); + return value; + } + +} + +#pragma warning(pop) + + diff --git a/SHADE_Engine/src/AudioSystem/SHAudioSystem.h b/SHADE_Engine/src/AudioSystem/SHAudioSystem.h new file mode 100644 index 00000000..04fad1f0 --- /dev/null +++ b/SHADE_Engine/src/AudioSystem/SHAudioSystem.h @@ -0,0 +1,110 @@ +#pragma once +#include +#include +#include +#include +#include +#include "ECS_Base/System/SHSystem.h" +#include "ECS_Base/System/SHSystemRoutine.h" +#include "ECS_Base/SHECSMacros.h" +#include "Math/SHMath.h" +#include +#include +#include "SH_API.h" +#define AUDIO_SYS_MAX_CHANNELS 1024 + +namespace SHADE +{ + typedef FMOD::Sound* SHSound; + typedef FMOD::Studio::Bank* SHBank; + + class SHAudioListenerComponent; + + typedef uint64_t AudioClipID; + + class AudioClip + { + public: + AudioClip() = default; + AudioClip(AudioClipID clipID, FMOD::Studio::EventInstance* inst); + ~AudioClip(); + void Play(bool isSfx = true); + void Play(SHVec3 position, bool isSfx = true); + void Stop(bool fadeOut = true); + + void SetPause(bool pause); + bool IsPaused(); + void SetParameter(const char* paramName, float value); + void SetParameterLabel(const char* paramName, const char* label); + float GetParameterValue(const char* paramName); + friend class SHAudioSystem; + private: + FMOD::Studio::EventInstance* instance; + AudioClipID id; + }; + + class SH_API SHAudioSystem : public SHSystem + { + public: + SHAudioSystem(); + ~SHAudioSystem(); + + void Init(); + void Run(float dt); + class SH_API AudioRoutine final : public SHSystemRoutine + { + public: + AudioRoutine(); + void Execute(double dt) noexcept override final; + }; + void Exit(); + + int GetAvailableChannelIndex(); + /*std::vector::size_type CreateSound(const char* filepath, bool loop = false);*/ + void PlaySFX(EntityID id, EntityID eid, const bool& loop, const bool& spatial, float min = 5.0f, float max = 1000.0f); + void PlayBGM(EntityID id, EntityID eid, const bool& loop, const bool& spatial, float min = 5.0f, float max = 1000.0f); + void PlayEventOnce(const char* path, bool isSFX = true, EntityID eid = MAX_EID, bool spatial = false); + void SetMute(EntityID id, bool); + void StopSound(EntityID id); + void StopAllSounds(); + + std::optional GetEventGUID(const char* path); + AudioClip* CreateAudioClip(const char* path); + //std::vector GetAllEvents(); + + float GetBgmVolume(); + float GetSfxVolume(); + float GetMasterVolume(); + void SetBgmVolume(float const bgmvol); + void SetSfxVolume(float const sfxvol); + void SetMasterVolume(float const mastervol); + void SetPaused(bool pause); + bool GetPaused() const; + SHVec3 GetListenerPosition(); + void LoadBank(const char* path); + private: + FMOD::Studio::System* fmodStudioSystem; + FMOD::System* fmodSystem; + bool paused; + void ErrorCheck() const; + + void* extraDriverData; + std::unordered_map soundList; + //std::unordered_map bankMap; + std::unordered_map bankMap; + std::unordered_map eventMap; + std::unordered_map eventInstances; + FMOD::ChannelGroup* bgmChannelGroup, * sfxChannelGroup, * masterGroup; + FMOD::Channel* audioChannels[AUDIO_SYS_MAX_CHANNELS]; + FMOD_RESULT result; + float bgmVolume, sfxVolume, masterVolume; + unsigned int version; + FMOD_SPEAKERMODE speakerMode; + SHBank masterBank, stringsBank, musicBank, sfxBank; //To do: change to map of banks loaded by resource manager + + std::vector* denseListener; + AudioClipID clipID = 0; + }; + +} + diff --git a/SHADE_Engine/src/ECS_Base/UnitTesting/SHTestComponents.h b/SHADE_Engine/src/ECS_Base/UnitTesting/SHTestComponents.h index e2e53d6b..b95a0233 100644 --- a/SHADE_Engine/src/ECS_Base/UnitTesting/SHTestComponents.h +++ b/SHADE_Engine/src/ECS_Base/UnitTesting/SHTestComponents.h @@ -1,6 +1,7 @@ #pragma once #include "../Components/SHComponent.h" +#include namespace SHADE { @@ -27,4 +28,50 @@ namespace SHADE std::string value{}; }; + class SHComponent_ENUM : public SHComponent + { + public: + enum class Option + { + OPT_A, + OPT_B, + OPT_C + }; + + bool boolTest{}; + int intTest{}; + float floatTest{}; + double doubleTest{}; + long longTest{}; + uint8_t uint8Test{}; + uint16_t uint16Test{}; + uint32_t uint32Test{}; + uint64_t uint64Test{}; + + + Option option; + RTTR_ENABLE() + }; + + RTTR_REGISTRATION + { + using namespace rttr; + registration::enumeration("Option") + ( + value("Option A", SHComponent_ENUM::Option::OPT_A), + value("Option B", SHComponent_ENUM::Option::OPT_B), + value("Option C", SHComponent_ENUM::Option::OPT_C) + ); + rttr::registration::class_("Enum Component") + .property("Option", &SHComponent_ENUM::option) + .property("boolTest", &SHComponent_ENUM::boolTest) + .property("intTest", &SHComponent_ENUM::intTest)( metadata("MIN", 0.0f), metadata("MAX", 1.f)) + .property("floatTest", &SHComponent_ENUM::floatTest)(metadata("MIN", 0.0f), metadata("MAX", 1.f)) + .property("doubleTest", &SHComponent_ENUM::doubleTest)(metadata("MIN", 0.0f), metadata("MAX", 1.f)) + .property("uint8Test", &SHComponent_ENUM::uint8Test)(metadata("MIN", 0.0f), metadata("MAX", 1.f)) + .property("uint16Test", &SHComponent_ENUM::uint16Test)(metadata("MIN", 0.0f), metadata("MAX", 1.f)) + .property("uint32Test", &SHComponent_ENUM::uint32Test)(metadata("MIN", 0.0f), metadata("MAX", 1.f)) + .property("uint64Test", &SHComponent_ENUM::uint64Test)(metadata("MIN", 0.0f), metadata("MAX", 1.f)); + } + } \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 080cbf2c..2d326d09 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -12,6 +12,7 @@ #include "Editor/IconsMaterialDesign.h" #include "ECS_Base/Components/SHComponent.h" #include "Editor/SHEditorWidgets.hpp" +#include "Reflection/SHReflectionMetadata.h" namespace SHADE { template::value, bool> = true> @@ -55,7 +56,124 @@ namespace SHADE { auto const& type = property.get_type(); - if (type == rttr::type::get()) + if(type.is_enumeration()) + { + auto enumAlign = type.get_enumeration(); + auto names = enumAlign.get_names(); + std::vector list; + for(auto const& name : names) + list.push_back(name.data()); + ComboBox(property.get_name().data(), list, [component, property]{return property.get_value(component).to_int();}, [component, property](int const& idx) + { + auto enumAlign = property.get_enumeration(); + auto values = enumAlign.get_values(); + auto it = std::next(values.begin(), idx); + property.set_value(component, *it); + }); + } + else if(type.is_arithmetic()) + { + if (type == rttr::type::get()) + { + CheckBox(property.get_name().data(), [component, property]{return property.get_value(component).to_bool();}, [component, property](bool const& result){property.set_value(component, result);}); + } + //else if (type == rttr::type::get()) + //{ + // + //} + else if (type == rttr::type::get() || type == rttr::type::get() || type == rttr::type::get() || type == rttr::type::get()) + { + auto metaMin = property.get_metadata(META::min); + auto metaMax = property.get_metadata(META::max); + if(metaMin && metaMax) + { + SliderInt(property.get_name().data(), metaMin.template get_value(), metaMin.template get_value(), [component, property]{return property.get_value(component).to_int();}, [component, property](int const& result){property.set_value(component, result);}); + } + else + { + DragInt(property.get_name().data(), [component, property]{return property.get_value(component).to_int();}, [component, property](int const& result){property.set_value(component, result);}); + } + } + else if (type == rttr::type::get()) + { + auto metaMin = property.get_metadata(META::min); + auto metaMax = property.get_metadata(META::max); + if(metaMin.is_valid() && metaMax.is_valid()) + { + SliderScalar(property.get_name().data(), ImGuiDataType_U8, metaMin.template get_value(), metaMax.template get_value(), [component, property]{return property.get_value(component).to_uint8();}, [component, property](uint8_t const& result){property.set_value(component, result);},"%zu"); + } + else + { + DragScalar(property.get_name().data(), ImGuiDataType_U8, [component, property]{return property.get_value(component).to_uint8();}, [component, property](uint8_t const& result){property.set_value(component, result);},0.1f,0,0,"%zu"); + } + } + else if (type == rttr::type::get()) + { + auto metaMin = property.get_metadata(META::min); + auto metaMax = property.get_metadata(META::max); + if(metaMin.is_valid() && metaMax.is_valid()) + { + SliderScalar(property.get_name().data(), ImGuiDataType_U16, metaMin.template get_value(), metaMin.template get_value(), [component, property]{return property.get_value(component).to_uint16();}, [component, property](uint16_t const& result){property.set_value(component, result);},"%zu"); + } + else + { + DragScalar(property.get_name().data(), ImGuiDataType_U16, [component, property]{return property.get_value(component).to_uint16();}, [component, property](uint16_t const& result){property.set_value(component, result);},0.1f,0,0,"%zu"); + } + } + else if (type == rttr::type::get()) + { + auto metaMin = property.get_metadata(META::min); + auto metaMax = property.get_metadata(META::max); + if (metaMin.is_valid() && metaMax.is_valid()) + { + SliderScalar(property.get_name().data(), ImGuiDataType_U32, metaMin.template get_value(), metaMin.template get_value(), [component, property]{ return property.get_value(component).to_uint32(); }, [component, property](uint32_t const& result){property.set_value(component, result); },"%zu"); + } + else + { + DragScalar(property.get_name().data(), ImGuiDataType_U32, [component, property]{ return property.get_value(component).to_uint32(); }, [component, property](uint32_t const& result){property.set_value(component, result); },0.1f,0,0,"%zu"); + } + } + else if (type == rttr::type::get()) + { + auto metaMin = property.get_metadata(META::min); + auto metaMax = property.get_metadata(META::max); + if(metaMin.is_valid() && metaMax.is_valid()) + { + SliderScalar(property.get_name().data(), ImGuiDataType_U64, metaMin.template get_value(), metaMin.template get_value(), [component, property]{return property.get_value(component).to_uint64();}, [component, property](uint64_t const& result){property.set_value(component, result);},"%zu"); + } + else + { + DragScalar(property.get_name().data(), ImGuiDataType_U64, [component, property]{return property.get_value(component).to_uint64();}, [component, property](uint64_t const& result){property.set_value(component, result);},0.1f,0,0,"%zu"); + } + } + else if (type == rttr::type::get()) + { + auto metaMin = property.get_metadata(META::min); + auto metaMax = property.get_metadata(META::max); + if(metaMin.is_valid() && metaMax.is_valid()) + { + SliderFloat(property.get_name().data(), metaMin.template get_value(), metaMin.template get_value(), [component, property]{return property.get_value(component).to_float();}, [component, property](float const& result){property.set_value(component, result);}); + } + else + { + DragFloat(property.get_name().data(), [component, property]{return property.get_value(component).to_float();}, [component, property](float const& result){property.set_value(component, result);}); + } + } + else if (type == rttr::type::get()) + { + auto metaMin = property.get_metadata(META::min); + auto metaMax = property.get_metadata(META::max); + if(metaMin.is_valid() && metaMax.is_valid()) + { + SliderScalar(property.get_name().data(), ImGuiDataType_Double, metaMin.template get_value(), metaMin.template get_value(), [component, property]{return property.get_value(component).to_double();}, [component, property](double const& result){property.set_value(component, result);}); + } + else + { + DragScalar(property.get_name().data(), ImGuiDataType_Double, [component, property]{return property.get_value(component).to_double();}, [component, property](double const& result){property.set_value(component, result);}, 0.1f); + } + } + } + else if (type == rttr::type::get()) { DragVec4(property.get_name().data(), { "X", "Y", "Z", "W" }, [component, property]() {return property.get_value(component).template convert(); }, [component, property](SHVec4 vec) {return property.set_value(component, vec); }); } @@ -63,6 +181,11 @@ namespace SHADE { DragVec3(property.get_name().data(), { "X", "Y", "Z" }, [component, property]() {return property.get_value(component).template convert(); }, [component, property](SHVec3 vec) {return property.set_value(component, vec); }); } + else if (type == rttr::type::get()) + { + DragVec2(property.get_name().data(), { "X", "Y"}, [component, property]() {return property.get_value(component).template convert(); }, [component, property](SHVec2 vec) {return property.set_value(component, vec); }); + } + } } else DrawContextMenu(component); diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp index fba9512e..7ba0c609 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp @@ -11,8 +11,12 @@ #include "Editor/SHImGuiHelpers.hpp" #include "Editor/SHEditorWidgets.hpp" #include "SHEditorComponentView.hpp" +#include "ECS_Base/UnitTesting/SHTestComponents.h" #include "Graphics/MiddleEnd/Interface/SHRenderable.h" +#include "ECS_Base/Managers/SHSystemManager.h" +#include "AudioSystem/SHAudioSystem.h" + namespace SHADE { template, bool> = true> @@ -54,11 +58,20 @@ namespace SHADE { DrawComponent(transformComponent); } + if(auto renderableComponent = SHComponentManager::GetComponent_s(eid)) + { + DrawComponent(renderableComponent); + } + if(auto testComponent = SHComponentManager::GetComponent_s(eid)) + { + DrawComponent(testComponent); + } ImGui::Separator(); if(ImGui::BeginMenu(std::format("{} Add Component", ICON_MD_LIBRARY_ADD).data())) { DrawAddComponentButton(eid); DrawAddComponentButton(eid); + DrawAddComponentButton(eid); ImGui::EndMenu(); } } diff --git a/SHADE_Engine/src/Editor/EditorWindow/Profiling/SHEditorProfiler.cpp b/SHADE_Engine/src/Editor/EditorWindow/Profiling/SHEditorProfiler.cpp new file mode 100644 index 00000000..4b36fe5d --- /dev/null +++ b/SHADE_Engine/src/Editor/EditorWindow/Profiling/SHEditorProfiler.cpp @@ -0,0 +1,48 @@ +#include "SHpch.h" +#include "SHEditorProfiler.h" +#include + +#include "ECS_Base/Managers/SHSystemManager.h" +#include "FRC/SHFramerateController.h" + +namespace SHADE +{ + SHEditorProfiler::SHEditorProfiler() + :SHEditorWindow("Profiler", ImGuiWindowFlags_None) + { + } + + void SHEditorProfiler::Init() + { + SHEditorWindow::Init(); + } + + void SHEditorProfiler::Update() + { + SHEditorWindow::Update(); + + const float dt = static_cast(SHFrameRateController::GetRawDeltaTime()); + if(frames.size() > MaxFramesDisplayed) + { + for (size_t i = 1; i < frames.size(); i++) + { + frames[i-1] = frames[i]; + } + frames[frames.size() - 1] = dt; + } + else + { + frames.push_back(dt); + } + if(Begin()) + { + ImGui::PlotLines("DT", frames.data(), static_cast(frames.size()), 0, nullptr, 0.0f, 16.0f); + ImGui::End(); + } + } + + void SHEditorProfiler::Exit() + { + SHEditorWindow::Exit(); + } +} diff --git a/SHADE_Engine/src/Editor/EditorWindow/Profiling/SHEditorProfiler.h b/SHADE_Engine/src/Editor/EditorWindow/Profiling/SHEditorProfiler.h new file mode 100644 index 00000000..3f817a53 --- /dev/null +++ b/SHADE_Engine/src/Editor/EditorWindow/Profiling/SHEditorProfiler.h @@ -0,0 +1,19 @@ +#pragma once + +#include "Editor/EditorWindow/SHEditorWindow.h" +#include +constexpr uint32_t MaxFramesDisplayed = 100; +namespace SHADE +{ + class SHEditorProfiler final : public SHEditorWindow + { + public: + SHEditorProfiler(); + void Init() override; + void Update() override; + void Exit() override; + + private: + std::vector frames; + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h index 2ed34109..d1ebfbf4 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h +++ b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h @@ -1,4 +1,5 @@ #pragma once #include "MenuBar/SHEditorMenuBar.h" //Menu Bar #include "HierarchyPanel/SHHierarchyPanel.h" //Hierarchy Panel -#include "Inspector/SHEditorInspector.h" //Inspector \ No newline at end of file +#include "Inspector/SHEditorInspector.h" //Inspector +#include "Profiling/SHEditorProfiler.h" //Profiler \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/SHEditor.cpp b/SHADE_Engine/src/Editor/SHEditor.cpp index 34ebe6a6..b36518fd 100644 --- a/SHADE_Engine/src/Editor/SHEditor.cpp +++ b/SHADE_Engine/src/Editor/SHEditor.cpp @@ -95,6 +95,7 @@ namespace SHADE CreateEditorWindow(); CreateEditorWindow(); CreateEditorWindow(); + CreateEditorWindow(); SHLOG_INFO("Successfully initialised SHADE Engine Editor") } @@ -106,7 +107,8 @@ namespace SHADE for (const auto& window : editorWindows | std::views::values) { - window->Update(); + if(window->isOpen) + window->Update(); } if(ImGui::IsKeyDown(ImGuiKey_LeftShift) && ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyReleased(ImGuiKey_Z)) @@ -292,6 +294,8 @@ namespace SHADE imguiCommandBuffer->EndRecording(); gfxSystem->GetQueue()->SubmitCommandBuffer({ imguiCommandBuffer }, {}, {}, vk::PipelineStageFlagBits::eNone, {}); + gfxSystem->GetDevice()->WaitIdle(); + ImGui_ImplVulkan_DestroyFontUploadObjects(); renderGraph->GetNode("ImGui Node")->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle& cmd) { diff --git a/SHADE_Engine/src/Editor/SHEditorWidgets.hpp b/SHADE_Engine/src/Editor/SHEditorWidgets.hpp index 4a934e8c..6dcf5dfd 100644 --- a/SHADE_Engine/src/Editor/SHEditorWidgets.hpp +++ b/SHADE_Engine/src/Editor/SHEditorWidgets.hpp @@ -80,13 +80,13 @@ namespace SHADE return valueChanged; } - static bool DragVec2(const std::string& fieldLabel, std::vectorconst& componentLabels, std::function get, + static bool DragVec2(const std::string& fieldLabel, std::vectorconst& componentLabels, std::function get, std::function set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f, ImGuiSliderFlags flags = 0) { SHVec2 values = get(); bool changed = false; - if (DragN(fieldLabel, componentLabels, {&values.x, &values.y}, speed, displayFormat, valueMin, valueMax, flags)) + if (DragN(fieldLabel, componentLabels, { &values.x, &values.y }, speed, displayFormat, valueMin, valueMax, flags)) { changed = true; } @@ -95,22 +95,22 @@ namespace SHADE { if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left)) SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), false); - else if(ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), true); - else if(ImGui::IsItemDeactivatedAfterEdit()) + else if (ImGui::IsItemDeactivatedAfterEdit()) SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), false); } return changed; } - static bool DragVec3(const std::string& fieldLabel, std::vectorconst& componentLabels, std::function get, + static bool DragVec3(const std::string& fieldLabel, std::vectorconst& componentLabels, std::function get, std::function set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f, ImGuiSliderFlags flags = 0) { SHVec3 values = get(); bool changed = false; - if (DragN(fieldLabel, componentLabels, {&values.x, &values.y, &values.z}, speed, displayFormat, valueMin, valueMax, flags)) + if (DragN(fieldLabel, componentLabels, { &values.x, &values.y, &values.z }, speed, displayFormat, valueMin, valueMax, flags)) { changed = true; } @@ -119,22 +119,22 @@ namespace SHADE { if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f)) SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), false); - else if(ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), true); - else if(ImGui::IsItemDeactivatedAfterEdit()) + else if (ImGui::IsItemDeactivatedAfterEdit()) SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), false); } return changed; } - static bool DragVec4(const std::string& fieldLabel, std::vectorconst& componentLabels, std::function get, + static bool DragVec4(const std::string& fieldLabel, std::vectorconst& componentLabels, std::function get, std::function set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f, ImGuiSliderFlags flags = 0) { SHVec4 values = get(); bool changed = false; - if (DragN(fieldLabel, componentLabels, {&values.x, &values.y, &values.z, &values.w}, speed, displayFormat, valueMin, valueMax, flags)) + if (DragN(fieldLabel, componentLabels, { &values.x, &values.y, &values.z, &values.w }, speed, displayFormat, valueMin, valueMax, flags)) { changed = true; } @@ -143,9 +143,9 @@ namespace SHADE { if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f)) SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), false); - else if(ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), true); - else if(ImGui::IsItemDeactivatedAfterEdit()) + else if (ImGui::IsItemDeactivatedAfterEdit()) SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), false); } @@ -155,7 +155,7 @@ namespace SHADE //#==============================================================# //|| Widget Extensions || //#==============================================================# - + static bool CheckBox(std::string const& label, std::function get, std::function set) { bool value = get(); @@ -182,6 +182,149 @@ namespace SHADE return true; } - + static bool InputText(const std::string& label, const std::function get, + const std::function set, ImGuiInputTextFlags flag = 0, + ImGuiInputTextCallback callback = (ImGuiInputTextCallback)0, void* userData = (void*)0) + { + std::string text = get(); + if (ImGui::InputText(label.c_str(), &text, flag, callback, userData)) + { + if (ImGui::IsItemDeactivatedAfterEdit()) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), text, set)), false); + + return true; + } + return false; + } + + template + static bool DragScalar(const std::string& fieldLabel, ImGuiDataType data_type, std::function get, std::function set, + float speed = 1.0f, T p_min = T(), T p_max = T(), const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0) + { + T value = get(); + std::cout << value <<" \n"; + //bool hasChange = ImGui::DragScalar(fieldLabel.c_str(), data_type, &value, speed, &p_min, &p_max, displayFormat, flags); + + if (ImGui::DragScalar(fieldLabel.c_str(), data_type, &value, speed, &p_min, &p_max, displayFormat, flags)) + { + if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), true); + else if (ImGui::IsItemDeactivatedAfterEdit()) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + + return true; + } + return false; + } + + static bool DragFloat(const std::string& fieldLabel, std::function get, std::function set, + float speed = 0.1f, float p_min = float(), float p_max = float(), const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0) + { + float value = get(); + //bool hasChange = ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags); + if (ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags)) + { + if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), true); + else if (ImGui::IsItemDeactivatedAfterEdit()) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + + return true; + } + + return false; + } + + static bool DragInt(const std::string& fieldLabel, std::function get, std::function set, + float speed = 1.0f, int p_min = int(), int p_max = int(), const char* displayFormat = "%d", ImGuiSliderFlags flags = 0) + { + int value = get(); + //bool hasChange = ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags); + if (ImGui::DragInt(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags)) + { + if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), true); + else if (ImGui::IsItemDeactivatedAfterEdit()) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + + return true; + } + + return false; + } + template + static bool SliderScalar(const std::string& fieldLabel, ImGuiDataType data_type, T min, T max, std::function get, std::function set, + const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0) + { + T value = get(); + if (ImGui::SliderScalar(fieldLabel.c_str(), data_type, &value, &min, &max, displayFormat, flags)) + { + if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), true); + + return true; + } + + return false; + } + + static bool SliderFloat(const std::string& fieldLabel, float min, float max, std::function get, std::function set, + const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0) + { + float value = get(); + if (ImGui::SliderFloat(fieldLabel.c_str(), &value, min, max, displayFormat, flags)) + { + if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), true); + + + return true; + } + + return false; + } + + static bool SliderInt(const std::string& fieldLabel, int min, int max, std::function get, std::function set, + const char* displayFormat = "%d", ImGuiSliderFlags flags = 0) + { + int value = get(); + if (ImGui::SliderInt(fieldLabel.c_str(), &value, min, max, displayFormat, flags)) + { + if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), true); + + return true; + } + + return false; + } + + static bool ComboBox(const std::string& fieldLabel, std::vector list, std::function get, std::function set) + { + bool edited = false; + int selected = get(); + ImGui::PushID(fieldLabel.c_str()); + ImGui::Text(fieldLabel.c_str()); ImGui::SameLine(); + + if (edited = ImGui::Combo("##Combo", &selected, list.data(), list.size())) + { + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), selected, set)), false); + } + ImGui::PopID(); + return edited; + } + }//namespace SHADE diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.h b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.h index 91112496..9a533d06 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.h +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.h @@ -39,8 +39,10 @@ namespace SHADE std::vector Limits = { { vk::DescriptorType::eCombinedImageSampler, 100 }, - { vk::DescriptorType::eUniformBuffer, 100 }, - { vk::DescriptorType::eUniformBufferDynamic, 100 } + { vk::DescriptorType::eUniformBuffer, 100 }, + { vk::DescriptorType::eUniformBufferDynamic, 100 }, + { vk::DescriptorType::eStorageImage, 100}, + { vk::DescriptorType::eStorageBufferDynamic, 100 } }; /// /// Maximum number of descriptor sets allowed diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp index c1732535..e50e717f 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp @@ -155,7 +155,7 @@ namespace SHADE */ /***************************************************************************/ - void SHVkDescriptorSetGroup::ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span, Handle>> const& imageViewsAndSamplers) noexcept + void SHVkDescriptorSetGroup::ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span, Handle, vk::ImageLayout>> const& imageViewsAndSamplers) noexcept { // Find the target writeDescSet BindingAndSetHash writeHash = binding; @@ -170,9 +170,10 @@ namespace SHADE for (uint32_t i = 0; i < imageViewsAndSamplers.size(); ++i) { // write sampler and image view - auto& ivs = imageViewsAndSamplers[i]; - writeInfo.descImageInfos[i].imageView = ivs.first->GetImageView(); - writeInfo.descImageInfos[i].sampler = ivs.second->GetVkSampler(); + auto& [view, sampler, layout] = imageViewsAndSamplers[i]; + writeInfo.descImageInfos[i].imageView = view->GetImageView(); + writeInfo.descImageInfos[i].sampler = sampler->GetVkSampler(); + writeInfo.descImageInfos[i].imageLayout = layout; } } diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h index d92d55e9..f2b886e8 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h @@ -1,5 +1,7 @@ #pragma once +#include + // Project Includes #include "Graphics/SHVulkanIncludes.h" #include "Resource/Handle.h" @@ -63,7 +65,7 @@ namespace SHADE void UpdateDescriptorSetImages(uint32_t set, uint32_t binding) noexcept; void UpdateDescriptorSetBuffer(uint32_t set, uint32_t binding) noexcept; - void ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span, Handle>> const& imageViewsAndSamplers) noexcept; + void ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span, Handle, vk::ImageLayout>> const& imageViewsAndSamplers) noexcept; void ModifyWriteDescBuffer (uint32_t set, uint32_t binding, std::span> const& buffers, uint32_t offset, uint32_t range) noexcept; diff --git a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp index 5ed17511..3fa797bf 100644 --- a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp +++ b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp @@ -16,6 +16,7 @@ #include "Graphics/Framebuffer/SHVkFramebuffer.h" #include "Graphics/Images/SHVkImageView.h" #include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" +#include "Graphics/Images/SHVkSampler.h" namespace SHADE { @@ -85,6 +86,17 @@ namespace SHADE } + uint32_t SHVkLogicalDevice::ComputeAlignedBufferSize(uint32_t originalSize, size_t alignmentSize) const noexcept + { + uint32_t alignedSize = originalSize; + //uint32_t minBuffer + if (alignmentSize > 0) + { + alignedSize = (alignedSize + alignmentSize - 1) & ~(alignmentSize - 1); + } + return alignedSize; + } + /***************************************************************************/ /*! @@ -176,6 +188,7 @@ namespace SHADE // point and lines fill mode features.fillModeNonSolid = true; features.samplerAnisotropy = VK_TRUE; + features.multiDrawIndirect = true; // for wide lines features.wideLines = true; @@ -288,13 +301,12 @@ namespace SHADE uint32_t SHVkLogicalDevice::PadUBOSize(uint32_t originalSize) const noexcept { - uint32_t alignedSize = originalSize; - //uint32_t minBuffer - if (uboBufferMemoryAlignment > 0) - { - alignedSize = (alignedSize + uboBufferMemoryAlignment - 1) & ~(uboBufferMemoryAlignment - 1); - } - return alignedSize; + return ComputeAlignedBufferSize(originalSize, uboBufferMemoryAlignment); + } + + uint32_t SHVkLogicalDevice::PadSSBOSize(uint32_t originalSize) const noexcept + { + return ComputeAlignedBufferSize(originalSize, ssboBufferMemoryAlignment); } /***************************************************************************/ @@ -499,6 +511,11 @@ namespace SHADE } + Handle SHVkLogicalDevice::CreateSampler(const SHVkSamplerParams& params) noexcept + { + return SHVkInstance::GetResourceManager().Create (GetHandle(), params); + } + Handle SHVkLogicalDevice::CreateRenderpass(std::span const vkDescriptions, std::vector const& subpasses) noexcept { return SHVkInstance::GetResourceManager().Create (GetHandle(), vkDescriptions, subpasses); diff --git a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h index 8a197ef8..1272f68f 100644 --- a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h +++ b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h @@ -21,7 +21,6 @@ #include "Graphics/Descriptors/SHVkDescriptorSetLayout.h" #include "Graphics/Images/SHVkImage.h" - namespace SHADE { /*-----------------------------------------------------------------------*/ @@ -41,6 +40,8 @@ namespace SHADE class SHShaderBlockInterface; class SHVkDescriptorSetGroup; class SHSubpass; + class SHVkSampler; + struct SHVkSamplerParams; /***************************************************************************/ /*! @@ -102,6 +103,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ void InitializeVMA (void) noexcept; void InitializeQueues (std::initializer_list queueCreateParams) noexcept; + uint32_t ComputeAlignedBufferSize(uint32_t originalSize, size_t typeSize) const noexcept; public: /*-----------------------------------------------------------------------*/ @@ -121,7 +123,8 @@ namespace SHADE // Miscellaneous functions void WaitIdle (void) noexcept; uint32_t FindMemoryType (uint32_t typeFilter, vk::MemoryPropertyFlags properties); - uint32_t PadUBOSize (uint32_t originalSize) const noexcept; + uint32_t PadUBOSize(uint32_t originalSize) const noexcept; + uint32_t PadSSBOSize(uint32_t originalSize) const noexcept; // creation functions Handle CreateSurface (HWND const& windowHandle) const noexcept; @@ -178,6 +181,7 @@ namespace SHADE Handle const& renderpassHdl, Handle subpass ) noexcept; + Handle CreateSampler (const SHVkSamplerParams& params) noexcept; Handle CreateRenderpass (std::span const vkDescriptions, std::vector const& subpasses) noexcept; Handle CreateRenderpass (std::span const vkDescriptions, std::span const spDescs, std::span const spDeps) noexcept; diff --git a/SHADE_Engine/src/Graphics/Images/SHVkImage.cpp b/SHADE_Engine/src/Graphics/Images/SHVkImage.cpp index b8bf273e..b6f20af4 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkImage.cpp +++ b/SHADE_Engine/src/Graphics/Images/SHVkImage.cpp @@ -26,7 +26,7 @@ namespace SHADE */ /***************************************************************************/ - void SHVkImage::PrepStagingBuffer(void* data, uint32_t srcSize) noexcept + void SHVkImage::PrepStagingBuffer(const void* data, uint32_t srcSize) noexcept { // For creation of buffer vk::BufferCreateInfo bufferInfo{}; @@ -70,7 +70,7 @@ namespace SHADE vmaMapMemory(*vmaAllocator, stagingAlloc, &stagingBufferMappedPtr); if (stagingBufferMappedPtr) - std::memcpy(static_cast(stagingBufferMappedPtr), static_cast(data), srcSize); + std::memcpy(static_cast(stagingBufferMappedPtr), static_cast(data), srcSize); const VkDeviceSize offsets = 0; const VkDeviceSize sizes = srcSize; @@ -82,7 +82,7 @@ namespace SHADE SHVkImage::SHVkImage( VmaAllocator const* allocator, SHImageCreateParams const& imageDetails, - unsigned char* data, + const unsigned char* data, uint32_t dataSize, std::span inMipOffsets, VmaMemoryUsage memUsage, diff --git a/SHADE_Engine/src/Graphics/Images/SHVkImage.h b/SHADE_Engine/src/Graphics/Images/SHVkImage.h index 91d4f2d2..39e695a5 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkImage.h +++ b/SHADE_Engine/src/Graphics/Images/SHVkImage.h @@ -107,7 +107,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ - void PrepStagingBuffer(void* data, uint32_t srcSize) noexcept; + void PrepStagingBuffer(const void* data, uint32_t srcSize) noexcept; public: @@ -119,7 +119,7 @@ namespace SHADE SHVkImage( VmaAllocator const* allocator, SHImageCreateParams const& imageDetails, - unsigned char* data, + const unsigned char* data, uint32_t dataSize, std::span inMipOffsets, VmaMemoryUsage memUsage, diff --git a/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp b/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp index b4bbf89b..f12b834d 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp +++ b/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp @@ -1,12 +1,62 @@ +/************************************************************************************//*! +\file SHVkSampler.cpp +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Sep 26, 2022 +\brief Contains definitions for all of the functions of the SHVkSampler 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. +*//*************************************************************************************/ #include "SHpch.h" #include "SHVkSampler.h" +#include "Graphics/Devices/SHVkLogicalDevice.h" + namespace SHADE { - - vk::Sampler SHVkSampler::GetVkSampler(void) const noexcept + /*-----------------------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------------------*/ + SHVkSampler::SHVkSampler(Handle logicalDevice, const SHVkSamplerParams& params) noexcept + : device { logicalDevice } { - return vkSampler; + const vk::SamplerCreateInfo SAMPLER_CREATE_INFO + { + .magFilter = params.magFilter, + .minFilter = params.minFilter, + .mipmapMode = params.mipmapMode, + .addressModeU = params.addressMode, + .addressModeV = params.addressMode, + .addressModeW = params.addressMode, + .minLod = params.minLod, + .maxLod = params.maxLod + }; + + // Create the sampler + vkSampler = device->GetVkLogicalDevice().createSampler(SAMPLER_CREATE_INFO); } + SHVkSampler::SHVkSampler(SHVkSampler&& rhs) noexcept + : vkSampler { rhs.vkSampler } + { + rhs.vkSampler = nullptr; + } + + SHVkSampler::~SHVkSampler() noexcept + { + if (vkSampler) + device->GetVkLogicalDevice().destroySampler(); + } + + /*-----------------------------------------------------------------------------------*/ + /* Overloaded Operators */ + /*-----------------------------------------------------------------------------------*/ + SHADE::SHVkSampler& SHVkSampler::operator=(SHVkSampler&& rhs) noexcept + { + vkSampler = rhs.vkSampler; + rhs.vkSampler = nullptr; + return *this; + } } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/Images/SHVkSampler.h b/SHADE_Engine/src/Graphics/Images/SHVkSampler.h index eae23adf..bb878a69 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkSampler.h +++ b/SHADE_Engine/src/Graphics/Images/SHVkSampler.h @@ -1,28 +1,80 @@ +/************************************************************************************//*! +\file SHVkSampler.h +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Sep 26, 2022 +\brief Contains definitions of the SHVkSampler 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. +*//*************************************************************************************/ #pragma once +// STL Includes +#include +// Project Includes #include "Graphics/SHVulkanIncludes.h" +#include "Resource/Handle.h" namespace SHADE { + /*-----------------------------------------------------------------------------------*/ + /* Forward Declarations */ + /*-----------------------------------------------------------------------------------*/ + class SHVkLogicalDevice; + + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + /*************************************************************************************/ + /*! + \brief + Holds parameters for constructing the SHVkSampler. + */ + /*************************************************************************************/ struct SHVkSamplerParams { - vk::Filter minFilter; - vk::Filter maxFilter; - //vk::Filter maxFilter; + vk::Filter minFilter = vk::Filter::eLinear; + vk::Filter magFilter = vk::Filter::eLinear; + vk::SamplerAddressMode addressMode = vk::SamplerAddressMode::eClampToEdge; + vk::SamplerMipmapMode mipmapMode = vk::SamplerMipmapMode::eLinear; + float minLod = 0; + float maxLod = 0; }; - + + /*************************************************************************************/ + /*! + \brief + Wrapper for a VkSampler. + */ + /*************************************************************************************/ class SHVkSampler { - private: - //! The vulkan sampler handler - vk::Sampler vkSampler; - - public: - SHVkSampler () noexcept; - SHVkSampler (SHVkSampler&& rhs) noexcept; - SHVkSampler&& operator=(SHVkSampler&& rhs) noexcept; + public: + /*---------------------------------------------------------------------------------*/ + /* Constructors */ + /*---------------------------------------------------------------------------------*/ + SHVkSampler(Handle logicalDevice, const SHVkSamplerParams& params = {}) noexcept; + SHVkSampler(SHVkSampler&& rhs) noexcept; + ~SHVkSampler() noexcept; - vk::Sampler GetVkSampler (void) const noexcept; + /*---------------------------------------------------------------------------------*/ + /* Overloaded Operators */ + /*---------------------------------------------------------------------------------*/ + SHVkSampler& operator=(SHVkSampler&& rhs) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + vk::Sampler GetVkSampler(void) const noexcept { return vkSampler; } + + private: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + vk::Sampler vkSampler; //! The Vulkan sampler handler + Handle device; //! Stored device for deallocating the object }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp index f73c5306..b1cd2cd3 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp @@ -22,8 +22,11 @@ of DigiPen Institute of Technology is prohibited. #include "Graphics/Pipeline/SHVkPipeline.h" #include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" +#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" #include "ECS_Base/Managers/SHComponentManager.h" #include "Math/Transform/SHTransformComponent.h" +#include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h" +#include "Graphics/Descriptors/SHVkDescriptorPool.h" namespace SHADE { @@ -120,7 +123,7 @@ namespace SHADE } } - void SHBatch::UpdateMaterialBuffer(uint32_t frameIndex) + void SHBatch::UpdateMaterialBuffer(uint32_t frameIndex, Handle descPool) { if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) { @@ -154,21 +157,17 @@ namespace SHADE if (!matBufferDirty[frameIndex]) return; - // Build CPI Buffer + // Build CPU Buffer char* propsCurrPtr = matPropsData.get(); for (auto& subBatch : subBatches) for (const SHRenderable* renderable : subBatch.Renderables) { renderable->GetMaterial()->ExportProperties(propsCurrPtr); - propsCurrPtr += singleMatPropSize; + propsCurrPtr += singleMatPropAlignedSize; } // Transfer to GPU - SHVkUtil::EnsureBufferAndCopyHostVisibleData - ( - device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast(matPropsDataSize), - vk::BufferUsageFlagBits::eStorageBuffer - ); + rebuildMaterialBuffers(frameIndex, descPool); // This frame is updated matBufferDirty[frameIndex] = false; @@ -207,7 +206,7 @@ namespace SHADE transformDataBuffer[frameIndex]->WriteToMemory(transformData.data(), static_cast(transformData.size() * sizeof(SHMatrix)), 0, 0); } - void SHBatch::Build(Handle _device, uint32_t frameIndex) + void SHBatch::Build(Handle _device, Handle descPool, uint32_t frameIndex) { if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) { @@ -215,6 +214,9 @@ namespace SHADE return; } + // Save logical device + device = _device; + // No need to build as there are no changes if (!isDirty[frameIndex]) return; @@ -247,7 +249,8 @@ namespace SHADE if (!EMPTY_MAT_PROPS) { singleMatPropSize = SHADER_INFO->GetBytesRequired(); - matPropTotalBytes = drawData.size() * singleMatPropSize; + singleMatPropAlignedSize = device->PadSSBOSize(singleMatPropSize); + matPropTotalBytes = numTotalElements * singleMatPropAlignedSize; if (matPropsDataSize < matPropTotalBytes) { matPropsData.reset(new char[matPropTotalBytes]); @@ -267,7 +270,7 @@ namespace SHADE .instanceCount = static_cast(subBatch.Renderables.size()), .firstIndex = subBatch.Mesh->FirstIndex, .vertexOffset = subBatch.Mesh->FirstVertex, - .firstInstance = nextInstanceIndex + .firstInstance = nextInstanceIndex++ }); // Fill in buffers (CPU) @@ -289,7 +292,7 @@ namespace SHADE if (!EMPTY_MAT_PROPS) { renderable->GetMaterial()->ExportProperties(propsCurrPtr); - propsCurrPtr += singleMatPropSize; + propsCurrPtr += singleMatPropAlignedSize; } } } @@ -304,30 +307,21 @@ namespace SHADE const uint32_t DRAW_DATA_BYTES = static_cast(drawData.size() * sizeof(vk::DrawIndexedIndirectCommand)); SHVkUtil::EnsureBufferAndCopyHostVisibleData ( - _device, drawDataBuffer[frameIndex], drawData.data(), DRAW_DATA_BYTES, + device, drawDataBuffer[frameIndex], drawData.data(), DRAW_DATA_BYTES, BuffUsage::eIndirectBuffer ); // - Transform Buffer const uint32_t TF_DATA_BYTES = static_cast(transformData.size() * sizeof(SHMatrix)); SHVkUtil::EnsureBufferAndCopyHostVisibleData ( - _device, transformDataBuffer[frameIndex], transformData.data(), TF_DATA_BYTES, + device, transformDataBuffer[frameIndex], transformData.data(), TF_DATA_BYTES, BuffUsage::eVertexBuffer ); // - Material Properties Buffer - if (matPropsData) - { - SHVkUtil::EnsureBufferAndCopyHostVisibleData - ( - _device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast(matPropsDataSize), - BuffUsage::eStorageBuffer - ); - } + rebuildMaterialBuffers(frameIndex, descPool); + // Mark this frame as no longer dirty isDirty[frameIndex] = false; - - // Save logical device - this->device = _device; } /*---------------------------------------------------------------------------------*/ @@ -341,8 +335,20 @@ namespace SHADE return; } + // Bind all required objects before drawing + static std::array dynamicOffset { 0 }; cmdBuffer->BindPipeline(pipeline); cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRANSFORM, transformDataBuffer[frameIndex], 0); + if (matPropsDescSet[frameIndex]) + { + cmdBuffer->BindDescriptorSet + ( + matPropsDescSet[frameIndex], + vk::PipelineBindPoint::eGraphics, + SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE, + dynamicOffset + ); + } cmdBuffer->DrawMultiIndirect(drawDataBuffer[frameIndex], static_cast(drawData.size())); } @@ -355,4 +361,39 @@ namespace SHADE dirt = true; isCPUBuffersDirty = true; } + + void SHBatch::rebuildMaterialBuffers(uint32_t frameIndex, Handle descPool) + { + if (matPropsData) + { + SHVkUtil::EnsureBufferAndCopyHostVisibleData + ( + device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast(matPropsDataSize), + vk::BufferUsageFlagBits::eStorageBuffer + ); + + if (!matPropsDescSet[frameIndex]) + { + matPropsDescSet[frameIndex] = descPool->Allocate + ( + { SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE] }, + { 0 } + ); + } + std::array, 1> bufferList = { matPropsBuffer[frameIndex] }; + matPropsDescSet[frameIndex]->ModifyWriteDescBuffer + ( + SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE, + SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA, + bufferList, + 0, matPropsDataSize + ); + matPropsDescSet[frameIndex]->UpdateDescriptorSetBuffer + ( + SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE, + SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA + ); + } + } + } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h index d40a66ea..abe691ca 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h @@ -35,6 +35,8 @@ namespace SHADE class SHRenderable; class SHVkLogicalDevice; class SHMaterialInstance; + class SHVkDescriptorSetGroup; + class SHVkDescriptorPool; /*---------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -74,9 +76,9 @@ namespace SHADE void Add(const SHRenderable* renderable); void Remove(const SHRenderable* renderable); void Clear(); - void UpdateMaterialBuffer(uint32_t frameIndex); + void UpdateMaterialBuffer(uint32_t frameIndex, Handle descPool); void UpdateTransformBuffer(uint32_t frameIndex); - void Build(Handle device, uint32_t frameIndex); + void Build(Handle device, Handle descPool, uint32_t frameIndex) ; void Draw(Handle cmdBuffer, uint32_t frameIndex); /*-----------------------------------------------------------------------------*/ @@ -84,34 +86,44 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ Handle GetPipeline() const noexcept { return pipeline; }; - private: + private: + /*-----------------------------------------------------------------------------*/ + /* Type Definition */ + /*-----------------------------------------------------------------------------*/ + using TripleBool = std::array; + using TripleBuffer = std::array, SHGraphicsConstants::NUM_FRAME_BUFFERS>; + using TripleDescSet = std::array, SHGraphicsConstants::NUM_FRAME_BUFFERS>; + /*-----------------------------------------------------------------------------*/ /* Data Members */ /*-----------------------------------------------------------------------------*/ // Resources - Handle device; + Handle device; // Batch Properties - Handle pipeline; + Handle pipeline; std::unordered_set> referencedMatInstances; - std::array matBufferDirty; + TripleBool matBufferDirty; // Batch Tree - std::vector subBatches; - std::array isDirty; - // CPU Buffers - std::vector drawData; - std::vector transformData; - std::unique_ptr matPropsData; - Byte matPropsDataSize = 0; - Byte singleMatPropSize = 0; - bool isCPUBuffersDirty = true; - // GPU Buffers - std::array, SHGraphicsConstants::NUM_FRAME_BUFFERS> drawDataBuffer; - std::array, SHGraphicsConstants::NUM_FRAME_BUFFERS> transformDataBuffer; - std::array, SHGraphicsConstants::NUM_FRAME_BUFFERS> matPropsBuffer; + std::vector subBatches; + TripleBool isDirty; + // CPU Buffers + std::vector drawData; + std::vector transformData; + std::unique_ptr matPropsData; + Byte matPropsDataSize = 0; + Byte singleMatPropAlignedSize = 0; + Byte singleMatPropSize = 0; + bool isCPUBuffersDirty = true; + // GPU Buffers + TripleBuffer drawDataBuffer; + TripleBuffer transformDataBuffer; + TripleBuffer matPropsBuffer; + TripleDescSet matPropsDescSet; /*-----------------------------------------------------------------------------*/ /* Helper Functions */ /*-----------------------------------------------------------------------------*/ void setAllDirtyFlags(); + void rebuildMaterialBuffers(uint32_t frameIndex, Handle descPool); }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.cpp index c4320aac..dc44e7f9 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.cpp @@ -91,12 +91,12 @@ namespace SHADE (*superBatch)->Remove(renderable); } - void SHBatcher::FinaliseBatches(Handle device, uint32_t frameIndex) + void SHBatcher::FinaliseBatches(Handle device, Handle descPool, uint32_t frameIndex) { // Build SuperBatches for (auto& batch : superBatches) { - batch->Build(device, frameIndex); + batch->Build(device, descPool, frameIndex); } } @@ -109,11 +109,11 @@ namespace SHADE superBatches.clear(); } - void SHBatcher::UpdateBuffers(uint32_t frameIndex) + void SHBatcher::UpdateBuffers(uint32_t frameIndex, Handle descPool) { for (auto& batch : superBatches) { - batch->UpdateBuffers(frameIndex); + batch->UpdateBuffers(frameIndex, descPool); } } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.h index 985e8e16..8074899d 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.h @@ -27,6 +27,7 @@ namespace SHADE class SHSuperBatch; class SHVkLogicalDevice; class SHVkCommandBuffer; + class SHVkDescriptorPool; /*---------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -51,9 +52,9 @@ namespace SHADE void PrepareBatches(); void AddToBatch(SHRenderable const* renderable); void RemoveFromBatch(SHRenderable const* renderable); - void FinaliseBatches(Handle device, uint32_t frameIndex); + void FinaliseBatches(Handle device, Handle descPool, uint32_t frameIndex); void ClearBatches(); - void UpdateBuffers(uint32_t frameIndex); + void UpdateBuffers(uint32_t frameIndex, Handle descPool); void RegisterSuperBatch(Handle superBatch); void DeregisterSuperBatch(Handle superBatch); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp index b0173399..0d75dca8 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp @@ -16,6 +16,7 @@ of DigiPen Institute of Technology is prohibited. #include "SHBatch.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" #include "Graphics/MiddleEnd/Interface/SHRenderable.h" +#include "Graphics/Descriptors/SHVkDescriptorPool.h" namespace SHADE { @@ -78,21 +79,21 @@ namespace SHADE batches.clear(); } - void SHSuperBatch::UpdateBuffers(uint32_t frameIndex) + void SHSuperBatch::UpdateBuffers(uint32_t frameIndex, Handle descPool) { for (auto& batch : batches) { - batch.UpdateMaterialBuffer(frameIndex); + batch.UpdateMaterialBuffer(frameIndex, descPool); batch.UpdateTransformBuffer(frameIndex); } } - void SHSuperBatch::Build(Handle device, uint32_t frameIndex) noexcept + void SHSuperBatch::Build(Handle device, Handle descPool, uint32_t frameIndex) noexcept { // Build all batches for (auto& batch : batches) { - batch.Build(device, frameIndex); + batch.Build(device, descPool, frameIndex); } } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h index a09fc64e..9743e7dc 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h @@ -55,8 +55,8 @@ namespace SHADE void Add(const SHRenderable* renderable) noexcept; void Remove(const SHRenderable* renderable) noexcept; void Clear() noexcept; - void UpdateBuffers(uint32_t frameIndex); - void Build(Handle device, uint32_t frameIndex) noexcept; + void UpdateBuffers(uint32_t frameIndex, Handle descPool); + void Build(Handle device, Handle descPool, uint32_t frameIndex) noexcept; void Draw(Handle cmdBuffer, uint32_t frameIndex) noexcept; /*-----------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp index ee6d0e8c..6a7b23f2 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp @@ -7,7 +7,22 @@ namespace SHADE { + /*-----------------------------------------------------------------------------------*/ + /* Static Definitions */ + /*-----------------------------------------------------------------------------------*/ + std::vector> SHGraphicsGlobalData::globalDescSetLayouts; + Handle SHGraphicsGlobalData::globalDescSets; + SHVertexInputState SHGraphicsGlobalData::defaultVertexInputState; + Handle SHGraphicsGlobalData::dummyPipelineLayout; + void SHGraphicsGlobalData::InitHighFrequencyGlobalData(void) noexcept + { + + } + + /*-----------------------------------------------------------------------------------*/ + /* Function Definitions */ + /*-----------------------------------------------------------------------------------*/ void SHGraphicsGlobalData::InitDescSetLayouts(Handle logicalDevice) noexcept { SHVkDescriptorSetLayout::Binding genericDataBinding @@ -87,18 +102,18 @@ namespace SHADE InitDefaultVertexInputState(); } - std::vector> const& SHGraphicsGlobalData::GetDescSetLayouts(void) const noexcept + std::vector> const& SHGraphicsGlobalData::GetDescSetLayouts(void) noexcept { return globalDescSetLayouts; } - SHVertexInputState const& SHGraphicsGlobalData::GetDefaultViState(void) const noexcept + SHVertexInputState const& SHGraphicsGlobalData::GetDefaultViState(void) noexcept { return defaultVertexInputState; } - Handle SHGraphicsGlobalData::GetDummyPipelineLayout(void) const noexcept + Handle SHGraphicsGlobalData::GetDummyPipelineLayout(void) noexcept { return dummyPipelineLayout; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h index 9333d0ab..344c2616 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h @@ -15,31 +15,38 @@ namespace SHADE { private: //! Global descriptor set layouts. Used to allocate descriptor sets - std::vector> globalDescSetLayouts; + static std::vector> globalDescSetLayouts; //! Global Descriptor sets - Handle globalDescSets; + static Handle globalDescSets; //! Default vertex input state (used by everything). - SHVertexInputState defaultVertexInputState; + static SHVertexInputState defaultVertexInputState; //! Since we want to bind global data but can't do so without a pipeline layout, //! we create a dummy pipeline layout to use it for binding. - Handle dummyPipelineLayout; + static Handle dummyPipelineLayout; + + static void InitHighFrequencyGlobalData (void) noexcept; + static void InitDescSetLayouts (Handle logicalDevice) noexcept; + static void InitDefaultVertexInputState (void) noexcept; - void InitDescSetLayouts (Handle logicalDevice) noexcept; - void InitDefaultVertexInputState(void) noexcept; public: + /*-----------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------*/ + SHGraphicsGlobalData() = delete; + /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ - void Init (Handle logicalDevice) noexcept; + static void Init (Handle logicalDevice) noexcept; /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ /*-----------------------------------------------------------------------*/ - std::vector> const& GetDescSetLayouts (void) const noexcept; - SHVertexInputState const& GetDefaultViState (void) const noexcept; - Handle GetDummyPipelineLayout (void) const noexcept; + static std::vector> const& GetDescSetLayouts (void) noexcept; + static SHVertexInputState const& GetDefaultViState (void) noexcept; + static Handle GetDummyPipelineLayout (void) noexcept; }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.cpp index 4a1117c3..2abdfa86 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.cpp @@ -23,22 +23,40 @@ namespace SHADE { SHVec3 view = target - pos; view = SHVec3::Normalise(view); SHVec3 right = SHVec3::Cross(view, up); right = SHVec3::Normalise(right); - const SHVec3 UP = SHVec3::Cross(right, view); + const SHVec3 UP = SHVec3::Cross(view, right); + //viewMatrix = SHMatrix::Identity; + //viewMatrix(0, 0) = UP[0]; + //viewMatrix(1, 0) = UP[1]; + //viewMatrix(2, 0) = UP[2]; + //viewMatrix(0, 1) = right[0]; + //viewMatrix(1, 1) = right[1]; + //viewMatrix(2, 1) = right[2]; + //viewMatrix(0, 2) = view[0]; + //viewMatrix(1, 2) = view[1]; + //viewMatrix(2, 2) = view[2]; + //viewMatrix(3, 0) = -UP.Dot(pos); + //viewMatrix(3, 1) = -right.Dot(pos); + //viewMatrix(3, 2) = -view.Dot(pos); + viewMatrix = SHMatrix::Identity; - viewMatrix(0, 0) = UP[0]; - viewMatrix(1, 0) = UP[1]; - viewMatrix(2, 0) = UP[2]; - viewMatrix(0, 1) = right[0]; - viewMatrix(1, 1) = right[1]; - viewMatrix(2, 1) = right[2]; - viewMatrix(0, 2) = view[0]; - viewMatrix(1, 2) = view[1]; - viewMatrix(2, 2) = view[2]; - viewMatrix(3, 0) = -UP.Dot(pos); - viewMatrix(3, 1) = -right.Dot(pos); - viewMatrix(3, 2) = -view.Dot(pos); - + viewMatrix(0, 0) = right[0]; + viewMatrix(0, 1) = right[1]; + viewMatrix(0, 2) = right[2]; + + viewMatrix(1, 0) = UP[0]; + viewMatrix(1, 1) = UP[1]; + viewMatrix(1, 2) = UP[2]; + + viewMatrix(2, 0) = view[0]; + viewMatrix(2, 1) = view[1]; + viewMatrix(2, 2) = view[2]; + + viewMatrix(0, 3) = -right.Dot(pos); + viewMatrix(1, 3) = -UP.Dot(pos); + viewMatrix(2, 3) = -view.Dot(pos); + + isDirty = true; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index 445d6119..40e24979 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -30,6 +30,8 @@ of DigiPen Institute of Technology is prohibited. #include "SHGraphicsConstants.h" #include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h" #include "Graphics/Buffers/SHVkBuffer.h" +#include "Graphics/Images/SHVkSampler.h" +#include "Assets/Asset Types/SHTextureAsset.h" namespace SHADE { @@ -91,8 +93,10 @@ namespace SHADE descPool = device->CreateDescriptorPools(); // Create generic command buffer - transferCmdPool = device->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::TRANSFER, SH_CMD_POOL_RESET::POOL_BASED, true); - transferCmdBuffer = transferCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY); + //transferCmdPool = device->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS, SH_CMD_POOL_RESET::POOL_BASED, true); + graphicsCmdPool = device->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS, SH_CMD_POOL_RESET::POOL_BASED, true); + transferCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY); + graphicsTexCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY); @@ -106,8 +110,7 @@ namespace SHADE - Global data /*-----------------------------------------------------------------------*/ - globalData = resourceManager.Create(); - globalData->Init(device); + SHGraphicsGlobalData::Init(device); // Set Up Cameras screenCamera = resourceManager.Create(); @@ -115,7 +118,7 @@ namespace SHADE screenCamera->SetOrthographic(static_cast(windowDims.first), static_cast(windowDims.second), 0.01f, 100.0f); worldCamera = resourceManager.Create(); //worldCamera->SetLookAt(SHVec3(1.0f, 0.0f, -1.0f), SHVec3(0.0f, 0.0f, 2.0f), SHVec3(0.0f, 1.0f, 0.0f)); - worldCamera->SetLookAt(SHVec3(0.0f, 5.0f, -1.0f), SHVec3(0.0f, 0.0f, 2.0f), SHVec3(0.0f, 1.0f, 0.0f)); + worldCamera->SetLookAt(SHVec3(0.0f, 0.0f, 0.0f), SHVec3(0.0f, 0.0f, -2.0f), SHVec3(0.0f, 1.0f, 0.0f)); worldCamera->SetPerspective(90.0f, static_cast(windowDims.first), static_cast(windowDims.second), 0.0f, 100.0f); // Create Default Viewport @@ -131,18 +134,20 @@ namespace SHADE } // Initialize world render graph - worldRenderGraph->Init(device, swapchain, globalData); + worldRenderGraph->Init(device, swapchain); + worldRenderGraph->AddResource("Depth Buffer", SH_ATT_DESC_TYPE::DEPTH_STENCIL, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint); //worldRenderGraph->AddResource("Position", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eR16G16B16A16Sfloat); //worldRenderGraph->AddResource("Normals", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eR16G16B16A16Sfloat); //worldRenderGraph->AddResource("Composite", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eR16G16B16A16Sfloat); - worldRenderGraph->AddResource("Scene", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eB8G8R8A8Unorm); + //worldRenderGraph->AddResource("Scene", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eB8G8R8A8Unorm); worldRenderGraph->AddResource("Present", SH_ATT_DESC_TYPE::COLOR_PRESENT, windowDims.first, windowDims.second); - auto node = worldRenderGraph->AddNode("G-Buffer", { /*"Composite", "Position", */"Present" }, {}); // no predecessors + auto node = worldRenderGraph->AddNode("G-Buffer", { /*"Composite", "Position", */"Depth Buffer", "Present" }, {}); // no predecessors //First subpass to write to G-Buffer auto gBufferWriteSubpass = node->AddSubpass("G-Buffer Write"); //gBufferWriteSubpass->AddColorOutput("Scene"); gBufferWriteSubpass->AddColorOutput("Present"); + gBufferWriteSubpass->AddDepthOutput ("Depth Buffer", SH_ATT_DESC_TYPE::DEPTH_STENCIL); //writeSubpass->AddColorOutput("Normals"); // //Second subpass to read from G-Buffer @@ -171,7 +176,7 @@ namespace SHADE debugWorldRenderer->SetCamera(worldCamera);*/ // Add world renderer to default viewport - worldRenderer = defaultViewport->AddRenderer(resourceManager, swapchain->GetNumImages(), renderContextCmdPools, descPool, globalData->GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS], worldRenderGraph); + worldRenderer = defaultViewport->AddRenderer(resourceManager, swapchain->GetNumImages(), renderContextCmdPools, descPool, SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS], worldRenderGraph); worldRenderer->SetCamera(worldCamera); @@ -184,8 +189,8 @@ namespace SHADE shaderModuleLibrary.ImportFromSourceLibrary(device, shaderSourceLibrary); auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl"); auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl"); - //triVS->Reflect(); - //triFS->Reflect(); + cubeVS->Reflect(); + cubeFS->Reflect(); defaultMaterial = AddMaterial(cubeVS, cubeFS, gBufferWriteSubpass); } @@ -224,6 +229,9 @@ namespace SHADE renderContext.ResetFence(); + // Bind textures + + // For every viewport for (int vpIndex = 0; vpIndex < static_cast(viewports.size()); ++vpIndex) { @@ -241,7 +249,7 @@ namespace SHADE // Begin recording the command buffer currentCmdBuffer->BeginRecording(); - currentCmdBuffer->ForceSetPipelineLayout(globalData->GetDummyPipelineLayout()); + currentCmdBuffer->ForceSetPipelineLayout(SHGraphicsGlobalData::GetDummyPipelineLayout()); // Bind all the buffers required for meshes for (auto& [buffer, bindingPoint] : MESH_DATA) @@ -252,11 +260,26 @@ namespace SHADE currentCmdBuffer->BindIndexBuffer(buffer, 0); } + + // Bind textures + auto textureDescSet = texLibrary.GetTextureDescriptorSetGroup(); + if (textureDescSet) + { + std::array texDynamicOffset {0}; + currentCmdBuffer->BindDescriptorSet + ( + textureDescSet, + vk::PipelineBindPoint::eGraphics, + 0, + texDynamicOffset + ); + } + // bind camera data renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex); // Draw first - renderers[renIndex]->Draw(frameIndex); + renderers[renIndex]->Draw(frameIndex, descPool); // End the command buffer recording currentCmdBuffer->EndRecording(); @@ -309,7 +332,7 @@ namespace SHADE for (auto vp : viewports) for (auto renderer : vp->GetRenderers()) { - renderer->GetRenderGraph()->FinaliseBatch(renderContext.GetCurrentFrame()); + renderer->GetRenderGraph()->FinaliseBatch(renderContext.GetCurrentFrame(), descPool); } // Resize @@ -455,9 +478,37 @@ namespace SHADE transferCmdBuffer->BeginRecording(); meshLibrary.BuildBuffers(device, transferCmdBuffer); transferCmdBuffer->EndRecording(); - transferQueue->SubmitCommandBuffer({ transferCmdBuffer }); + graphicsQueue->SubmitCommandBuffer({ transferCmdBuffer }); } - + + /*---------------------------------------------------------------------------------*/ + /* Texture Registration Functions */ + /*---------------------------------------------------------------------------------*/ + Handle SHGraphicsSystem::Add(const SHTextureAsset& texAsset) + { + auto sampler = samplerCache.GetSampler(device, SHVkSamplerParams { .maxLod = static_cast(texAsset.mipOffsets.size()) }); + return texLibrary.Add(texAsset, sampler); + } + + SHADE::Handle SHGraphicsSystem::Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, uint32_t width, uint32_t height, SHTexture::TextureFormat format, std::vector mipOffsets) + { + auto sampler = samplerCache.GetSampler(device, SHVkSamplerParams{ .maxLod = static_cast(mipOffsets.size()) }); + return texLibrary.Add(pixelCount, pixelData, width, height, format, mipOffsets, sampler); + } + + void SHGraphicsSystem::Remove(Handle tex) + { + texLibrary.Remove(tex); + } + + void SHGraphicsSystem::BuildTextures() + { + texLibrary.BuildTextures + ( + device, graphicsTexCmdBuffer, graphicsQueue, descPool + ); + } + void SHGraphicsSystem::SetWindow(SHWindow* wind) noexcept { window = wind; @@ -493,9 +544,13 @@ namespace SHADE oldSuperBatch->Remove(&renderable); } - // Add to new SuperBatch - Handle newSuperBatch = renderable.GetMaterial()->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch(); - newSuperBatch->Add(&renderable); + // Add to new SuperBatch if there is a material + Handle newMatInstance = renderable.GetMaterial(); + if (newMatInstance) + { + Handle newSuperBatch = newMatInstance->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch(); + newSuperBatch->Add(&renderable); + } // Unset change flag renderable.ResetChangedFlag(); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h index 7e652a02..84dc39cd 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h @@ -29,6 +29,8 @@ of DigiPen Institute of Technology is prohibited. #include "Graphics/MiddleEnd/Shaders/SHShaderModuleLibrary.h" #include "SHMeshLibrary.h" #include "Graphics/MiddleEnd/Materials/SHMaterialInstanceCache.h" +#include "../Textures/SHTextureLibrary.h" +#include "../Textures/SHVkSamplerCache.h" namespace SHADE { @@ -188,6 +190,62 @@ namespace SHADE /***************************************************************************/ void BuildMeshBuffers(); + /*-----------------------------------------------------------------------------*/ + /* Texture Registration Functions */ + /*-----------------------------------------------------------------------------*/ + /*******************************************************************************/ + /*! + + \brief + Adds a texture to the Texture Library. But this does not mean that the + textures have been added yet. A call to "BuildTextures()" is required to + transfer all textures into the GPU. + + \param pixelCount + Number of pixels in this Mesh. + \param positions + Pointer to the first in a contiguous array of SHMathVec3s that define vertex + positions. + \param format + Format of the texture loaded in. + + \return + Handle to the created Texture. This is not valid to be used until a call to + BuildImages(). + + */ + /*******************************************************************************/ + Handle Add(const SHTextureAsset& texAsset); + Handle Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, uint32_t width, uint32_t height, SHTexture::TextureFormat format, std::vector mipOffsets); + /*******************************************************************************/ + /*! + + \brief + Removes a mesh from the Texture Library. But this does not mean that the + textures have been removed yet. A call to "BuildTextures()" is required to + finalise all changes. + + \param mesh + Handle to the Texture to remove. + + */ + /*******************************************************************************/ + void Remove(Handle tex); + /***************************************************************************/ + /*! + + \brief + Finalises all changes to the Texture Library into the GPU buffers. + + \param cmdBuffer + Command buffer used to set up transfers of data in the GPU memory. This + call must be preceded by calls to cmdBuffer's BeginRecording() and ended + with EndRecording(). Do recall to also submit the cmdBuffer to a transfer + queue. + */ + /***************************************************************************/ + void BuildTextures(); + /*-----------------------------------------------------------------------------*/ /* Setters */ /*-----------------------------------------------------------------------------*/ @@ -220,19 +278,20 @@ namespace SHADE Handle graphicsQueue; Handle transferQueue; Handle descPool; + Handle graphicsCmdPool; Handle transferCmdPool; Handle transferCmdBuffer; + Handle graphicsTexCmdBuffer; SHRenderContext renderContext; std::array, 2> graphSemaphores; // Not Owned Resources SHWindow* window = nullptr; - // global data (descriptor sets as well) - Handle globalData; - // Middle End Resources ResourceManager resourceManager; SHMeshLibrary meshLibrary; + SHTextureLibrary texLibrary; + SHSamplerCache samplerCache; SHMaterialInstanceCache materialInstanceCache; // Viewports Handle defaultViewport; // Whole screen diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.cpp index 0e5a61dd..350580bf 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.cpp @@ -40,8 +40,6 @@ namespace SHADE void SHMaterialInstance::ExportProperties(void* dest) { - assert(dataStore != nullptr); - if (!baseMaterial) throw std::runtime_error("[SHMaterialInstance] Attempted to set export a Material Instance with no base Material!"); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.h index 5d6c4925..d111acb9 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.h @@ -15,6 +15,7 @@ of DigiPen Institute of Technology is prohibited. // Project Includes #include "Resource/Handle.h" #include "Graphics/Shaders/BlockInterface/SHShaderBlockInterface.h" +#include "SH_API.h" namespace SHADE { @@ -34,7 +35,7 @@ namespace SHADE a SHRenderable. */ /***********************************************************************************/ - class SHMaterialInstance + class SH_API SHMaterialInstance { public: /*-----------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.hpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.hpp index b3dc6c3a..4621c273 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.hpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.hpp @@ -48,7 +48,7 @@ namespace SHADE } // Get offset and modify the memory directly - T* dataPtr = dataStore.get() + od.StoredDataOffset; + T* dataPtr = reinterpret_cast(dataStore.get() + od.StoredDataOffset); *dataPtr = value; // Save the override data information diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp index a4cda42d..0b1c1b66 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp @@ -81,7 +81,7 @@ namespace SHADE if (!material) { SHGraphicsSystem* gfxSystem = SHSystemManager::GetSystem(); - material = gfxSystem->AddOrGetBaseMaterialInstance(sharedMaterial->GetBaseMaterial()); + material = gfxSystem->AddMaterialInstanceCopy(sharedMaterial); } return material; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp index c7e2a86d..84ac3ee2 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp @@ -60,9 +60,9 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ /* Drawing Functions */ /*-----------------------------------------------------------------------------------*/ - void SHRenderer::Draw(uint32_t frameIndex) noexcept + void SHRenderer::Draw(uint32_t frameIndex, Handle descPool) noexcept { - renderGraph->Execute(frameIndex, commandBuffers[frameIndex]); + renderGraph->Execute(frameIndex, commandBuffers[frameIndex], descPool); } void SHRenderer::UpdateDataAndBind(Handle cmdBuffer, uint32_t frameIndex) noexcept diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h index 255ab289..5e72da85 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h @@ -74,7 +74,7 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Drawing Functions */ /*-----------------------------------------------------------------------------*/ - void Draw(uint32_t frameIndex) noexcept; + void Draw(uint32_t frameIndex, Handle descPool) noexcept; void UpdateDataAndBind (Handle cmdBuffer, uint32_t frameIndex) noexcept; void UpdateCameraDataToBuffer (void) noexcept; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp index 92d832f1..10b42a9e 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp @@ -11,7 +11,7 @@ namespace SHADE SHPipelineLayoutParams params { .shaderModules = {vsFsPair.first, vsFsPair.second}, - .globalDescSetLayouts = globalData->GetDescSetLayouts() + .globalDescSetLayouts = SHGraphicsGlobalData::GetDescSetLayouts() }; // Create the pipeline layout @@ -19,7 +19,7 @@ namespace SHADE // Create the pipeline and configure the default vertex input state auto newPipeline = logicalDevice->CreateGraphicsPipeline(pipelineLayout, nullptr, renderpass, subpass); - newPipeline->GetPipelineState().SetVertexInputState(globalData->GetDefaultViState()); + newPipeline->GetPipelineState().SetVertexInputState(SHGraphicsGlobalData::GetDefaultViState()); // Actually construct the pipeline newPipeline->ConstructPipeline(); @@ -30,10 +30,9 @@ namespace SHADE return newPipeline; } - void SHPipelineLibrary::Init(Handle device, Handle inGlobalData) noexcept + void SHPipelineLibrary::Init(Handle device) noexcept { logicalDevice = device; - globalData = inGlobalData; } Handle SHPipelineLibrary::GetDrawPipline(std::pair, Handle> const& vsFsPair) noexcept diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h index a16976f7..9a411d25 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h @@ -24,14 +24,9 @@ namespace SHADE //! a map of pipelines that are hashed using a pair of shader module handles std::unordered_map, Handle>, Handle> pipelines; - - // Global data - Handle globalData; - - public: - void Init (Handle device, Handle inGlobalData) noexcept; + void Init (Handle device) noexcept; // Draw pipeline functions. used only when creating pipelines for drawing using a vertex and fragment shader Handle CreateDrawPipeline ( diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.cpp index 6459ff9a..6a7439e5 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.cpp @@ -20,18 +20,36 @@ of DigiPen Institute of Technology is prohibited. #include "Graphics/Commands/SHVkCommandBuffer.h" #include "Graphics/SHVkUtil.h" #include "Tools/SHLogger.h" +#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" +#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" +#include "Graphics/Images/SHVkImage.h" +#include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h" +#include "Assets/Asset Types/SHTextureAsset.h" namespace SHADE { /*---------------------------------------------------------------------------------*/ /* Usage Functions */ /*---------------------------------------------------------------------------------*/ - Handle SHTextureLibrary::Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, SHTexture::TextureFormat format, uint32_t mipLevels) + Handle SHTextureLibrary::Add(const SHTextureAsset& texAsset, Handle sampler) + { + return Add + ( + texAsset.numBytes, + texAsset.pixelData, + texAsset.width, texAsset.height, + texAsset.format, + texAsset.mipOffsets, + sampler + ); + } + + Handle SHTextureLibrary::Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, uint32_t width, uint32_t height, SHTexture::TextureFormat format, std::vector mipOffsets, Handle sampler) { isDirty = true; auto handle = resourceManager.Create(); - addJobs.emplace_back(AddJob { pixelCount, pixelData, format, mipLevels }); + addJobs.emplace_back(AddJob { pixelCount, pixelData, format, sampler, mipOffsets, width, height, handle }); return handle; } @@ -44,22 +62,48 @@ namespace SHADE isDirty = true; } - void SHTextureLibrary::BuildImages(Handle device, Handle cmdBuffer, Handle graphicsQueue, Handle descPool, Handle descLayout) + void SHTextureLibrary::BuildTextures(Handle device, Handle cmdBuffer, Handle graphicsQueue, Handle descPool) { + // Don't do anything if there are no updates + if (!isDirty) + return; + /* Remove Textures */ - std::vector pipelineBarriers(addJobs.size()); + // TODO /* Add Textures */ - // Transition + // Load Textures - Transitions + std::vector pipelineBarriers(addJobs.size()); for (int i = 0; auto& job : addJobs) { - job.Image = resourceManager.Create(); + job.Image = resourceManager.Create + ( + &device->GetVMAAllocator(), + SHImageCreateParams + { + .imageType = vk::ImageType::e2D, + .width = job.Width, + .height = job.Height, + .depth = 1, + .levels = static_cast(job.MipOffsets.size()), + .arrayLayers = 1, + .imageFormat = job.TextureFormat, + .usageFlags = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst, + .createFlags = {} + }, + job.PixelData, + job.PixelCount, + job.MipOffsets, + VmaMemoryUsage::VMA_MEMORY_USAGE_AUTO, + VmaAllocationCreateFlagBits {} + ); job.Image->PrepareImageTransitionInfo(vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, pipelineBarriers[i]); ++i; } vk::PipelineStageFlagBits srcStage = vk::PipelineStageFlagBits::eTopOfPipe; vk::PipelineStageFlagBits dstStage = vk::PipelineStageFlagBits::eTopOfPipe; preparePipelineBarriers(vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, srcStage, dstStage, pipelineBarriers); + cmdBuffer->BeginRecording(); cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, pipelineBarriers); // Copy @@ -73,13 +117,16 @@ namespace SHADE { // Transition job.Image->PrepareImageTransitionInfo(vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal, pipelineBarriers[i]); + ++i; } preparePipelineBarriers(vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal, srcStage, dstStage, pipelineBarriers); - cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, pipelineBarriers); + cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {}, {}, {}, pipelineBarriers); // Execute Commands + cmdBuffer->EndRecording(); graphicsQueue->SubmitCommandBuffer({ cmdBuffer }); device->WaitIdle(); + graphicsQueue->GetVkQueue().waitIdle(); // Create Image View for (auto& job : addJobs) @@ -90,16 +137,45 @@ namespace SHADE .format = job.TextureFormat, .imageAspectFlags = vk::ImageAspectFlagBits::eColor, .baseMipLevel = 0, - .mipLevelCount = job.MipLevels, + .mipLevelCount = static_cast(job.MipOffsets.size()), .baseArrayLayer = 0, - .layerCount = 0 + .layerCount = 1 }; - job.Handle->ImageView = job.Image->CreateImageView(device, job.Image, DETAILS); + job.TextureHandle->ImageView = job.Image->CreateImageView(device, job.Image, DETAILS); } - // Build Descriptor - Handle descSetGroup = descPool->Allocate({ descLayout }, { 1 }); - + // Add Textures + for (auto& job : addJobs) + { + texOrder.emplace_back(job.TextureHandle); + combinedImageSamplers.emplace_back(std::make_tuple(job.TextureHandle->ImageView, job.Sampler, vk::ImageLayout::eShaderReadOnlyOptimal)); + job.TextureHandle->TextureArrayIndex = texOrder.size() - 1; + } + addJobs.clear(); + + /* Build Descriptor Set with all the Textures only if there are textures */ + if (!texOrder.empty()) + { + if (!texDescriptors) + { + texDescriptors = descPool->Allocate + ( + { SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::STATIC_GLOBALS] }, + { static_cast(texOrder.size()) } + ); + } + texDescriptors->ModifyWriteDescImage + ( + SHGraphicsConstants::DescriptorSetIndex::STATIC_GLOBALS, + SHGraphicsConstants::DescriptorSetBindings::IMAGE_AND_SAMPLERS_DATA, + combinedImageSamplers + ); + texDescriptors->UpdateDescriptorSetImages + ( + SHGraphicsConstants::DescriptorSetIndex::STATIC_GLOBALS, + SHGraphicsConstants::DescriptorSetBindings::IMAGE_AND_SAMPLERS_DATA + ); + } isDirty = false; } @@ -139,4 +215,65 @@ namespace SHADE } } + vk::Format SHTextureLibrary::ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear) + { + switch (format) + { + case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm: + return vk::Format::eBc1RgbaUnormBlock; + case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm_SRGB: + return vk::Format::eBc1RgbaSrgbBlock; + case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm: + case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm_SRGB: + return isLinear ? vk::Format::eBc2UnormBlock : vk::Format::eBc2SrgbBlock; + case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm: + case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm_SRGB: + return isLinear ? vk::Format::eBc3UnormBlock : vk::Format::eBc3SrgbBlock; + case tinyddsloader::DDSFile::DXGIFormat::BC5_UNorm: + case tinyddsloader::DDSFile::DXGIFormat::BC5_SNorm: + return isLinear ? vk::Format::eBc5UnormBlock : vk::Format::eBc5SnormBlock; + case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm: + case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm_SRGB: + return isLinear ? vk::Format::eR8G8B8A8Unorm : vk::Format::eR8G8B8A8Srgb; + case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_SNorm: + return vk::Format::eR8G8B8A8Snorm; + case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm: + case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm_SRGB: + return isLinear ? vk::Format::eB8G8R8A8Unorm : vk::Format::eB8G8R8A8Srgb; + case tinyddsloader::DDSFile::DXGIFormat::B8G8R8X8_UNorm: + case tinyddsloader::DDSFile::DXGIFormat::B8G8R8X8_UNorm_SRGB: + return isLinear ? vk::Format::eB8G8R8A8Unorm : vk::Format::eB8G8R8Srgb; + default: + throw std::runtime_error("Unsupported DDS format."); + } + + //switch (format) + //{ + //case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm: + //case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm_SRGB: + // return (isLinear) ? vk::Format::eR8G8B8A8Unorm : vk::Format::eR8G8B8A8Srgb; + // + + //case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm: + //case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm_SRGB: + // return (isLinear) ? vk::Format::eB8G8R8A8Unorm : vk::Format::eB8G8R8A8Srgb; + // + + //case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm: + //case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm_SRGB: + // return (isLinear) ? vk::Format::eBc1RgbaUnormBlock : vk::Format::eBc1RgbaSrgbBlock; + + //case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm: + //case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm_SRGB: + // return (isLinear) ? vk::Format::eBc2UnormBlock : vk::Format::eBc2SrgbBlock; + + //case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm: + //case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm_SRGB: + // return (isLinear) ? vk::Format::eBc3UnormBlock : vk::Format::eBc3SrgbBlock; + + //case tinyddsloader::DDSFile::DXGIFormat::BC5_UNorm: + // return (isLinear) ? vk::Format::eBc5UnormBlock : vk::Format::eBc5SnormBlock; + // + //} + } } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.h b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.h index 5cf974ef..660d93eb 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.h @@ -14,6 +14,8 @@ of DigiPen Institute of Technology is prohibited. // STL Includes #include +// External Dependencies +#include "tinyddsloader.h" // Project Includes #include "Resource/Handle.h" #include "Resource/ResourceLibrary.h" @@ -33,6 +35,9 @@ namespace SHADE class SHVkQueue; class SHVkDescriptorPool; class SHVkDescriptorSetLayout; + class SHVkDescriptorSetGroup; + class SHVkSampler; + class SHTextureAsset; /*---------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -43,7 +48,7 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Type Definitions */ /*-----------------------------------------------------------------------------*/ - using PixelChannel = float; + using PixelChannel = unsigned char; using TextureFormat = vk::Format; // TODO: Change using Index = uint32_t; @@ -71,7 +76,7 @@ namespace SHADE \brief Adds a texture to the Texture Library. But this does not mean that the - textures have been added yet. A call to "BuildImages()" is required to + textures have been added yet. A call to "BuildTextures()" is required to transfer all textures into the GPU. \param pixelCount @@ -88,13 +93,15 @@ namespace SHADE */ /*******************************************************************************/ - Handle Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, SHTexture::TextureFormat format, uint32_t mipLevels); + + Handle Add(const SHTextureAsset& texAsset, Handle sampler); + Handle Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, uint32_t width, uint32_t height, SHTexture::TextureFormat format, std::vector mipOffsets, Handle sampler); /*******************************************************************************/ /*! \brief Removes a mesh from the Texture Library. But this does not mean that the - textures have been removed yet. A call to "BuildImages()" is required to + textures have been removed yet. A call to "BuildTextures()" is required to finalise all changes. \param mesh @@ -118,12 +125,12 @@ namespace SHADE queue. */ /***************************************************************************/ - void BuildImages(Handle device, Handle cmdBuffer, Handle graphicsQueue, Handle descPool, Handle descLayout); + void BuildTextures(Handle device, Handle cmdBuffer, Handle graphicsQueue, Handle descPool); /*-----------------------------------------------------------------------------*/ /* Getter Functions */ /*-----------------------------------------------------------------------------*/ - Handle GetTextureBuffer() const noexcept { return texStorageBuffer; } + Handle GetTextureDescriptorSetGroup() const noexcept { return texDescriptors; } private: /*-----------------------------------------------------------------------------*/ @@ -134,9 +141,12 @@ namespace SHADE uint32_t PixelCount = 0; const SHTexture::PixelChannel* PixelData = nullptr; SHTexture::TextureFormat TextureFormat = {}; - uint32_t MipLevels = 0; + Handle Sampler; + std::vector MipOffsets; + uint32_t Width; + uint32_t Height; + Handle TextureHandle; Handle Image; - Handle Handle; }; /*-----------------------------------------------------------------------------*/ @@ -149,9 +159,9 @@ namespace SHADE ResourceManager resourceManager; std::vector> texOrder; // CPU Storage - std::vector texStorage; + std::vector, Handle, vk::ImageLayout>> combinedImageSamplers; // GPU Storage - Handle texStorageBuffer{}; + Handle texDescriptors; // Flags bool isDirty = true; @@ -159,5 +169,6 @@ namespace SHADE /* Helper Functions */ /*-----------------------------------------------------------------------------*/ void preparePipelineBarriers(vk::ImageLayout oldLayout, vk::ImageLayout newLayout, vk::PipelineStageFlagBits& srcStage, vk::PipelineStageFlagBits& dstStage, std::vector& barriers); + vk::Format ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear); }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHVkSamplerCache.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHVkSamplerCache.cpp new file mode 100644 index 00000000..6938dae5 --- /dev/null +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHVkSamplerCache.cpp @@ -0,0 +1,75 @@ +/************************************************************************************//*! +\file SHVkSamplerCache.cpp +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Mar 16, 2022 +\brief Contains the implementation for the SHVkSamplerCache 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. +*//*************************************************************************************/ +#include "SHpch.h" +#include "SHVkSamplerCache.h" + +// Standard Library +#include +// Project Header +#include "Graphics/Images/SHVkSampler.h" +#include "Graphics/Devices/SHVkLogicalDevice.h" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Utility Functions */ + /*---------------------------------------------------------------------------------*/ + void SHSamplerCache::Clear() + { + samplersMap.clear(); + } + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + Handle SHSamplerCache::GetSampler(Handle device, const SHVkSamplerParams& params) + { + // Get the hash to check if it was cached + const RawSamplerHash HASH = calcHash + ( + params.minFilter, + params.magFilter, + params.addressMode, + params.mipmapMode, + params.minLod, + params.maxLod + ); + + // Check if it was cached + auto sampler = samplersMap.find(HASH); + if (sampler == samplersMap.end()) + { + const auto BUILD_RESULT = samplersMap.emplace(HASH, device->CreateSampler(params)); + sampler = BUILD_RESULT.first; + } + + return sampler->second; + } + + /*---------------------------------------------------------------------------------*/ + /* Helper Functions */ + /*---------------------------------------------------------------------------------*/ + SHSamplerCache::RawSamplerHash SHSamplerCache::calcHash(vk::Filter minFilter, vk::Filter magFilter, vk::SamplerAddressMode addressMode, vk::SamplerMipmapMode mipmapMode, float minLod, float maxLod) + { + static auto charHasher = std::hash{}; + static auto floatHasher = std::hash{}; + + const RawSamplerHash H1 = charHasher(static_cast(minFilter)); + const RawSamplerHash H2 = charHasher(static_cast(magFilter)); + const RawSamplerHash H3 = charHasher(static_cast(addressMode)); + const RawSamplerHash H4 = charHasher(static_cast(mipmapMode)); + const RawSamplerHash H5 = floatHasher(minLod); + const RawSamplerHash H6 = floatHasher(maxLod); + + return H1 ^ (H2 << 1) ^ (H3 << 2) ^ (H4 << 3) ^ (H5 << 4) ^ (H6 << 5); + } +} diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHVkSamplerCache.h b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHVkSamplerCache.h new file mode 100644 index 00000000..c1529577 --- /dev/null +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHVkSamplerCache.h @@ -0,0 +1,80 @@ +/************************************************************************************//*! +\file SHSamplerCache.h +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Mar 16, 2022 +\brief Contains the interface for the SHSamplerCache 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. +*//*************************************************************************************/ +#pragma once + +// Standard Libraries +#include +// External Dependencies +#include "Graphics/SHVulkanIncludes.h" +// Project Includes +#include "Resource/Handle.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Forward Declarations */ + /*-----------------------------------------------------------------------------------*/ + class SHVkLogicalDevice; + class SHVkSampler; + struct SHVkSamplerParams; + + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + /*************************************************************************************/ + /*! + \brief + Class that is responsible for caching and providing Samplers to the user for + sampling textures. + */ + /*************************************************************************************/ + class SHSamplerCache + { + public: + /*---------------------------------------------------------------------------------*/ + /* Utility Functions */ + /*---------------------------------------------------------------------------------*/ + /// + /// Clears the cache, destroying all created samplers. + /// + void Clear(); + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + /// + /// Retrieves a Vulkan Sampler of the specified type. If this was retrieved + /// before, a cached copy of the Vulkan Sampler will be provided. + /// + /// Logical device to create the sampler with if needed. + /// Describes the parameters for the sampler. + /// Handle to the SHVkSampler object specified. + Handle GetSampler(Handle device, const SHVkSamplerParams& params); + + private: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + using RawSamplerHash = size_t; + + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + // Resources + std::unordered_map> samplersMap; + + /*---------------------------------------------------------------------------------*/ + /* Helper Functions */ + /*---------------------------------------------------------------------------------*/ + static RawSamplerHash calcHash(vk::Filter minFilter, vk::Filter magFilter, vk::SamplerAddressMode addressMode, vk::SamplerMipmapMode mipmapMode, float minLod, float maxLod); + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp index 25be112e..7a76447d 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp +++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp @@ -216,10 +216,13 @@ namespace SHADE /***************************************************************************/ void SHVkPipelineLayout::PrepareVkDescriptorSetLayouts(void) noexcept { + descriptorSetLayoutsPipeline.reserve(descriptorSetLayoutsAllocate.size() + descriptorSetLayoutsGlobal.size()); + // Settle allocate layouts first vkDescriptorSetLayoutsAllocate.reserve(descriptorSetLayoutsAllocate.size()); for (auto const& layout : descriptorSetLayoutsAllocate) { + descriptorSetLayoutsPipeline.emplace_back(layout); vkDescriptorSetLayoutsAllocate.emplace_back(layout->GetVkHandle()); } @@ -228,7 +231,10 @@ namespace SHADE // First we insert the global layouts for (auto const& layout : descriptorSetLayoutsGlobal) + { + descriptorSetLayoutsPipeline.emplace_back(layout); 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)); @@ -435,6 +441,16 @@ namespace SHADE return {}; } + std::vector> SHVkPipelineLayout::GetDescriptorSetLayoutsPipeline(void) const noexcept + { + return descriptorSetLayoutsPipeline; + } + + std::vector> SHVkPipelineLayout::GetDescriptorSetLayoutsAllocate(void) const noexcept + { + return descriptorSetLayoutsAllocate; + } + SHVkPipelineLayout& SHVkPipelineLayout::operator=(SHVkPipelineLayout&& rhs) noexcept { if (&rhs == this) diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h index e43ceb73..f5d363fa 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h +++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h @@ -42,6 +42,9 @@ namespace SHADE //! We want to store this also because we need to allocate later std::vector vkDescriptorSetLayoutsAllocate; + //! Store for descriptor set group creation + std::vector> descriptorSetLayoutsPipeline; + //! Store for pipeline layout recreation std::vector vkDescriptorSetLayoutsPipeline; @@ -71,10 +74,12 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ /*-----------------------------------------------------------------------*/ - std::vector> const& GetShaderModules (void) const noexcept; - vk::PipelineLayout GetVkPipelineLayout (void) const noexcept; - SHPushConstantInterface const& GetPushConstantInterface (void) const noexcept; - Handle GetShaderBlockInterface (uint32_t set, uint32_t binding, vk::ShaderStageFlagBits shaderStage) const noexcept; + std::vector> const& GetShaderModules (void) const noexcept; + vk::PipelineLayout GetVkPipelineLayout (void) const noexcept; + SHPushConstantInterface const& GetPushConstantInterface (void) const noexcept; + Handle GetShaderBlockInterface (uint32_t set, uint32_t binding, vk::ShaderStageFlagBits shaderStage) const noexcept; + std::vector> GetDescriptorSetLayoutsPipeline(void) const noexcept; + std::vector> GetDescriptorSetLayoutsAllocate(void) const noexcept; }; } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h b/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h new file mode 100644 index 00000000..dc21fa37 --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h @@ -0,0 +1,14 @@ +#pragma once + +namespace SHADE +{ + // Used for attachment description creation for renderpass node + enum class SH_ATT_DESC_TYPE + { + COLOR, + COLOR_PRESENT, + DEPTH, + STENCIL, + DEPTH_STENCIL, + }; +} diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp index 3f5641c0..828a83f1 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp @@ -11,655 +11,7 @@ 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 const& logicalDevice, Handle 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. - - */ - /***************************************************************************/ - SHSubpass::SHSubpass(ResourceManager& rm, Handle const& parent, uint32_t index, std::unordered_map const* mapping, std::unordered_map> const* resources) noexcept - : resourceAttachmentMapping{ mapping } - , ptrToResources{ resources } - , parentNode{ parent } - , subpassIndex{ index } - , superBatch{} - , colorReferences{} - , depthReferences{} - , inputReferences{} - { - } - - /***************************************************************************/ - /*! - - \brief - Move constructor for subpass. - - \param rhs - The subpass the move from. - - */ - /***************************************************************************/ - SHSubpass::SHSubpass(SHSubpass&& rhs) noexcept - : subpassIndex{ std::move(rhs.subpassIndex) } - , parentNode{ std::move(rhs.parentNode) } - , superBatch{ std::move(rhs.superBatch) } - , 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. - - */ - /***************************************************************************/ - SHSubpass& SHSubpass::operator=(SHSubpass&& rhs) noexcept - { - if (this == &rhs) - return *this; - - subpassIndex = std::move(rhs.subpassIndex); - parentNode = std::move(rhs.parentNode); - superBatch = std::move(rhs.superBatch); - 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 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 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 SHSubpass::AddInput(std::string resourceToReference) noexcept - { - inputReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eShaderReadOnlyOptimal }); - } - - void SHSubpass::Execute(Handle& commandBuffer, uint32_t frameIndex) noexcept - { - // Ensure correct transforms are provided - superBatch->UpdateBuffers(frameIndex); - - // Draw all the batches - superBatch->Draw(commandBuffer, frameIndex); - - // Draw all the exterior draw calls - for (auto& drawCall : exteriorDrawCalls) - { - drawCall(commandBuffer); - } - } - - void SHSubpass::AddExteriorDrawCalls(std::function&)> const& newDrawCall) noexcept - { - exteriorDrawCalls.push_back(newDrawCall); - } - - void SHSubpass::Init(ResourceManager& resourceManager) noexcept - { - superBatch = resourceManager.Create(GetHandle()); - - } - - /***************************************************************************/ - /*! - - \brief - Getter for parent renderpass. - - \return - Returns the parent renderpass the subpass belongs to. - - */ - /***************************************************************************/ - Handle const& SHSubpass::GetParentNode(void) const noexcept - { - return parentNode; - } - - SHADE::SHSubPassIndex SHSubpass::GetIndex() const noexcept - { - return subpassIndex; - } - - Handle SHSubpass::GetSuperBatch(void) const noexcept - { - return superBatch; - } - - /***************************************************************************/ - /*! - - \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> imageViews(attResources.size()); - uint32_t fbWidth = std::numeric_limits::max(); - uint32_t fbHeight = std::numeric_limits::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 const& logicalDevice, Handle const& swapchain, std::vector> attRes, std::vector> predecessors, std::unordered_map> const* resources, Handle globalData) noexcept - : logicalDeviceHdl{ logicalDevice } - , renderpass{} - , framebuffers{} - , prereqNodes{ std::move(predecessors) } - , attachmentDescriptions{} - , resourceAttachmentMapping{} - , attResources{ std::move(attRes) } - , subpasses{} - , executed{ false } - , configured{ false } - , resourceManager{ rm } - , ptrToResources{ resources } - { - // pipeline library initialization - pipelineLibrary.Init(logicalDeviceHdl, globalData); - - 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::eStore; - - newDesc.stencilLoadOp = vk::AttachmentLoadOp::eClear; - newDesc.stencilStoreOp = vk::AttachmentStoreOp::eStore; - - 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 } - , pipelineLibrary{ std::move(rhs.pipelineLibrary) } - , batcher { std::move(rhs.batcher) } - - { - 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); - pipelineLibrary = std::move(rhs.pipelineLibrary); - batcher = std::move(rhs.batcher); - - 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::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(resourceManager, GetHandle(), subpasses.size(), &resourceAttachmentMapping, ptrToResources)); - subpassIndexing.try_emplace(subpassName, static_cast(subpasses.size()) - 1u); - Handle subpass = subpasses.back(); - subpass->Init(resourceManager); - - // Register the SuperBatch - batcher.RegisterSuperBatch(subpass->GetSuperBatch()); - - return subpass; - } - - void SHRenderGraphNode::Execute(Handle& commandBuffer, uint32_t frameIndex) noexcept - { - frameIndex = (framebuffers.size() > 1) ? frameIndex : 0; - commandBuffer->BeginRenderpass(renderpass, framebuffers[frameIndex]); - - for (uint32_t i = 0; i < subpasses.size(); ++i) - { - subpasses[i]->Execute(commandBuffer, frameIndex); - - // Go to next subpass if not last subpass - if (i != subpasses.size() - 1) - commandBuffer->NextSubpass(); - } - - commandBuffer->EndRenderpass(); - } - - Handle SHRenderGraphNode::GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept - { - // verify subpass exists - if (subpass->GetIndex() >= subpasses.size()) - { - SHLOG_ERROR("Subpass index passed in is not valid. RenderGraphNode does not have that many passes. "); - return {}; - } - - Handle pipeline = pipelineLibrary.GetDrawPipline(vsFsPair); - if (!pipeline) - { - pipeline = pipelineLibrary.CreateDrawPipeline - ( - vsFsPair, - renderpass, - subpass - ); - } - - return pipeline; - } - - void SHRenderGraphNode::FinaliseBatch(uint32_t frameIndex) - { - batcher.FinaliseBatches(logicalDeviceHdl, frameIndex); - } - - /***************************************************************************/ - /*! - - \brief - Get the renderpass from the node. - - \return - Handle to the renderpass. - - */ - /***************************************************************************/ - Handle SHRenderGraphNode::GetRenderpass(void) const noexcept - { - return renderpass; - } - - Handle SHRenderGraphNode::GetSubpass(std::string_view subpassName) const noexcept - { - return subpasses[subpassIndexing.at(subpassName.data())]; - } + /***************************************************************************/ /*! @@ -779,7 +131,7 @@ namespace SHADE attDesc.loadOp = vk::AttachmentLoadOp::eLoad; predAttDesc.storeOp = vk::AttachmentStoreOp::eStore; - // TODO: Stecil load and store + // TODO: Stencil 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 @@ -976,11 +328,10 @@ namespace SHADE */ /***************************************************************************/ - void SHRenderGraph::Init(Handle const& logicalDevice, Handle const& swapchain, Handle inGlobalData) noexcept + void SHRenderGraph::Init(Handle const& logicalDevice, Handle const& swapchain) noexcept { logicalDeviceHdl = logicalDevice; swapchainHdl = swapchain; - globalData = inGlobalData; } /***************************************************************************/ @@ -1012,7 +363,6 @@ namespace SHADE , nodes{ std::move(rhs.nodes) } , graphResources{ std::move(rhs.graphResources) } , resourceManager{ std::move(rhs.resourceManager) } - , globalData{ rhs.globalData } { } @@ -1028,7 +378,6 @@ namespace SHADE nodes = std::move(rhs.nodes); graphResources = std::move(rhs.graphResources); resourceManager = std::move(rhs.resourceManager); - globalData = rhs.globalData; return *this; } @@ -1086,7 +435,7 @@ namespace SHADE } } - nodes.emplace_back(resourceManager.Create(resourceManager, logicalDeviceHdl, swapchainHdl, std::move(resources), std::move(predecessors), &graphResources, globalData)); + nodes.emplace_back(resourceManager.Create(resourceManager, logicalDeviceHdl, swapchainHdl, std::move(resources), std::move(predecessors), &graphResources)); nodeIndexing.emplace(nodeName, static_cast(nodes.size()) - 1u); return nodes.at(nodeIndexing[nodeName]); } @@ -1114,20 +463,20 @@ namespace SHADE // TODO: The graph scope buffers were meant to bind vertex buffers and index buffers for meshes. Find a // better way to manage these - void SHRenderGraph::Execute(uint32_t frameIndex, Handle cmdBuffer) noexcept + void SHRenderGraph::Execute(uint32_t frameIndex, Handle cmdBuffer, Handle descPool) noexcept { // TODO: DON'T HARDCODE THIS cmdBuffer->SetViewportScissor(1920.0f, 1080.0f, 1920, 1080); for (auto& node : nodes) - node->Execute(cmdBuffer, frameIndex); + node->Execute(cmdBuffer, descPool, frameIndex); } - void SHRenderGraph::FinaliseBatch(uint32_t frameIndex) + void SHRenderGraph::FinaliseBatch(uint32_t frameIndex, Handle descPool) { for (auto& node : nodes) { - node->FinaliseBatch(frameIndex); + node->FinaliseBatch(frameIndex, descPool); } } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h index 91a2f1f5..8b5b2212 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h @@ -7,6 +7,12 @@ #include "Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h" #include "Graphics/MiddleEnd/Batching/SHSuperBatch.h" #include "../MiddleEnd/Batching/SHBatcher.h" +#include "SHRenderGraphNode.h" +#include "SHSubpass.h" +#include "SHRenderGraphResource.h" +#include "SHRenderGraphNode.h" +#include "SHSubpass.h" +#include "SHAttachmentDescriptionType.h" #include #include @@ -24,223 +30,6 @@ namespace SHADE class SHRenderGraphNode; class SHGraphicsGlobalData; - // Used for attachment description creation for renderpass node - enum class SH_ATT_DESC_TYPE - { - COLOR, - COLOR_PRESENT, - DEPTH, - STENCIL, - DEPTH_STENCIL, - }; - - - class SH_API 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> images; - - //! Views to resources (vector because same rationale as images. see above). - std::vector> 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 const& logicalDevice, Handle 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 SH_API SHSubpass : public ISelfHandle - { - private: - /*---------------------------------------------------------------------*/ - /* PRIVATE MEMBER VARIABLES */ - /*---------------------------------------------------------------------*/ - //! The index of the subpass in the render graph - uint32_t subpassIndex; - - //! The parent renderpass that this subpass belongs to - Handle parentNode; - - //! - Handle superBatch; - - //! Color attachments - std::vector colorReferences; - - //! Depth attachments - std::vector depthReferences; - - //! Input attachments - std::vector inputReferences; - - //! For getting attachment reference indices using handles - std::unordered_map const* resourceAttachmentMapping; - - //! Pointer to resources in the render graph (for getting handle IDs) - std::unordered_map> const* ptrToResources; - - //! Sometimes there exists entities that we want to render onto a render target - //! but don't want it to come from the batching system. An example would be ImGUI. - //! For these entities we want to link a function from the outside and draw them - //! after we draw everything from the batch. Because of this, these draw calls - //! are always the last things drawn, so DO NOT USE THIS FUNCTIONALITY FOR ANYTHING - //! COMPLEX. - std::vector&)>> exteriorDrawCalls; - - public: - /*-----------------------------------------------------------------------*/ - /* CTORS AND DTORS */ - /*-----------------------------------------------------------------------*/ - SHSubpass(ResourceManager& rm, Handle const& parent, uint32_t index, std::unordered_map const* mapping, std::unordered_map> const* ptrToResources) noexcept; - SHSubpass(SHSubpass&& rhs) noexcept; - SHSubpass& operator=(SHSubpass&& rhs) noexcept; - - /*-----------------------------------------------------------------------*/ - /* PUBLIC MEMBER FUNCTIONS */ - /*-----------------------------------------------------------------------*/ - // Preparation functions - 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; - - // Runtime functions - void Execute(Handle& commandBuffer, uint32_t frameIndex) noexcept; - void AddExteriorDrawCalls(std::function&)> const& newDrawCall) noexcept; - - void Init (ResourceManager& resourceManager) noexcept; - - /*-----------------------------------------------------------------------*/ - /* GETTERS AND SETTERS */ - /*-----------------------------------------------------------------------*/ - Handle const& GetParentNode(void) const noexcept; - SHSubPassIndex GetIndex() const noexcept; - Handle GetSuperBatch (void) const noexcept; - - - friend class SHRenderGraphNode; - friend class SHRenderGraph; - }; - - class SH_API SHRenderGraphNode : public ISelfHandle - { - private: - /*-----------------------------------------------------------------------*/ - /* PRIVATE MEMBER VARIABLES */ - /*-----------------------------------------------------------------------*/ - ResourceManager& resourceManager; - - //! For Vulkan object creation - Handle logicalDeviceHdl; - - //! Each node will have a renderpass and each renderpass will have its own subpasses. - //! These subpasses will execute sequentially. - Handle 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> framebuffers; - - //! Nodes that must finish execution before this node is executed will be in this container - std::vector> prereqNodes; - - //! Container of Attachment descriptions - std::vector attachmentDescriptions; - - //! Resources used in this renderpass - std::vector> attResources; - - //! Vector of subpasses - std::vector> subpasses; - - //! Descriptions to pass to renderpass for renderpass creation. We want to keep this here because - std::vector spDescs; - - //! Subpass dependencies for renderpass creation - std::vector spDeps; - - //! For indexing resources fast - std::unordered_map resourceAttachmentMapping; - - //! For indexing subpasses - std::map subpassIndexing; - - //! Pointer to resources in the render graph (for getting handle IDs) - std::unordered_map> const* ptrToResources; - - //! Every renderpass will require a pipeline library that will contain pipelines compatible with this renderpass - SHPipelineLibrary pipelineLibrary; - - //! Whether or not the node has finished execution - bool executed; - - //! Whether or not the node has been configured already or not - bool configured; - - SHBatcher batcher; - - /*-----------------------------------------------------------------------*/ - /* PRIVATE MEMBER FUNCTIONS */ - /*-----------------------------------------------------------------------*/ - void CreateRenderpass (void) noexcept; - void CreateFramebuffer(void) noexcept; - - public: - /*-----------------------------------------------------------------------*/ - /* CTORS AND DTORS */ - /*-----------------------------------------------------------------------*/ - SHRenderGraphNode (ResourceManager& rm, Handle const& logicalDevice, Handle const& swapchain, std::vector> attRes, std::vector> predecessors, std::unordered_map> const* resources, Handle globalData) noexcept; - SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept; - SHRenderGraphNode& operator= (SHRenderGraphNode&& rhs) noexcept; - - /*-----------------------------------------------------------------------*/ - /* PUBLIC MEMBER FUNCTIONS */ - /*-----------------------------------------------------------------------*/ - Handle AddSubpass (std::string subpassName) noexcept; - // TODO: RemoveSubpass() - void Execute (Handle& commandBuffer, uint32_t frameIndex) noexcept; - Handle GetOrCreatePipeline (std::pair, Handle> const& vsFsPair, Handle subpass) noexcept; - void FinaliseBatch(uint32_t frameIndex); - - /*-----------------------------------------------------------------------*/ - /* SETTERS AND GETTERS */ - /*-----------------------------------------------------------------------*/ - Handle GetRenderpass (void) const noexcept; - Handle GetSubpass(std::string_view subpassName) const noexcept; - friend class SHRenderGraph; - }; class SH_API SHRenderGraph { @@ -272,9 +61,6 @@ namespace SHADE //! Resource library for graph handles ResourceManager resourceManager; - - //! Handle to global data - Handle globalData; public: /*-----------------------------------------------------------------------*/ @@ -288,12 +74,12 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ - void Init (Handle const& logicalDevice, Handle const& swapchain, Handle inGlobalData) noexcept; + void Init (Handle const& logicalDevice, Handle const& swapchain) noexcept; void AddResource (std::string resourceName, SH_ATT_DESC_TYPE type, uint32_t w = static_cast(-1), uint32_t h = static_cast(-1), vk::Format format = vk::Format::eB8G8R8A8Unorm, uint8_t levels = 1, vk::ImageCreateFlagBits createFlags = {}); Handle AddNode (std::string nodeName, std::initializer_list resourceNames, std::initializer_list predecessorNodes) noexcept; void Generate (void) noexcept; - void Execute (uint32_t frameIndex, Handle cmdBuffer) noexcept; - void FinaliseBatch(uint32_t frameIndex); + void Execute (uint32_t frameIndex, Handle cmdBuffer, Handle descPool) noexcept; + void FinaliseBatch(uint32_t frameIndex, Handle descPool); /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp new file mode 100644 index 00000000..b981225a --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp @@ -0,0 +1,276 @@ +#include "SHpch.h" +#include "SHRenderGraphNode.h" +#include "Graphics/Devices/SHVkLogicalDevice.h" +#include "Graphics/Images/SHVkImageView.h" +#include "Graphics/Swapchain/SHVkSwapchain.h" +#include "SHRenderGraphResource.h" +#include "SHSubpass.h" + +namespace SHADE +{ + + /***************************************************************************/ + /*! + + \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> imageViews(attResources.size()); + uint32_t fbWidth = std::numeric_limits::max(); + uint32_t fbHeight = std::numeric_limits::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 const& logicalDevice, Handle const& swapchain, std::vector> attRes, std::vector> predecessors, std::unordered_map> 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 } + { + // pipeline library initialization + pipelineLibrary.Init(logicalDeviceHdl); + + 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::eStore; + + newDesc.stencilLoadOp = vk::AttachmentLoadOp::eClear; + newDesc.stencilStoreOp = vk::AttachmentStoreOp::eStore; + + 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 } + , pipelineLibrary{ std::move(rhs.pipelineLibrary) } + , batcher{ std::move(rhs.batcher) } + + { + 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); + pipelineLibrary = std::move(rhs.pipelineLibrary); + batcher = std::move(rhs.batcher); + + 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::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(resourceManager, GetHandle(), subpasses.size(), &resourceAttachmentMapping, ptrToResources)); + subpassIndexing.try_emplace(subpassName, static_cast(subpasses.size()) - 1u); + Handle subpass = subpasses.back(); + subpass->Init(resourceManager); + + // Register the SuperBatch + batcher.RegisterSuperBatch(subpass->GetSuperBatch()); + + return subpass; + } + + void SHRenderGraphNode::Execute(Handle& commandBuffer, Handle descPool, uint32_t frameIndex) noexcept + { + frameIndex = (framebuffers.size() > 1) ? frameIndex : 0; + commandBuffer->BeginRenderpass(renderpass, framebuffers[frameIndex]); + + for (uint32_t i = 0; i < subpasses.size(); ++i) + { + subpasses[i]->Execute(commandBuffer, descPool, frameIndex); + + // Go to next subpass if not last subpass + if (i != subpasses.size() - 1) + commandBuffer->NextSubpass(); + } + + commandBuffer->EndRenderpass(); + } + + Handle SHRenderGraphNode::GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept + { + // verify subpass exists + if (subpass->GetIndex() >= subpasses.size()) + { + SHLOG_ERROR("Subpass index passed in is not valid. RenderGraphNode does not have that many passes. "); + return {}; + } + + Handle pipeline = pipelineLibrary.GetDrawPipline(vsFsPair); + if (!pipeline) + { + pipeline = pipelineLibrary.CreateDrawPipeline + ( + vsFsPair, + renderpass, + subpass + ); + } + + return pipeline; + } + + void SHRenderGraphNode::FinaliseBatch(uint32_t frameIndex, Handle descPool) + { + batcher.FinaliseBatches(logicalDeviceHdl, descPool, frameIndex); + } + + /***************************************************************************/ + /*! + + \brief + Get the renderpass from the node. + + \return + Handle to the renderpass. + + */ + /***************************************************************************/ + Handle SHRenderGraphNode::GetRenderpass(void) const noexcept + { + return renderpass; + } + + Handle SHRenderGraphNode::GetSubpass(std::string_view subpassName) const noexcept + { + return subpasses[subpassIndexing.at(subpassName.data())]; + } + +} \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h new file mode 100644 index 00000000..59b20271 --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h @@ -0,0 +1,110 @@ +#pragma once + +#include +#include +#include +#include +#include "SHAttachmentDescriptionType.h" +#include "Graphics/SHVulkanIncludes.h" +#include "SH_API.h" +#include "Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h" +#include "Graphics/MiddleEnd/Batching/SHBatcher.h" + +namespace SHADE +{ + class ResourceManager; + class SHVkFramebuffer; + class SHRenderGraphResource; + class SHVkLogicalDevice; + class SHVkRenderpass; + class SHVkDescriptorPool; + + class SH_API SHRenderGraphNode : public ISelfHandle + { + private: + /*-----------------------------------------------------------------------*/ + /* PRIVATE MEMBER VARIABLES */ + /*-----------------------------------------------------------------------*/ + ResourceManager& resourceManager; + + //! For Vulkan object creation + Handle logicalDeviceHdl; + + //! Each node will have a renderpass and each renderpass will have its own subpasses. + //! These subpasses will execute sequentially. + Handle 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> framebuffers; + + //! Nodes that must finish execution before this node is executed will be in this container + std::vector> prereqNodes; + + //! Container of Attachment descriptions + std::vector attachmentDescriptions; + + //! Resources used in this renderpass + std::vector> attResources; + + //! Vector of subpasses + std::vector> subpasses; + + //! Descriptions to pass to renderpass for renderpass creation. We want to keep this here because + std::vector spDescs; + + //! Subpass dependencies for renderpass creation + std::vector spDeps; + + //! For indexing resources fast + std::unordered_map resourceAttachmentMapping; + + //! For indexing subpasses + std::map subpassIndexing; + + //! Pointer to resources in the render graph (for getting handle IDs) + std::unordered_map> const* ptrToResources; + + //! Every renderpass will require a pipeline library that will contain pipelines compatible with this renderpass + SHPipelineLibrary pipelineLibrary; + + //! Whether or not the node has finished execution + bool executed; + + //! Whether or not the node has been configured already or not + bool configured; + + SHBatcher batcher; + + /*-----------------------------------------------------------------------*/ + /* PRIVATE MEMBER FUNCTIONS */ + /*-----------------------------------------------------------------------*/ + void CreateRenderpass(void) noexcept; + void CreateFramebuffer(void) noexcept; + + public: + /*-----------------------------------------------------------------------*/ + /* CTORS AND DTORS */ + /*-----------------------------------------------------------------------*/ + SHRenderGraphNode(ResourceManager& rm, Handle const& logicalDevice, Handle const& swapchain, std::vector> attRes, std::vector> predecessors, std::unordered_map> const* resources) noexcept; + SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept; + SHRenderGraphNode& operator= (SHRenderGraphNode&& rhs) noexcept; + + /*-----------------------------------------------------------------------*/ + /* PUBLIC MEMBER FUNCTIONS */ + /*-----------------------------------------------------------------------*/ + Handle AddSubpass(std::string subpassName) noexcept; + // TODO: RemoveSubpass() + void Execute(Handle& commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; + Handle GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept; + void FinaliseBatch(uint32_t frameIndex, Handle descPool); + + /*-----------------------------------------------------------------------*/ + /* SETTERS AND GETTERS */ + /*-----------------------------------------------------------------------*/ + Handle GetRenderpass(void) const noexcept; + Handle GetSubpass(std::string_view subpassName) const noexcept; + friend class SHRenderGraph; + }; + +} diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp new file mode 100644 index 00000000..eb873b16 --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp @@ -0,0 +1,192 @@ +#include "SHpch.h" +#include "SHRenderGraphResource.h" +#include "Graphics/Devices/SHVkLogicalDevice.h" +#include "Graphics/Swapchain/SHVkSwapchain.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 const& logicalDevice, Handle 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 + { + + } + +} \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h new file mode 100644 index 00000000..fcb16601 --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h @@ -0,0 +1,62 @@ +#pragma once + +#include +#include "SHAttachmentDescriptionType.h" +#include +#include "Resource/Handle.h" +#include "Graphics/SHVulkanIncludes.h" +#include "SH_API.h" + +namespace SHADE +{ + class SHVkImage; + class SHVkImageView; + class SHVkLogicalDevice; + class SHVkSwapchain; + + class SH_API 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> images; + + //! Views to resources (vector because same rationale as images. see above). + std::vector> 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 const& logicalDevice, Handle 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; + }; +} diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp new file mode 100644 index 00000000..007502dd --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp @@ -0,0 +1,210 @@ +#include "SHpch.h" +#include "SHSubpass.h" +#include "Graphics/MiddleEnd/Batching/SHSuperBatch.h" +#include "Graphics/Devices/SHVkLogicalDevice.h" + +namespace SHADE +{ + + /***************************************************************************/ + /*! + + \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. + + */ + /***************************************************************************/ + SHSubpass::SHSubpass(ResourceManager& rm, Handle const& parent, uint32_t index, std::unordered_map const* mapping, std::unordered_map> const* resources) noexcept + : resourceAttachmentMapping{ mapping } + , ptrToResources{ resources } + , parentNode{ parent } + , subpassIndex{ index } + , superBatch{} + , colorReferences{} + , depthReferences{} + , inputReferences{} + { + } + + /***************************************************************************/ + /*! + + \brief + Move constructor for subpass. + + \param rhs + The subpass the move from. + + */ + /***************************************************************************/ + SHSubpass::SHSubpass(SHSubpass&& rhs) noexcept + : subpassIndex{ std::move(rhs.subpassIndex) } + , parentNode{ std::move(rhs.parentNode) } + , superBatch{ std::move(rhs.superBatch) } + , 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. + + */ + /***************************************************************************/ + SHSubpass& SHSubpass::operator=(SHSubpass&& rhs) noexcept + { + if (this == &rhs) + return *this; + + subpassIndex = std::move(rhs.subpassIndex); + parentNode = std::move(rhs.parentNode); + superBatch = std::move(rhs.superBatch); + 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 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 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 SHSubpass::AddInput(std::string resourceToReference) noexcept + { + inputReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eShaderReadOnlyOptimal }); + } + + void SHSubpass::Execute(Handle& commandBuffer, Handle descPool, uint32_t frameIndex) noexcept + { + // Ensure correct transforms are provided + superBatch->UpdateBuffers(frameIndex, descPool); + + // Draw all the batches + superBatch->Draw(commandBuffer, frameIndex); + + // Draw all the exterior draw calls + for (auto& drawCall : exteriorDrawCalls) + { + drawCall(commandBuffer); + } + } + + void SHSubpass::AddExteriorDrawCalls(std::function&)> const& newDrawCall) noexcept + { + exteriorDrawCalls.push_back(newDrawCall); + } + + void SHSubpass::Init(ResourceManager& resourceManager) noexcept + { + superBatch = resourceManager.Create(GetHandle()); + + } + + /***************************************************************************/ + /*! + + \brief + Getter for parent renderpass. + + \return + Returns the parent renderpass the subpass belongs to. + + */ + /***************************************************************************/ + Handle const& SHSubpass::GetParentNode(void) const noexcept + { + return parentNode; + } + + SHADE::SHSubPassIndex SHSubpass::GetIndex() const noexcept + { + return subpassIndex; + } + + Handle SHSubpass::GetSuperBatch(void) const noexcept + { + return superBatch; + } +} \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h new file mode 100644 index 00000000..b8b8717f --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h @@ -0,0 +1,94 @@ +#pragma once + +#include "SHAttachmentDescriptionType.h" +#include +#include "SH_API.h" +#include "Resource/Handle.h" +#include "Graphics/SHVulkanIncludes.h" + + +namespace SHADE +{ + class SHRenderGraphNode; + class SHSuperBatch; + class SHRenderGraphResource; + class SHVkCommandBuffer; + class SHVkDescriptorSetLayout; + class SHVkDescriptorPool; + + class SH_API SHSubpass : public ISelfHandle + { + private: + /*---------------------------------------------------------------------*/ + /* PRIVATE MEMBER VARIABLES */ + /*---------------------------------------------------------------------*/ + //! The index of the subpass in the render graph + uint32_t subpassIndex; + + //! The parent renderpass that this subpass belongs to + Handle parentNode; + + //! + Handle superBatch; + + //! Descriptor set layout to hold attachments + Handle descriptorSetLayout; + + //! Color attachments + std::vector colorReferences; + + //! Depth attachments + std::vector depthReferences; + + //! Input attachments + std::vector inputReferences; + + //! For getting attachment reference indices using handles + std::unordered_map const* resourceAttachmentMapping; + + //! Pointer to resources in the render graph (for getting handle IDs) + std::unordered_map> const* ptrToResources; + + //! Sometimes there exists entities that we want to render onto a render target + //! but don't want it to come from the batching system. An example would be ImGUI. + //! For these entities we want to link a function from the outside and draw them + //! after we draw everything from the batch. Because of this, these draw calls + //! are always the last things drawn, so DO NOT USE THIS FUNCTIONALITY FOR ANYTHING + //! COMPLEX. + std::vector&)>> exteriorDrawCalls; + + + public: + /*-----------------------------------------------------------------------*/ + /* CTORS AND DTORS */ + /*-----------------------------------------------------------------------*/ + SHSubpass(ResourceManager& rm, Handle const& parent, uint32_t index, std::unordered_map const* mapping, std::unordered_map> const* ptrToResources) noexcept; + SHSubpass(SHSubpass&& rhs) noexcept; + SHSubpass& operator=(SHSubpass&& rhs) noexcept; + + /*-----------------------------------------------------------------------*/ + /* PUBLIC MEMBER FUNCTIONS */ + /*-----------------------------------------------------------------------*/ + // Preparation functions + 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; + + // Runtime functions + void Execute(Handle& commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; + void AddExteriorDrawCalls(std::function&)> const& newDrawCall) noexcept; + + void Init(ResourceManager& resourceManager) noexcept; + + /*-----------------------------------------------------------------------*/ + /* GETTERS AND SETTERS */ + /*-----------------------------------------------------------------------*/ + Handle const& GetParentNode(void) const noexcept; + SHSubPassIndex GetIndex() const noexcept; + Handle GetSuperBatch(void) const noexcept; + + + friend class SHRenderGraphNode; + friend class SHRenderGraph; + }; +} diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.cpp new file mode 100644 index 00000000..ccd0e6c3 --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.cpp @@ -0,0 +1,23 @@ +#include "SHpch.h" +#include "SHSubpassCompute.h" +#include "Graphics/Pipeline/SHVkPipeline.h" +#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" +#include "Graphics/Descriptors/SHVkDescriptorPool.h" + +namespace SHADE +{ + SHSubpassCompute::SHSubpassCompute(Handle inPipeline, Handle descPool) noexcept + : pipeline {inPipeline} + { + // Get the descriptor set layouts required to allocate. we will bind a different pipeline layout, one that includes the layout for global. + auto const& layouts = pipeline->GetPipelineLayout()->GetDescriptorSetLayoutsAllocate(); + + // Variable counts for the descriptor sets (all should be 1). + std::vector variableCounts{static_cast(layouts.size())}; + std::fill (variableCounts.begin(), variableCounts.end(), 0); + + // Allocate descriptor sets to hold the images for reading (STORAGE_IMAGE) + descPool->Allocate(layouts, variableCounts); + } + +} diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.h b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.h new file mode 100644 index 00000000..3ebc5676 --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +namespace SHADE +{ + class SHVkPipeline; + class SHVkDescriptorSetGroup; + class SHVkDescriptorPool; + + class SHSubpassCompute + { + private: + //! To run the dispatch command + Handle pipeline; + + //! Descriptor set group + Handle descSetGroup; + + public: + SHSubpassCompute (Handle inPipeline, Handle descPool) noexcept; + + }; +} + diff --git a/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.h b/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.h index afed0736..b0ae7445 100644 --- a/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.h +++ b/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.h @@ -10,10 +10,6 @@ namespace SHADE { class SHVkLogicalDevice; class SHVkFramebuffer; - /*-----------------------------------------------------------------------*/ - /* TYPE DEFINTIIONS */ - /*-----------------------------------------------------------------------*/ - using SHSubPassIndex = uint32_t; class SHVkRenderpass { diff --git a/SHADE_Engine/src/Graphics/SHVulkanDefines.h b/SHADE_Engine/src/Graphics/SHVulkanDefines.h index 2f625f7e..1cbcae0f 100644 --- a/SHADE_Engine/src/Graphics/SHVulkanDefines.h +++ b/SHADE_Engine/src/Graphics/SHVulkanDefines.h @@ -5,9 +5,13 @@ namespace SHADE { + /*-----------------------------------------------------------------------*/ + /* TYPE DEFINTIIONS */ + /*-----------------------------------------------------------------------*/ using SHQueueFamilyIndex = uint32_t; using BindingAndSetHash = uint64_t; using SetIndex = uint32_t; + using SHSubPassIndex = uint32_t; } diff --git a/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.cpp b/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.cpp index 7ed50c59..75ede865 100644 --- a/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.cpp +++ b/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.cpp @@ -27,7 +27,7 @@ namespace SHADE SHADE::SHShaderBlockInterface::Variable const* const SHShaderBlockInterface::GetVariable(uint32_t index) const noexcept { - if (variableIndexing.size() < index) + if (index < variableIndexing.size()) return &variables.at(index); return nullptr; diff --git a/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.h b/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.h index ee7e7726..e546b452 100644 --- a/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.h +++ b/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.h @@ -2,10 +2,12 @@ #include +#include "SH_API.h" + namespace SHADE { - class SHShaderBlockInterface + class SH_API SHShaderBlockInterface { public: struct Variable diff --git a/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp b/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp index 1e5fb074..41327988 100644 --- a/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp +++ b/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp @@ -111,6 +111,7 @@ namespace SHADE biggestAlignment = std::max(biggestAlignment, 4u); break; case SpvOp::SpvOpTypeStruct: + case SpvOp::SpvOpTypeRuntimeArray: recurseForInfo(&member, interfaceHdl, member.offset, biggestAlignment, parentVarName + std::string(member.name) + "."); break; } diff --git a/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp b/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp index f698bd41..6b05e323 100644 --- a/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp +++ b/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp @@ -47,7 +47,7 @@ namespace SHADE void SHTransformSystem::Init() { - + } void SHTransformSystem::Exit() diff --git a/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp index d27469ad..df69ad04 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp +++ b/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp @@ -178,9 +178,6 @@ namespace SHADE settings.defaultPositionSolverNbIterations = 3; world = factory.createPhysicsWorld(settings); - - // Create component sparse sets - SHADE::SHComponentManager::CreateComponentSparseSet(); } void SHPhysicsSystem::Exit() @@ -190,10 +187,10 @@ namespace SHADE void SHPhysicsSystem::PhysicsPreUpdate::Execute([[maybe_unused]]double dt) noexcept { - auto* system = reinterpret_cast(GetSystem()); + auto* system = reinterpret_cast(GetSystem()); system->ClearUpdateQueue(); - system->SyncActiveStates(SHSceneManager::GetCurrentSceneGraph()); + //system->SyncActiveStates(SHSceneManager::GetCurrentSceneGraph()); } void SHPhysicsSystem::PhysicsFixedUpdate::FixedExecute(double dt) noexcept @@ -207,8 +204,11 @@ namespace SHADE void SHPhysicsSystem::PhysicsPostUpdate::Execute(double dt) noexcept { + auto* system = reinterpret_cast(GetSystem()); + // Interpolate transforms for rendering const auto& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); + //system->SyncTransforms(sceneGraph); // TODO(Diren): Handle trigger messages for scripting } diff --git a/SHADE_Engine/src/Reflection/SHReflectionMetadata.h b/SHADE_Engine/src/Reflection/SHReflectionMetadata.h new file mode 100644 index 00000000..0cc6d8a5 --- /dev/null +++ b/SHADE_Engine/src/Reflection/SHReflectionMetadata.h @@ -0,0 +1,11 @@ +#pragma once +#include "string_view" +namespace SHADE +{ + namespace META + { + constexpr const char* min = "MIN"; + constexpr const char* max = "MAX"; + constexpr const char* tooltip = "tooltip"; + } +} diff --git a/SHADE_Engine/src/Resource/Handle.h b/SHADE_Engine/src/Resource/Handle.h index a0272290..9579063c 100644 --- a/SHADE_Engine/src/Resource/Handle.h +++ b/SHADE_Engine/src/Resource/Handle.h @@ -54,7 +54,7 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Usage Functions */ /*-----------------------------------------------------------------------------*/ - inline Id GetId() const; + inline Id GetId() const noexcept; /*-----------------------------------------------------------------------------*/ /* Overloaded Operators */ @@ -62,7 +62,7 @@ namespace SHADE /// /// Converts to true if this is a valid Handle. /// - inline operator bool() const; + inline operator bool() const noexcept; protected: /*-----------------------------------------------------------------------------*/ @@ -101,6 +101,7 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Overloaded Operators */ /*-----------------------------------------------------------------------------*/ + inline bool operator==(const Handle& rhs) const noexcept; /// /// Returns the underlying object pointed to by the Handle. /// diff --git a/SHADE_Engine/src/Resource/Handle.hpp b/SHADE_Engine/src/Resource/Handle.hpp index 27cdd1cd..45468ec1 100644 --- a/SHADE_Engine/src/Resource/Handle.hpp +++ b/SHADE_Engine/src/Resource/Handle.hpp @@ -8,15 +8,15 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* HandleBase - Usage Functions */ /*---------------------------------------------------------------------------------*/ - inline HandleBase::Id HandleBase::GetId() const + inline HandleBase::Id HandleBase::GetId() const noexcept { return id; } /*---------------------------------------------------------------------------------*/ /* HandleBase - Overloaded Operators */ - inline HandleBase::operator bool() const /*---------------------------------------------------------------------------------*/ + inline HandleBase::operator bool() const noexcept { return id.Raw != INVALID_ID.Raw; } @@ -33,6 +33,12 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* Handle - Overloaded Operators */ /*---------------------------------------------------------------------------------*/ + template + bool SHADE::Handle::operator==(const Handle& rhs) const noexcept + { + return id.Raw == rhs.id.Raw && library == rhs.library; + } + template T& Handle::operator*() { diff --git a/TempShaderFolder/TestCubeFs.glsl b/TempShaderFolder/TestCubeFs.glsl index 7d49eda4..3a25ad71 100644 --- a/TempShaderFolder/TestCubeFs.glsl +++ b/TempShaderFolder/TestCubeFs.glsl @@ -1,72 +1,44 @@ #version 450 #extension GL_ARB_separate_shader_objects : enable #extension GL_ARB_shading_language_420pack : enable +#extension GL_EXT_nonuniform_qualifier : require + +struct MatPropData +{ + vec4 color; + int textureIndex; + float alpha; + vec3 beta; +}; layout(location = 0) in struct { - //mat3 BTN; vec4 vertColor; - //vec3 localSpacePosition; - //vec2 uv; - //vec3 localLightPosition; - //vec3 localEyePosition; + vec2 uv; } In; -//layout(std140, push_constant) uniform TestPushConstant -//{ -// mat4 pvMat; -// vec4 lightPosition; -// vec4 eyePosition; -// vec4 ambientColor; -// vec4 lightColor; -// -//} testPushConstant; +// material stuff +layout(location = 2) flat in struct +{ + int materialIndex; +} In2; + +//layout (set = 0, binding = ) + +layout (set = 0, binding = 1) uniform sampler2D textures[]; // for textures (global) +layout (set = 3, binding = 0) buffer MaterialProperties // For materials +{ + MatPropData data[]; +} MatProp; layout(location = 0) out vec4 outColor; -//layout(binding = 0) uniform sampler2D diffuseMap; -//layout(binding = 1) uniform sampler2D normalMap; -//layout(binding = 2) uniform sampler2D aoMap; -//layout(binding = 3) uniform sampler2D glossinessMap; -//layout(binding = 4) uniform sampler2D samplerRoughnessMap; - void main() { - //vec3 normal; - //// Get the tangent space normal from normal map. It is a BC5 texture and therefore only use red and green - //normal.xy = (texture (normalMap, In.uv).gr * 2.0f) - 1.0f; + outColor = texture(textures[nonuniformEXT(MatProp.data[In2.materialIndex].textureIndex)], In.uv) + + MatProp.data[In2.materialIndex].color / MatProp.data[In2.materialIndex].alpha; - //// z value is derived (TODO: Find out what this does) - //normal.z = sqrt(1.0f - dot(normal.xy, normal.xy)); - - //// Transform the normal from tangent space to local space - //normal = In.BTN * normal; - - //// Get the vector from fragment to light - //vec3 localLightDir = normalize(In.localLightPosition - In.localSpacePosition); - - //// get the value of dot between normal from texture and frag to light - //float diffuse = max(0, dot(normal, localLightDir)); - - //// sample the diffuse texture - //vec4 diffuseColor = texture (diffuseMap, In.uv) * In.vertColor; - - //vec3 eyeDirection = normalize(In.localSpacePosition - In.localEyePosition); - - //const float shininess = mix(1, 100, 1 - texture (samplerRoughnessMap, In.uv).r); - - //float specular = pow(max(0, dot(normal, normalize(localLightDir - eyeDirection))), shininess); - - //outColor.rgb = testPushConstant.ambientColor.rgb * diffuseColor.rgb * texture (aoMap, In.uv).rgb; - - //outColor.rgb += testPushConstant.lightColor.rgb * (specular.rrr * 0.4 + diffuse.rrr * diffuseColor.rgb); - - //const float gamma = testPushConstant.eyePosition.w; - //outColor.rgb = pow(outColor.rgb, vec3(1.0f / gamma)); - //outColor.a = diffuseColor.a; - - - outColor = vec4 (1.0f); + //outColor = vec4 (1.0f); } \ No newline at end of file diff --git a/TempShaderFolder/TestCubeFs.spv b/TempShaderFolder/TestCubeFs.spv index 669dc8b8..07f67a45 100644 Binary files a/TempShaderFolder/TestCubeFs.spv and b/TempShaderFolder/TestCubeFs.spv differ diff --git a/TempShaderFolder/TestCubeVs.glsl b/TempShaderFolder/TestCubeVs.glsl index b2d52104..eb5b2dff 100644 --- a/TempShaderFolder/TestCubeVs.glsl +++ b/TempShaderFolder/TestCubeVs.glsl @@ -9,27 +9,20 @@ layout(location = 2) in vec3 aNormal; layout(location = 3) in vec3 aTangent; layout(location = 4) in mat4 worldTransform; -//layout(std140, push_constant) uniform TestPushConstant -//{ -// mat4 pvMat; -// vec4 lightPosition; -// vec4 eyePosition; -// vec4 ambientColor; -// vec4 lightColor; -// -//} testPushConstant; layout(location = 0) out struct { - //mat3 BTN; - vec4 vertColor; - //vec3 localSpacePosition; - //vec2 uv; - //vec3 localLightPosition; - //vec3 localEyePosition; + vec4 vertColor; // location 0 + vec2 uv; // location = 1 } Out; +// material stuff +layout(location = 2) out struct +{ + int materialIndex; +} Out2; + layout(set = 2, binding = 0) uniform CameraData { vec4 position; @@ -38,25 +31,8 @@ layout(set = 2, binding = 0) uniform CameraData void main() { - //const float gamma = testPushConstant.eyePosition.w; - //mat4 W2L = inverse(worldTransform); - - //// Since attributes are instanced we want the local positions of light and eye (camera) - //Out.localLightPosition = vec3(W2L * vec4(testPushConstant.lightPosition.xyz, 1.0f)); - //Out.localEyePosition = vec3(W2L * vec4(testPushConstant.eyePosition.xyz, 1.0f)); - - //vec3 biTangent = normalize(cross(aNormal, aTangent)); - - //gl_Position = testPushConstant.pvMat * worldTransform * vec4(aVertexPos, 1.0); - - //// Since the normal we are sampling is in tangent space, we want to later convert them to local space - //// so we need this matrix to multiply with the sampled texel of the normal map. - //Out.BTN = mat3(aTangent, biTangent, aNormal); - //Out.localSpacePosition = aVertexPos; - //Out.uv = aUV; - - // render NDC first - //gl_Position = vec4(aVertexPos, 1.0f); + Out.uv = aUV; + Out2.materialIndex = gl_InstanceIndex; gl_Position = cameraData.vpMat * worldTransform * vec4 (aVertexPos, 1.0f); Out.vertColor = vec4 (aVertexPos, 1.0f); } \ No newline at end of file diff --git a/TempShaderFolder/TestCubeVs.spv b/TempShaderFolder/TestCubeVs.spv index eb9a1209..dfc9eda1 100644 Binary files a/TempShaderFolder/TestCubeVs.spv and b/TempShaderFolder/TestCubeVs.spv differ