diff --git a/Assets/Editor/Layouts/UserLayout.ini b/Assets/Editor/Layouts/UserLayout.ini new file mode 100644 index 00000000..baced6b8 --- /dev/null +++ b/Assets/Editor/Layouts/UserLayout.ini @@ -0,0 +1,54 @@ +[Window][MainStatusBar] +Pos=0,1060 +Size=1920,20 +Collapsed=0 + +[Window][SHEditorMenuBar] +Pos=0,48 +Size=1920,1012 +Collapsed=0 + +[Window][Hierarchy Panel] +Pos=0,142 +Size=387,918 +Collapsed=0 +DockId=0x00000004,0 + +[Window][Debug##Default] +Pos=60,60 +Size=400,400 +Collapsed=0 + +[Window][Inspector] +Pos=1649,48 +Size=271,1012 +Collapsed=0 +DockId=0x00000006,0 + +[Window][Profiler] +Pos=0,48 +Size=387,92 +Collapsed=0 +DockId=0x00000003,0 + +[Window][Viewport] +Pos=648,48 +Size=2519,1319 +Collapsed=0 +DockId=0x00000002,0 + +[Window][ Viewport] +Pos=389,48 +Size=1258,1012 +Collapsed=0 +DockId=0x00000002,0 + +[Docking][Data] +DockSpace ID=0xC5C9B8AB Window=0xBE4044E9 Pos=8,79 Size=1920,1012 Split=X + DockNode ID=0x00000005 Parent=0xC5C9B8AB SizeRef=1992,1036 Split=X + DockNode ID=0x00000001 Parent=0x00000005 SizeRef=387,1036 Split=Y Selected=0x1E6EB881 + DockNode ID=0x00000003 Parent=0x00000001 SizeRef=225,94 Selected=0x1E6EB881 + DockNode ID=0x00000004 Parent=0x00000001 SizeRef=225,940 Selected=0xE096E5AE + DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1258,1036 CentralNode=1 Selected=0xB41284E7 + DockNode ID=0x00000006 Parent=0xC5C9B8AB SizeRef=271,1036 Selected=0xE7039252 + diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index a9f632da..e33bdf8a 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -93,6 +93,7 @@ namespace Sandbox SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); + SHSystemManager::RegisterRoutine(); #ifdef SHEDITOR SHSystemManager::RegisterRoutine(); diff --git a/SHADE_Application/src/Scenes/SBTestScene.cpp b/SHADE_Application/src/Scenes/SBTestScene.cpp index 41326174..b414ecaf 100644 --- a/SHADE_Application/src/Scenes/SBTestScene.cpp +++ b/SHADE_Application/src/Scenes/SBTestScene.cpp @@ -14,6 +14,7 @@ #include "Physics/Components/SHColliderComponent.h" #include "Assets/SHAssetManager.h" +#include "Camera/SHCameraComponent.h" #include "Resource/SHResourceManager.h" using namespace SHADE; @@ -155,6 +156,10 @@ namespace Sandbox transformShowcase.SetWorldPosition({ 3.0f, -1.0f, -1.0f }); transformShowcase.SetLocalScale({ 5.0f, 5.0f, 5.0f }); scriptEngine->AddScript(raccoonShowcase, "RaccoonShowcase"); + + SHComponentManager::AddComponent(0); + SHComponentManager::RemoveComponent (0); + SHComponentManager::RemoveComponent (0); } void SBTestScene::Update(float dt) diff --git a/SHADE_Engine/src/Camera/SHCameraComponent.cpp b/SHADE_Engine/src/Camera/SHCameraComponent.cpp index 7ba6855c..5d49c887 100644 --- a/SHADE_Engine/src/Camera/SHCameraComponent.cpp +++ b/SHADE_Engine/src/Camera/SHCameraComponent.cpp @@ -1,7 +1,9 @@ #include "SHpch.h" #include "SHCameraComponent.h" #include "ECS_Base/Managers/SHComponentManager.h" - +#include "SHCameraSystem.h" +#include "ECS_Base/Managers/SHSystemManager.h" +#include "Math/Transform/SHTransformComponent.h" namespace SHADE { @@ -22,33 +24,69 @@ namespace SHADE void SHCameraComponent::SetYaw(float yaw) noexcept { this->yaw = yaw; + if (SHComponentManager::HasComponent(GetEID())) + { + auto transform = SHComponentManager::GetComponent(GetEID()); + SHVec3 rotation = transform->GetWorldRotation(); + transform->SetWorldRotation(SHVec3{rotation.x,yaw, rotation.z}); + } dirtyView = true; } void SHCameraComponent::SetPitch(float pitch) noexcept { this->pitch = pitch; + if (SHComponentManager::HasComponent(GetEID())) + { + auto transform = SHComponentManager::GetComponent(GetEID()); + SHVec3 rotation = transform->GetWorldRotation(); + transform->SetWorldRotation(SHVec3{ pitch,rotation.y, rotation.z }); + } dirtyView = true; } void SHCameraComponent::SetRoll(float roll) noexcept { this->roll = roll; + if (SHComponentManager::HasComponent(GetEID())) + { + auto transform = SHComponentManager::GetComponent(GetEID()); + SHVec3 rotation = transform->GetWorldRotation(); + transform->SetWorldRotation(SHVec3{ rotation.x,rotation.y, roll}); + } dirtyView = true; } void SHCameraComponent::SetPositionX(float x) noexcept { position.x = x; + if (SHComponentManager::HasComponent(GetEID())) + { + auto transform = SHComponentManager::GetComponent(GetEID()); + SHVec3 position = transform->GetWorldPosition(); + transform->SetWorldRotation(SHVec3{ x,position.y, position.z}); + } dirtyView = true; } void SHCameraComponent::SetPositionY(float y) noexcept { position.y = y; + if (SHComponentManager::HasComponent(GetEID())) + { + auto transform = SHComponentManager::GetComponent(GetEID()); + SHVec3 position = transform->GetWorldPosition(); + transform->SetWorldRotation(SHVec3{ position.x,y, position.z }); + } dirtyView = true; } void SHCameraComponent::SetPositionZ(float z) noexcept { position.z = z; + if (SHComponentManager::HasComponent(GetEID())) + { + auto transform = SHComponentManager::GetComponent(GetEID()); + SHVec3 position = transform->GetWorldPosition(); + transform->SetWorldRotation(SHVec3{ position.x,position.y, z }); + } dirtyView = true; } void SHCameraComponent::SetPosition(float x,float y, float z) noexcept @@ -56,11 +94,23 @@ namespace SHADE position.x = x; position.y = y; position.z = z; + if (SHComponentManager::HasComponent(GetEID())) + { + auto transform = SHComponentManager::GetComponent(GetEID()); + SHVec3 position = transform->GetWorldPosition(); + transform->SetWorldRotation(SHVec3{ x,y, z }); + } dirtyView = true; } void SHCameraComponent::SetPosition(SHVec3& pos) noexcept { this->position = pos; + if (SHComponentManager::HasComponent(GetEID())) + { + auto transform = SHComponentManager::GetComponent(GetEID()); + SHVec3 position = transform->GetWorldPosition(); + transform->SetWorldRotation(pos); + } dirtyView = true; } @@ -128,4 +178,12 @@ namespace SHADE return projMatrix; } + void SHCameraComponent::SetMainCamera(size_t directorCameraIndex) noexcept + { + auto system = SHSystemManager::GetSystem(); + system->GetDirector(directorCameraIndex)->SetMainCamera(*this); + } + + + } diff --git a/SHADE_Engine/src/Camera/SHCameraComponent.h b/SHADE_Engine/src/Camera/SHCameraComponent.h index c86fa160..1149b1e1 100644 --- a/SHADE_Engine/src/Camera/SHCameraComponent.h +++ b/SHADE_Engine/src/Camera/SHCameraComponent.h @@ -70,6 +70,8 @@ namespace SHADE const SHMatrix& GetViewMatrix() const noexcept; const SHMatrix& GetProjMatrix() const noexcept; + void SetMainCamera(size_t cameraDirectorIndex = 0) noexcept; + float movementSpeed; SHVec3 turnSpeed; diff --git a/SHADE_Engine/src/Camera/SHCameraDirector.cpp b/SHADE_Engine/src/Camera/SHCameraDirector.cpp new file mode 100644 index 00000000..559897c0 --- /dev/null +++ b/SHADE_Engine/src/Camera/SHCameraDirector.cpp @@ -0,0 +1,65 @@ +#include "SHpch.h" +#include "SHCameraDirector.h" +#include "SHCameraComponent.h" +#include "ECS_Base/Managers/SHComponentManager.h" +#include "ECS_Base/SHECSMacros.h" +#include "ECS_Base/Managers/SHEntityManager.h" +#include "Tools/SHLog.h" + +namespace SHADE +{ + SHCameraDirector::SHCameraDirector() + :mainCameraEID(MAX_EID), transitionCameraEID(MAX_EID) + { + } + + + SHMatrix SHCameraDirector::GetViewMatrix() const noexcept + { + return viewMatrix; + } + SHMatrix SHCameraDirector::GetProjMatrix() const noexcept + { + return projMatrix; + } + SHMatrix SHCameraDirector::GetVPMatrix() const noexcept + { + return projMatrix * viewMatrix; + } + + void SHCameraDirector::UpdateMatrix() noexcept + { + if (mainCameraEID == MAX_EID) + { + auto& dense = SHComponentManager::GetDense(); + if (dense.size() == 0) + { + return; + } + mainCameraEID = dense[0].GetEID(); + } + SHCameraComponent* camComponent = SHComponentManager::GetComponent_s(mainCameraEID); + if (!camComponent) + { + SHLOG_WARNING("Camera Director warning: Entity does not have a camera"); + } + else + { + viewMatrix = camComponent->GetViewMatrix(); + projMatrix = camComponent->GetProjMatrix(); + } + } + + void SHCameraDirector::SetMainCamera(SHCameraComponent& camera) noexcept + { + if (SHEntityManager::IsValidEID(camera.GetEID()) == false) + { + SHLOG_WARNING("Camera Director Warning: Attempting to set an invalid entity as main camera.") + return; + } + mainCameraEID = camera.GetEID(); + } + + + +} diff --git a/SHADE_Engine/src/Camera/SHCameraDirector.h b/SHADE_Engine/src/Camera/SHCameraDirector.h new file mode 100644 index 00000000..5d09788b --- /dev/null +++ b/SHADE_Engine/src/Camera/SHCameraDirector.h @@ -0,0 +1,43 @@ +#pragma once + +#include "SH_API.h" +#include "ECS_Base/Entity/SHEntity.h" +#include "Math/SHMatrix.h" +#include "Resource/SHHandle.h" + + +namespace SHADE +{ + class SHCameraComponent; + + + + class SH_API SHCameraDirector + { + public: + SHCameraDirector(); + ~SHCameraDirector() = default; + + + EntityID mainCameraEID; + EntityID transitionCameraEID; + + SHMatrix GetViewMatrix() const noexcept; + SHMatrix GetProjMatrix() const noexcept; + SHMatrix GetVPMatrix() const noexcept; + void UpdateMatrix() noexcept; + void SetMainCamera(SHCameraComponent& cam) noexcept; + + + private: + + + protected: + SHMatrix viewMatrix; + SHMatrix projMatrix; + + }; + + typedef Handle DirectorHandle; + +} diff --git a/SHADE_Engine/src/Camera/SHCameraSystem.cpp b/SHADE_Engine/src/Camera/SHCameraSystem.cpp index 7c6ea176..0d86c17a 100644 --- a/SHADE_Engine/src/Camera/SHCameraSystem.cpp +++ b/SHADE_Engine/src/Camera/SHCameraSystem.cpp @@ -3,12 +3,63 @@ #include "Math/SHMathHelpers.h" #include "Input/SHInputManager.h" #include "Math/Vector/SHVec2.h" - +#include "ECS_Base/Managers/SHComponentManager.h" +#include "Math/Transform/SHTransformComponent.h" namespace SHADE { + void SHCameraSystem::UpdateEditorCamera(double dt) noexcept + { + + auto& camera = editorCamera; + SHVec3 view, right, UP; + GetCameraAxis(camera, view, right, UP); + if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::A)) + { + camera.position -= right * dt * camera.movementSpeed; + camera.dirtyView = true; + } + if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::D)) + { + camera.position += right * dt * camera.movementSpeed; + camera.dirtyView = true; + } + if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::W)) + { + camera.position += view * dt * camera.movementSpeed; + camera.dirtyView = true; + } + if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::S)) + { + camera.position -= view * dt * camera.movementSpeed; + camera.dirtyView = true; + } + if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::Q)) + { + camera.position += UP * dt * camera.movementSpeed; + camera.dirtyView = true; + } + if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::E)) + { + camera.position -= UP * dt * camera.movementSpeed; + camera.dirtyView = true; + } + if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::RMB)) + { + double mouseX, mouseY; + SHInputManager::GetMouseVelocity(&mouseX, &mouseY); + + //std::cout << camera.yaw << std::endl; + + camera.pitch -= mouseY * dt * camera.turnSpeed.x; + camera.yaw -= mouseX * dt * camera.turnSpeed.y; + camera.dirtyView = true; + } + + UpdateCameraComponent(editorCamera); + } void SHCameraSystem::EditorCameraUpdate::Execute(double dt) noexcept { SHCameraSystem* system = static_cast(GetSystem()); @@ -18,6 +69,7 @@ namespace SHADE if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::A)) { + //std::cout << "Camera movement: "<UpdateCameraComponent(system->editorCamera); } @@ -83,10 +136,26 @@ namespace SHADE void SHCameraSystem::UpdateCameraComponent(SHCameraComponent& camera) noexcept { + if (SHComponentManager::HasComponent(camera.GetEID()) == true && &camera != &editorCamera) + { + auto transform = SHComponentManager::GetComponent(camera.GetEID()); + SHVec3 rotation = transform->GetWorldRotation(); + camera.pitch = SHMath::RadiansToDegrees(rotation.x); + camera.yaw = SHMath::RadiansToDegrees(rotation.y); + camera.roll = SHMath::RadiansToDegrees(rotation.z); + camera.position = transform->GetWorldPosition(); + camera.dirtyView = true; + } + + if (camera.dirtyView) { SHVec3 view, right, UP; + + + //ClampCameraRotation(camera); + GetCameraAxis(camera, view, right, UP); camera.viewMatrix = SHMatrix::Identity; @@ -168,5 +237,55 @@ namespace SHADE upVec = SHVec3::Cross(forward, right); } + void SHCameraSystem::CameraSystemUpdate::Execute(double dt) noexcept + { + SHCameraSystem* system = static_cast(GetSystem()); + auto& dense = SHComponentManager::GetDense(); + for (auto& cam : dense) + { + system->UpdateCameraComponent(cam); + } + for (auto& handle : system->directorHandleList) + { + handle->UpdateMatrix(); + } + + + } + + + DirectorHandle SHCameraSystem::CreateDirector() noexcept + { + auto handle = directorLibrary.Create(); + directorHandleList.emplace_back(handle); + return handle; + } + + DirectorHandle SHCameraSystem::GetDirector(size_t index) noexcept + { + if (index < directorHandleList.size()) + { + return directorHandleList[index]; + } + else + { + return CreateDirector(); + } + } + void SHCameraSystem::ClampCameraRotation(SHCameraComponent& camera) noexcept + { + + + + if (camera.pitch > 85) + camera.SetPitch(85); + if (camera.pitch < -85) + camera.SetPitch(-85); + if (camera.roll > 85) + camera.SetRoll(85); + if (camera.roll < -85) + camera.SetRoll(-85); + + } } diff --git a/SHADE_Engine/src/Camera/SHCameraSystem.h b/SHADE_Engine/src/Camera/SHCameraSystem.h index 43e386e7..68071160 100644 --- a/SHADE_Engine/src/Camera/SHCameraSystem.h +++ b/SHADE_Engine/src/Camera/SHCameraSystem.h @@ -3,9 +3,10 @@ #include "ECS_Base/System/SHSystem.h" #include "SHCameraComponent.h" #include "ECS_Base/System/SHSystemRoutine.h" +#include "Resource/SHResourceLibrary.h" +#include "SHCameraDirector.h" #include "SH_API.h" - namespace SHADE { class SH_API SHCameraSystem final : public SHSystem @@ -14,8 +15,9 @@ namespace SHADE //A camera component that represents editor camera. //This is not tied to any entity. Hence this EID should not be used. SHCameraComponent editorCamera; - + SHResourceLibrary directorLibrary; + std::vector directorHandleList; public: SHCameraSystem(void) = default; @@ -34,13 +36,26 @@ namespace SHADE }; friend class EditorCameraUpdate; - SHCameraComponent* GetEditorCamera (void) noexcept; + class SH_API CameraSystemUpdate final: public SHSystemRoutine + { + public: + CameraSystemUpdate() : SHSystemRoutine("Camera System Update", false) {}; + virtual void Execute(double dt)noexcept override final; + }; + friend class CameraSystemUpdate; + + SHCameraComponent* GetEditorCamera (void) noexcept; + void GetCameraAxis(SHCameraComponent const& camera, SHVec3& forward, SHVec3& right, SHVec3& up) const noexcept; + DirectorHandle CreateDirector() noexcept; + DirectorHandle GetDirector(size_t index) noexcept; + void ClampCameraRotation(SHCameraComponent& camera) noexcept; + void UpdateEditorCamera(double dt) noexcept; protected: void UpdateCameraComponent(SHCameraComponent& camera) noexcept; - void GetCameraAxis(SHCameraComponent const& camera, SHVec3& forward, SHVec3& right, SHVec3& up) const noexcept; + }; diff --git a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp index 4501ba7b..a744c795 100644 --- a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp +++ b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp @@ -10,6 +10,7 @@ #include "Graphics/Buffers/SHVkBuffer.h" #include "Graphics/Images/SHVkImage.h" #include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" +#include "Graphics/SHVkUtil.h" namespace SHADE @@ -299,7 +300,7 @@ namespace SHADE SHLOG_ERROR("Command buffer must have started recording before a pipeline can be bound. "); return; } - boundPipelineLayoutHdl = pipelineHdl->GetPipelineLayout(); + bindPointData[static_cast(pipelineHdl->GetPipelineType())].boundPipelineLayoutHdl = pipelineHdl->GetPipelineLayout(); vkCommandBuffer.bindPipeline(pipelineHdl->GetPipelineBindPoint(), pipelineHdl->GetVkPipeline()); } @@ -358,9 +359,10 @@ namespace SHADE } } - void SHVkCommandBuffer::BindDescriptorSet(Handle descSetGroup, vk::PipelineBindPoint bindPoint, uint32_t firstSet, std::span dynamicOffsets) + void SHVkCommandBuffer::BindDescriptorSet(Handle descSetGroup, SH_PIPELINE_TYPE bindPoint, uint32_t firstSet, std::span dynamicOffsets) { - vkCommandBuffer.bindDescriptorSets(bindPoint, boundPipelineLayoutHdl->GetVkPipelineLayout(), firstSet, descSetGroup->GetVkHandle(), dynamicOffsets); + uint32_t bindPointIndex = static_cast(bindPoint); + vkCommandBuffer.bindDescriptorSets(SHVkUtil::GetPipelineBindPointFromType(bindPoint), bindPointData[bindPointIndex].boundPipelineLayoutHdl->GetVkPipelineLayout(), firstSet, descSetGroup->GetVkHandle(), dynamicOffsets); } /***************************************************************************/ @@ -452,6 +454,11 @@ namespace SHADE vkCommandBuffer.drawIndexedIndirect(indirectDrawData->GetVkBuffer(), 0, drawCount, sizeof(vk::DrawIndexedIndirectCommand)); } + void SHVkCommandBuffer::ComputeDispatch(uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) noexcept + { + vkCommandBuffer.dispatch (groupCountX, groupCountY, groupCountZ); + } + void SHVkCommandBuffer::CopyBufferToImage(const vk::Buffer& src, const vk::Image& dst, const std::vector& copyInfo) { vkCommandBuffer.copyBufferToImage @@ -500,9 +507,9 @@ namespace SHADE // //vkCommandBuffer.pipelineBarrier() //} - void SHVkCommandBuffer::ForceSetPipelineLayout(Handle pipelineLayout) noexcept + void SHVkCommandBuffer::ForceSetPipelineLayout(Handle pipelineLayout, SH_PIPELINE_TYPE pipelineType) noexcept { - boundPipelineLayoutHdl = pipelineLayout; + bindPointData[static_cast(pipelineType)].boundPipelineLayoutHdl = pipelineLayout; } /***************************************************************************/ @@ -513,12 +520,13 @@ namespace SHADE */ /***************************************************************************/ - void SHVkCommandBuffer::SubmitPushConstants(void) const noexcept + void SHVkCommandBuffer::SubmitPushConstants(SH_PIPELINE_TYPE bindPoint) const noexcept { - vkCommandBuffer.pushConstants(boundPipelineLayoutHdl->GetVkPipelineLayout(), - boundPipelineLayoutHdl->GetPushConstantInterface().GetShaderStageFlags(), + auto layoutHdl = bindPointData[static_cast(bindPoint)].boundPipelineLayoutHdl; + vkCommandBuffer.pushConstants(layoutHdl->GetVkPipelineLayout(), + layoutHdl->GetPushConstantInterface().GetShaderStageFlags(), 0, - boundPipelineLayoutHdl->GetPushConstantInterface().GetSize(), pushConstantData); + layoutHdl->GetPushConstantInterface().GetSize(), pushConstantData); } /***************************************************************************/ @@ -695,7 +703,7 @@ namespace SHADE , usageFlags{ rhs.usageFlags } , commandBufferCount{ rhs.commandBufferCount } , parentPool{ rhs.parentPool } - , boundPipelineLayoutHdl{ rhs.boundPipelineLayoutHdl } + , bindPointData{ std::move (rhs.bindPointData)} { memcpy(pushConstantData, rhs.pushConstantData, PUSH_CONSTANT_SIZE); @@ -728,7 +736,7 @@ namespace SHADE usageFlags = rhs.usageFlags; commandBufferCount = rhs.commandBufferCount; parentPool = rhs.parentPool; - boundPipelineLayoutHdl = rhs.boundPipelineLayoutHdl; + bindPointData = std::move(rhs.bindPointData); memcpy(pushConstantData, rhs.pushConstantData, PUSH_CONSTANT_SIZE); rhs.vkCommandBuffer = VK_NULL_HANDLE; diff --git a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.h b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.h index deb1131c..4c978c34 100644 --- a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.h +++ b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.h @@ -6,6 +6,7 @@ #include "SHCommandPoolResetMode.h" #include "Resource/SHResourceLibrary.h" #include "Graphics/Pipeline/SHVkPipelineLayout.h" +#include "Graphics/Pipeline/SHPipelineType.h" namespace SHADE { @@ -39,7 +40,14 @@ namespace SHADE friend class SHResourceLibrary; static constexpr uint16_t PUSH_CONSTANT_SIZE = 512; + private: + struct PipelineBindPointData + { + //! The currently bound pipeline + Handle boundPipelineLayoutHdl; + }; + /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ /*-----------------------------------------------------------------------*/ @@ -66,8 +74,8 @@ namespace SHADE //! The command pool that this command buffer belongs to Handle parentPool; - //! The currently bound pipeline - Handle boundPipelineLayoutHdl; + //! Every command buffer will have a set of pipeline bind point specific data + std::array(SH_PIPELINE_TYPE::NUM_TYPES)> bindPointData; //! The push constant data for the command buffer uint8_t pushConstantData[PUSH_CONSTANT_SIZE]; @@ -112,13 +120,16 @@ namespace SHADE void BindPipeline (Handle const& pipelineHdl) noexcept; void BindVertexBuffer (uint32_t bindingPoint, Handle const& buffer, vk::DeviceSize offset) noexcept; void BindIndexBuffer (Handle const& buffer, uint32_t startingIndex) const noexcept; - void BindDescriptorSet (Handle descSetGroup, vk::PipelineBindPoint bindPoint, uint32_t firstSet, std::span dynamicOffsets); + void BindDescriptorSet (Handle descSetGroup, SH_PIPELINE_TYPE bindPoint, uint32_t firstSet, std::span dynamicOffsets); // Draw Commands void DrawArrays (uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) const noexcept; void DrawIndexed (uint32_t indexCount, uint32_t firstIndex, uint32_t vertexOffset) const noexcept; void DrawMultiIndirect (Handle indirectDrawData, uint32_t drawCount); + // Compute Commands + void ComputeDispatch (uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) noexcept; + // Buffer Copy void CopyBufferToImage (const vk::Buffer& src, const vk::Image& dst, const std::vector& copyInfo); void CopyImageToBuffer (const vk::Image& src, const vk::Buffer& dst, const std::vector& copyInfo); @@ -138,13 +149,13 @@ namespace SHADE // Push Constant variable setting template - void SetPushConstantVariable(std::string variableName, T const& data) noexcept + void SetPushConstantVariable(std::string variableName, T const& data, SH_PIPELINE_TYPE bindPoint) noexcept { - memcpy (static_cast(pushConstantData) + boundPipelineLayoutHdl->GetPushConstantInterface().GetOffset(variableName), &data, sizeof (T)); + memcpy (static_cast(pushConstantData) + bindPointData[static_cast(bindPoint)].boundPipelineLayoutHdl->GetPushConstantInterface().GetOffset(variableName), &data, sizeof (T)); }; - void ForceSetPipelineLayout (Handle pipelineLayout) noexcept; + void ForceSetPipelineLayout (Handle pipelineLayout, SH_PIPELINE_TYPE pipelineType) noexcept; - void SubmitPushConstants (void) const noexcept; + void SubmitPushConstants (SH_PIPELINE_TYPE bindPoint) const noexcept; /*-----------------------------------------------------------------------*/ /* GETTERS AND SETTERS */ diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.cpp b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.cpp index 6b770c3d..e5618c9c 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.cpp +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.cpp @@ -25,7 +25,8 @@ namespace SHADE } SHVkDescriptorPool::SHVkDescriptorPool(SHVkDescriptorPool&& rhs) noexcept - : device{ rhs.device } + : ISelfHandle (rhs) + , device{ rhs.device } , pool{ rhs.pool } { rhs.pool = VK_NULL_HANDLE; diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp index ea859718..de68c583 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp @@ -91,7 +91,7 @@ namespace SHADE // new write for the binding updater.writeInfos.emplace_back(); - updater.writeHashMap.try_emplace(writeHash, updater.writeInfos.size() - 1); + updater.writeHashMap.try_emplace(writeHash, static_cast(updater.writeInfos.size()) - 1u); auto& writeInfo = updater.writeInfos.back(); // Descriptor count for the write descriptor set. Usually this is set to 1, but if binding is variable sized, set to info passed in @@ -102,10 +102,10 @@ namespace SHADE //case vk::DescriptorType::eSampler: //case vk::DescriptorType::eSampledImage: case vk::DescriptorType::eCombinedImageSampler: + case vk::DescriptorType::eStorageImage: + case vk::DescriptorType::eInputAttachment: writeInfo.descImageInfos.resize(descriptorCount); - break; - //case vk::DescriptorType::eStorageImage: - // break; + break; case vk::DescriptorType::eUniformTexelBuffer: case vk::DescriptorType::eStorageTexelBuffer: case vk::DescriptorType::eUniformBuffer: @@ -165,6 +165,7 @@ namespace SHADE if (imageViewsAndSamplers.size() > writeInfo.descImageInfos.size()) { SHLOG_ERROR("Attempting write too many descriptors into descriptor set. Failed to write to vk::WriteDescriptorSet. "); + return; } for (uint32_t i = 0; i < imageViewsAndSamplers.size(); ++i) diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h index b2536de8..3f42afcc 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h @@ -31,6 +31,8 @@ namespace SHADE class SHVkDescriptorSetGroup { public: + using viewSamplerLayout = std::tuple, Handle, vk::ImageLayout>; + /*-----------------------------------------------------------------------------*/ /* Constructor/Destructors */ /*-----------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp index 7c7acfc5..a6b415a9 100644 --- a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp +++ b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp @@ -233,6 +233,8 @@ namespace SHADE , vmaAllocator{rhs.vmaAllocator} , nonDedicatedBestIndex {0} , parentPhysicalDeviceHdl {rhs.parentPhysicalDeviceHdl} + , uboBufferMemoryAlignment{ 0 } + , ssboBufferMemoryAlignment{ 0 } { rhs.vkLogicalDevice = VK_NULL_HANDLE; } @@ -261,6 +263,8 @@ namespace SHADE vmaAllocator = rhs.vmaAllocator; nonDedicatedBestIndex = 0; parentPhysicalDeviceHdl = rhs.parentPhysicalDeviceHdl; + uboBufferMemoryAlignment = rhs.uboBufferMemoryAlignment; + ssboBufferMemoryAlignment = rhs.ssboBufferMemoryAlignment; rhs.vkLogicalDevice = VK_NULL_HANDLE; @@ -529,6 +533,11 @@ namespace SHADE } + Handle SHVkLogicalDevice::CreateComputePipeline(Handle const& pipelineLayoutHdl) noexcept + { + return SHVkInstance::GetResourceManager().Create (GetHandle(), pipelineLayoutHdl); + } + Handle SHVkLogicalDevice::CreateSampler(const SHVkSamplerParams& params) noexcept { return SHVkInstance::GetResourceManager().Create (GetHandle(), params); diff --git a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h index 3d59d5c6..2aa59941 100644 --- a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h +++ b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h @@ -175,12 +175,17 @@ namespace SHADE std::string const& shaderName ) noexcept; - Handle CreateGraphicsPipeline ( + Handle CreateGraphicsPipeline ( Handle const& pipelineLayoutHdl, SHVkPipelineState const* const state, Handle const& renderpassHdl, Handle subpass ) noexcept; + + Handle CreateComputePipeline ( + Handle const& pipelineLayoutHdl + ) noexcept; + Handle CreateSampler (const SHVkSamplerParams& params) noexcept; Handle CreateRenderpass (std::span const vkDescriptions, std::vector const& subpasses) noexcept; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp index 2705b4d1..40826047 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp @@ -369,7 +369,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ void SHBatch::Draw(Handle cmdBuffer, uint32_t frameIndex) { - if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) + if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) { SHLOG_WARNING("[SHBatch] Attempted to draw a batch with an invalid frame index."); return; @@ -385,7 +385,7 @@ namespace SHADE cmdBuffer->BindDescriptorSet ( matPropsDescSet[frameIndex], - vk::PipelineBindPoint::eGraphics, + SH_PIPELINE_TYPE::GRAPHICS, SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE, dynamicOffset ); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp index add51196..14f2aa76 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp @@ -20,91 +20,91 @@ of DigiPen Institute of Technology is prohibited. namespace SHADE { - /*---------------------------------------------------------------------------------*/ - /* Constructor/Destructors */ - /*---------------------------------------------------------------------------------*/ + /*---------------------------------------------------------------------------------*/ + /* Constructor/Destructors */ + /*---------------------------------------------------------------------------------*/ - SHSuperBatch::SHSuperBatch(Handle sp) - : subpass { sp } - {} + SHSuperBatch::SHSuperBatch(Handle sp) + : subpass{ sp } + {} - /*---------------------------------------------------------------------------------*/ - /* Usage Functions */ - /*---------------------------------------------------------------------------------*/ - void SHSuperBatch::Add(const SHRenderable* renderable) noexcept + /*---------------------------------------------------------------------------------*/ + /* Usage Functions */ + /*---------------------------------------------------------------------------------*/ + void SHSuperBatch::Add(const SHRenderable* renderable) noexcept + { + const Handle PIPELINE = renderable->GetMaterial()->GetBaseMaterial()->GetPipeline(); + + // Check if we have a batch with the same pipeline first + auto batch = std::find_if(batches.begin(), batches.end(), [&](const SHBatch& batch) + { + return batch.GetPipeline() == PIPELINE; + }); + + + // Create one if not found + if (batch == batches.end()) { - const Handle PIPELINE = renderable->GetMaterial()->GetBaseMaterial()->GetPipeline(); - - // Check if we have a batch with the same pipeline first - auto batch = std::find_if(batches.begin(), batches.end(), [&](const SHBatch& batch) - { - return batch.GetPipeline() == PIPELINE; - }); - - - // Create one if not found - if (batch == batches.end()) - { - batches.emplace_back(PIPELINE); - batch = batches.end() - 1; - } - - // Add renderable in - batch->Add(renderable); + batches.emplace_back(PIPELINE); + batch = batches.end() - 1; } - void SHSuperBatch::Remove(const SHRenderable* renderable) noexcept + // Add renderable in + batch->Add(renderable); + } + + void SHSuperBatch::Remove(const SHRenderable* renderable) noexcept + { + const Handle PIPELINE = renderable->GetMaterial()->GetBaseMaterial()->GetPipeline(); + + // Check if we have a Batch with the same pipeline yet + auto batch = std::find_if(batches.begin(), batches.end(), [&](const SHBatch& batch) + { + return batch.GetPipeline() == PIPELINE; + }); + + // Attempt to remove if it exists + if (batch == batches.end()) + return; + + batch->Remove(renderable); + } + + void SHSuperBatch::Clear() noexcept + { + for (auto& batch : batches) { - const Handle PIPELINE = renderable->GetMaterial()->GetBaseMaterial()->GetPipeline(); - - // Check if we have a Batch with the same pipeline yet - auto batch = std::find_if(batches.begin(), batches.end(), [&](const SHBatch& batch) - { - return batch.GetPipeline() == PIPELINE; - }); - - // Attempt to remove if it exists - if (batch == batches.end()) - return; - - batch->Remove(renderable); + batch.Clear(); } + batches.clear(); + } - void SHSuperBatch::Clear() noexcept + void SHSuperBatch::UpdateBuffers(uint32_t frameIndex, Handle descPool) + { + for (auto& batch : batches) { - for (auto& batch : batches) - { - batch.Clear(); - } - batches.clear(); + batch.UpdateMaterialBuffer(frameIndex, descPool); + batch.UpdateTransformBuffer(frameIndex); + batch.UpdateEIDBuffer(frameIndex); } + } - void SHSuperBatch::UpdateBuffers(uint32_t frameIndex, Handle descPool) + void SHSuperBatch::Build(Handle device, Handle descPool, uint32_t frameIndex) noexcept + { + // Build all batches + for (auto& batch : batches) { - for (auto& batch : batches) - { - batch.UpdateMaterialBuffer(frameIndex, descPool); - batch.UpdateTransformBuffer(frameIndex); - batch.UpdateEIDBuffer(frameIndex); - } + batch.Build(device, descPool, frameIndex); } + } - void SHSuperBatch::Build(Handle device, Handle descPool, uint32_t frameIndex) noexcept + void SHSuperBatch::Draw(Handle cmdBuffer, uint32_t frameIndex) noexcept + { + // Build all batches + for (auto& batch : batches) { - // Build all batches - for (auto& batch : batches) - { - batch.Build(device, descPool, frameIndex); - } - } - - void SHSuperBatch::Draw(Handle cmdBuffer, uint32_t frameIndex) noexcept - { - // Build all batches - for (auto& batch : batches) - { - batch.Draw(cmdBuffer, frameIndex); - } + batch.Draw(cmdBuffer, frameIndex); } + } } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h index 67cbc001..a0457b65 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h @@ -63,6 +63,14 @@ namespace SHADE */ /***************************************************************************/ static constexpr uint32_t PER_INSTANCE = 3; + /***************************************************************************/ + /*! + \brief + DescriptorSet Index for render graph resources. + */ + /***************************************************************************/ + static constexpr uint32_t RENDERGRAPH_RESOURCE = 4; + }; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index 44404bc7..7ecd92d2 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -115,6 +115,23 @@ namespace SHADE 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); + + + // TODO: This is VERY temporarily here until a more solid resource management system is implemented + shaderSourceLibrary.Init("../../TempShaderFolder/"); + + shaderSourceLibrary.LoadShader(0, "TestCubeVs.glsl", SH_SHADER_TYPE::VERTEX, true); + shaderSourceLibrary.LoadShader(1, "TestCubeFs.glsl", SH_SHADER_TYPE::FRAGMENT, true); + + shaderSourceLibrary.LoadShader(2, "KirschCs.glsl", SH_SHADER_TYPE::COMPUTE, true); + + shaderModuleLibrary.ImportFromSourceLibrary(device, shaderSourceLibrary); + auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl"); + auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl"); + auto greyscale = shaderModuleLibrary.GetShaderModule("KirschCs.glsl"); + cubeVS->Reflect(); + cubeFS->Reflect(); + greyscale->Reflect(); } void SHGraphicsSystem::InitSceneRenderGraph(void) noexcept @@ -130,6 +147,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ auto windowDims = window->GetWindowSize(); + auto cameraSystem = SHSystemManager::GetSystem(); // Set Up Cameras screenCamera = resourceManager.Create(); @@ -154,21 +172,21 @@ namespace SHADE // Initialize world render graph worldRenderGraph->Init(device, swapchain); - worldRenderGraph->AddResource("Scene", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT }, windowDims.first, windowDims.second); + worldRenderGraph->AddResource("Scene Pre-Process", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second); + worldRenderGraph->AddResource("Scene", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second); worldRenderGraph->AddResource("Depth Buffer", { SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL }, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint); worldRenderGraph->AddResource("Entity ID", { SH_ATT_DESC_TYPE_FLAGS::COLOR }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); - auto node = worldRenderGraph->AddNode("G-Buffer", { "Entity ID", "Depth Buffer", "Scene"}, {}); // no predecessors + auto node = worldRenderGraph->AddNode("G-Buffer", { "Entity ID", "Depth Buffer", "Scene", "Scene Pre-Process"}, {}); // no predecessors //First subpass to write to G-Buffer auto gBufferWriteSubpass = node->AddSubpass("G-Buffer Write"); - gBufferWriteSubpass->AddColorOutput("Scene"); + gBufferWriteSubpass->AddColorOutput("Scene Pre-Process"); gBufferWriteSubpass->AddColorOutput("Entity ID"); gBufferWriteSubpass->AddDepthOutput("Depth Buffer", SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL); - // We do this to just transition our scene layout to shader read - auto sceneLayoutTransitionSubpass = node->AddSubpass("Scene Layout Transition"); - sceneLayoutTransitionSubpass->AddInput("Scene"); + auto greyscale = shaderModuleLibrary.GetShaderModule("KirschCs.glsl"); + node->AddNodeCompute (greyscale, {"Scene Pre-Process", "Scene"}); // Generate world render graph worldRenderGraph->Generate(); @@ -177,20 +195,13 @@ namespace SHADE worldRenderer = worldViewport->AddRenderer(resourceManager, swapchain->GetNumImages(), renderContextCmdPools, descPool, SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS], worldRenderGraph); worldRenderer->SetCamera(worldCamera); + worldRenderer->SetCameraDirector(cameraSystem->CreateDirector()); - // TODO: This is VERY temporarily here until a more solid resource management system is implemented - shaderSourceLibrary.Init("../../TempShaderFolder/"); - - shaderSourceLibrary.LoadShader(0, "TestCubeVs.glsl", SH_SHADER_TYPE::VERTEX, true); - shaderSourceLibrary.LoadShader(1, "TestCubeFs.glsl", SH_SHADER_TYPE::FRAGMENT, true); - - shaderModuleLibrary.ImportFromSourceLibrary(device, shaderSourceLibrary); auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl"); auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl"); - cubeVS->Reflect(); - cubeFS->Reflect(); defaultMaterial = AddMaterial(cubeVS, cubeFS, gBufferWriteSubpass); + } void SHGraphicsSystem::InitMiddleEnd(void) noexcept @@ -323,21 +334,7 @@ namespace SHADE auto cameraSystem = SHSystemManager::GetSystem(); -#ifdef SHEDITOR - auto editorSystem = SHSystemManager::GetSystem(); - if (editorSystem->editorState != SHEditor::State::PLAY) - { - worldRenderer->SetViewProjectionMatrix(SHMatrix::Transpose(cameraSystem->GetEditorCamera()->GetProjMatrix() * cameraSystem->GetEditorCamera()->GetViewMatrix())); - } - else - { - // main camera - } - -#else - // main camera -#endif // For every viewport for (int vpIndex = 0; vpIndex < static_cast(viewports.size()); ++vpIndex) @@ -360,7 +357,7 @@ namespace SHADE uint32_t h = static_cast(viewports[vpIndex]->GetHeight()); currentCmdBuffer->SetViewportScissor (static_cast(w), static_cast(h), w, h); - currentCmdBuffer->ForceSetPipelineLayout(SHGraphicsGlobalData::GetDummyPipelineLayout()); + currentCmdBuffer->ForceSetPipelineLayout(SHGraphicsGlobalData::GetDummyPipelineLayout(), SH_PIPELINE_TYPE::GRAPHICS); // Bind all the buffers required for meshes for (auto& [buffer, bindingPoint] : MESH_DATA) @@ -380,14 +377,29 @@ namespace SHADE currentCmdBuffer->BindDescriptorSet ( textureDescSet, - vk::PipelineBindPoint::eGraphics, + SH_PIPELINE_TYPE::GRAPHICS, 0, texDynamicOffset ); } // bind camera data + //renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex); + +#ifdef SHEDITOR + if (renderers[renIndex] == worldRenderer) + { + auto editorSystem = SHSystemManager::GetSystem(); + if (editorSystem->editorState != SHEditor::State::PLAY) + worldRenderer->UpdateDataAndBind(currentCmdBuffer, frameIndex, SHMatrix::Transpose(cameraSystem->GetEditorCamera()->GetProjMatrix() * cameraSystem->GetEditorCamera()->GetViewMatrix())); + else + renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex); + } + else + renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex); +#else renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex); +#endif // Draw first renderers[renIndex]->Draw(frameIndex, descPool); @@ -726,8 +738,8 @@ namespace SHADE auto cameraSystem = SHSystemManager::GetSystem(); #ifdef SHEDITOR - cameraSystem->GetEditorCamera()->SetWidth(resizeWidth); - cameraSystem->GetEditorCamera()->SetHeight(resizeHeight); + cameraSystem->GetEditorCamera()->SetWidth(static_cast(resizeWidth)); + cameraSystem->GetEditorCamera()->SetHeight(static_cast(resizeHeight)); #else #endif diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHPostOffscreenRenderSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHPostOffscreenRenderSystem.cpp index 8b41a979..ebce5c9e 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHPostOffscreenRenderSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHPostOffscreenRenderSystem.cpp @@ -68,7 +68,7 @@ namespace SHADE { std::vector combinedImageSampler { - std::make_tuple(offscreenRender->GetImageView(), offscreenRenderSampler, vk::ImageLayout::eShaderReadOnlyOptimal), + std::make_tuple(offscreenRender->GetImageView(), offscreenRenderSampler, vk::ImageLayout::eGeneral), }; // Register the image view and sampler with the descriptor set. Now whenever rendering to the offscreen image is done, the descriptor set will see the change diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp index 2532f308..962130be 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp @@ -21,6 +21,7 @@ of DigiPen Institute of Technology is prohibited. #include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" #include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" #include "Graphics/Buffers/SHVkBuffer.h" +#include "Camera/SHCameraDirector.h" namespace SHADE { @@ -65,6 +66,11 @@ namespace SHADE camera = _camera; } + void SHRenderer::SetCameraDirector(Handle director) noexcept + { + cameraDirector = director; + } + /*-----------------------------------------------------------------------------------*/ /* Drawing Functions */ /*-----------------------------------------------------------------------------------*/ @@ -75,17 +81,24 @@ namespace SHADE void SHRenderer::UpdateDataAndBind(Handle cmdBuffer, uint32_t frameIndex) noexcept { - if (camera) + if (camera && cameraDirector) { - //cpuCameraData.viewProjectionMatrix = camera->GetViewProjectionMatrix(); - cameraBuffer->WriteToMemory(&cpuCameraData, sizeof(SHShaderCameraData), 0, cameraDataAlignedSize * frameIndex); - - std::array dynamicOffsets{ frameIndex * cameraDataAlignedSize }; - - cmdBuffer->BindDescriptorSet(cameraDescriptorSet, vk::PipelineBindPoint::eGraphics, SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS, std::span{ dynamicOffsets.data(), 1 }); + UpdateDataAndBind(cmdBuffer, frameIndex, SHMatrix::Transpose(cameraDirector->GetVPMatrix())); } } + void SHRenderer::UpdateDataAndBind(Handle cmdBuffer, uint32_t frameIndex, SHMatrix exteriorMatrix) noexcept + { + SetViewProjectionMatrix(exteriorMatrix); + + //cpuCameraData.viewProjectionMatrix = camera->GetViewProjectionMatrix(); + cameraBuffer->WriteToMemory(&cpuCameraData, sizeof(SHShaderCameraData), 0, cameraDataAlignedSize * frameIndex); + + std::array dynamicOffsets{ frameIndex * cameraDataAlignedSize }; + + cmdBuffer->BindDescriptorSet(cameraDescriptorSet, SH_PIPELINE_TYPE::GRAPHICS, SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS, std::span{ dynamicOffsets.data(), 1 }); + } + void SHRenderer::UpdateCameraDataToBuffer(void) noexcept { } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h index dbd1e415..87cf8ee9 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h @@ -40,6 +40,7 @@ namespace SHADE class SHGraphicsGlobalData; class SHVkDescriptorPool; class SHVkBuffer; + class SHCameraDirector; struct SHShaderCameraData { @@ -71,12 +72,14 @@ namespace SHADE /* Camera Registration */ /*-----------------------------------------------------------------------------*/ void SetCamera(Handle _camera); + void SetCameraDirector (Handle director) noexcept; /*-----------------------------------------------------------------------------*/ /* Drawing Functions */ /*-----------------------------------------------------------------------------*/ void Draw(uint32_t frameIndex, Handle descPool) noexcept; - void UpdateDataAndBind (Handle cmdBuffer, uint32_t frameIndex) noexcept; + void UpdateDataAndBind(Handle cmdBuffer, uint32_t frameIndex) noexcept; + void UpdateDataAndBind(Handle cmdBuffer, uint32_t frameIndex, SHMatrix exteriorMatrix) noexcept; void UpdateCameraDataToBuffer (void) noexcept; void SetViewProjectionMatrix (SHMatrix const& vpMatrix) noexcept; @@ -99,6 +102,8 @@ namespace SHADE Handle cameraDescriptorSet; Handle cameraBuffer; + Handle cameraDirector; + // we really only need 1 copy even though we need %swapchainImages copies for // GPU. SHShaderCameraData cpuCameraData; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp index 682b549c..495a3d37 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp @@ -8,7 +8,7 @@ namespace SHADE { - Handle SHPipelineLibrary::CreateDrawPipeline(std::pair, Handle> const& vsFsPair, Handle renderpass, Handle subpass) noexcept + Handle SHPipelineLibrary::CreateGraphicsPipelines(std::pair, Handle> const& vsFsPair, Handle renderpass, Handle subpass) noexcept { SHPipelineLayoutParams params { @@ -52,7 +52,7 @@ namespace SHADE newPipeline->ConstructPipeline(); // Emplace the new pipeline - pipelines.emplace (vsFsPair, newPipeline); + graphicsPipelines.emplace (vsFsPair, newPipeline); return newPipeline; } @@ -62,19 +62,19 @@ namespace SHADE logicalDevice = device; } - Handle SHPipelineLibrary::GetDrawPipline(std::pair, Handle> const& vsFsPair) noexcept + Handle SHPipelineLibrary::GetGraphicsPipeline(std::pair, Handle> const& vsFsPair) noexcept { // return the pipeline requested for - if (pipelines.contains(vsFsPair)) - return pipelines.at(vsFsPair); + if (graphicsPipelines.contains(vsFsPair)) + return graphicsPipelines.at(vsFsPair); else return {}; } - bool SHPipelineLibrary::CheckDrawPipelineExistence(std::pair, Handle> const& vsFsPair) noexcept + bool SHPipelineLibrary::CheckGraphicsPipelineExistence(std::pair, Handle> const& vsFsPair) noexcept { // Returns if a pipeline exists or not - return pipelines.contains(vsFsPair); + return graphicsPipelines.contains(vsFsPair); } } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h index 9a411d25..aeb023c5 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h @@ -23,19 +23,19 @@ namespace SHADE Handle logicalDevice; //! a map of pipelines that are hashed using a pair of shader module handles - std::unordered_map, Handle>, Handle> pipelines; + std::unordered_map, Handle>, Handle> graphicsPipelines; public: void Init (Handle device) noexcept; // Draw pipeline functions. used only when creating pipelines for drawing using a vertex and fragment shader - Handle CreateDrawPipeline ( + Handle CreateGraphicsPipelines ( std::pair, Handle> const& vsFsPair, Handle renderpass, Handle subpass ) noexcept; - Handle GetDrawPipline (std::pair, Handle> const& vsFsPair) noexcept; - bool CheckDrawPipelineExistence (std::pair, Handle> const& vsFsPair) noexcept; + Handle GetGraphicsPipeline (std::pair, Handle> const& vsFsPair) noexcept; + bool CheckGraphicsPipelineExistence (std::pair, Handle> const& vsFsPair) noexcept; }; } diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineType.h b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineType.h index e7f5b6a8..2c1c80ff 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineType.h +++ b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineType.h @@ -5,9 +5,13 @@ namespace SHADE { enum class SH_PIPELINE_TYPE { - GRAPHICS, + GRAPHICS = 0, COMPUTE, + RAY_TRACING, + NUM_TYPES, }; + + } #endif \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.cpp b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.cpp index c03fd2a7..973ae72f 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.cpp +++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.cpp @@ -4,6 +4,7 @@ #include "Graphics/Shaders/SHVkShaderModule.h" #include "Graphics/Debugging/SHVulkanDebugUtil.h" #include "Graphics/RenderGraph/SHRenderGraph.h" +#include "Graphics/SHVkUtil.h" namespace SHADE { @@ -171,6 +172,29 @@ namespace SHADE void SHVkPipeline::CreateComputePipeline(void) noexcept { + auto shaderModule = pipelineLayout->GetShaderModules()[0]; + + vk::PipelineShaderStageCreateInfo shaderStageCreateInfo + { + .stage = vk::ShaderStageFlagBits::eCompute, + .module = shaderModule->GetVkShaderModule(), + .pName = shaderModule->GetEntryPoint().c_str(), + }; + + vk::ComputePipelineCreateInfo cpCreateInfo + { + .flags = {}, + .stage = shaderStageCreateInfo, + .layout = pipelineLayout->GetVkPipelineLayout(), + }; + + if (auto result = logicalDeviceHdl->GetVkLogicalDevice().createComputePipelines({}, 1, &cpCreateInfo, nullptr, &vkPipeline); result != vk::Result::eSuccess) + SHVulkanDebugUtil::ReportVkError(result, "Failed to create Compute Pipeline. "); + else + { + SHVulkanDebugUtil::ReportVkSuccess("Successfully created a Compute Pipeline. "); + created = true; + } } @@ -245,7 +269,7 @@ namespace SHADE , logicalDeviceHdl{ rhs.logicalDeviceHdl } , pipelineLayout { rhs.pipelineLayout } { - vkPipeline = VK_NULL_HANDLE; + rhs.vkPipeline = VK_NULL_HANDLE; } /***************************************************************************/ @@ -285,7 +309,8 @@ namespace SHADE /***************************************************************************/ SHVkPipeline::~SHVkPipeline(void) noexcept { - logicalDeviceHdl->GetVkLogicalDevice().destroyPipeline(vkPipeline, nullptr); + if (vkPipeline) + logicalDeviceHdl->GetVkLogicalDevice().destroyPipeline(vkPipeline, nullptr); } /***************************************************************************/ @@ -313,7 +338,7 @@ namespace SHADE created = rhs.created; logicalDeviceHdl = rhs.logicalDeviceHdl; - vkPipeline = VK_NULL_HANDLE; + rhs.vkPipeline = VK_NULL_HANDLE; return *this; } @@ -399,18 +424,7 @@ namespace SHADE /***************************************************************************/ vk::PipelineBindPoint SHVkPipeline::GetPipelineBindPoint(void) const noexcept { - switch (pipelineType) - { - case SH_PIPELINE_TYPE::GRAPHICS: - return vk::PipelineBindPoint::eGraphics; - case SH_PIPELINE_TYPE::COMPUTE: - return vk::PipelineBindPoint::eCompute; - break; - default: - return vk::PipelineBindPoint::eGraphics; - break; - - } + return SHVkUtil::GetPipelineBindPointFromType(pipelineType); } /***************************************************************************/ @@ -450,4 +464,9 @@ namespace SHADE return pipelineLayout; } + SH_PIPELINE_TYPE SHVkPipeline::GetPipelineType(void) const noexcept + { + return pipelineType; + } + } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.h b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.h index 1103d3d0..7378cc48 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.h +++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.h @@ -77,6 +77,7 @@ namespace SHADE vk::Pipeline GetVkPipeline (void) const noexcept; bool GetIsCreated (void) const noexcept; Handle GetPipelineLayout (void) const noexcept; + SH_PIPELINE_TYPE GetPipelineType (void) const noexcept; }; } diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp index 7a76447d..37d00795 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp +++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp @@ -216,9 +216,18 @@ namespace SHADE /***************************************************************************/ void SHVkPipelineLayout::PrepareVkDescriptorSetLayouts(void) noexcept { + // pipeline layouts contain global layouts first, then layouts for allocation descriptorSetLayoutsPipeline.reserve(descriptorSetLayoutsAllocate.size() + descriptorSetLayoutsGlobal.size()); + vkDescriptorSetLayoutsPipeline.reserve(descriptorSetLayoutsAllocate.size() + descriptorSetLayoutsGlobal.size()); - // Settle allocate layouts first + // First we insert the global layouts + for (auto const& layout : descriptorSetLayoutsGlobal) + { + descriptorSetLayoutsPipeline.emplace_back(layout); + //vkDescriptorSetLayoutsPipeline.emplace_back(layout->GetVkHandle()); + } + + // Then the allocate layouts vkDescriptorSetLayoutsAllocate.reserve(descriptorSetLayoutsAllocate.size()); for (auto const& layout : descriptorSetLayoutsAllocate) { @@ -226,18 +235,13 @@ namespace SHADE vkDescriptorSetLayoutsAllocate.emplace_back(layout->GetVkHandle()); } - // pipeline layouts contain global layouts first, then layouts for allocation - vkDescriptorSetLayoutsPipeline.reserve(descriptorSetLayoutsAllocate.size() + descriptorSetLayoutsGlobal.size()); - - // First we insert the global layouts - for (auto const& layout : descriptorSetLayoutsGlobal) + for (auto const& layout : descriptorSetLayoutsPipeline) { - 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)); + //std::copy(vkDescriptorSetLayoutsAllocate.begin(), vkDescriptorSetLayoutsAllocate.end(), std::back_inserter(vkDescriptorSetLayoutsPipeline)); } /***************************************************************************/ @@ -294,6 +298,7 @@ namespace SHADE , descriptorSetLayoutsGlobal{pipelineLayoutParams.globalDescSetLayouts } // do a copy, some other pipeline layout might need this , descriptorSetLayoutsAllocate{} , vkDescriptorSetLayoutsAllocate{} + , descriptorSetLayoutsPipeline{} , vkDescriptorSetLayoutsPipeline{} { for (auto& mod : shaderModules) @@ -318,6 +323,7 @@ namespace SHADE , descriptorSetLayoutsGlobal{} , descriptorSetLayoutsAllocate{} , vkDescriptorSetLayoutsAllocate{} + , descriptorSetLayoutsPipeline{} , vkDescriptorSetLayoutsPipeline{} { @@ -368,7 +374,8 @@ namespace SHADE , descriptorSetLayoutsGlobal {std::move (rhs.descriptorSetLayoutsGlobal)} , descriptorSetLayoutsAllocate {std::move (rhs.descriptorSetLayoutsAllocate)} , vkDescriptorSetLayoutsAllocate{std::move (rhs.vkDescriptorSetLayoutsAllocate)} - , vkDescriptorSetLayoutsPipeline{std::move (rhs.vkDescriptorSetLayoutsAllocate)} + , descriptorSetLayoutsPipeline { std::move(rhs.descriptorSetLayoutsPipeline) } + , vkDescriptorSetLayoutsPipeline{ std::move(rhs.vkDescriptorSetLayoutsPipeline) } { rhs.vkPipelineLayout = VK_NULL_HANDLE; } @@ -441,12 +448,12 @@ namespace SHADE return {}; } - std::vector> SHVkPipelineLayout::GetDescriptorSetLayoutsPipeline(void) const noexcept + std::vector> const& SHVkPipelineLayout::GetDescriptorSetLayoutsPipeline(void) const noexcept { return descriptorSetLayoutsPipeline; } - std::vector> SHVkPipelineLayout::GetDescriptorSetLayoutsAllocate(void) const noexcept + std::vector> const& SHVkPipelineLayout::GetDescriptorSetLayoutsAllocate(void) const noexcept { return descriptorSetLayoutsAllocate; } @@ -464,7 +471,8 @@ namespace SHADE descriptorSetLayoutsGlobal = std::move(rhs.descriptorSetLayoutsGlobal); descriptorSetLayoutsAllocate = std::move(rhs.descriptorSetLayoutsAllocate); vkDescriptorSetLayoutsAllocate = std::move(rhs.vkDescriptorSetLayoutsAllocate); - vkDescriptorSetLayoutsPipeline = std::move(rhs.vkDescriptorSetLayoutsAllocate); + descriptorSetLayoutsPipeline = std::move(rhs.descriptorSetLayoutsPipeline); + vkDescriptorSetLayoutsPipeline = std::move(rhs.vkDescriptorSetLayoutsPipeline); rhs.vkPipelineLayout = VK_NULL_HANDLE; diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h index f5d363fa..b4298e00 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h +++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h @@ -74,12 +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> GetDescriptorSetLayoutsPipeline(void) const noexcept; - std::vector> GetDescriptorSetLayoutsAllocate(void) 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> const& GetDescriptorSetLayoutsPipeline(void) const noexcept; + std::vector> const& GetDescriptorSetLayoutsAllocate(void) const noexcept; }; } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h b/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h index 241292d4..c4d44ea8 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h @@ -10,6 +10,8 @@ namespace SHADE DEPTH = 0x04, STENCIL = 0x08, DEPTH_STENCIL = 0x10, - INPUT = 0x20 + INPUT = 0x20, + STORAGE = 0x40 }; + } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp index 0bc2c98b..4684419a 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp @@ -9,6 +9,8 @@ #include "Graphics/Buffers/SHVkBuffer.h" #include "Tools/SHLogger.h" #include "SHAttachmentDescInitParams.h" +#include "SHRenderGraphStorage.h" +#include "Graphics/RenderGraph/SHRenderGraphNodeCompute.h" namespace SHADE { @@ -52,12 +54,12 @@ namespace SHADE // If we set to if (w == static_cast(-1) && h == static_cast(-1)) { - w = swapchainHdl->GetSwapchainImage(0)->GetWidth(); - h = swapchainHdl->GetSwapchainImage(0)->GetHeight(); - format = swapchainHdl->GetSurfaceFormatKHR().format; + w = renderGraphStorage->swapchain->GetSwapchainImage(0)->GetWidth(); + h = renderGraphStorage->swapchain->GetSwapchainImage(0)->GetHeight(); + format = renderGraphStorage->swapchain->GetSurfaceFormatKHR().format; } - graphResources.try_emplace(resourceName, resourceManager->Create(logicalDeviceHdl, swapchainHdl, resourceName, typeFlags, format, w, h, levels, usageFlags, createFlags)); + renderGraphStorage->graphResources->try_emplace(resourceName, resourceManager->Create(renderGraphStorage, resourceName, typeFlags, format, w, h, levels, usageFlags, createFlags)); } /***************************************************************************/ @@ -77,36 +79,38 @@ namespace SHADE for (uint32_t i = 0; auto& node : nodes) { - // key is handle ID, value is pair (first is initial layout, second is final layout). - std::unordered_map resourceAttLayouts; + // key is handle ID, value is final layout. + std::unordered_map resourceAttFinalLayouts; if (node->subpasses.empty()) { SHLOG_ERROR("Node does not contain a subpass. Cannot configure attachment descriptions as a result. "); return; } + // attempt to get all final layouts for all resources for (auto& subpass : node->subpasses) { for (auto& color : subpass->colorReferences) { + // If final renderpass and attachment is a COLOR_PRESENT resource, make resource transition to present after last subpass if (i == nodes.size() - 1 && (node->attResources[color.attachment]->resourceTypeFlags & static_cast(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT))) - resourceAttLayouts[color.attachment] = vk::ImageLayout::ePresentSrcKHR; + resourceAttFinalLayouts[color.attachment] = vk::ImageLayout::ePresentSrcKHR; else - resourceAttLayouts[color.attachment] = color.layout; + resourceAttFinalLayouts[color.attachment] = color.layout; } for (auto& depth : subpass->depthReferences) - resourceAttLayouts[depth.attachment] = depth.layout; + resourceAttFinalLayouts[depth.attachment] = depth.layout; for (auto& input : subpass->inputReferences) - resourceAttLayouts[input.attachment] = input.layout; + resourceAttFinalLayouts[input.attachment] = input.layout; } for (uint32_t j = 0; j < node->attachmentDescriptions.size(); ++j) { auto& att = node->attachmentDescriptions[j]; att.initialLayout = vk::ImageLayout::eUndefined; - att.finalLayout = resourceAttLayouts[j]; + att.finalLayout = resourceAttFinalLayouts[j]; } ++i; } @@ -292,6 +296,9 @@ namespace SHADE dep.dstAccessMask = dstAccess; dep.srcStageMask = srcStage; + + // initialize input descriptors + node->subpasses[i]->CreateInputDescriptors(); } } } @@ -343,10 +350,18 @@ namespace SHADE */ /***************************************************************************/ - void SHRenderGraph::Init(Handle const& logicalDevice, Handle const& swapchain) noexcept + void SHRenderGraph::Init(Handle logicalDevice, Handle swapchain) noexcept { - logicalDeviceHdl = logicalDevice; - swapchainHdl = swapchain; + resourceManager = std::make_shared(); + + renderGraphStorage = resourceManager->Create(); + renderGraphStorage->graphResources = resourceManager->Create>>(); + + renderGraphStorage->logicalDevice = logicalDevice; + renderGraphStorage->swapchain = swapchain; + + renderGraphStorage->resourceManager = resourceManager; + renderGraphStorage->descriptorPool = logicalDevice->CreateDescriptorPools(); } /***************************************************************************/ @@ -361,24 +376,19 @@ namespace SHADE */ /***************************************************************************/ SHRenderGraph::SHRenderGraph(void) noexcept - : logicalDeviceHdl{ } - , swapchainHdl{ } + : renderGraphStorage{} , nodes{} - , graphResources{} , resourceManager{nullptr} { - resourceManager = std::make_shared(); } SHRenderGraph::SHRenderGraph(SHRenderGraph&& rhs) noexcept - : logicalDeviceHdl{ rhs.logicalDeviceHdl } - , swapchainHdl{ rhs.swapchainHdl } + : renderGraphStorage{ rhs.renderGraphStorage } , nodeIndexing{ std::move(rhs.nodeIndexing) } , nodes{ std::move(rhs.nodes) } - , graphResources{ std::move(rhs.graphResources) } , resourceManager{ std::move(rhs.resourceManager) } { - + } SHRenderGraph& SHRenderGraph::operator=(SHRenderGraph&& rhs) noexcept @@ -386,11 +396,9 @@ namespace SHADE if (&rhs == this) return *this; - logicalDeviceHdl = rhs.logicalDeviceHdl; - swapchainHdl = rhs.swapchainHdl; + renderGraphStorage = rhs.renderGraphStorage; nodeIndexing = std::move(rhs.nodeIndexing); nodes = std::move(rhs.nodes); - graphResources = std::move(rhs.graphResources); resourceManager = std::move(rhs.resourceManager); return *this; @@ -426,12 +434,12 @@ namespace SHADE for (auto const& instruction : resourceInstruction) { // If the resource that the new node is requesting for exists, allow the graph to reference it - if (graphResources.contains(instruction.resourceName)) + if (renderGraphStorage->graphResources->contains(instruction.resourceName)) { descInitParams.push_back( { - .resourceHdl = graphResources.at(instruction.resourceName), - .dontClearOnLoad = false, + .resourceHdl = renderGraphStorage->graphResources->at(instruction.resourceName), + .dontClearOnLoad = instruction.dontClearOnLoad, } ); } @@ -456,7 +464,7 @@ namespace SHADE } } - nodes.emplace_back(resourceManager->Create(resourceManager, logicalDeviceHdl, swapchainHdl, std::move(descInitParams), std::move(predecessors), &graphResources)); + nodes.emplace_back(resourceManager->Create(renderGraphStorage, std::move(descInitParams), std::move(predecessors))); nodeIndexing.emplace(nodeName, static_cast(nodes.size()) - 1u); return nodes.at(nodeIndexing[nodeName]); } @@ -476,12 +484,31 @@ namespace SHADE /***************************************************************************/ void SHRenderGraph::Generate(void) noexcept { + CheckForNodeComputes(); ConfigureAttachmentDescriptions(); ConfigureSubpasses(); ConfigureRenderpasses(); ConfigureFramebuffers(); } + /***************************************************************************/ + /*! + + \brief + This function goes through all renderpasses and checks for existence of + node computes. If they exist, adds dummy subpasses to transition resources + into general. + + */ + /***************************************************************************/ + void SHRenderGraph::CheckForNodeComputes(void) noexcept + { + for (auto& node : nodes) + { + node->AddDummySubpassIfNeeded(); + } + } + // 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, Handle descPool) noexcept @@ -501,7 +528,7 @@ namespace SHADE void SHRenderGraph::HandleResize(uint32_t newWidth, uint32_t newHeight) noexcept { // resize resources - for (auto& [name, resource]: graphResources) + for (auto& [name, resource] : *renderGraphStorage->graphResources) resource->HandleResize(newWidth, newHeight); for (auto& node : nodes) @@ -521,9 +548,9 @@ namespace SHADE Handle SHRenderGraph::GetRenderGraphResource(std::string const& resourceName) const noexcept { - if (graphResources.contains(resourceName)) + if (renderGraphStorage->graphResources->contains(resourceName)) { - return graphResources.at(resourceName); + return renderGraphStorage->graphResources->at(resourceName); } return {}; } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h index a919c4ff..d90b66df 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h @@ -30,7 +30,8 @@ namespace SHADE class SHVkCommandBuffer; class SHRenderGraphNode; class SHGraphicsGlobalData; - + class SHVkDescriptorPool; + class SHRenderGraphStorage; class SH_API SHRenderGraph { @@ -56,10 +57,8 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ /*-----------------------------------------------------------------------*/ - Handle logicalDeviceHdl; - //! swapchain used for querying image count - Handle swapchainHdl; + Handle renderGraphStorage; //! For indexing render graph node container std::map nodeIndexing; @@ -67,9 +66,6 @@ namespace SHADE //! Render graph nodes std::vector> nodes; - //! Resources that exist for the entire render graph - std::unordered_map> graphResources; - //! Resource library for graph handles std::shared_ptr resourceManager; @@ -85,14 +81,15 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ - void Init (Handle const& logicalDevice, Handle const& swapchain) noexcept; + void Init (Handle logicalDevice, Handle swapchain) noexcept; void AddResource(std::string resourceName, std::initializer_list typeFlags, uint32_t w = static_cast(-1), uint32_t h = static_cast(-1), vk::Format format = vk::Format::eB8G8R8A8Unorm, uint8_t levels = 1, vk::ImageUsageFlagBits usageFlags = {}, vk::ImageCreateFlagBits createFlags = {}); Handle AddNode (std::string nodeName, std::initializer_list resourceInstruction, std::initializer_list predecessorNodes) noexcept; - void Generate (void) noexcept; - void Execute (uint32_t frameIndex, Handle cmdBuffer, Handle descPool) noexcept; - void FinaliseBatch(uint32_t frameIndex, Handle descPool); - void HandleResize (uint32_t newWidth, uint32_t newHeight) noexcept; + void Generate (void) noexcept; + void CheckForNodeComputes (void) noexcept; + void Execute (uint32_t frameIndex, Handle cmdBuffer, Handle descPool) noexcept; + void FinaliseBatch (uint32_t frameIndex, Handle descPool); + void HandleResize (uint32_t newWidth, uint32_t newHeight) noexcept; /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp index 5950426e..c315bffd 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp @@ -6,6 +6,9 @@ #include "Graphics/Framebuffer/SHVkFramebuffer.h" #include "SHRenderGraphResource.h" #include "SHSubpass.h" +#include "SHRenderGraphStorage.h" +#include "Graphics/RenderGraph/SHRenderGraphNodeCompute.h" +#include "Graphics/SHVkUtil.h" namespace SHADE { @@ -21,7 +24,7 @@ namespace SHADE /***************************************************************************/ void SHRenderGraphNode::CreateRenderpass(void) noexcept { - renderpass = logicalDeviceHdl->CreateRenderpass(attachmentDescriptions, spDescs, spDeps); + renderpass = graphStorage->logicalDevice->CreateRenderpass(attachmentDescriptions, spDescs, spDeps); } /***************************************************************************/ @@ -53,7 +56,7 @@ namespace SHADE } - framebuffers[i] = logicalDeviceHdl->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight); + framebuffers[i] = graphStorage->logicalDevice->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight); } } @@ -79,9 +82,18 @@ namespace SHADE fbHeight = attResources[j]->height; } - framebuffers[i]->HandleResize(renderpass, imageViews, fbWidth, fbHeight); } + + for (auto& subpass : subpasses) + { + subpass->HandleResize(); + } + + for (auto& nodeCompute : nodeComputes) + { + nodeCompute->HandleResize(); + } } /***************************************************************************/ @@ -104,8 +116,8 @@ namespace SHADE */ /***************************************************************************/ - SHRenderGraphNode::SHRenderGraphNode(std::shared_ptr rm, Handle const& logicalDevice, Handle const& swapchain, std::vector attDescInitParams, std::vector> predecessors, std::unordered_map> const* resources) noexcept - : logicalDeviceHdl{ logicalDevice } + SHRenderGraphNode::SHRenderGraphNode(Handle renderGraphStorage, std::vector attDescInitParams, std::vector> predecessors) noexcept + : graphStorage{ renderGraphStorage} , renderpass{} , framebuffers{} , prereqNodes{ std::move(predecessors) } @@ -115,11 +127,10 @@ namespace SHADE , subpasses{} , executed{ false } , configured{ false } - , resourceManager{ rm } - , ptrToResources{ resources } + , nodeComputes{} { // pipeline library initialization - pipelineLibrary.Init(logicalDeviceHdl); + pipelineLibrary.Init(graphStorage->logicalDevice); // Store all the handles to resources attResources.reserve (attDescInitParams.size()); @@ -155,15 +166,14 @@ namespace SHADE if (!containsSwapchainImage) framebuffers.resize(1); else - framebuffers.resize(swapchain->GetNumImages()); + framebuffers.resize(graphStorage->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{ std::move (rhs.resourceManager) } - , logicalDeviceHdl{ rhs.logicalDeviceHdl } + : graphStorage{ rhs.graphStorage} , renderpass{ rhs.renderpass } , framebuffers{ std::move(rhs.framebuffers) } , prereqNodes{ std::move(rhs.prereqNodes) } @@ -174,11 +184,11 @@ namespace SHADE , subpassIndexing{ std::move(rhs.subpassIndexing) } , configured{ rhs.configured } , executed{ rhs.executed } - , ptrToResources{ rhs.ptrToResources } , pipelineLibrary{ std::move(rhs.pipelineLibrary) } , batcher{ std::move(rhs.batcher) } , spDescs{ std::move(rhs.spDescs) } , spDeps{ std::move(rhs.spDeps) } + , nodeComputes{ std::move(rhs.nodeComputes) } { rhs.renderpass = {}; @@ -189,8 +199,7 @@ namespace SHADE if (&rhs == this) return *this; - resourceManager = std::move(rhs.resourceManager); - logicalDeviceHdl = rhs.logicalDeviceHdl; + graphStorage = rhs.graphStorage; renderpass = rhs.renderpass; framebuffers = std::move(rhs.framebuffers); prereqNodes = std::move(rhs.prereqNodes); @@ -199,11 +208,11 @@ namespace SHADE 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); spDescs = std::move(rhs.spDescs); spDeps = std::move(rhs.spDeps); + nodeComputes = std::move(rhs.nodeComputes); rhs.renderpass = {}; @@ -235,10 +244,10 @@ namespace SHADE } // Add subpass to container and create mapping for it - subpasses.emplace_back(resourceManager->Create(GetHandle(), subpasses.size(), &resourceAttachmentMapping, ptrToResources)); + subpasses.emplace_back(graphStorage->resourceManager->Create(graphStorage, GetHandle(), static_cast(subpasses.size()), &resourceAttachmentMapping)); subpassIndexing.try_emplace(subpassName, static_cast(subpasses.size()) - 1u); Handle subpass = subpasses.back(); - subpass->Init(*resourceManager); + subpass->Init(*graphStorage->resourceManager); // Register the SuperBatch batcher.RegisterSuperBatch(subpass->GetSuperBatch()); @@ -246,21 +255,84 @@ namespace SHADE return subpass; } + Handle SHRenderGraphNode::AddNodeCompute(Handle computeShaderModule, std::initializer_list resources, float numWorkGroupScale/* = 1.0f*/) noexcept + { + // Look for the required resources in the graph + std::vector> nodeComputeResources{}; + nodeComputeResources.reserve(resources.size()); + + for (auto& resourceName : resources) + { + auto resource = graphStorage->graphResources->at(resourceName); + nodeComputeResources.push_back(resource); + } + + // Create the subpass compute with the resources + auto nodeCompute = graphStorage->resourceManager->Create(graphStorage, computeShaderModule, std::move(nodeComputeResources)); + nodeComputes.push_back(nodeCompute); + + return nodeCompute; + } + + /***************************************************************************/ + /*! + + \brief + This function checks all node computes and adds a subpass to transition + all needed resources to general. + + */ + /***************************************************************************/ + void SHRenderGraphNode::AddDummySubpassIfNeeded(void) noexcept + { + if (!nodeComputes.empty()) + { + // we save the resource names involved + std::unordered_set resourcesInvolved; + for (auto& compute : nodeComputes) + { + for (auto& resource : compute->resources) + { + resourcesInvolved.emplace(resource->GetName()); + } + } + + // insert them all for a subpass to transition them. This subpass is the last subpass + auto dummySubpass = AddSubpass("dummy"); + for (auto& resource : resourcesInvolved) + { + dummySubpass->AddGeneralInput(resource); + + if (SHVkUtil::IsDepthStencilAttachment(graphStorage->graphResources->at(resource)->GetResourceFormat())) + dummySubpass->AddGeneralDepthOutput(resource); + else + dummySubpass->AddGeneralColorOutput(resource); + } + } + } + void SHRenderGraphNode::Execute(Handle& commandBuffer, Handle descPool, uint32_t frameIndex) noexcept { - frameIndex = (framebuffers.size() > 1) ? frameIndex : 0; - commandBuffer->BeginRenderpass(renderpass, framebuffers[frameIndex]); + uint32_t framebufferIndex = (framebuffers.size() > 1) ? frameIndex : 0; + commandBuffer->BeginRenderpass(renderpass, framebuffers[framebufferIndex]); 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) + if (i != static_cast(subpasses.size()) - 1u) commandBuffer->NextSubpass(); } commandBuffer->EndRenderpass(); + + + // Execute all subpass computes + for (auto& sbCompute : nodeComputes) + { + sbCompute->Execute(commandBuffer, frameIndex); + } } Handle SHRenderGraphNode::GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept @@ -273,10 +345,10 @@ namespace SHADE } - Handle pipeline = pipelineLibrary.GetDrawPipline(vsFsPair); + Handle pipeline = pipelineLibrary.GetGraphicsPipeline(vsFsPair); if (!pipeline) { - pipeline = pipelineLibrary.CreateDrawPipeline + pipeline = pipelineLibrary.CreateGraphicsPipelines ( vsFsPair, renderpass, @@ -289,7 +361,7 @@ namespace SHADE void SHRenderGraphNode::FinaliseBatch(uint32_t frameIndex, Handle descPool) { - batcher.FinaliseBatches(logicalDeviceHdl, descPool, frameIndex); + batcher.FinaliseBatches(graphStorage->logicalDevice, descPool, frameIndex); } /***************************************************************************/ diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h index 3cb1c4ee..16f3f914 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h @@ -19,6 +19,9 @@ namespace SHADE class SHVkLogicalDevice; class SHVkRenderpass; class SHVkDescriptorPool; + class SHGraphicsGlobalData; + class SHRenderGraphStorage; + class SHRenderGraphNodeCompute; class SH_API SHRenderGraphNode : public ISelfHandle { @@ -26,10 +29,9 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ /*-----------------------------------------------------------------------*/ - std::shared_ptr resourceManager; - //! For Vulkan object creation - Handle logicalDeviceHdl; + //Handle logicalDeviceHdl; + Handle graphStorage; //! Each node will have a renderpass and each renderpass will have its own subpasses. //! These subpasses will execute sequentially. @@ -63,12 +65,13 @@ namespace SHADE //! 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; + //! Sometimes we want the subpass to do something to the images instead + //! of drawing objects on the image (i.e. compute). + std::vector> nodeComputes; + //! Whether or not the node has finished execution bool executed; @@ -77,6 +80,7 @@ namespace SHADE SHBatcher batcher; + /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ @@ -88,7 +92,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* CTORS AND DTORS */ /*-----------------------------------------------------------------------*/ - SHRenderGraphNode(std::shared_ptr rm, Handle const& logicalDevice, Handle const& swapchain, std::vector attDescInitParams, std::vector> predecessors, std::unordered_map> const* resources) noexcept; + SHRenderGraphNode(Handle renderGraphStorage, std::vector attDescInitParams, std::vector> predecessors) noexcept; SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept; SHRenderGraphNode& operator= (SHRenderGraphNode&& rhs) noexcept; @@ -96,6 +100,9 @@ namespace SHADE /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ Handle AddSubpass(std::string subpassName) noexcept; + Handle AddNodeCompute(Handle computeShaderModule, std::initializer_list resources, float numWorkGroupScale = 1.0f) noexcept; + void AddDummySubpassIfNeeded (void) noexcept; + // TODO: RemoveSubpass() void Execute(Handle& commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; Handle GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp new file mode 100644 index 00000000..a5208fcf --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp @@ -0,0 +1,109 @@ +#include "SHpch.h" +#include "SHRenderGraphNodeCompute.h" +#include "Graphics/Pipeline/SHVkPipeline.h" +#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" +#include "Graphics/Descriptors/SHVkDescriptorPool.h" +#include "Graphics/Descriptors/SHVkDescriptorSetLayout.h" +#include "Graphics/Devices/SHVkLogicalDevice.h" +#include "Graphics/Pipeline/SHVkPipelineLayout.h" +#include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h" +#include "SHRenderGraphStorage.h" +#include "SHRenderGraphResource.h" +#include "Graphics/Commands/SHVkCommandBuffer.h" + +namespace SHADE +{ + SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, float inNumWorkGroupScale/* = 1.0f*/) noexcept + : computePipeline{} + , pipelineLayout{} + , resources{} + , groupSizeX{0} + , groupSizeY{0} + , numWorkGroupScale {std::clamp(inNumWorkGroupScale, 0.0f, 1.0f)} + { + SHPipelineLayoutParams pipelineLayoutParams + { + .shaderModules = {computeShaderModule}, + .globalDescSetLayouts = SHGraphicsGlobalData::GetDescSetLayouts() + }; + + // Create pipeline layout from parameters + pipelineLayout = graphStorage->logicalDevice->CreatePipelineLayout (pipelineLayoutParams); + + // Create the compute pipeline + computePipeline = graphStorage->logicalDevice->CreateComputePipeline(pipelineLayout); + + // and construct it + computePipeline->ConstructPipeline(); + + // save the resources + resources = std::move (subpassComputeResources); + + //Get the descriptor set layouts required to allocate. We only want the ones for allocate because + //global descriptors are already bound in the main system. + auto const& layouts = computePipeline->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) + for (uint32_t i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i) + { + descSetGroups[i] = graphStorage->descriptorPool->Allocate(layouts, variableCounts); + } + + + HandleResize(); + } + + void SHRenderGraphNodeCompute::Execute(Handle cmdBuffer, uint32_t frameIndex) noexcept + { + // bind the compute pipeline + cmdBuffer->BindPipeline(computePipeline); + + // bind descriptor sets + cmdBuffer->BindDescriptorSet(descSetGroups[frameIndex], SH_PIPELINE_TYPE::COMPUTE, SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, {}); + + // dispatch compute + cmdBuffer->ComputeDispatch(groupSizeX, groupSizeY, 1); + + // TODO: barrier + + } + + void SHRenderGraphNodeCompute::HandleResize(void) noexcept + { + // Get the layout for the render graph resource. We can index it this way because the container returned is a container of layouts that includes the global ones + auto pipelineDescSetLayouts = computePipeline->GetPipelineLayout()->GetDescriptorSetLayoutsPipeline()[SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE]; + + // everything below here needs resizing + for (uint32_t frameIndex = 0; frameIndex < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++frameIndex) + { + uint32_t i = 0; + + // loop through bindings and write descriptor sets + for (auto& binding : pipelineDescSetLayouts->GetBindings()) + { + uint32_t imageIndex = (resources[i]->resourceTypeFlags & static_cast(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)) ? frameIndex : 0; + + SHVkDescriptorSetGroup::viewSamplerLayout vsl = std::make_tuple(resources[i]->GetImageView(imageIndex), Handle{}, vk::ImageLayout::eGeneral); + descSetGroups[frameIndex]->ModifyWriteDescImage(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint, { &vsl, 1 }); + descSetGroups[frameIndex]->UpdateDescriptorSetImages(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint); + ++i; + } + } + + // Get the group size from the max width and height + uint32_t maxWidth = 0, maxHeight = 0; + for (auto& resource : resources) + { + maxWidth = std::max(resource->GetWidth(), maxWidth); + maxHeight = std::max(resource->GetHeight(), maxHeight); + } + + groupSizeX = maxWidth / workGroupSizeX; + groupSizeY = maxHeight / workGroupSizeY; + } + +} diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h new file mode 100644 index 00000000..ba4cf387 --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h @@ -0,0 +1,57 @@ +#pragma once + +#include "Resource/SHHandle.h" +#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" +#include +#include +#include + +namespace SHADE +{ + class SHVkPipeline; + class SHVkDescriptorSetGroup; + class SHVkDescriptorPool; + class SHVkLogicalDevice; + class SHVkPipelineLayout; + class SHRenderGraphStorage; + class SHRenderGraphResource; + class SHVkShaderModule; + class SHVkCommandBuffer; + + class SHRenderGraphNodeCompute + { + private: + static constexpr uint32_t workGroupSizeX = 16; + static constexpr uint32_t workGroupSizeY = 16; + + //! To run the dispatch command + Handle computePipeline; + + //! Pipeline layout for the pipeline creation + Handle pipelineLayout; + + //! Descriptor set group to hold the images for reading (STORAGE_IMAGE) + std::array, SHGraphicsConstants::NUM_FRAME_BUFFERS> descSetGroups; + + //! vector of resources needed by the subpass compute + std::vector> resources; + + //! X dimension work group size. Should scale with resource size. + uint32_t groupSizeX; + + //! Y dimension work group size + uint32_t groupSizeY; + + float numWorkGroupScale; + + public: + SHRenderGraphNodeCompute(Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, float inNumWorkGroupScale = 1.0f) noexcept; + + void Execute (Handle cmdBuffer, uint32_t frameIndex) noexcept; + void HandleResize (void) noexcept; + + friend class SHRenderGraph; + friend class SHRenderGraphNode; + }; +} + diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp index adf3b6cd..502e09b2 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp @@ -5,6 +5,7 @@ #include "Graphics/Images/SHVkImageView.h" #include "Graphics/Buffers/SHVkBuffer.h" #include "Graphics/SHVkUtil.h" +#include "SHRenderGraphStorage.h" namespace SHADE { @@ -45,9 +46,8 @@ namespace SHADE */ /***************************************************************************/ - SHRenderGraphResource::SHRenderGraphResource(Handle const& logicalDevice, Handle const& swapchain, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept - : logicalDevice {logicalDevice} - , swapchain{ swapchain } + SHRenderGraphResource::SHRenderGraphResource(Handle renderGraphStorage, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept + : graphStorage{renderGraphStorage} , resourceTypeFlags{ } , resourceFormat{ format } , images{} @@ -66,7 +66,7 @@ namespace SHADE SHImageViewDetails viewDetails { .viewType = vk::ImageViewType::e2D, - .format = swapchain->GetSurfaceFormatKHR().format, + .format = graphStorage->swapchain->GetSurfaceFormatKHR().format, .imageAspectFlags = vk::ImageAspectFlagBits::eColor, .baseMipLevel = 0, .mipLevelCount = 1, @@ -75,13 +75,13 @@ namespace SHADE }; // We want an image handle for every swapchain image - images.resize(swapchain->GetNumImages()); - imageViews.resize(swapchain->GetNumImages()); + images.resize(graphStorage->swapchain->GetNumImages()); + imageViews.resize(graphStorage->swapchain->GetNumImages()); - for (uint32_t i = 0; i < swapchain->GetNumImages(); ++i) + for (uint32_t i = 0; i < graphStorage->swapchain->GetNumImages(); ++i) { - images[i] = swapchain->GetSwapchainImage(i); - imageViews[i] = images[i]->CreateImageView(logicalDevice, images[i], viewDetails); + images[i] = graphStorage->swapchain->GetSwapchainImage(i); + imageViews[i] = images[i]->CreateImageView(graphStorage->logicalDevice, images[i], viewDetails); } } else // if swapchain image resource @@ -117,6 +117,9 @@ namespace SHADE usage |= vk::ImageUsageFlagBits::eInputAttachment; usage |= vk::ImageUsageFlagBits::eSampled; break; + case SH_ATT_DESC_TYPE_FLAGS::STORAGE: + usage |= vk::ImageUsageFlagBits::eStorage; + break; case SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT: { SHLOG_ERROR ("COLOR_PRESENT cannot be with other resource type flags. "); @@ -126,7 +129,7 @@ namespace SHADE } // 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)); + images.push_back(graphStorage->logicalDevice->CreateImage(width, height, mipLevels, resourceFormat, usage, createFlags)); // prepare image view details SHImageViewDetails viewDetails @@ -141,7 +144,7 @@ namespace SHADE }; // just 1 image view created - imageViews.push_back(images[0]->CreateImageView(logicalDevice, images[0], viewDetails)); + imageViews.push_back(images[0]->CreateImageView(graphStorage->logicalDevice, images[0], viewDetails)); } } @@ -166,7 +169,7 @@ namespace SHADE , height{ rhs.height } , mipLevels{ rhs.mipLevels } , imageAspectFlags{ rhs.imageAspectFlags } - , swapchain {rhs.swapchain} + , graphStorage{rhs.graphStorage} { } @@ -198,7 +201,7 @@ namespace SHADE height = rhs.height; mipLevels = rhs.mipLevels; imageAspectFlags = rhs.imageAspectFlags; - swapchain = rhs.swapchain; + graphStorage = rhs.graphStorage; return *this; } @@ -247,7 +250,7 @@ namespace SHADE SHImageViewDetails viewDetails { .viewType = vk::ImageViewType::e2D, - .format = swapchain->GetSurfaceFormatKHR().format, + .format = graphStorage->swapchain->GetSurfaceFormatKHR().format, .imageAspectFlags = vk::ImageAspectFlagBits::eColor, .baseMipLevel = 0, .mipLevelCount = 1, @@ -255,9 +258,9 @@ namespace SHADE .layerCount = 1, }; - for (uint32_t i = 0; i < swapchain->GetNumImages(); ++i) + for (uint32_t i = 0; i < graphStorage->swapchain->GetNumImages(); ++i) { - images[i] = swapchain->GetSwapchainImage(i); + images[i] = graphStorage->swapchain->GetSwapchainImage(i); imageViews[i]->ViewNewImage(images[i], viewDetails); } } @@ -308,6 +311,7 @@ namespace SHADE return resourceFormat; } + uint32_t SHRenderGraphResource::GetWidth(void) const noexcept { return width; @@ -323,4 +327,19 @@ namespace SHADE return imageViews [index]; } + Handle SHRenderGraphResource::GetImage(uint32_t index /*= NON_SWAPCHAIN_RESOURCE_INDEX*/) const noexcept + { + return images[index]; + } + + uint8_t SHRenderGraphResource::GetMipLevels(void) const noexcept + { + return mipLevels; + } + + std::string SHRenderGraphResource::GetName(void) const noexcept + { + return resourceName; + } + } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h index fc8b05f7..e2fc5d8d 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h @@ -15,6 +15,7 @@ namespace SHADE class SHVkSwapchain; class SHVkCommandBuffer; class SHVkBuffer; + class SHRenderGraphStorage; static constexpr uint32_t NON_SWAPCHAIN_RESOURCE_INDEX = 0; @@ -24,11 +25,8 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ /*-----------------------------------------------------------------------*/ - // for creation/recreation - Handle logicalDevice; - - // for creation/recreation - Handle swapchain; + //! Storage from the render graph + Handle graphStorage; //! Name of the resource std::string resourceName; @@ -69,7 +67,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* CTORS AND DTORS */ /*-----------------------------------------------------------------------*/ - SHRenderGraphResource(Handle const& logicalDevice, Handle const& swapchain, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept; + SHRenderGraphResource(Handle renderGraphStorage, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept; SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept; SHRenderGraphResource& operator=(SHRenderGraphResource&& rhs) noexcept; ~SHRenderGraphResource(void) noexcept; @@ -84,12 +82,17 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ /*-----------------------------------------------------------------------*/ - vk::Format GetResourceFormat (void) const noexcept; - uint32_t GetWidth (void) const noexcept; - uint32_t GetHeight (void) const noexcept; - Handle GetImageView (uint32_t index = NON_SWAPCHAIN_RESOURCE_INDEX) const noexcept; + vk::Format GetResourceFormat (void) const noexcept; + uint32_t GetWidth (void) const noexcept; + uint32_t GetHeight (void) const noexcept; + Handle GetImageView (uint32_t index = NON_SWAPCHAIN_RESOURCE_INDEX) const noexcept; + Handle GetImage (uint32_t index = NON_SWAPCHAIN_RESOURCE_INDEX) const noexcept; + uint8_t GetMipLevels (void) const noexcept; + std::string GetName (void) const noexcept; friend class SHRenderGraphNode; friend class SHRenderGraph; + friend class SHSubpass; + friend class SHRenderGraphNodeCompute; }; } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphStorage.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphStorage.h new file mode 100644 index 00000000..54ef705a --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphStorage.h @@ -0,0 +1,43 @@ +#pragma once + +#include "Resource/SHHandle.h" +#include + +namespace SHADE +{ + class SHVkLogicalDevice; + class SHVkSwapchain; + class SHGraphicsGlobalData; + class SHVkDescriptorPool; + class SHRenderGraphResource; + + class SHRenderGraphStorage + { + //! Logical device for creation of vulkan objects + Handle logicalDevice; + + //! swapchain handle + Handle swapchain; + + //! Resource manager for creation of objects + std::shared_ptr resourceManager; + + //! Descriptor pool for the descriptor sets to be created in the subpasses + Handle descriptorPool; + + //! For accessing resources anywhere in the graph + Handle>> graphResources; + + //SHRenderGraphStorage(void) noexcept; + //SHRenderGraphStorage(SHRenderGraphStorage&& rhs) noexcept; + //SHRenderGraphStorage& operator=(SHRenderGraphStorage&& rhs) noexcept; + + friend class SHRenderGraph; + friend class SHRenderGraphNode; + friend class SHSubpass; + friend class SHRenderGraphResource; + friend class SHRenderGraphNodeCompute; + }; + + +} diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp index 7c5021f8..af6f3089 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp @@ -4,6 +4,13 @@ #include "Graphics/Devices/SHVkLogicalDevice.h" #include "SHRenderGraphNode.h" #include "SHRenderGraphResource.h" +#include "Graphics/Shaders/SHVkShaderModule.h" +#include "SHRenderGraphNode.h" +#include "SHRenderGraphStorage.h" +#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" +#include "Graphics/Swapchain/SHVkSwapchain.h" +#include "Graphics/Images/SHVkSampler.h" +#include "SHRenderGraphResource.h" namespace SHADE { @@ -23,15 +30,16 @@ namespace SHADE */ /***************************************************************************/ - SHSubpass::SHSubpass(Handle const& parent, uint32_t index, std::unordered_map const* mapping, std::unordered_map> const* resources) noexcept + SHSubpass::SHSubpass(Handle renderGraphStorage, Handle const& parent, uint32_t index, std::unordered_map const* mapping) noexcept : resourceAttachmentMapping{ mapping } - , ptrToResources{ resources } , parentNode{ parent } , subpassIndex{ index } , superBatch{} , colorReferences{} , depthReferences{} , inputReferences{} + , graphStorage{ renderGraphStorage } + , inputImageDescriptors {SHGraphicsConstants::NUM_FRAME_BUFFERS} { } @@ -54,9 +62,14 @@ namespace SHADE , depthReferences{ std::move(rhs.depthReferences) } , inputReferences{ std::move(rhs.inputReferences) } , resourceAttachmentMapping{ rhs.resourceAttachmentMapping } - , ptrToResources{ rhs.ptrToResources } , descriptorSetLayout{ rhs.descriptorSetLayout } - , exteriorDrawCalls{ std::move (rhs.exteriorDrawCalls) } + , exteriorDrawCalls{ std::move(rhs.exteriorDrawCalls) } + , graphStorage{ rhs.graphStorage } + , inputNames{ std::move(rhs.inputNames) } + , inputImageDescriptors{ std::move(rhs.inputImageDescriptors) } + , inputDescriptorLayout{ rhs.inputDescriptorLayout } + , inputSamplers{ rhs.inputSamplers } + { } @@ -84,9 +97,13 @@ namespace SHADE depthReferences = std::move(rhs.depthReferences); inputReferences = std::move(rhs.inputReferences); resourceAttachmentMapping = rhs.resourceAttachmentMapping; - ptrToResources = rhs.ptrToResources; descriptorSetLayout = rhs.descriptorSetLayout; exteriorDrawCalls = std::move(rhs.exteriorDrawCalls); + graphStorage = rhs.graphStorage; + inputNames = std::move(rhs.inputNames); + inputImageDescriptors = std::move(rhs.inputImageDescriptors); + inputDescriptorLayout = rhs.inputDescriptorLayout; + inputSamplers = rhs.inputSamplers; return *this; } @@ -105,7 +122,12 @@ namespace SHADE /***************************************************************************/ void SHSubpass::AddColorOutput(std::string resourceToReference) noexcept { - colorReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eColorAttachmentOptimal }); + colorReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eColorAttachmentOptimal }); + } + + void SHSubpass::AddGeneralColorOutput(std::string resourceToReference) noexcept + { + colorReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eGeneral }); } /***************************************************************************/ @@ -142,7 +164,13 @@ namespace SHADE //Invalid return; } - depthReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), imageLayout }); + depthReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), imageLayout }); + } + + void SHSubpass::AddGeneralDepthOutput(std::string resourceToReference) noexcept + { + depthReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eGeneral }); + } /***************************************************************************/ @@ -159,7 +187,14 @@ namespace SHADE /***************************************************************************/ void SHSubpass::AddInput(std::string resourceToReference) noexcept { - inputReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eShaderReadOnlyOptimal }); + inputReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eShaderReadOnlyOptimal }); + + inputNames.push_back(resourceToReference); + } + + void SHSubpass::AddGeneralInput(std::string resourceToReference) noexcept + { + inputReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eGeneral }); } void SHSubpass::Execute(Handle& commandBuffer, Handle descPool, uint32_t frameIndex) noexcept @@ -175,6 +210,12 @@ namespace SHADE { drawCall(commandBuffer); } + + } + + void SHSubpass::HandleResize(void) noexcept + { + UpdateWriteDescriptors(); } void SHSubpass::AddExteriorDrawCalls(std::function&)> const& newDrawCall) noexcept @@ -188,6 +229,152 @@ namespace SHADE } + void SHSubpass::CreateInputDescriptors(void) noexcept + { + if (inputNames.empty()) + return; + + std::vector bindings{}; + + for (auto& input : inputReferences) + { + SHVkDescriptorSetLayout::Binding newBinding + { + .Type = (input.layout == vk::ImageLayout::eShaderReadOnlyOptimal) ? vk::DescriptorType::eInputAttachment : vk::DescriptorType::eStorageImage, + .Stage = vk::ShaderStageFlagBits::eFragment, + .BindPoint = static_cast(bindings.size()), + .DescriptorCount = 1, + .flags = {}, + }; + + bindings.push_back(newBinding); + } + + // We build a new descriptor set layout to store our images + inputDescriptorLayout = graphStorage->logicalDevice->CreateDescriptorSetLayout(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, bindings); + + // we store a sampler if its an input attachment. if it is storage image, no need sampler, store an empty handle. + for (uint32_t i = 0; i < bindings.size(); ++i) + { + if (bindings[i].Type == vk::DescriptorType::eInputAttachment) + { + auto newSampler = graphStorage->logicalDevice->CreateSampler(SHVkSamplerParams + { + .minFilter = vk::Filter::eLinear, + .magFilter = vk::Filter::eLinear, + .addressMode = vk::SamplerAddressMode::eRepeat, + .mipmapMode = vk::SamplerMipmapMode::eLinear, + .minLod = -1000, + .maxLod = 1000 + } + ); + + inputSamplers.push_back(newSampler); + } + else + { + inputSamplers.push_back({}); + } + } + + //// maybe do this in handle resize? + //UpdateWriteDescriptors(); + } + + void SHSubpass::UpdateWriteDescriptors(void) noexcept + { + if (inputNames.empty()) + return; + + auto const& bindings = inputDescriptorLayout->GetBindings(); + + std::vector variableCounts{ static_cast(bindings.size()) }; + std::fill (variableCounts.begin(), variableCounts.end(), 0u); + + + // For every frame's descriptor set + for (auto& group : inputImageDescriptors) + { + if (group) + group.Free(); + + group = graphStorage->descriptorPool->Allocate({ inputDescriptorLayout }, variableCounts); + + uint32_t i = 0; + for (auto& binding : bindings) + { + // get the resource + auto resource = graphStorage->graphResources->at(inputNames[binding.BindPoint]); + + // If resource is swapchain image, get the correct image, if not just get 0. + uint32_t viewIndex = (resource->resourceTypeFlags & static_cast(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)) ? i : 0; + + // layout is GENERAL if image is meant to be used as storage image, if not use SHADER_READ_ONLY_OPTINAL + vk::ImageLayout descriptorLayout = (binding.Type == vk::DescriptorType::eStorageImage) ? vk::ImageLayout::eGeneral : vk::ImageLayout::eShaderReadOnlyOptimal; + + // Update descriptor sets + auto args = std::make_tuple(resource->GetImageView(viewIndex), inputSamplers[i], descriptorLayout); + group->ModifyWriteDescImage(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint, std::span{&args, 1}); + group->UpdateDescriptorSetImages(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint); + } + + ++i; + } + } + + //void SHSubpass::InitComputeBarriers(void) noexcept + //{ + // std::unordered_set handleBarriers{}; + + // // we will have swapchainNumImages vectors of vector of barriers + // subpassComputeBarriers.resize(graphStorage->swapchain->GetNumImages()); + + // for (auto sbCompute : subpassComputes) + // { + // // for every resource the subpass compute is using + // for (auto resource : sbCompute->resources) + // { + // // Get the resource handle + // uint64_t resourceRaw = resource.GetId().Raw; + + // // if the barrier is not registered + // if (!handleBarriers.contains(resourceRaw)) + // { + // // If the resource is a swapchain image + // bool isSwapchainImage = (resource->resourceTypeFlags & static_cast(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)); + // for (uint32_t i = 0; i < graphStorage->swapchain->GetNumImages(); ++i) + // { + // // if swapchain image, we want the index of the swapchain image, if not take base image + // uint32_t imageIndex = isSwapchainImage ? i : 0; + + // // Prepare image barrier + // vk::ImageMemoryBarrier imageBarrier + // { + // .oldLayout = colorReferences[resourceAttachmentMapping->at(resource.GetId().Raw)].layout, + // .newLayout = vk::ImageLayout::eGeneral, + // .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + // .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + // .image = resource->GetImage(imageIndex)->GetVkImage(), + // .subresourceRange = + // { + // .aspectMask = resource->imageAspectFlags, + // .levelCount = resource->GetMipLevels(), + // .baseArrayLayer = 0, + // .layerCount = 1 + // } + // }; + + // // push the barrier + // subpassComputeBarriers[i].push_back(imageBarrier); + // } + + // // Image transition registered + // handleBarriers.emplace(resourceRaw); + // } + // } + // } + //} + /***************************************************************************/ /*! diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h index e5094708..166f0d76 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h @@ -14,7 +14,11 @@ namespace SHADE class SHRenderGraphResource; class SHVkCommandBuffer; class SHVkDescriptorSetLayout; + class SHVkDescriptorSetGroup; class SHVkDescriptorPool; + class SHRenderGraphStorage; + class SHVkShaderModule; + class SHVkSampler; class SH_API SHSubpass : public ISelfHandle { @@ -22,32 +26,49 @@ namespace SHADE /*---------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ /*---------------------------------------------------------------------*/ + Handle graphStorage; + //! The index of the subpass in the render graph - uint32_t subpassIndex; + uint32_t subpassIndex; //! The parent renderpass that this subpass belongs to - Handle parentNode; + Handle parentNode; //! - Handle superBatch; + Handle superBatch; //! Descriptor set layout to hold attachments - Handle descriptorSetLayout; + Handle descriptorSetLayout; //! Color attachments - std::vector colorReferences; + std::vector colorReferences; //! Depth attachments - std::vector depthReferences; + std::vector depthReferences; //! Input attachments - std::vector inputReferences; + std::vector inputReferences; + + //! This is mainly for when we want to retrieve resources using names. + std::vector inputNames; //! 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; + //! Descriptor set group to hold the images for input + std::vector> inputImageDescriptors; + + //! Descriptor set layout for allocating descriptor set for inputs + Handle inputDescriptorLayout; + + std::vector> inputSamplers; + + + ////! subpass compute image barriers. We do this because every frame has a different + ////! swapchain image. If the resource we want to transition is not a swapchain image, + ////! we duplicate the barrier anyway, not much memory wasted. ;) + //std::vector> subpassComputeBarriers{}; + //! 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. @@ -62,7 +83,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* CTORS AND DTORS */ /*-----------------------------------------------------------------------*/ - SHSubpass(Handle const& parent, uint32_t index, std::unordered_map const* mapping, std::unordered_map> const* ptrToResources) noexcept; + SHSubpass(Handle renderGraphStorage, Handle const& parent, uint32_t index, std::unordered_map const* mapping) noexcept; SHSubpass(SHSubpass&& rhs) noexcept; SHSubpass& operator=(SHSubpass&& rhs) noexcept; @@ -71,14 +92,22 @@ namespace SHADE /*-----------------------------------------------------------------------*/ // Preparation functions void AddColorOutput(std::string resourceToReference) noexcept; + void AddGeneralColorOutput(std::string resourceToReference) noexcept; void AddDepthOutput(std::string resourceToReference, SH_ATT_DESC_TYPE_FLAGS attachmentDescriptionType = SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL) noexcept; + void AddGeneralDepthOutput(std::string resourceToReference) noexcept; void AddInput(std::string resourceToReference) noexcept; + void AddGeneralInput (std::string resourceToReference) noexcept; + void AddExteriorDrawCalls(std::function&)> const& newDrawCall) noexcept; // Runtime functions void Execute(Handle& commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; - void AddExteriorDrawCalls(std::function&)> const& newDrawCall) noexcept; + void HandleResize (void) noexcept; void Init(SHResourceHub& resourceManager) noexcept; + + //void InitComputeBarriers (void) noexcept; + void CreateInputDescriptors (void) noexcept; + void UpdateWriteDescriptors (void) noexcept; /*-----------------------------------------------------------------------*/ /* GETTERS AND SETTERS */ @@ -91,5 +120,6 @@ namespace SHADE friend class SHRenderGraphNode; friend class SHRenderGraph; + friend class SHSubpass; }; } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.cpp deleted file mode 100644 index ccd0e6c3..00000000 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#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 deleted file mode 100644 index 7bbbe051..00000000 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.h +++ /dev/null @@ -1,25 +0,0 @@ -#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/SHVkUtil.cpp b/SHADE_Engine/src/Graphics/SHVkUtil.cpp index c8c563a1..cf486a7a 100644 --- a/SHADE_Engine/src/Graphics/SHVkUtil.cpp +++ b/SHADE_Engine/src/Graphics/SHVkUtil.cpp @@ -55,6 +55,21 @@ namespace SHADE return 0; } + vk::PipelineBindPoint SHVkUtil::GetPipelineBindPointFromType(SH_PIPELINE_TYPE pipelineType) noexcept + { + switch (pipelineType) + { + case SH_PIPELINE_TYPE::GRAPHICS: + return vk::PipelineBindPoint::eGraphics; + case SH_PIPELINE_TYPE::COMPUTE: + return vk::PipelineBindPoint::eCompute; + case SH_PIPELINE_TYPE::RAY_TRACING: + return vk::PipelineBindPoint::eRayTracingKHR; + default: + return vk::PipelineBindPoint::eGraphics; + } + } + void SHVkUtil::EnsureBufferAndCopyData(Handle device, Handle cmdBuffer, Handle& bufferHandle, void* src, uint32_t size, vk::BufferUsageFlagBits usage) { if (bufferHandle) diff --git a/SHADE_Engine/src/Graphics/SHVkUtil.h b/SHADE_Engine/src/Graphics/SHVkUtil.h index dbf17826..de700ea5 100644 --- a/SHADE_Engine/src/Graphics/SHVkUtil.h +++ b/SHADE_Engine/src/Graphics/SHVkUtil.h @@ -4,6 +4,7 @@ #include "SHVulkanIncludes.h" #include "Resource/SHHandle.h" +#include "Graphics/Pipeline/SHPipelineType.h" namespace SHADE { @@ -20,11 +21,12 @@ namespace SHADE class SHVkUtil { public: - static bool IsDepthOnlyFormat (vk::Format format) noexcept; - static bool IsDepthStencilAttachment (vk::Format format) noexcept; - static bool IsBlendCompatible (vk::Format format) noexcept; - static uint32_t GetBytesPerPixelFromFormat (vk::Format format) noexcept; - + static bool IsDepthOnlyFormat (vk::Format format) noexcept; + static bool IsDepthStencilAttachment (vk::Format format) noexcept; + static bool IsBlendCompatible (vk::Format format) noexcept; + static uint32_t GetBytesPerPixelFromFormat (vk::Format format) noexcept; + static vk::PipelineBindPoint GetPipelineBindPointFromType (SH_PIPELINE_TYPE pipelineType) noexcept; + /***********************************************************************************/ /*! diff --git a/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp b/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp index 41327988..e635f763 100644 --- a/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp +++ b/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp @@ -177,6 +177,9 @@ namespace SHADE return vk::DescriptorType::eStorageBufferDynamic; case SpvReflectDescriptorType::SPV_REFLECT_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: return vk::DescriptorType::eInputAttachment; + case SpvReflectDescriptorType::SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE: + return vk::DescriptorType::eStorageImage; + break; default: return vk::DescriptorType::eCombinedImageSampler; break; diff --git a/SHADE_Engine/src/Input/SHInputManager.cpp b/SHADE_Engine/src/Input/SHInputManager.cpp index 18d9e3e2..c665a9c9 100644 --- a/SHADE_Engine/src/Input/SHInputManager.cpp +++ b/SHADE_Engine/src/Input/SHInputManager.cpp @@ -19,6 +19,10 @@ namespace SHADE /*------------------------------------------------------------------------*/ /* Static defines */ /*------------------------------------------------------------------------*/ + + bool SHInputManager::controllerInUse = false; + + std::map SHInputManager::bindings; unsigned SHInputManager::keyCount = 0; bool SHInputManager::keys[MAX_KEYS]; @@ -41,6 +45,60 @@ namespace SHADE int SHInputManager::mouseWheelVerticalDelta = 0; int SHInputManager::mouseWheelVerticalDeltaPoll = 0; + unsigned char SHInputManager::controllersConnectedCount = 0; + unsigned SHInputManager::controllersInputCount[XUSER_MAX_COUNT]; + unsigned SHInputManager::controllersButtonCount[XUSER_MAX_COUNT]; + short SHInputManager::controllers[XUSER_MAX_COUNT][MAX_CONTROLLER_INPUT]; + short SHInputManager::controllersLast[XUSER_MAX_COUNT][MAX_CONTROLLER_INPUT]; + double SHInputManager::controllersHeldTime[XUSER_MAX_COUNT][MAX_CONTROLLER_INPUT]; + double SHInputManager::controllersReleasedTime[XUSER_MAX_COUNT][MAX_CONTROLLER_INPUT]; + + //Internal helper function for splitting between inputs + bool SHInputManager::controllerConsideredHeld(size_t inputIdx, short value) noexcept + { + if (inputIdx >= MAX_CONTROLLER_INPUT) return false; //Bounds check + else + { + if (inputIdx < NUM_CONTROLLER_BUTTON) + { + return static_cast(value); + } + else if (inputIdx < NUM_CONTROLLER_BUTTON + NUM_CONTROLLER_TRIGGER) + { + return (value > XINPUT_GAMEPAD_TRIGGER_THRESHOLD); + } + else if (inputIdx < NUM_CONTROLLER_BUTTON + NUM_CONTROLLER_TRIGGER + NUM_CONTROLLER_TRIGGER) + { + return (std::abs(value) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); + } + else + { + return (std::abs(value) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); + } + } + } + + //Internal helper function for getting normalised input value + double SHInputManager::controllerNormalisedValue(size_t inputIdx, short value) noexcept + { + if (inputIdx >= MAX_CONTROLLER_INPUT) return 0.0; //Bounds check + else + { + if (inputIdx < NUM_CONTROLLER_BUTTON) + { + return static_cast(value); + } + else if (inputIdx < NUM_CONTROLLER_BUTTON + NUM_CONTROLLER_TRIGGER) //8-bit triggers, 0 to 255 + { + return static_cast(value) / static_cast(UCHAR_MAX); + } + else //16-bit thumbsticks, -32768 to 32767 + { + return static_cast(value) / static_cast(SHRT_MAX); + } + } + } + void SHInputManager::UpdateInput(double dt) noexcept { //Keyboard and Mouse Buttons//////////////////////////////////////////////// @@ -120,6 +178,273 @@ namespace SHADE mouseWheelVerticalDelta = 0; mouseWheelVerticalDelta = mouseWheelVerticalDeltaPoll; mouseWheelVerticalDeltaPoll = 0; + + //Controllers////////////////////////////////////////////////////////////// + + controllersConnectedCount = 0; + + //Set last controller states + memcpy(controllersLast, controllers, sizeof(controllers)); + + //Reset controller states + SecureZeroMemory(&controllers, sizeof(controllers)); + + //https://learn.microsoft.com/en-us/windows/win32/xinput/getting-started-with-xinput#getting-controller-state + for (DWORD c = 0; c < XUSER_MAX_COUNT; ++c) + { + controllersInputCount[c] = 0; + controllersButtonCount[c] = 0; + + XINPUT_STATE state; + SecureZeroMemory(&state, sizeof(XINPUT_STATE)); + + //Get the state of controller from XInput + DWORD result = XInputGetState(c, &state); + + //Write gamepad data + if (result == ERROR_SUCCESS) + { + ++controllersConnectedCount; + + //DIGITAL BUTTONS/////////////////////////////////////// + + //DPAD UP + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) + { + controllers[c][static_cast(SH_CONTROLLERCODE::DPAD_UP)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::DPAD_UP)] = 0; + } + + //DPAD DOWN + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) + { + controllers[c][static_cast(SH_CONTROLLERCODE::DPAD_DOWN)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::DPAD_DOWN)] = 0; + } + + //DPAD LEFT + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) + { + controllers[c][static_cast(SH_CONTROLLERCODE::DPAD_LEFT)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::DPAD_LEFT)] = 0; + } + + //DPAD RIGHT + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) + { + controllers[c][static_cast(SH_CONTROLLERCODE::DPAD_RIGHT)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::DPAD_RIGHT)] = 0; + } + + //START + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_START) + { + controllers[c][static_cast(SH_CONTROLLERCODE::START)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::START)] = 0; + } + + //BACK + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) + { + controllers[c][static_cast(SH_CONTROLLERCODE::BACK)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::BACK)] = 0; + } + + //LEFT THUMBSTICK BUTTON + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) + { + controllers[c][static_cast(SH_CONTROLLERCODE::LEFT_THUMBSTICK)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::LEFT_THUMBSTICK)] = 0; + } + + //RIGHT THUMBSTICK BUTTON + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) + { + controllers[c][static_cast(SH_CONTROLLERCODE::RIGHT_THUMBSTICK)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::RIGHT_THUMBSTICK)] = 0; + } + + //LEFT SHOULDER BUTTON + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) + { + controllers[c][static_cast(SH_CONTROLLERCODE::LEFT_SHOULDER)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::LEFT_SHOULDER)] = 0; + } + + //RIGHT SHOULDER BUTTON + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) + { + controllers[c][static_cast(SH_CONTROLLERCODE::RIGHT_SHOULDER)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::RIGHT_SHOULDER)] = 0; + } + + //A + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_A) + { + controllers[c][static_cast(SH_CONTROLLERCODE::A)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::A)] = 0; + } + + //B + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_B) + { + controllers[c][static_cast(SH_CONTROLLERCODE::B)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::B)] = 0; + } + + //X + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_X) + { + controllers[c][static_cast(SH_CONTROLLERCODE::X)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::X)] = 0; + } + + //Y + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_Y) + { + controllers[c][static_cast(SH_CONTROLLERCODE::Y)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::Y)] = 0; + } + + //8 BIT VALUES (0 - 255)/////////////////////////////////// + + //LEFT TRIGGER + controllers[c][static_cast(SH_CONTROLLERCODE::LEFT_TRIGGER)] = state.Gamepad.bLeftTrigger; + if (state.Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) + { + ++controllersInputCount[c]; //Registered as held + } + + //RIGHT TRIGGER + controllers[c][static_cast(SH_CONTROLLERCODE::RIGHT_TRIGGER)] = state.Gamepad.bRightTrigger; + if (state.Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) + { + ++controllersInputCount[c]; //Registered as held + } + + //16 BIT VALUES (0 - 65535)//////////////////////////////// + + //LEFT THUMBSTICK X + controllers[c][static_cast(SH_CONTROLLERCODE::LEFT_THUMBSTICK_X)] = state.Gamepad.sThumbLX; + if (std::abs(state.Gamepad.sThumbLX) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) + { + ++controllersInputCount[c]; + } + + //LEFT THUMBSTICK Y + controllers[c][static_cast(SH_CONTROLLERCODE::LEFT_THUMBSTICK_Y)] = state.Gamepad.sThumbLY; + if (std::abs(state.Gamepad.sThumbLY) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) + { + ++controllersInputCount[c]; + } + + //RIGHT THUMBSTICK X + controllers[c][static_cast(SH_CONTROLLERCODE::RIGHT_THUMBSTICK_X)] = state.Gamepad.sThumbRX; + if (std::abs(state.Gamepad.sThumbRX) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) + { + ++controllersInputCount[c]; + } + + //RIGHT THUMBSTICK Y + controllers[c][static_cast(SH_CONTROLLERCODE::RIGHT_THUMBSTICK_Y)] = state.Gamepad.sThumbRY; + if (std::abs(state.Gamepad.sThumbRY) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) + { + ++controllersInputCount[c]; + } + } + + //Timers and updating if controller is presently in use + for (size_t i = 0; i < MAX_CONTROLLER_INPUT; ++i) + { + if (controllerConsideredHeld(i, controllers[c][i])) //Considered on + { + controllerInUse = true; + if (!controllerConsideredHeld(i, controllersLast[c][i])) //Just on + { + controllersHeldTime[c][i] = 0.0; //Reset timer + } + controllersHeldTime[c][i] += dt; //Tick up + } + else //Considered off + { + if (controllerConsideredHeld(i, controllersLast[c][i])) //Just off + { + controllersReleasedTime[c][i] = 0.0; //Reset timer + } + controllersReleasedTime[c][i] += dt; //Tick up + } + } + } } bool SHInputManager::AnyKeyDown(SH_KEYCODE* firstDetected) noexcept @@ -161,4 +486,336 @@ namespace SHADE return false; } + //Any controller input being held + //For analog, this means going being deadzone values + bool SHInputManager::AnyControllerInput(SH_CONTROLLERCODE* firstDetected, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return false; + for (size_t i = 0; i < MAX_CONTROLLER_INPUT; ++i) + { + if (controllerConsideredHeld(i, controllers[cNum][i])) + { + if (firstDetected) *firstDetected = static_cast(i); + return true; + } + } + return false; + } + + bool SHInputManager::AnyControllerInputDown(SH_CONTROLLERCODE* firstDetected, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return false; + for (size_t i = 0; i < MAX_CONTROLLER_INPUT; ++i) + { + if (controllerConsideredHeld(i, controllers[cNum][i]) && !controllerConsideredHeld(i, controllersLast[cNum][i])) + { + if (firstDetected) *firstDetected = static_cast(i); + return true; + } + } + return false; + } + + bool SHInputManager::AnyControllerInputUp(SH_CONTROLLERCODE* firstDetected, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return false; + for (size_t i = 0; i < MAX_CONTROLLER_INPUT; ++i) + { + if (!controllerConsideredHeld(i, controllers[cNum][i]) && controllerConsideredHeld(i, controllersLast[cNum][i])) + { + if (firstDetected) *firstDetected = static_cast(i); + return true; + } + } + return false; + } + + bool SHInputManager::AnyControllerButton(SH_CONTROLLERCODE* firstDetected, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return false; + for (size_t i = 0; i < NUM_CONTROLLER_BUTTON; ++i) + { + if (controllerConsideredHeld(i, controllers[cNum][i])) + { + if (firstDetected) *firstDetected = static_cast(i); + return true; + } + } + return false; + } + + bool SHInputManager::AnyControllerButtonDown(SH_CONTROLLERCODE* firstDetected, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return false; + for (size_t i = 0; i < NUM_CONTROLLER_BUTTON; ++i) + { + if (controllerConsideredHeld(i, controllers[cNum][i]) && !controllerConsideredHeld(i, controllersLast[cNum][i])) + { + if (firstDetected) *firstDetected = static_cast(i); + return true; + } + } + return false; + } + + bool SHInputManager::AnyControllerButtonUp(SH_CONTROLLERCODE* firstDetected, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return false; + for (size_t i = 0; i < NUM_CONTROLLER_BUTTON; ++i) + { + if (!controllerConsideredHeld(i, controllers[cNum][i]) && controllerConsideredHeld(i, controllersLast[cNum][i])) + { + if (firstDetected) *firstDetected = static_cast(i); + return true; + } + } + return false; + } + + //Only get of largest magnitude + double SHInputManager::GetBindingAxis(std::string bindingName, size_t cNum) noexcept + { + //Over keycodes, prioritise positive + for (SH_KEYCODE k : bindings[bindingName].positiveKeyCodes) + { + if (GetKey(k)) return 1.0; + } + for (SH_KEYCODE k : bindings[bindingName].negativeKeyCodes) + { + if (GetKey(k)) return -1.0; + } + + double largestMagnitude = 0.0; + + //Over controllerCodes + for (SH_CONTROLLERCODE c : bindings[bindingName].positiveControllerCodes) + { + double newValue = 0.0; + if (GetControllerInput(c, &newValue, nullptr, nullptr, cNum)) + if (std::abs(newValue) > std::abs(largestMagnitude)) largestMagnitude = newValue; + } + for (SH_CONTROLLERCODE c : bindings[bindingName].negativeControllerCodes) + { + double newValue = 0.0; + if (GetControllerInput(c, &newValue, nullptr, nullptr, cNum)) + if (std::abs(newValue) > std::abs(largestMagnitude)) largestMagnitude = -newValue; + } + + return largestMagnitude; + } + + bool SHInputManager::GetBindingPositiveButton(std::string bindingName, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return false; + + //Over keycodes + for (SH_KEYCODE k : bindings[bindingName].positiveKeyCodes) + { + if (GetKey(k)) return true; + } + + //Over controller buttons + for (SH_CONTROLLERCODE c : bindings[bindingName].positiveControllerCodes) + { + if (GetControllerInput(c, nullptr, nullptr, nullptr, cNum)) return true; + } + + return false; + } + + bool SHInputManager::GetBindingNegativeButton(std::string bindingName, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return false; + + //Over keycodes + for (SH_KEYCODE k : bindings[bindingName].negativeKeyCodes) + { + if (GetKey(k)) return true; + } + + //Over controller buttons + for (SH_CONTROLLERCODE c : bindings[bindingName].negativeControllerCodes) + { + if (GetControllerInput(c, nullptr, nullptr, nullptr, cNum)) return true; + } + + return false; + } + + bool SHInputManager::GetBindingPositiveButtonDown(std::string bindingName, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return false; + + //Over keycodes + for (SH_KEYCODE k : bindings[bindingName].positiveKeyCodes) + { + if (GetKeyDown(k)) return true; + } + + //Over controller buttons + for (SH_CONTROLLERCODE c : bindings[bindingName].positiveControllerCodes) + { + if (GetControllerInputDown(c, nullptr, cNum)) return true; + } + + return false; + } + + bool SHInputManager::GetBindingNegativeButtonDown(std::string bindingName, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return false; + + //Over keycodes + for (SH_KEYCODE k : bindings[bindingName].negativeKeyCodes) + { + if (GetKeyDown(k)) return true; + } + + //Over controller buttons + for (SH_CONTROLLERCODE c : bindings[bindingName].negativeControllerCodes) + { + if (GetControllerInputDown(c, nullptr, cNum)) return true; + } + + return false; + } + + bool SHInputManager::GetBindingPositiveButtonUp(std::string bindingName, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return false; + + //Over keycodes + for (SH_KEYCODE k : bindings[bindingName].positiveKeyCodes) + { + if (GetKeyUp(k)) return true; + } + + //Over controller buttons + for (SH_CONTROLLERCODE c : bindings[bindingName].positiveControllerCodes) + { + if (GetControllerInputUp(c, nullptr, cNum)) return true; + } + + return false; + } + + bool SHInputManager::GetBindingNegativeButtonUp(std::string bindingName, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return false; + + //Over keycodes + for (SH_KEYCODE k : bindings[bindingName].negativeKeyCodes) + { + if (GetKeyUp(k)) return true; + } + + //Over controller buttons + for (SH_CONTROLLERCODE c : bindings[bindingName].negativeControllerCodes) + { + if (GetControllerInputUp(c, nullptr, cNum)) return true; + } + + return false; + } + + //Fetches longest hold time + double SHInputManager::GetBindingPositiveHeldTime(std::string bindingName, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return 0.0; + + double maxHeldTime = 0.0; + + //Over keycodes + for (SH_KEYCODE k : bindings[bindingName].positiveKeyCodes) + { + if (GetKeyHeldTime(k) > maxHeldTime) maxHeldTime = GetKeyHeldTime(k); + } + + //Over controller buttons + for (SH_CONTROLLERCODE c : bindings[bindingName].positiveControllerCodes) + { + if (GetControllerInputHeldTime(c, cNum) > maxHeldTime) maxHeldTime = GetControllerInputHeldTime(c); + } + + return maxHeldTime; + } + + double SHInputManager::GetBindingNegativeHeldTime(std::string bindingName, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return 0.0; + + double maxHeldTime = 0.0; + + //Over keycodes + for (SH_KEYCODE k : bindings[bindingName].negativeKeyCodes) + { + if (GetKeyHeldTime(k) > maxHeldTime) maxHeldTime = GetKeyHeldTime(k); + } + + //Over controller buttons + for (SH_CONTROLLERCODE c : bindings[bindingName].negativeControllerCodes) + { + if (GetControllerInputHeldTime(c, cNum) > maxHeldTime) maxHeldTime = GetControllerInputHeldTime(c); + } + + return maxHeldTime; + } + + //Fetches shortest release time + double SHInputManager::GetBindingPositiveReleasedTime(std::string bindingName, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return 0.0; + + double minReleaseTime = _HUGE_ENUF; + + //Over keycodes + for (SH_KEYCODE k : bindings[bindingName].positiveKeyCodes) + { + if (GetKeyReleasedTime(k) < minReleaseTime) minReleaseTime = GetKeyReleasedTime(k); + } + + //Over controller buttons + for (SH_CONTROLLERCODE c : bindings[bindingName].positiveControllerCodes) + { + if (GetControllerInputReleasedTime(c, cNum) < minReleaseTime) minReleaseTime = GetControllerInputReleasedTime(c); + } + + return minReleaseTime; + } + + double SHInputManager::GetBindingNegativeReleasedTime(std::string bindingName, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return 0.0; + + double minReleaseTime = _HUGE_ENUF; + + //Over keycodes + for (SH_KEYCODE k : bindings[bindingName].negativeKeyCodes) + { + if (GetKeyReleasedTime(k) < minReleaseTime) minReleaseTime = GetKeyReleasedTime(k); + } + + //Over controller buttons + for (SH_CONTROLLERCODE c : bindings[bindingName].negativeControllerCodes) + { + if (GetControllerInputReleasedTime(c, cNum) < minReleaseTime) minReleaseTime = GetControllerInputReleasedTime(c); + } + + return minReleaseTime; + } + + //Only for mouse movement + //Get largest delta + double SHInputManager::GetBindingMouseVelocity(std::string bindingName, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return 0.0; + + //Mouse velocity + double velX = 0.0; + double velY = 0.0; + GetMouseVelocity(&velX, &velY); + + return bindings[bindingName].mouseXPositiveMultiplier * velX + bindings[bindingName].mouseYPositiveMultiplier * velY; + } + } //namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Input/SHInputManager.h b/SHADE_Engine/src/Input/SHInputManager.h index d3e31004..04e5871d 100644 --- a/SHADE_Engine/src/Input/SHInputManager.h +++ b/SHADE_Engine/src/Input/SHInputManager.h @@ -10,9 +10,12 @@ *********************************************************************/ #pragma once -//#include -//#include "../../SHADE_Managed/src/SHpch.h" +#include +#include +#include +#include "../../SHADE_Managed/src/SHpch.h" #include "SH_API.h" +#pragma comment(lib, "xinput.lib") namespace SHADE { @@ -268,6 +271,58 @@ namespace SHADE OEM_CLEAR }; + enum class SH_CONTROLLERCODE + { + //Digital + DPAD_UP, + DPAD_DOWN, + DPAD_LEFT, + DPAD_RIGHT, + START, + BACK, + LEFT_THUMBSTICK, + RIGHT_THUMBSTICK, + LEFT_SHOULDER, + RIGHT_SHOULDER, + A, + B, + X, + Y, + + //1 Byte Unsigned Analog + LEFT_TRIGGER, + RIGHT_TRIGGER, + + //2 Byte Signed Analog + LEFT_THUMBSTICK_X, + LEFT_THUMBSTICK_Y, + RIGHT_THUMBSTICK_X, + RIGHT_THUMBSTICK_Y + }; + + private: + /*------------------------------------------------------------------------*/ + /* Struct for logical bindings */ + /*------------------------------------------------------------------------*/ + struct SH_API SHLogicalBindingData + { + //Key codes mapped to positive + std::set positiveKeyCodes; + + //Key codes mapped to negative + std::set negativeKeyCodes; + + //Controller Codes mapped to positive + std::set positiveControllerCodes; + + //Controller Codes mapped to negative + std::set negativeControllerCodes; + + //Mouse movement mapped to axes? + double mouseXPositiveMultiplier; + double mouseYPositiveMultiplier; + }; + public: //Updates current state of the input, with dt to be fetched from FRC //TODO should dt be fixed or variable? @@ -392,7 +447,7 @@ namespace SHADE keysToggleLast[static_cast(key)]); } - //Mouse///////////// + //Mouse///////////////////////////////////////////////////// //Get the mouse location with respect to the screen static inline void GetMouseScreenPosition (int* x = nullptr, @@ -428,7 +483,95 @@ namespace SHADE return mouseWheelVerticalDelta; } - //GET INPUT TIMINGS/////////////////////////////////////////////////////////// + /*------------------------------------------------------------------------*/ + /* Input state accessors (KB & M) */ + /*------------------------------------------------------------------------*/ + + //How many controller inputs of any kind are being used now + static inline unsigned GetControllerInputCount(size_t cNum = 0) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return 0; + return controllersInputCount[cNum]; + } + + //How many controller buttons are being pressed now + //Subtract from getControllerInputCount() for analog triggers / thumbsticks + static inline unsigned GetControllerButtonCount(size_t cNum = 0) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return 0; + return controllersButtonCount[cNum]; + } + + //Any controller input being held + //For analog, this means going being deadzone values + //controllerNum should be between 0 and 3 + static bool AnyControllerInput(SH_CONTROLLERCODE* firstDetected = nullptr, size_t controllerNum = 0) noexcept; + + //Any controller input activated in THIS FRAME ONLY + //For analog, this means going being deadzone values + //controllerNum should be between 0 and 3 + static bool AnyControllerInputDown(SH_CONTROLLERCODE* firstDetected = nullptr, size_t controllerNum = 0) noexcept; + + //Any controller input deactivated in THIS FRAME ONLY + //For analog, this means going below deadzone values + //controllerNum should be between 0 and 3 + static bool AnyControllerInputUp(SH_CONTROLLERCODE* firstDetected = nullptr, size_t controllerNum = 0) noexcept; + + //Any DIGITAL controller buttons being held + //controllerNum should be between 0 and 3 + static bool AnyControllerButton(SH_CONTROLLERCODE* firstDetected = nullptr, size_t controllerNum = 0) noexcept; + + //Any DIGITAL controller button activated in THIS FRAME ONLY + //controllerNum should be between 0 and 3 + static bool AnyControllerButtonDown(SH_CONTROLLERCODE* firstDetected = nullptr, size_t controllerNum = 0) noexcept; + + //Any DIGITAL controller button deactivated in THIS FRAME ONLY + //controllerNum should be between 0 and 3 + static bool AnyControllerButtonUp(SH_CONTROLLERCODE* firstDetected = nullptr, size_t controllerNum = 0) noexcept; + + //If controller input is being held in the current frame + //normalisedValue is the value of the input between 0 and 1, relevant for trigger and thumbstick data + //controllerNum should be between 0 and 3 + static inline bool GetControllerInput(SH_CONTROLLERCODE input, + double* normalisedValue = nullptr, + double* heldTime = nullptr, + double* releasedTime = nullptr, + size_t controllerNum = 0) noexcept + { + if (controllerNum >= XUSER_MAX_COUNT) return false; + if (normalisedValue) *normalisedValue = controllerNormalisedValue(static_cast(input), controllers[controllerNum][static_cast(input)]); + if (heldTime) *heldTime = controllersHeldTime[controllerNum][static_cast(input)]; + if (releasedTime) *releasedTime = controllersReleasedTime[controllerNum][static_cast(input)]; + return controllerConsideredHeld(static_cast(input), controllers[controllerNum][static_cast(input)]); + } + + //If controller input was considered to be held down in THIS FRAME ONLY + //controllerNum should be between 0 and 3 + static inline bool GetControllerInputDown(SH_CONTROLLERCODE input, + double* releasedTime = nullptr, + size_t controllerNum = 0) noexcept + { + if (controllerNum >= XUSER_MAX_COUNT) return false; + if (releasedTime) *releasedTime = controllersReleasedTime[controllerNum][static_cast(input)]; + return (controllerConsideredHeld(static_cast(input), controllers[controllerNum][static_cast(input)]) && + !controllerConsideredHeld(static_cast(input), controllersLast[controllerNum][static_cast(input)])); + } + + //If controller input was considered to be released in THIS FRAME ONLY + //controllerNum should be between 0 and 3 + static inline bool GetControllerInputUp(SH_CONTROLLERCODE input, + double* releasedTime = nullptr, + size_t controllerNum = 0) noexcept + { + if (controllerNum >= XUSER_MAX_COUNT) return false; + if (releasedTime) *releasedTime = controllersReleasedTime[controllerNum][static_cast(input)]; + return (!controllerConsideredHeld(static_cast(input), controllers[controllerNum][static_cast(input)]) && + controllerConsideredHeld(static_cast(input), controllersLast[controllerNum][static_cast(input)])); + } + + /*------------------------------------------------------------------------*/ + /* Timing accessors */ + /*------------------------------------------------------------------------*/ //Keyboard///////////// @@ -456,6 +599,191 @@ namespace SHADE return keysToggleOffTime[static_cast(key)]; } + //Controller////////////////////// + + //How long has this controller input been considered to be held down for + static inline double GetControllerInputHeldTime(SH_CONTROLLERCODE code, + size_t controllerNum = 0) noexcept + { + if (controllerNum >= XUSER_MAX_COUNT) return 0.0; + return controllersHeldTime[controllerNum][static_cast(code)]; + } + + //How long has this controller input been considered to be released for + static inline double GetControllerInputReleasedTime(SH_CONTROLLERCODE code, + size_t controllerNum = 0) noexcept + { + if (controllerNum >= XUSER_MAX_COUNT) return 0.0; + return controllersReleasedTime[controllerNum][static_cast(code)]; + } + + /*------------------------------------------------------------------------*/ + /* Binding Functions */ + /*------------------------------------------------------------------------*/ + + //Add a new binding to the map + static inline void BindingsAdd(std::string newBindingName) noexcept + { + bindings.insert({ newBindingName, SHLogicalBindingData() }); + } + + //Remove a binding from the map + //Returns 1 if found and removed, 0 if not found + static inline size_t BindingsRemove(std::string targetBindingName) noexcept + { + return bindings.erase(targetBindingName); + } + + //Clears all bindings from the list + static inline void BindingsClear() noexcept + { + bindings.clear(); + } + + //Get the number of bindings present + static inline size_t BindingsCount() noexcept + { + return bindings.size(); + } + + //Check positive keycodes to binding + static inline std::set const& BindingsGetPositiveKeyCodes(std::string bindingName) noexcept + { + return bindings[bindingName].positiveKeyCodes; + } + + //Add positive SH_KEYCODE to binding + static inline void BindingsAddPositiveKeyCode(std::string targetBindingName, + SH_KEYCODE toAdd) noexcept + { + bindings[targetBindingName].positiveKeyCodes.insert(toAdd); + } + + //Remove positive SH_KEYCODE from binding + //If toRemove found and removed, returns 1. Otherwise, 0. + static inline size_t BindingsRemovePositiveKeyCode(std::string targetBindingName, + SH_KEYCODE toRemove) noexcept + { + return bindings[targetBindingName].positiveKeyCodes.erase(toRemove); + } + + //Check negative keycodes to binding + static inline std::set const& BindingsGetNegativeKeyCodes(std::string bindingName) noexcept + { + return bindings[bindingName].negativeKeyCodes; + } + + //Add negative SH_KEYCODE to binding + static inline void BindingsAddNegativeKeyCode(std::string targetBindingName, + SH_KEYCODE toAdd) noexcept + { + bindings[targetBindingName].negativeKeyCodes.insert(toAdd); + } + + //Remove negative SH_KEYCODE from binding + //If toRemove found and removed, returns 1. Otherwise, 0. + static inline size_t BindingsRemoveNegativeKeyCode(std::string targetBindingName, + SH_KEYCODE toRemove) noexcept + { + return bindings[targetBindingName].negativeKeyCodes.erase(toRemove); + } + + //Check positive controllercodes to binding + static inline std::set const& BindingsGetPositiveControllerCodes(std::string bindingName) noexcept + { + return bindings[bindingName].positiveControllerCodes; + } + + //Add positive SH_CONTROLLERCODE to binding + static inline void BindingsAddPositiveControllerCode(std::string targetBindingName, + SH_CONTROLLERCODE toAdd) noexcept + { + bindings[targetBindingName].positiveControllerCodes.insert(toAdd); + } + + //Remove positive SH_CONTROLLERCODE from binding + //If toRemove found and removed, returns 1. Otherwise, 0. + static inline size_t BindingsRemovePositiveControllerCode(std::string targetBindingName, + SH_CONTROLLERCODE toRemove) noexcept + { + return bindings[targetBindingName].positiveControllerCodes.erase(toRemove); + } + + //Check negative controllercodes to binding + static inline std::set const& BindingsGetNegativeControllerCodes(std::string bindingName) noexcept + { + return bindings[bindingName].negativeControllerCodes; + } + + //Add negative SH_CONTROLLERCODE to binding + static inline void BindingsAddNegativeControllerCode(std::string targetBindingName, + SH_CONTROLLERCODE toAdd) noexcept + { + bindings[targetBindingName].negativeControllerCodes.insert(toAdd); + } + + //Remove negative SH_CONTROLLERCODE from binding + //If toRemove found and removed, returns 1. Otherwise, 0. + static inline size_t BindingsRemoveNegativeControllerCode(std::string targetBindingName, + SH_CONTROLLERCODE toRemove) noexcept + { + return bindings[targetBindingName].negativeControllerCodes.erase(toRemove); + } + + //Mouse movement bindings + + static inline double const BindingsGetMouseXPositiveMultiplier(std::string bindingName) noexcept + { + return bindings[bindingName].mouseXPositiveMultiplier; + } + + static inline void BindingsSetMouseXPositiveMultiplier(std::string bindingName, double newValue) noexcept + { + bindings[bindingName].mouseXPositiveMultiplier = newValue; + } + + static inline double const BindingsGetMouseYPositiveMultiplier(std::string bindingName) noexcept + { + return bindings[bindingName].mouseXPositiveMultiplier; + } + + static inline void BindingsSetMouseYPositiveMultiplier(std::string bindingName, double newValue) noexcept + { + bindings[bindingName].mouseXPositiveMultiplier = newValue; + } + + //Get the axis value of binding, between -1 and 1 + static double GetBindingAxis(std::string bindingName, size_t controllerNumber = 0) noexcept; + + //Whether binding is being held or not + //Does not work for mouse movement + static bool GetBindingPositiveButton(std::string bindingName, size_t controllerNumber = 0) noexcept; + static bool GetBindingNegativeButton(std::string bindingName, size_t controllerNumber = 0) noexcept; + + //Whether binding is pressed down IN THIS FRAME ONLY + //Does not work for mouse movement + static bool GetBindingPositiveButtonDown(std::string bindingName, size_t controllerNumber = 0) noexcept; + static bool GetBindingNegativeButtonDown(std::string bindingName, size_t controllerNumber = 0) noexcept; + + //Whether binding is released IN THIS FRAME ONLY + //Does not work for mouse movement + static bool GetBindingPositiveButtonUp(std::string bindingName, size_t controllerNumber = 0) noexcept; + static bool GetBindingNegativeButtonUp(std::string bindingName, size_t controllerNumber = 0) noexcept; + + //Binding times + + //Does not work for mouse movement + static double GetBindingPositiveHeldTime(std::string bindingName, size_t controllerNumber = 0) noexcept; + static double GetBindingNegativeHeldTime(std::string bindingName, size_t controllerNumber = 0) noexcept; + + //Does not work for mouse movement + static double GetBindingPositiveReleasedTime(std::string bindingName, size_t controllerNumber = 0) noexcept; + static double GetBindingNegativeReleasedTime(std::string bindingName, size_t controllerNumber = 0) noexcept; + + //Binding mouse velocity + //Only for mouse movement + static double GetBindingMouseVelocity(std::string bindingName, size_t controllerNumber = 0) noexcept; + /*------------------------------------------------------------------------*/ /* Other Functions */ /*------------------------------------------------------------------------*/ @@ -482,10 +810,36 @@ namespace SHADE /*------------------------------------------------------------------------*/ static constexpr size_t MAX_KEYS = UCHAR_MAX + 1; + //How many recognised controller inputs there are + //To see the list, see the enum class in this file + static constexpr size_t MAX_CONTROLLER_INPUT = 20; + + //On/off button count + static constexpr size_t NUM_CONTROLLER_BUTTON = 14; + + //8-bit trigger values + static constexpr size_t NUM_CONTROLLER_TRIGGER = 2; + + //16-bit thumbstick values + static constexpr size_t NUM_CONTROLLER_THUMBSTICK = 4; + /*------------------------------------------------------------------------*/ /* Data Members */ /*------------------------------------------------------------------------*/ + //If the last input is from controller(s) or KB/M + //True if from controller(s), False if from KB/M + //Useful for switching control hints between controllers and KB/M + static bool controllerInUse; + + //BINDINGS////////////////////////////////////////////////////////////////// + + //Key is for binding names, they must be unique + //Multiple physical inputs per virtual/logical input are to be added to + //sets inside the logicalBinding values + //TODO make this an array of 4 / 5 users for multiplayer support + static std::map bindings; + //KEYBOARD AND MOUSE BUTTONS//////////////////////////////////////////////// //How many keys are presently being pressed @@ -558,15 +912,48 @@ namespace SHADE //CONTROLLER VARIABLES////////////////////////////////////////////////////// - //OTHER VARIABLES/////////////////////////////////////////////////////////// + //Count how many controllers are presently connected + //Useful for if the game is to decide to take in controller or KB/M input + //Between 0 and 4 (inclusive) + static unsigned char controllersConnectedCount; - //Axis bindings - //X - - //Y + //How many inputs (of any kind) on the controller are being used now + //Includes analog triggers and thumbsticks + static unsigned controllersInputCount[XUSER_MAX_COUNT]; - //Other mappings + //How many DIGITAL buttons on the controller are being pressed now + static unsigned controllersButtonCount[XUSER_MAX_COUNT]; - //Buffer + //Current state of controllers + //First index is for controller number + //Second index is for input type + static short controllers[XUSER_MAX_COUNT][MAX_CONTROLLER_INPUT]; + + //State of controllers in the last frame + //First index is for controller number + //Second index is for input type + static short controllersLast[XUSER_MAX_COUNT][MAX_CONTROLLER_INPUT]; + + //Held and released times + + //Controller held durations + //Stops ticking up when released + //Will be reset when held again + static double controllersHeldTime[XUSER_MAX_COUNT][MAX_CONTROLLER_INPUT]; + + //Key released durations + //Stops ticking up when held + //Will be reset when off again + static double controllersReleasedTime[XUSER_MAX_COUNT][MAX_CONTROLLER_INPUT]; + + /*------------------------------------------------------------------------*/ + /* Internal Helper Functions */ + /*------------------------------------------------------------------------*/ + + //Internal helper function for checking if input is considered held or not + static bool controllerConsideredHeld(size_t inputIdx, short value) noexcept; + + //Internal helper function for getting normalised controller value + static double controllerNormalisedValue(size_t inputIdx, short value) noexcept; }; } \ No newline at end of file diff --git a/TempShaderFolder/KirschCs.glsl b/TempShaderFolder/KirschCs.glsl new file mode 100644 index 00000000..3dec174d --- /dev/null +++ b/TempShaderFolder/KirschCs.glsl @@ -0,0 +1,167 @@ +//#version 450 +// +//layout(local_size_x = 16, local_size_y = 16) in; +//layout(set = 4, binding = 0, rgba8) uniform image2D targetImage; +// +// +//void main() +//{ +// ivec2 imageSize = imageSize (targetImage); +// +// if (gl_GlobalInvocationID.x >= imageSize.x && gl_GlobalInvocationID.y >= imageSize.y) +// return; +// +// // load the image +// vec4 color = imageLoad (targetImage, ivec2 (gl_GlobalInvocationID)); +// +// // get the average +// float average = 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b; +// +// // store result into result image +// imageStore(targetImage, ivec2(gl_GlobalInvocationID), vec4(average, average, average, 1.0f)); +// +//} +// +// +// +// + +/* Start Header *****************************************************************/ + +/*! \file (e.g. kirsch.comp) + + \author William Zheng, william.zheng, 60001906. Brandon Mak, brandon.hao 390003920. + + \par william.zheng\@digipen.edu. brandon.hao\@digipen.edu. + + \date Sept 20, 2022 + + \brief Copyright (C) 20xx 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. */ + + /* End Header *******************************************************************/ + +#version 450 + +#define MASK_WIDTH 3 +#define HALF_M_WIDTH MASK_WIDTH / 2 +#define SHM_WIDTH 18 +#define NUM_MASKS 8 + +layout(local_size_x = 16, local_size_y = 16) in; +layout(set = 4, binding = 0, rgba8) uniform image2D inputImage; +layout(set = 4, binding = 1, rgba8) uniform image2D resultImage; + +const float kirsch[8][3][3] = { + { + {5, 5, 5}, + {-3, 0, -3}, /*rotation 1 */ + {-3, -3, -3} + }, + { + {5, 5, -3}, + {5, 0, -3}, /*rotation 2 */ + {-3, -3, -3} + }, + { + {5, -3, -3}, + {5, 0, -3}, /*rotation 3 */ + {5, -3, -3} + }, + { + {-3, -3, -3}, + {5, 0, -3}, /*rotation 4 */ + {5, 5, -3} + }, + { + {-3, -3, -3}, + {-3, 0, -3}, /*rotation 5 */ + {5, 5, 5} + }, + { + {-3, -3, -3}, + {-3, 0, 5}, /*rotation 6 */ + {-3, 5, 5} + }, + { + {-3, -3, 5}, + {-3, 0, 5}, /*rotation 7 */ + {-3, -3, 5} + }, + { + {-3, 5, 5}, + {-3, 0, 5}, /*rotation 8 */ + {-3, -3, -3} + } +}; + +vec3 GetImageValues(ivec2 uv, ivec2 inputImageSize) +{ + if (uv.x >= 0 && uv.y >= 0 && uv.x < inputImageSize.x && uv.y < inputImageSize.y) + { + return imageLoad(inputImage, uv).rgb; + } + else + return vec3(0.0f); +} + +//two extra row/col +shared vec3 sData[16 + 2][16 + 2]; + +void main() +{ + // convenient variables + ivec3 globalThread = ivec3(gl_GlobalInvocationID); + ivec3 localThread = ivec3(gl_LocalInvocationID); + ivec2 inputImageSize = imageSize(inputImage); + + // load shared memory + ivec2 start = ivec2(gl_WorkGroupID) * ivec2(gl_WorkGroupSize) - ivec2(HALF_M_WIDTH); + for (int i = localThread.x; i < SHM_WIDTH; i += int(gl_WorkGroupSize.x)) + { + for (int j = localThread.y; j < SHM_WIDTH; j += int(gl_WorkGroupSize.y)) + { + // get from source image (either real values or 0) + vec3 sourceValue = GetImageValues(start + ivec2(i, j), inputImageSize); + sData[i][j] = sourceValue; + } + } + + // wait for shared memory to finish loading + barrier(); + + // max (between all 8 masks) + vec3 maxSum = vec3(0.0f); + + // loop through all masks + for (int i = 0; i < NUM_MASKS; ++i) + { + vec3 sum = vec3(0.0f); + + // start of shared memory + ivec2 shmStart = ivec2(localThread + HALF_M_WIDTH); + for (int j = -1; j < HALF_M_WIDTH + 1; ++j) + { + for (int k = -1; k < HALF_M_WIDTH + 1; ++k) + { + // Perform convolution using shared_memory + sum += sData[shmStart.x + j][shmStart.y + k] * kirsch[i][j + 1][k + 1]; + } + } + + // Get highest sum + maxSum = max(sum, maxSum); + } + + // average the max sum + maxSum = min(max(maxSum / 8, 0), 1.0f); + + // store result into result image + imageStore(resultImage, ivec2(gl_GlobalInvocationID.xy), vec4(maxSum, 1.0f)); + +} + + + + diff --git a/TempShaderFolder/KirschCs.spv b/TempShaderFolder/KirschCs.spv new file mode 100644 index 00000000..1ae5408b Binary files /dev/null and b/TempShaderFolder/KirschCs.spv differ