diff --git a/Assets/TD_Checker_Base_Color.dds b/Assets/TD_Checker_Base_Color.dds new file mode 100644 index 00000000..9dcbfeee Binary files /dev/null and b/Assets/TD_Checker_Base_Color.dds differ diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index 28b38940..64095e03 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -84,6 +84,7 @@ namespace Sandbox SHADE::SHAssetManager::LoadDataTemp("../../Assets/racoon.gltf"); SHADE::SHAssetManager::LoadDataTemp("../../Assets/RaccoonBag_Color_Ver4.dds"); SHADE::SHAssetManager::LoadDataTemp("../../Assets/RaccoonPreTexturedVer1_Base9.dds"); + SHADE::SHAssetManager::LoadDataTemp("../../Assets/TD_Checker_Base_Color.dds"); //TODO: REMOVE AFTER PRESENTATION //SHADE::SHSystemManager::RegisterRoutine(); diff --git a/SHADE_Application/src/Scenes/SBTestScene.cpp b/SHADE_Application/src/Scenes/SBTestScene.cpp index 0f42b419..74ac4c1d 100644 --- a/SHADE_Application/src/Scenes/SBTestScene.cpp +++ b/SHADE_Application/src/Scenes/SBTestScene.cpp @@ -9,6 +9,7 @@ #include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h" #include "Scripting/SHScriptEngine.h" #include "Math/Transform/SHTransformComponent.h" +#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" #include "Assets/SHAssetManager.h" @@ -57,70 +58,103 @@ namespace Sandbox } graphicsSystem->BuildMeshBuffers(); - //Test Textures - auto textures{ SHADE::SHAssetManager::GetAllTextures() }; + // Load Textures + auto textures = SHADE::SHAssetManager::GetAllTextures(); + std::vector> texHandles; + for (const auto& tex : textures) + { + auto texture = graphicsSystem->Add(tex); + texHandles.push_back(texture); + } + graphicsSystem->BuildTextures(); // Create Materials auto matInst = graphicsSystem->AddOrGetBaseMaterialInstance(); + auto customMat = graphicsSystem->AddMaterialInstanceCopy(matInst); + customMat->SetProperty("data.color", SHVec4(0.0f, 1.0f, 1.0f, 1.0f)); + customMat->SetProperty("data.textureIndex", 1); + customMat->SetProperty("data.alpha", 0.1f); // Create Stress Test Objects - static const SHVec3 TEST_OBJ_SCALE = { 0.2f, 0.2f, 0.2f }; - constexpr int NUM_ROWS = 1; - constexpr int NUM_COLS = 1; - static const SHVec3 TEST_OBJ_SPACING = { 1.0f, 1.0f, 1.0f }; - static const SHVec3 TEST_OBJ_START_POS = { - (NUM_COLS / 2 * TEST_OBJ_SPACING.x ), 0.0f, 0.0f }; - //for (int z = 0; z < NUM_ROWS; ++z) - //for (int x = 0; x < NUM_COLS; ++x) - //{ - // auto entity = SHEntityManager::CreateEntity(); - // auto& renderable = *SHComponentManager::GetComponent_s(entity); - // auto& transform = *SHComponentManager::GetComponent_s(entity); - - // renderable.Mesh = handles.front(); - // renderable.SetMaterial(matInst); - - // // Set initial positions - // transform.SetWorldPosition(TEST_OBJ_START_POS + SHVec3{ x * TEST_OBJ_SPACING.x, 0.0f, z * TEST_OBJ_SPACING.z }); - // //transform.SetLocalScale(TEST_OBJ_SCALE); - - // stressTestObjects.emplace_back(entity); - //} + static const SHVec3 TEST_OBJ_SCALE = { 0.05f, 0.05f, 0.05f }; + constexpr int NUM_ROWS = 100; + constexpr int NUM_COLS = 100; + static const SHVec3 TEST_OBJ_SPACING = { 0.05f, 0.05f, 0.05f }; + static const SHVec3 TEST_OBJ_START_POS = { - (NUM_COLS / 2 * TEST_OBJ_SPACING.x ) + 1.0f, -2.0f, -1.0f }; + for (int y = 0; y < NUM_ROWS; ++y) + for (int x = 0; x < NUM_COLS; ++x) + { auto entity = SHEntityManager::CreateEntity(); auto& renderable = *SHComponentManager::GetComponent_s(entity); auto& transform = *SHComponentManager::GetComponent_s(entity); renderable.Mesh = handles.front(); - renderable.SetMaterial(matInst); + renderable.SetMaterial(customMat); - //transform.SetLocalScale(TEST_OBJ_SCALE); + if (y == 50) + renderable.GetModifiableMaterial()->SetProperty("data.color", SHVec4(1.0f, 0.0f, 0.0f, 1.0f)); + + //Set initial positions + transform.SetWorldPosition(TEST_OBJ_START_POS + SHVec3{ + x * TEST_OBJ_SPACING.x, + y * TEST_OBJ_SPACING.y, + 0.0f + }); + //transform.SetWorldPosition({-1.0f, -1.0f, -1.0f}); + //transform.SetWorldRotation(3.14159265f * 1.5f, -3.14159265f / 2.0f, 0.0f); + transform.SetLocalScale(TEST_OBJ_SCALE); stressTestObjects.emplace_back(entity); + } + + auto entity = SHEntityManager::CreateEntity(); + auto& renderable = *SHComponentManager::GetComponent_s(entity); + auto& transform = *SHComponentManager::GetComponent_s(entity); + + renderable.Mesh = handles.front(); + renderable.SetMaterial(customMat); + renderable.GetModifiableMaterial()->SetProperty("data.color", SHVec4(0.0f, 0.0f, 0.0f, 0.0f)); + renderable.GetModifiableMaterial()->SetProperty("data.alpha", 1.0f); + renderable.GetModifiableMaterial()->SetProperty("data.textureIndex", 1); + + transform.SetWorldPosition ({-3.0f, -1.0f, -1.0f}); + transform.SetLocalScale({5.0f, 5.0f, 5.0f}); + + //auto entity = SHEntityManager::CreateEntity(); + //auto& renderable = *SHComponentManager::GetComponent_s(entity); + //auto& transform = *SHComponentManager::GetComponent_s(entity); + + //renderable.Mesh = handles.back(); + //renderable.SetMaterial(customMat); + + //transform.SetLocalScale(TEST_OBJ_SCALE); + //transform.SetWorldPosition({-1.0f, -1.0f, -1.0f}); // Create blank entity with a script - testObj = SHADE::SHEntityManager::CreateEntity(); + //testObj = SHADE::SHEntityManager::CreateEntity(); + //auto& testObjRenderable = *SHComponentManager::GetComponent_s(testObj); + //testObjRenderable.Mesh = CUBE_MESH; + //testObjRenderable.SetMaterial(matInst); + SHADE::SHScriptEngine* scriptEngine = static_cast(SHADE::SHSystemManager::GetSystem()); scriptEngine->AddScript(testObj, "TestScript"); } void SBTestScene::Update(float dt) { - /*static float rotation = 0.0f; + static float rotation = 0.0f; - auto& transform = *SHADE::SHComponentManager::GetComponent_s(testObj); + //auto& transform = *SHADE::SHComponentManager::GetComponent_s(testObj); - transform.SetLocalRotation(rotation, 0.0f, 0.0f); - rotation += dt * 10.0f;*/ - /*static float rotation = 0.0f; - - auto& transform = *SHADE::SHComponentManager::GetComponent_s(stressTestObjects[0]); - - transform.SetWorldPosition({rotation, 0.0f, 0.0f}); - rotation += dt * 10.0f;*/ + //transform.SetWorldPosition({1.0f, 1.0f, -1.0f}); + //transform.SetWorldRotation(0.0f, 0.0f + rotation, 0.0f); + //rotation += dt * 0.2f; // Destroy entity if space is pressed if (GetKeyState(VK_SPACE) & 0x8000) { + rotation = 0.0f; SHADE::SHScriptEngine* scriptEngine = static_cast(SHADE::SHSystemManager::GetSystem()); scriptEngine->RemoveAllScripts(testObj); } @@ -128,6 +162,7 @@ namespace Sandbox void SBTestScene::Render() { + } void SBTestScene::Unload() diff --git a/SHADE_Engine/premake5.lua b/SHADE_Engine/premake5.lua index 434c9e10..f11ccf79 100644 --- a/SHADE_Engine/premake5.lua +++ b/SHADE_Engine/premake5.lua @@ -133,6 +133,9 @@ project "SHADE_Engine" "xcopy /r /y /q \"%{IncludeDir.fmod}\\lib\\fmodstudio.dll\" \"$(OutDir)\"" } + filter "configurations:Publish" + postbuildcommands {"xcopy /r /y /q \"%{IncludeDir.assimp}\\bin\\Release\\assimp-vc142-mt.dll\" \"$(OutDir)\""} + warnings 'Extra' filter "configurations:Debug" diff --git a/SHADE_Engine/src/Assets/Asset Types/SHMeshAsset.h b/SHADE_Engine/src/Assets/Asset Types/SHMeshAsset.h index b4632c2e..18674a04 100644 --- a/SHADE_Engine/src/Assets/Asset Types/SHMeshAsset.h +++ b/SHADE_Engine/src/Assets/Asset Types/SHMeshAsset.h @@ -2,16 +2,17 @@ #include #include "Math/SHMath.h" +#include "SH_API.h" namespace SHADE { - struct SHMeshAssetHeader + struct SH_API SHMeshAssetHeader { uint32_t vertexCount; uint32_t indexCount; }; - struct SHMeshAsset + struct SH_API SHMeshAsset { bool compiled; bool changed; diff --git a/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp b/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp index 33270bb6..4f510c0a 100644 --- a/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp +++ b/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp @@ -74,12 +74,12 @@ namespace SHADE for (auto i{0}; i < file.GetMipCount(); ++i) { - mipOff.push_back(totalBytes); + mipOff[i] = totalBytes; totalBytes += file.GetImageData(i, 0)->m_memSlicePitch; } SHTexture::PixelChannel* pixel = new SHTexture::PixelChannel[totalBytes]; - std::memcpy(pixel, file.GetDDSData(), totalBytes); + std::memcpy(pixel, file.GetImageData()->m_mem, totalBytes); //pixel = std::move(reinterpret_cast(file.GetDDSData())); asset.numBytes = totalBytes; diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.h b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.h index 91112496..9a533d06 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.h +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.h @@ -39,8 +39,10 @@ namespace SHADE std::vector Limits = { { vk::DescriptorType::eCombinedImageSampler, 100 }, - { vk::DescriptorType::eUniformBuffer, 100 }, - { vk::DescriptorType::eUniformBufferDynamic, 100 } + { vk::DescriptorType::eUniformBuffer, 100 }, + { vk::DescriptorType::eUniformBufferDynamic, 100 }, + { vk::DescriptorType::eStorageImage, 100}, + { vk::DescriptorType::eStorageBufferDynamic, 100 } }; /// /// Maximum number of descriptor sets allowed diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp index c1732535..e50e717f 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp @@ -155,7 +155,7 @@ namespace SHADE */ /***************************************************************************/ - void SHVkDescriptorSetGroup::ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span, Handle>> const& imageViewsAndSamplers) noexcept + void SHVkDescriptorSetGroup::ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span, Handle, vk::ImageLayout>> const& imageViewsAndSamplers) noexcept { // Find the target writeDescSet BindingAndSetHash writeHash = binding; @@ -170,9 +170,10 @@ namespace SHADE for (uint32_t i = 0; i < imageViewsAndSamplers.size(); ++i) { // write sampler and image view - auto& ivs = imageViewsAndSamplers[i]; - writeInfo.descImageInfos[i].imageView = ivs.first->GetImageView(); - writeInfo.descImageInfos[i].sampler = ivs.second->GetVkSampler(); + auto& [view, sampler, layout] = imageViewsAndSamplers[i]; + writeInfo.descImageInfos[i].imageView = view->GetImageView(); + writeInfo.descImageInfos[i].sampler = sampler->GetVkSampler(); + writeInfo.descImageInfos[i].imageLayout = layout; } } diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h index d92d55e9..f2b886e8 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h @@ -1,5 +1,7 @@ #pragma once +#include + // Project Includes #include "Graphics/SHVulkanIncludes.h" #include "Resource/Handle.h" @@ -63,7 +65,7 @@ namespace SHADE void UpdateDescriptorSetImages(uint32_t set, uint32_t binding) noexcept; void UpdateDescriptorSetBuffer(uint32_t set, uint32_t binding) noexcept; - void ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span, Handle>> const& imageViewsAndSamplers) noexcept; + void ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span, Handle, vk::ImageLayout>> const& imageViewsAndSamplers) noexcept; void ModifyWriteDescBuffer (uint32_t set, uint32_t binding, std::span> const& buffers, uint32_t offset, uint32_t range) noexcept; diff --git a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp index 5ed17511..3fa797bf 100644 --- a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp +++ b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp @@ -16,6 +16,7 @@ #include "Graphics/Framebuffer/SHVkFramebuffer.h" #include "Graphics/Images/SHVkImageView.h" #include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" +#include "Graphics/Images/SHVkSampler.h" namespace SHADE { @@ -85,6 +86,17 @@ namespace SHADE } + uint32_t SHVkLogicalDevice::ComputeAlignedBufferSize(uint32_t originalSize, size_t alignmentSize) const noexcept + { + uint32_t alignedSize = originalSize; + //uint32_t minBuffer + if (alignmentSize > 0) + { + alignedSize = (alignedSize + alignmentSize - 1) & ~(alignmentSize - 1); + } + return alignedSize; + } + /***************************************************************************/ /*! @@ -176,6 +188,7 @@ namespace SHADE // point and lines fill mode features.fillModeNonSolid = true; features.samplerAnisotropy = VK_TRUE; + features.multiDrawIndirect = true; // for wide lines features.wideLines = true; @@ -288,13 +301,12 @@ namespace SHADE uint32_t SHVkLogicalDevice::PadUBOSize(uint32_t originalSize) const noexcept { - uint32_t alignedSize = originalSize; - //uint32_t minBuffer - if (uboBufferMemoryAlignment > 0) - { - alignedSize = (alignedSize + uboBufferMemoryAlignment - 1) & ~(uboBufferMemoryAlignment - 1); - } - return alignedSize; + return ComputeAlignedBufferSize(originalSize, uboBufferMemoryAlignment); + } + + uint32_t SHVkLogicalDevice::PadSSBOSize(uint32_t originalSize) const noexcept + { + return ComputeAlignedBufferSize(originalSize, ssboBufferMemoryAlignment); } /***************************************************************************/ @@ -499,6 +511,11 @@ namespace SHADE } + Handle SHVkLogicalDevice::CreateSampler(const SHVkSamplerParams& params) noexcept + { + return SHVkInstance::GetResourceManager().Create (GetHandle(), params); + } + Handle SHVkLogicalDevice::CreateRenderpass(std::span const vkDescriptions, std::vector const& subpasses) noexcept { return SHVkInstance::GetResourceManager().Create (GetHandle(), vkDescriptions, subpasses); diff --git a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h index 8a197ef8..1272f68f 100644 --- a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h +++ b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h @@ -21,7 +21,6 @@ #include "Graphics/Descriptors/SHVkDescriptorSetLayout.h" #include "Graphics/Images/SHVkImage.h" - namespace SHADE { /*-----------------------------------------------------------------------*/ @@ -41,6 +40,8 @@ namespace SHADE class SHShaderBlockInterface; class SHVkDescriptorSetGroup; class SHSubpass; + class SHVkSampler; + struct SHVkSamplerParams; /***************************************************************************/ /*! @@ -102,6 +103,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ void InitializeVMA (void) noexcept; void InitializeQueues (std::initializer_list queueCreateParams) noexcept; + uint32_t ComputeAlignedBufferSize(uint32_t originalSize, size_t typeSize) const noexcept; public: /*-----------------------------------------------------------------------*/ @@ -121,7 +123,8 @@ namespace SHADE // Miscellaneous functions void WaitIdle (void) noexcept; uint32_t FindMemoryType (uint32_t typeFilter, vk::MemoryPropertyFlags properties); - uint32_t PadUBOSize (uint32_t originalSize) const noexcept; + uint32_t PadUBOSize(uint32_t originalSize) const noexcept; + uint32_t PadSSBOSize(uint32_t originalSize) const noexcept; // creation functions Handle CreateSurface (HWND const& windowHandle) const noexcept; @@ -178,6 +181,7 @@ namespace SHADE Handle const& renderpassHdl, Handle subpass ) noexcept; + Handle CreateSampler (const SHVkSamplerParams& params) noexcept; Handle CreateRenderpass (std::span const vkDescriptions, std::vector const& subpasses) noexcept; Handle CreateRenderpass (std::span const vkDescriptions, std::span const spDescs, std::span const spDeps) noexcept; diff --git a/SHADE_Engine/src/Graphics/Images/SHVkImage.cpp b/SHADE_Engine/src/Graphics/Images/SHVkImage.cpp index b8bf273e..b6f20af4 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkImage.cpp +++ b/SHADE_Engine/src/Graphics/Images/SHVkImage.cpp @@ -26,7 +26,7 @@ namespace SHADE */ /***************************************************************************/ - void SHVkImage::PrepStagingBuffer(void* data, uint32_t srcSize) noexcept + void SHVkImage::PrepStagingBuffer(const void* data, uint32_t srcSize) noexcept { // For creation of buffer vk::BufferCreateInfo bufferInfo{}; @@ -70,7 +70,7 @@ namespace SHADE vmaMapMemory(*vmaAllocator, stagingAlloc, &stagingBufferMappedPtr); if (stagingBufferMappedPtr) - std::memcpy(static_cast(stagingBufferMappedPtr), static_cast(data), srcSize); + std::memcpy(static_cast(stagingBufferMappedPtr), static_cast(data), srcSize); const VkDeviceSize offsets = 0; const VkDeviceSize sizes = srcSize; @@ -82,7 +82,7 @@ namespace SHADE SHVkImage::SHVkImage( VmaAllocator const* allocator, SHImageCreateParams const& imageDetails, - unsigned char* data, + const unsigned char* data, uint32_t dataSize, std::span inMipOffsets, VmaMemoryUsage memUsage, diff --git a/SHADE_Engine/src/Graphics/Images/SHVkImage.h b/SHADE_Engine/src/Graphics/Images/SHVkImage.h index 91d4f2d2..39e695a5 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkImage.h +++ b/SHADE_Engine/src/Graphics/Images/SHVkImage.h @@ -107,7 +107,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ - void PrepStagingBuffer(void* data, uint32_t srcSize) noexcept; + void PrepStagingBuffer(const void* data, uint32_t srcSize) noexcept; public: @@ -119,7 +119,7 @@ namespace SHADE SHVkImage( VmaAllocator const* allocator, SHImageCreateParams const& imageDetails, - unsigned char* data, + const unsigned char* data, uint32_t dataSize, std::span inMipOffsets, VmaMemoryUsage memUsage, diff --git a/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp b/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp index b4bbf89b..f12b834d 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp +++ b/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp @@ -1,12 +1,62 @@ +/************************************************************************************//*! +\file SHVkSampler.cpp +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Sep 26, 2022 +\brief Contains definitions for all of the functions of the SHVkSampler class. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ #include "SHpch.h" #include "SHVkSampler.h" +#include "Graphics/Devices/SHVkLogicalDevice.h" + namespace SHADE { - - vk::Sampler SHVkSampler::GetVkSampler(void) const noexcept + /*-----------------------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------------------*/ + SHVkSampler::SHVkSampler(Handle logicalDevice, const SHVkSamplerParams& params) noexcept + : device { logicalDevice } { - return vkSampler; + const vk::SamplerCreateInfo SAMPLER_CREATE_INFO + { + .magFilter = params.magFilter, + .minFilter = params.minFilter, + .mipmapMode = params.mipmapMode, + .addressModeU = params.addressMode, + .addressModeV = params.addressMode, + .addressModeW = params.addressMode, + .minLod = params.minLod, + .maxLod = params.maxLod + }; + + // Create the sampler + vkSampler = device->GetVkLogicalDevice().createSampler(SAMPLER_CREATE_INFO); } + SHVkSampler::SHVkSampler(SHVkSampler&& rhs) noexcept + : vkSampler { rhs.vkSampler } + { + rhs.vkSampler = nullptr; + } + + SHVkSampler::~SHVkSampler() noexcept + { + if (vkSampler) + device->GetVkLogicalDevice().destroySampler(); + } + + /*-----------------------------------------------------------------------------------*/ + /* Overloaded Operators */ + /*-----------------------------------------------------------------------------------*/ + SHADE::SHVkSampler& SHVkSampler::operator=(SHVkSampler&& rhs) noexcept + { + vkSampler = rhs.vkSampler; + rhs.vkSampler = nullptr; + return *this; + } } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/Images/SHVkSampler.h b/SHADE_Engine/src/Graphics/Images/SHVkSampler.h index eae23adf..bb878a69 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkSampler.h +++ b/SHADE_Engine/src/Graphics/Images/SHVkSampler.h @@ -1,28 +1,80 @@ +/************************************************************************************//*! +\file SHVkSampler.h +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Sep 26, 2022 +\brief Contains definitions of the SHVkSampler class. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ #pragma once +// STL Includes +#include +// Project Includes #include "Graphics/SHVulkanIncludes.h" +#include "Resource/Handle.h" namespace SHADE { + /*-----------------------------------------------------------------------------------*/ + /* Forward Declarations */ + /*-----------------------------------------------------------------------------------*/ + class SHVkLogicalDevice; + + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + /*************************************************************************************/ + /*! + \brief + Holds parameters for constructing the SHVkSampler. + */ + /*************************************************************************************/ struct SHVkSamplerParams { - vk::Filter minFilter; - vk::Filter maxFilter; - //vk::Filter maxFilter; + vk::Filter minFilter = vk::Filter::eLinear; + vk::Filter magFilter = vk::Filter::eLinear; + vk::SamplerAddressMode addressMode = vk::SamplerAddressMode::eClampToEdge; + vk::SamplerMipmapMode mipmapMode = vk::SamplerMipmapMode::eLinear; + float minLod = 0; + float maxLod = 0; }; - + + /*************************************************************************************/ + /*! + \brief + Wrapper for a VkSampler. + */ + /*************************************************************************************/ class SHVkSampler { - private: - //! The vulkan sampler handler - vk::Sampler vkSampler; - - public: - SHVkSampler () noexcept; - SHVkSampler (SHVkSampler&& rhs) noexcept; - SHVkSampler&& operator=(SHVkSampler&& rhs) noexcept; + public: + /*---------------------------------------------------------------------------------*/ + /* Constructors */ + /*---------------------------------------------------------------------------------*/ + SHVkSampler(Handle logicalDevice, const SHVkSamplerParams& params = {}) noexcept; + SHVkSampler(SHVkSampler&& rhs) noexcept; + ~SHVkSampler() noexcept; - vk::Sampler GetVkSampler (void) const noexcept; + /*---------------------------------------------------------------------------------*/ + /* Overloaded Operators */ + /*---------------------------------------------------------------------------------*/ + SHVkSampler& operator=(SHVkSampler&& rhs) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + vk::Sampler GetVkSampler(void) const noexcept { return vkSampler; } + + private: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + vk::Sampler vkSampler; //! The Vulkan sampler handler + Handle device; //! Stored device for deallocating the object }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp index f73c5306..b1cd2cd3 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp @@ -22,8 +22,11 @@ of DigiPen Institute of Technology is prohibited. #include "Graphics/Pipeline/SHVkPipeline.h" #include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" +#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" #include "ECS_Base/Managers/SHComponentManager.h" #include "Math/Transform/SHTransformComponent.h" +#include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h" +#include "Graphics/Descriptors/SHVkDescriptorPool.h" namespace SHADE { @@ -120,7 +123,7 @@ namespace SHADE } } - void SHBatch::UpdateMaterialBuffer(uint32_t frameIndex) + void SHBatch::UpdateMaterialBuffer(uint32_t frameIndex, Handle descPool) { if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) { @@ -154,21 +157,17 @@ namespace SHADE if (!matBufferDirty[frameIndex]) return; - // Build CPI Buffer + // Build CPU Buffer char* propsCurrPtr = matPropsData.get(); for (auto& subBatch : subBatches) for (const SHRenderable* renderable : subBatch.Renderables) { renderable->GetMaterial()->ExportProperties(propsCurrPtr); - propsCurrPtr += singleMatPropSize; + propsCurrPtr += singleMatPropAlignedSize; } // Transfer to GPU - SHVkUtil::EnsureBufferAndCopyHostVisibleData - ( - device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast(matPropsDataSize), - vk::BufferUsageFlagBits::eStorageBuffer - ); + rebuildMaterialBuffers(frameIndex, descPool); // This frame is updated matBufferDirty[frameIndex] = false; @@ -207,7 +206,7 @@ namespace SHADE transformDataBuffer[frameIndex]->WriteToMemory(transformData.data(), static_cast(transformData.size() * sizeof(SHMatrix)), 0, 0); } - void SHBatch::Build(Handle _device, uint32_t frameIndex) + void SHBatch::Build(Handle _device, Handle descPool, uint32_t frameIndex) { if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) { @@ -215,6 +214,9 @@ namespace SHADE return; } + // Save logical device + device = _device; + // No need to build as there are no changes if (!isDirty[frameIndex]) return; @@ -247,7 +249,8 @@ namespace SHADE if (!EMPTY_MAT_PROPS) { singleMatPropSize = SHADER_INFO->GetBytesRequired(); - matPropTotalBytes = drawData.size() * singleMatPropSize; + singleMatPropAlignedSize = device->PadSSBOSize(singleMatPropSize); + matPropTotalBytes = numTotalElements * singleMatPropAlignedSize; if (matPropsDataSize < matPropTotalBytes) { matPropsData.reset(new char[matPropTotalBytes]); @@ -267,7 +270,7 @@ namespace SHADE .instanceCount = static_cast(subBatch.Renderables.size()), .firstIndex = subBatch.Mesh->FirstIndex, .vertexOffset = subBatch.Mesh->FirstVertex, - .firstInstance = nextInstanceIndex + .firstInstance = nextInstanceIndex++ }); // Fill in buffers (CPU) @@ -289,7 +292,7 @@ namespace SHADE if (!EMPTY_MAT_PROPS) { renderable->GetMaterial()->ExportProperties(propsCurrPtr); - propsCurrPtr += singleMatPropSize; + propsCurrPtr += singleMatPropAlignedSize; } } } @@ -304,30 +307,21 @@ namespace SHADE const uint32_t DRAW_DATA_BYTES = static_cast(drawData.size() * sizeof(vk::DrawIndexedIndirectCommand)); SHVkUtil::EnsureBufferAndCopyHostVisibleData ( - _device, drawDataBuffer[frameIndex], drawData.data(), DRAW_DATA_BYTES, + device, drawDataBuffer[frameIndex], drawData.data(), DRAW_DATA_BYTES, BuffUsage::eIndirectBuffer ); // - Transform Buffer const uint32_t TF_DATA_BYTES = static_cast(transformData.size() * sizeof(SHMatrix)); SHVkUtil::EnsureBufferAndCopyHostVisibleData ( - _device, transformDataBuffer[frameIndex], transformData.data(), TF_DATA_BYTES, + device, transformDataBuffer[frameIndex], transformData.data(), TF_DATA_BYTES, BuffUsage::eVertexBuffer ); // - Material Properties Buffer - if (matPropsData) - { - SHVkUtil::EnsureBufferAndCopyHostVisibleData - ( - _device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast(matPropsDataSize), - BuffUsage::eStorageBuffer - ); - } + rebuildMaterialBuffers(frameIndex, descPool); + // Mark this frame as no longer dirty isDirty[frameIndex] = false; - - // Save logical device - this->device = _device; } /*---------------------------------------------------------------------------------*/ @@ -341,8 +335,20 @@ namespace SHADE return; } + // Bind all required objects before drawing + static std::array dynamicOffset { 0 }; cmdBuffer->BindPipeline(pipeline); cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRANSFORM, transformDataBuffer[frameIndex], 0); + if (matPropsDescSet[frameIndex]) + { + cmdBuffer->BindDescriptorSet + ( + matPropsDescSet[frameIndex], + vk::PipelineBindPoint::eGraphics, + SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE, + dynamicOffset + ); + } cmdBuffer->DrawMultiIndirect(drawDataBuffer[frameIndex], static_cast(drawData.size())); } @@ -355,4 +361,39 @@ namespace SHADE dirt = true; isCPUBuffersDirty = true; } + + void SHBatch::rebuildMaterialBuffers(uint32_t frameIndex, Handle descPool) + { + if (matPropsData) + { + SHVkUtil::EnsureBufferAndCopyHostVisibleData + ( + device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast(matPropsDataSize), + vk::BufferUsageFlagBits::eStorageBuffer + ); + + if (!matPropsDescSet[frameIndex]) + { + matPropsDescSet[frameIndex] = descPool->Allocate + ( + { SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE] }, + { 0 } + ); + } + std::array, 1> bufferList = { matPropsBuffer[frameIndex] }; + matPropsDescSet[frameIndex]->ModifyWriteDescBuffer + ( + SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE, + SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA, + bufferList, + 0, matPropsDataSize + ); + matPropsDescSet[frameIndex]->UpdateDescriptorSetBuffer + ( + SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE, + SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA + ); + } + } + } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h index d40a66ea..abe691ca 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h @@ -35,6 +35,8 @@ namespace SHADE class SHRenderable; class SHVkLogicalDevice; class SHMaterialInstance; + class SHVkDescriptorSetGroup; + class SHVkDescriptorPool; /*---------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -74,9 +76,9 @@ namespace SHADE void Add(const SHRenderable* renderable); void Remove(const SHRenderable* renderable); void Clear(); - void UpdateMaterialBuffer(uint32_t frameIndex); + void UpdateMaterialBuffer(uint32_t frameIndex, Handle descPool); void UpdateTransformBuffer(uint32_t frameIndex); - void Build(Handle device, uint32_t frameIndex); + void Build(Handle device, Handle descPool, uint32_t frameIndex) ; void Draw(Handle cmdBuffer, uint32_t frameIndex); /*-----------------------------------------------------------------------------*/ @@ -84,34 +86,44 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ Handle GetPipeline() const noexcept { return pipeline; }; - private: + private: + /*-----------------------------------------------------------------------------*/ + /* Type Definition */ + /*-----------------------------------------------------------------------------*/ + using TripleBool = std::array; + using TripleBuffer = std::array, SHGraphicsConstants::NUM_FRAME_BUFFERS>; + using TripleDescSet = std::array, SHGraphicsConstants::NUM_FRAME_BUFFERS>; + /*-----------------------------------------------------------------------------*/ /* Data Members */ /*-----------------------------------------------------------------------------*/ // Resources - Handle device; + Handle device; // Batch Properties - Handle pipeline; + Handle pipeline; std::unordered_set> referencedMatInstances; - std::array matBufferDirty; + TripleBool matBufferDirty; // Batch Tree - std::vector subBatches; - std::array isDirty; - // CPU Buffers - std::vector drawData; - std::vector transformData; - std::unique_ptr matPropsData; - Byte matPropsDataSize = 0; - Byte singleMatPropSize = 0; - bool isCPUBuffersDirty = true; - // GPU Buffers - std::array, SHGraphicsConstants::NUM_FRAME_BUFFERS> drawDataBuffer; - std::array, SHGraphicsConstants::NUM_FRAME_BUFFERS> transformDataBuffer; - std::array, SHGraphicsConstants::NUM_FRAME_BUFFERS> matPropsBuffer; + std::vector subBatches; + TripleBool isDirty; + // CPU Buffers + std::vector drawData; + std::vector transformData; + std::unique_ptr matPropsData; + Byte matPropsDataSize = 0; + Byte singleMatPropAlignedSize = 0; + Byte singleMatPropSize = 0; + bool isCPUBuffersDirty = true; + // GPU Buffers + TripleBuffer drawDataBuffer; + TripleBuffer transformDataBuffer; + TripleBuffer matPropsBuffer; + TripleDescSet matPropsDescSet; /*-----------------------------------------------------------------------------*/ /* Helper Functions */ /*-----------------------------------------------------------------------------*/ void setAllDirtyFlags(); + void rebuildMaterialBuffers(uint32_t frameIndex, Handle descPool); }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.cpp index c4320aac..dc44e7f9 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.cpp @@ -91,12 +91,12 @@ namespace SHADE (*superBatch)->Remove(renderable); } - void SHBatcher::FinaliseBatches(Handle device, uint32_t frameIndex) + void SHBatcher::FinaliseBatches(Handle device, Handle descPool, uint32_t frameIndex) { // Build SuperBatches for (auto& batch : superBatches) { - batch->Build(device, frameIndex); + batch->Build(device, descPool, frameIndex); } } @@ -109,11 +109,11 @@ namespace SHADE superBatches.clear(); } - void SHBatcher::UpdateBuffers(uint32_t frameIndex) + void SHBatcher::UpdateBuffers(uint32_t frameIndex, Handle descPool) { for (auto& batch : superBatches) { - batch->UpdateBuffers(frameIndex); + batch->UpdateBuffers(frameIndex, descPool); } } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.h index 985e8e16..8074899d 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.h @@ -27,6 +27,7 @@ namespace SHADE class SHSuperBatch; class SHVkLogicalDevice; class SHVkCommandBuffer; + class SHVkDescriptorPool; /*---------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -51,9 +52,9 @@ namespace SHADE void PrepareBatches(); void AddToBatch(SHRenderable const* renderable); void RemoveFromBatch(SHRenderable const* renderable); - void FinaliseBatches(Handle device, uint32_t frameIndex); + void FinaliseBatches(Handle device, Handle descPool, uint32_t frameIndex); void ClearBatches(); - void UpdateBuffers(uint32_t frameIndex); + void UpdateBuffers(uint32_t frameIndex, Handle descPool); void RegisterSuperBatch(Handle superBatch); void DeregisterSuperBatch(Handle superBatch); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp index b0173399..0d75dca8 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp @@ -16,6 +16,7 @@ of DigiPen Institute of Technology is prohibited. #include "SHBatch.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" #include "Graphics/MiddleEnd/Interface/SHRenderable.h" +#include "Graphics/Descriptors/SHVkDescriptorPool.h" namespace SHADE { @@ -78,21 +79,21 @@ namespace SHADE batches.clear(); } - void SHSuperBatch::UpdateBuffers(uint32_t frameIndex) + void SHSuperBatch::UpdateBuffers(uint32_t frameIndex, Handle descPool) { for (auto& batch : batches) { - batch.UpdateMaterialBuffer(frameIndex); + batch.UpdateMaterialBuffer(frameIndex, descPool); batch.UpdateTransformBuffer(frameIndex); } } - void SHSuperBatch::Build(Handle device, uint32_t frameIndex) noexcept + void SHSuperBatch::Build(Handle device, Handle descPool, uint32_t frameIndex) noexcept { // Build all batches for (auto& batch : batches) { - batch.Build(device, frameIndex); + batch.Build(device, descPool, frameIndex); } } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h index a09fc64e..9743e7dc 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h @@ -55,8 +55,8 @@ namespace SHADE void Add(const SHRenderable* renderable) noexcept; void Remove(const SHRenderable* renderable) noexcept; void Clear() noexcept; - void UpdateBuffers(uint32_t frameIndex); - void Build(Handle device, uint32_t frameIndex) noexcept; + void UpdateBuffers(uint32_t frameIndex, Handle descPool); + void Build(Handle device, Handle descPool, uint32_t frameIndex) noexcept; void Draw(Handle cmdBuffer, uint32_t frameIndex) noexcept; /*-----------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp index ee6d0e8c..6a7b23f2 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp @@ -7,7 +7,22 @@ namespace SHADE { + /*-----------------------------------------------------------------------------------*/ + /* Static Definitions */ + /*-----------------------------------------------------------------------------------*/ + std::vector> SHGraphicsGlobalData::globalDescSetLayouts; + Handle SHGraphicsGlobalData::globalDescSets; + SHVertexInputState SHGraphicsGlobalData::defaultVertexInputState; + Handle SHGraphicsGlobalData::dummyPipelineLayout; + void SHGraphicsGlobalData::InitHighFrequencyGlobalData(void) noexcept + { + + } + + /*-----------------------------------------------------------------------------------*/ + /* Function Definitions */ + /*-----------------------------------------------------------------------------------*/ void SHGraphicsGlobalData::InitDescSetLayouts(Handle logicalDevice) noexcept { SHVkDescriptorSetLayout::Binding genericDataBinding @@ -87,18 +102,18 @@ namespace SHADE InitDefaultVertexInputState(); } - std::vector> const& SHGraphicsGlobalData::GetDescSetLayouts(void) const noexcept + std::vector> const& SHGraphicsGlobalData::GetDescSetLayouts(void) noexcept { return globalDescSetLayouts; } - SHVertexInputState const& SHGraphicsGlobalData::GetDefaultViState(void) const noexcept + SHVertexInputState const& SHGraphicsGlobalData::GetDefaultViState(void) noexcept { return defaultVertexInputState; } - Handle SHGraphicsGlobalData::GetDummyPipelineLayout(void) const noexcept + Handle SHGraphicsGlobalData::GetDummyPipelineLayout(void) noexcept { return dummyPipelineLayout; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h index 9333d0ab..344c2616 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h @@ -15,31 +15,38 @@ namespace SHADE { private: //! Global descriptor set layouts. Used to allocate descriptor sets - std::vector> globalDescSetLayouts; + static std::vector> globalDescSetLayouts; //! Global Descriptor sets - Handle globalDescSets; + static Handle globalDescSets; //! Default vertex input state (used by everything). - SHVertexInputState defaultVertexInputState; + static SHVertexInputState defaultVertexInputState; //! Since we want to bind global data but can't do so without a pipeline layout, //! we create a dummy pipeline layout to use it for binding. - Handle dummyPipelineLayout; + static Handle dummyPipelineLayout; + + static void InitHighFrequencyGlobalData (void) noexcept; + static void InitDescSetLayouts (Handle logicalDevice) noexcept; + static void InitDefaultVertexInputState (void) noexcept; - void InitDescSetLayouts (Handle logicalDevice) noexcept; - void InitDefaultVertexInputState(void) noexcept; public: + /*-----------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------*/ + SHGraphicsGlobalData() = delete; + /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ - void Init (Handle logicalDevice) noexcept; + static void Init (Handle logicalDevice) noexcept; /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ /*-----------------------------------------------------------------------*/ - std::vector> const& GetDescSetLayouts (void) const noexcept; - SHVertexInputState const& GetDefaultViState (void) const noexcept; - Handle GetDummyPipelineLayout (void) const noexcept; + static std::vector> const& GetDescSetLayouts (void) noexcept; + static SHVertexInputState const& GetDefaultViState (void) noexcept; + static Handle GetDummyPipelineLayout (void) noexcept; }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.cpp index 4a1117c3..2abdfa86 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.cpp @@ -23,22 +23,40 @@ namespace SHADE { SHVec3 view = target - pos; view = SHVec3::Normalise(view); SHVec3 right = SHVec3::Cross(view, up); right = SHVec3::Normalise(right); - const SHVec3 UP = SHVec3::Cross(right, view); + const SHVec3 UP = SHVec3::Cross(view, right); + //viewMatrix = SHMatrix::Identity; + //viewMatrix(0, 0) = UP[0]; + //viewMatrix(1, 0) = UP[1]; + //viewMatrix(2, 0) = UP[2]; + //viewMatrix(0, 1) = right[0]; + //viewMatrix(1, 1) = right[1]; + //viewMatrix(2, 1) = right[2]; + //viewMatrix(0, 2) = view[0]; + //viewMatrix(1, 2) = view[1]; + //viewMatrix(2, 2) = view[2]; + //viewMatrix(3, 0) = -UP.Dot(pos); + //viewMatrix(3, 1) = -right.Dot(pos); + //viewMatrix(3, 2) = -view.Dot(pos); + viewMatrix = SHMatrix::Identity; - viewMatrix(0, 0) = UP[0]; - viewMatrix(1, 0) = UP[1]; - viewMatrix(2, 0) = UP[2]; - viewMatrix(0, 1) = right[0]; - viewMatrix(1, 1) = right[1]; - viewMatrix(2, 1) = right[2]; - viewMatrix(0, 2) = view[0]; - viewMatrix(1, 2) = view[1]; - viewMatrix(2, 2) = view[2]; - viewMatrix(3, 0) = -UP.Dot(pos); - viewMatrix(3, 1) = -right.Dot(pos); - viewMatrix(3, 2) = -view.Dot(pos); - + viewMatrix(0, 0) = right[0]; + viewMatrix(0, 1) = right[1]; + viewMatrix(0, 2) = right[2]; + + viewMatrix(1, 0) = UP[0]; + viewMatrix(1, 1) = UP[1]; + viewMatrix(1, 2) = UP[2]; + + viewMatrix(2, 0) = view[0]; + viewMatrix(2, 1) = view[1]; + viewMatrix(2, 2) = view[2]; + + viewMatrix(0, 3) = -right.Dot(pos); + viewMatrix(1, 3) = -UP.Dot(pos); + viewMatrix(2, 3) = -view.Dot(pos); + + isDirty = true; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index 445d6119..40e24979 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -30,6 +30,8 @@ of DigiPen Institute of Technology is prohibited. #include "SHGraphicsConstants.h" #include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h" #include "Graphics/Buffers/SHVkBuffer.h" +#include "Graphics/Images/SHVkSampler.h" +#include "Assets/Asset Types/SHTextureAsset.h" namespace SHADE { @@ -91,8 +93,10 @@ namespace SHADE descPool = device->CreateDescriptorPools(); // Create generic command buffer - transferCmdPool = device->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::TRANSFER, SH_CMD_POOL_RESET::POOL_BASED, true); - transferCmdBuffer = transferCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY); + //transferCmdPool = device->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS, SH_CMD_POOL_RESET::POOL_BASED, true); + graphicsCmdPool = device->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS, SH_CMD_POOL_RESET::POOL_BASED, true); + transferCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY); + graphicsTexCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY); @@ -106,8 +110,7 @@ namespace SHADE - Global data /*-----------------------------------------------------------------------*/ - globalData = resourceManager.Create(); - globalData->Init(device); + SHGraphicsGlobalData::Init(device); // Set Up Cameras screenCamera = resourceManager.Create(); @@ -115,7 +118,7 @@ namespace SHADE screenCamera->SetOrthographic(static_cast(windowDims.first), static_cast(windowDims.second), 0.01f, 100.0f); worldCamera = resourceManager.Create(); //worldCamera->SetLookAt(SHVec3(1.0f, 0.0f, -1.0f), SHVec3(0.0f, 0.0f, 2.0f), SHVec3(0.0f, 1.0f, 0.0f)); - worldCamera->SetLookAt(SHVec3(0.0f, 5.0f, -1.0f), SHVec3(0.0f, 0.0f, 2.0f), SHVec3(0.0f, 1.0f, 0.0f)); + worldCamera->SetLookAt(SHVec3(0.0f, 0.0f, 0.0f), SHVec3(0.0f, 0.0f, -2.0f), SHVec3(0.0f, 1.0f, 0.0f)); worldCamera->SetPerspective(90.0f, static_cast(windowDims.first), static_cast(windowDims.second), 0.0f, 100.0f); // Create Default Viewport @@ -131,18 +134,20 @@ namespace SHADE } // Initialize world render graph - worldRenderGraph->Init(device, swapchain, globalData); + worldRenderGraph->Init(device, swapchain); + worldRenderGraph->AddResource("Depth Buffer", SH_ATT_DESC_TYPE::DEPTH_STENCIL, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint); //worldRenderGraph->AddResource("Position", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eR16G16B16A16Sfloat); //worldRenderGraph->AddResource("Normals", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eR16G16B16A16Sfloat); //worldRenderGraph->AddResource("Composite", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eR16G16B16A16Sfloat); - worldRenderGraph->AddResource("Scene", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eB8G8R8A8Unorm); + //worldRenderGraph->AddResource("Scene", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eB8G8R8A8Unorm); worldRenderGraph->AddResource("Present", SH_ATT_DESC_TYPE::COLOR_PRESENT, windowDims.first, windowDims.second); - auto node = worldRenderGraph->AddNode("G-Buffer", { /*"Composite", "Position", */"Present" }, {}); // no predecessors + auto node = worldRenderGraph->AddNode("G-Buffer", { /*"Composite", "Position", */"Depth Buffer", "Present" }, {}); // no predecessors //First subpass to write to G-Buffer auto gBufferWriteSubpass = node->AddSubpass("G-Buffer Write"); //gBufferWriteSubpass->AddColorOutput("Scene"); gBufferWriteSubpass->AddColorOutput("Present"); + gBufferWriteSubpass->AddDepthOutput ("Depth Buffer", SH_ATT_DESC_TYPE::DEPTH_STENCIL); //writeSubpass->AddColorOutput("Normals"); // //Second subpass to read from G-Buffer @@ -171,7 +176,7 @@ namespace SHADE debugWorldRenderer->SetCamera(worldCamera);*/ // Add world renderer to default viewport - worldRenderer = defaultViewport->AddRenderer(resourceManager, swapchain->GetNumImages(), renderContextCmdPools, descPool, globalData->GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS], worldRenderGraph); + worldRenderer = defaultViewport->AddRenderer(resourceManager, swapchain->GetNumImages(), renderContextCmdPools, descPool, SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS], worldRenderGraph); worldRenderer->SetCamera(worldCamera); @@ -184,8 +189,8 @@ namespace SHADE shaderModuleLibrary.ImportFromSourceLibrary(device, shaderSourceLibrary); auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl"); auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl"); - //triVS->Reflect(); - //triFS->Reflect(); + cubeVS->Reflect(); + cubeFS->Reflect(); defaultMaterial = AddMaterial(cubeVS, cubeFS, gBufferWriteSubpass); } @@ -224,6 +229,9 @@ namespace SHADE renderContext.ResetFence(); + // Bind textures + + // For every viewport for (int vpIndex = 0; vpIndex < static_cast(viewports.size()); ++vpIndex) { @@ -241,7 +249,7 @@ namespace SHADE // Begin recording the command buffer currentCmdBuffer->BeginRecording(); - currentCmdBuffer->ForceSetPipelineLayout(globalData->GetDummyPipelineLayout()); + currentCmdBuffer->ForceSetPipelineLayout(SHGraphicsGlobalData::GetDummyPipelineLayout()); // Bind all the buffers required for meshes for (auto& [buffer, bindingPoint] : MESH_DATA) @@ -252,11 +260,26 @@ namespace SHADE currentCmdBuffer->BindIndexBuffer(buffer, 0); } + + // Bind textures + auto textureDescSet = texLibrary.GetTextureDescriptorSetGroup(); + if (textureDescSet) + { + std::array texDynamicOffset {0}; + currentCmdBuffer->BindDescriptorSet + ( + textureDescSet, + vk::PipelineBindPoint::eGraphics, + 0, + texDynamicOffset + ); + } + // bind camera data renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex); // Draw first - renderers[renIndex]->Draw(frameIndex); + renderers[renIndex]->Draw(frameIndex, descPool); // End the command buffer recording currentCmdBuffer->EndRecording(); @@ -309,7 +332,7 @@ namespace SHADE for (auto vp : viewports) for (auto renderer : vp->GetRenderers()) { - renderer->GetRenderGraph()->FinaliseBatch(renderContext.GetCurrentFrame()); + renderer->GetRenderGraph()->FinaliseBatch(renderContext.GetCurrentFrame(), descPool); } // Resize @@ -455,9 +478,37 @@ namespace SHADE transferCmdBuffer->BeginRecording(); meshLibrary.BuildBuffers(device, transferCmdBuffer); transferCmdBuffer->EndRecording(); - transferQueue->SubmitCommandBuffer({ transferCmdBuffer }); + graphicsQueue->SubmitCommandBuffer({ transferCmdBuffer }); } - + + /*---------------------------------------------------------------------------------*/ + /* Texture Registration Functions */ + /*---------------------------------------------------------------------------------*/ + Handle SHGraphicsSystem::Add(const SHTextureAsset& texAsset) + { + auto sampler = samplerCache.GetSampler(device, SHVkSamplerParams { .maxLod = static_cast(texAsset.mipOffsets.size()) }); + return texLibrary.Add(texAsset, sampler); + } + + SHADE::Handle SHGraphicsSystem::Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, uint32_t width, uint32_t height, SHTexture::TextureFormat format, std::vector mipOffsets) + { + auto sampler = samplerCache.GetSampler(device, SHVkSamplerParams{ .maxLod = static_cast(mipOffsets.size()) }); + return texLibrary.Add(pixelCount, pixelData, width, height, format, mipOffsets, sampler); + } + + void SHGraphicsSystem::Remove(Handle tex) + { + texLibrary.Remove(tex); + } + + void SHGraphicsSystem::BuildTextures() + { + texLibrary.BuildTextures + ( + device, graphicsTexCmdBuffer, graphicsQueue, descPool + ); + } + void SHGraphicsSystem::SetWindow(SHWindow* wind) noexcept { window = wind; @@ -493,9 +544,13 @@ namespace SHADE oldSuperBatch->Remove(&renderable); } - // Add to new SuperBatch - Handle newSuperBatch = renderable.GetMaterial()->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch(); - newSuperBatch->Add(&renderable); + // Add to new SuperBatch if there is a material + Handle newMatInstance = renderable.GetMaterial(); + if (newMatInstance) + { + Handle newSuperBatch = newMatInstance->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch(); + newSuperBatch->Add(&renderable); + } // Unset change flag renderable.ResetChangedFlag(); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h index 7e652a02..84dc39cd 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h @@ -29,6 +29,8 @@ of DigiPen Institute of Technology is prohibited. #include "Graphics/MiddleEnd/Shaders/SHShaderModuleLibrary.h" #include "SHMeshLibrary.h" #include "Graphics/MiddleEnd/Materials/SHMaterialInstanceCache.h" +#include "../Textures/SHTextureLibrary.h" +#include "../Textures/SHVkSamplerCache.h" namespace SHADE { @@ -188,6 +190,62 @@ namespace SHADE /***************************************************************************/ void BuildMeshBuffers(); + /*-----------------------------------------------------------------------------*/ + /* Texture Registration Functions */ + /*-----------------------------------------------------------------------------*/ + /*******************************************************************************/ + /*! + + \brief + Adds a texture to the Texture Library. But this does not mean that the + textures have been added yet. A call to "BuildTextures()" is required to + transfer all textures into the GPU. + + \param pixelCount + Number of pixels in this Mesh. + \param positions + Pointer to the first in a contiguous array of SHMathVec3s that define vertex + positions. + \param format + Format of the texture loaded in. + + \return + Handle to the created Texture. This is not valid to be used until a call to + BuildImages(). + + */ + /*******************************************************************************/ + Handle Add(const SHTextureAsset& texAsset); + Handle Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, uint32_t width, uint32_t height, SHTexture::TextureFormat format, std::vector mipOffsets); + /*******************************************************************************/ + /*! + + \brief + Removes a mesh from the Texture Library. But this does not mean that the + textures have been removed yet. A call to "BuildTextures()" is required to + finalise all changes. + + \param mesh + Handle to the Texture to remove. + + */ + /*******************************************************************************/ + void Remove(Handle tex); + /***************************************************************************/ + /*! + + \brief + Finalises all changes to the Texture Library into the GPU buffers. + + \param cmdBuffer + Command buffer used to set up transfers of data in the GPU memory. This + call must be preceded by calls to cmdBuffer's BeginRecording() and ended + with EndRecording(). Do recall to also submit the cmdBuffer to a transfer + queue. + */ + /***************************************************************************/ + void BuildTextures(); + /*-----------------------------------------------------------------------------*/ /* Setters */ /*-----------------------------------------------------------------------------*/ @@ -220,19 +278,20 @@ namespace SHADE Handle graphicsQueue; Handle transferQueue; Handle descPool; + Handle graphicsCmdPool; Handle transferCmdPool; Handle transferCmdBuffer; + Handle graphicsTexCmdBuffer; SHRenderContext renderContext; std::array, 2> graphSemaphores; // Not Owned Resources SHWindow* window = nullptr; - // global data (descriptor sets as well) - Handle globalData; - // Middle End Resources ResourceManager resourceManager; SHMeshLibrary meshLibrary; + SHTextureLibrary texLibrary; + SHSamplerCache samplerCache; SHMaterialInstanceCache materialInstanceCache; // Viewports Handle defaultViewport; // Whole screen diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.cpp index 0e5a61dd..350580bf 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.cpp @@ -40,8 +40,6 @@ namespace SHADE void SHMaterialInstance::ExportProperties(void* dest) { - assert(dataStore != nullptr); - if (!baseMaterial) throw std::runtime_error("[SHMaterialInstance] Attempted to set export a Material Instance with no base Material!"); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.h index 5d6c4925..d111acb9 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.h @@ -15,6 +15,7 @@ of DigiPen Institute of Technology is prohibited. // Project Includes #include "Resource/Handle.h" #include "Graphics/Shaders/BlockInterface/SHShaderBlockInterface.h" +#include "SH_API.h" namespace SHADE { @@ -34,7 +35,7 @@ namespace SHADE a SHRenderable. */ /***********************************************************************************/ - class SHMaterialInstance + class SH_API SHMaterialInstance { public: /*-----------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.hpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.hpp index b3dc6c3a..4621c273 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.hpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.hpp @@ -48,7 +48,7 @@ namespace SHADE } // Get offset and modify the memory directly - T* dataPtr = dataStore.get() + od.StoredDataOffset; + T* dataPtr = reinterpret_cast(dataStore.get() + od.StoredDataOffset); *dataPtr = value; // Save the override data information diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp index a4cda42d..0b1c1b66 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp @@ -81,7 +81,7 @@ namespace SHADE if (!material) { SHGraphicsSystem* gfxSystem = SHSystemManager::GetSystem(); - material = gfxSystem->AddOrGetBaseMaterialInstance(sharedMaterial->GetBaseMaterial()); + material = gfxSystem->AddMaterialInstanceCopy(sharedMaterial); } return material; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp index c7e2a86d..84ac3ee2 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp @@ -60,9 +60,9 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ /* Drawing Functions */ /*-----------------------------------------------------------------------------------*/ - void SHRenderer::Draw(uint32_t frameIndex) noexcept + void SHRenderer::Draw(uint32_t frameIndex, Handle descPool) noexcept { - renderGraph->Execute(frameIndex, commandBuffers[frameIndex]); + renderGraph->Execute(frameIndex, commandBuffers[frameIndex], descPool); } void SHRenderer::UpdateDataAndBind(Handle cmdBuffer, uint32_t frameIndex) noexcept diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h index 255ab289..5e72da85 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h @@ -74,7 +74,7 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Drawing Functions */ /*-----------------------------------------------------------------------------*/ - void Draw(uint32_t frameIndex) noexcept; + void Draw(uint32_t frameIndex, Handle descPool) noexcept; void UpdateDataAndBind (Handle cmdBuffer, uint32_t frameIndex) noexcept; void UpdateCameraDataToBuffer (void) noexcept; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp index 92d832f1..10b42a9e 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp @@ -11,7 +11,7 @@ namespace SHADE SHPipelineLayoutParams params { .shaderModules = {vsFsPair.first, vsFsPair.second}, - .globalDescSetLayouts = globalData->GetDescSetLayouts() + .globalDescSetLayouts = SHGraphicsGlobalData::GetDescSetLayouts() }; // Create the pipeline layout @@ -19,7 +19,7 @@ namespace SHADE // Create the pipeline and configure the default vertex input state auto newPipeline = logicalDevice->CreateGraphicsPipeline(pipelineLayout, nullptr, renderpass, subpass); - newPipeline->GetPipelineState().SetVertexInputState(globalData->GetDefaultViState()); + newPipeline->GetPipelineState().SetVertexInputState(SHGraphicsGlobalData::GetDefaultViState()); // Actually construct the pipeline newPipeline->ConstructPipeline(); @@ -30,10 +30,9 @@ namespace SHADE return newPipeline; } - void SHPipelineLibrary::Init(Handle device, Handle inGlobalData) noexcept + void SHPipelineLibrary::Init(Handle device) noexcept { logicalDevice = device; - globalData = inGlobalData; } Handle SHPipelineLibrary::GetDrawPipline(std::pair, Handle> const& vsFsPair) noexcept diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h index a16976f7..9a411d25 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h @@ -24,14 +24,9 @@ namespace SHADE //! a map of pipelines that are hashed using a pair of shader module handles std::unordered_map, Handle>, Handle> pipelines; - - // Global data - Handle globalData; - - public: - void Init (Handle device, Handle inGlobalData) noexcept; + void Init (Handle device) noexcept; // Draw pipeline functions. used only when creating pipelines for drawing using a vertex and fragment shader Handle CreateDrawPipeline ( diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.cpp index 6459ff9a..6a7439e5 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.cpp @@ -20,18 +20,36 @@ of DigiPen Institute of Technology is prohibited. #include "Graphics/Commands/SHVkCommandBuffer.h" #include "Graphics/SHVkUtil.h" #include "Tools/SHLogger.h" +#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" +#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" +#include "Graphics/Images/SHVkImage.h" +#include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h" +#include "Assets/Asset Types/SHTextureAsset.h" namespace SHADE { /*---------------------------------------------------------------------------------*/ /* Usage Functions */ /*---------------------------------------------------------------------------------*/ - Handle SHTextureLibrary::Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, SHTexture::TextureFormat format, uint32_t mipLevels) + Handle SHTextureLibrary::Add(const SHTextureAsset& texAsset, Handle sampler) + { + return Add + ( + texAsset.numBytes, + texAsset.pixelData, + texAsset.width, texAsset.height, + texAsset.format, + texAsset.mipOffsets, + sampler + ); + } + + Handle SHTextureLibrary::Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, uint32_t width, uint32_t height, SHTexture::TextureFormat format, std::vector mipOffsets, Handle sampler) { isDirty = true; auto handle = resourceManager.Create(); - addJobs.emplace_back(AddJob { pixelCount, pixelData, format, mipLevels }); + addJobs.emplace_back(AddJob { pixelCount, pixelData, format, sampler, mipOffsets, width, height, handle }); return handle; } @@ -44,22 +62,48 @@ namespace SHADE isDirty = true; } - void SHTextureLibrary::BuildImages(Handle device, Handle cmdBuffer, Handle graphicsQueue, Handle descPool, Handle descLayout) + void SHTextureLibrary::BuildTextures(Handle device, Handle cmdBuffer, Handle graphicsQueue, Handle descPool) { + // Don't do anything if there are no updates + if (!isDirty) + return; + /* Remove Textures */ - std::vector pipelineBarriers(addJobs.size()); + // TODO /* Add Textures */ - // Transition + // Load Textures - Transitions + std::vector pipelineBarriers(addJobs.size()); for (int i = 0; auto& job : addJobs) { - job.Image = resourceManager.Create(); + job.Image = resourceManager.Create + ( + &device->GetVMAAllocator(), + SHImageCreateParams + { + .imageType = vk::ImageType::e2D, + .width = job.Width, + .height = job.Height, + .depth = 1, + .levels = static_cast(job.MipOffsets.size()), + .arrayLayers = 1, + .imageFormat = job.TextureFormat, + .usageFlags = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst, + .createFlags = {} + }, + job.PixelData, + job.PixelCount, + job.MipOffsets, + VmaMemoryUsage::VMA_MEMORY_USAGE_AUTO, + VmaAllocationCreateFlagBits {} + ); job.Image->PrepareImageTransitionInfo(vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, pipelineBarriers[i]); ++i; } vk::PipelineStageFlagBits srcStage = vk::PipelineStageFlagBits::eTopOfPipe; vk::PipelineStageFlagBits dstStage = vk::PipelineStageFlagBits::eTopOfPipe; preparePipelineBarriers(vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, srcStage, dstStage, pipelineBarriers); + cmdBuffer->BeginRecording(); cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, pipelineBarriers); // Copy @@ -73,13 +117,16 @@ namespace SHADE { // Transition job.Image->PrepareImageTransitionInfo(vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal, pipelineBarriers[i]); + ++i; } preparePipelineBarriers(vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal, srcStage, dstStage, pipelineBarriers); - cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, pipelineBarriers); + cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {}, {}, {}, pipelineBarriers); // Execute Commands + cmdBuffer->EndRecording(); graphicsQueue->SubmitCommandBuffer({ cmdBuffer }); device->WaitIdle(); + graphicsQueue->GetVkQueue().waitIdle(); // Create Image View for (auto& job : addJobs) @@ -90,16 +137,45 @@ namespace SHADE .format = job.TextureFormat, .imageAspectFlags = vk::ImageAspectFlagBits::eColor, .baseMipLevel = 0, - .mipLevelCount = job.MipLevels, + .mipLevelCount = static_cast(job.MipOffsets.size()), .baseArrayLayer = 0, - .layerCount = 0 + .layerCount = 1 }; - job.Handle->ImageView = job.Image->CreateImageView(device, job.Image, DETAILS); + job.TextureHandle->ImageView = job.Image->CreateImageView(device, job.Image, DETAILS); } - // Build Descriptor - Handle descSetGroup = descPool->Allocate({ descLayout }, { 1 }); - + // Add Textures + for (auto& job : addJobs) + { + texOrder.emplace_back(job.TextureHandle); + combinedImageSamplers.emplace_back(std::make_tuple(job.TextureHandle->ImageView, job.Sampler, vk::ImageLayout::eShaderReadOnlyOptimal)); + job.TextureHandle->TextureArrayIndex = texOrder.size() - 1; + } + addJobs.clear(); + + /* Build Descriptor Set with all the Textures only if there are textures */ + if (!texOrder.empty()) + { + if (!texDescriptors) + { + texDescriptors = descPool->Allocate + ( + { SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::STATIC_GLOBALS] }, + { static_cast(texOrder.size()) } + ); + } + texDescriptors->ModifyWriteDescImage + ( + SHGraphicsConstants::DescriptorSetIndex::STATIC_GLOBALS, + SHGraphicsConstants::DescriptorSetBindings::IMAGE_AND_SAMPLERS_DATA, + combinedImageSamplers + ); + texDescriptors->UpdateDescriptorSetImages + ( + SHGraphicsConstants::DescriptorSetIndex::STATIC_GLOBALS, + SHGraphicsConstants::DescriptorSetBindings::IMAGE_AND_SAMPLERS_DATA + ); + } isDirty = false; } @@ -139,4 +215,65 @@ namespace SHADE } } + vk::Format SHTextureLibrary::ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear) + { + switch (format) + { + case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm: + return vk::Format::eBc1RgbaUnormBlock; + case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm_SRGB: + return vk::Format::eBc1RgbaSrgbBlock; + case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm: + case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm_SRGB: + return isLinear ? vk::Format::eBc2UnormBlock : vk::Format::eBc2SrgbBlock; + case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm: + case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm_SRGB: + return isLinear ? vk::Format::eBc3UnormBlock : vk::Format::eBc3SrgbBlock; + case tinyddsloader::DDSFile::DXGIFormat::BC5_UNorm: + case tinyddsloader::DDSFile::DXGIFormat::BC5_SNorm: + return isLinear ? vk::Format::eBc5UnormBlock : vk::Format::eBc5SnormBlock; + case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm: + case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm_SRGB: + return isLinear ? vk::Format::eR8G8B8A8Unorm : vk::Format::eR8G8B8A8Srgb; + case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_SNorm: + return vk::Format::eR8G8B8A8Snorm; + case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm: + case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm_SRGB: + return isLinear ? vk::Format::eB8G8R8A8Unorm : vk::Format::eB8G8R8A8Srgb; + case tinyddsloader::DDSFile::DXGIFormat::B8G8R8X8_UNorm: + case tinyddsloader::DDSFile::DXGIFormat::B8G8R8X8_UNorm_SRGB: + return isLinear ? vk::Format::eB8G8R8A8Unorm : vk::Format::eB8G8R8Srgb; + default: + throw std::runtime_error("Unsupported DDS format."); + } + + //switch (format) + //{ + //case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm: + //case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm_SRGB: + // return (isLinear) ? vk::Format::eR8G8B8A8Unorm : vk::Format::eR8G8B8A8Srgb; + // + + //case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm: + //case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm_SRGB: + // return (isLinear) ? vk::Format::eB8G8R8A8Unorm : vk::Format::eB8G8R8A8Srgb; + // + + //case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm: + //case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm_SRGB: + // return (isLinear) ? vk::Format::eBc1RgbaUnormBlock : vk::Format::eBc1RgbaSrgbBlock; + + //case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm: + //case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm_SRGB: + // return (isLinear) ? vk::Format::eBc2UnormBlock : vk::Format::eBc2SrgbBlock; + + //case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm: + //case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm_SRGB: + // return (isLinear) ? vk::Format::eBc3UnormBlock : vk::Format::eBc3SrgbBlock; + + //case tinyddsloader::DDSFile::DXGIFormat::BC5_UNorm: + // return (isLinear) ? vk::Format::eBc5UnormBlock : vk::Format::eBc5SnormBlock; + // + //} + } } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.h b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.h index 5cf974ef..660d93eb 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.h @@ -14,6 +14,8 @@ of DigiPen Institute of Technology is prohibited. // STL Includes #include +// External Dependencies +#include "tinyddsloader.h" // Project Includes #include "Resource/Handle.h" #include "Resource/ResourceLibrary.h" @@ -33,6 +35,9 @@ namespace SHADE class SHVkQueue; class SHVkDescriptorPool; class SHVkDescriptorSetLayout; + class SHVkDescriptorSetGroup; + class SHVkSampler; + class SHTextureAsset; /*---------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -43,7 +48,7 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Type Definitions */ /*-----------------------------------------------------------------------------*/ - using PixelChannel = float; + using PixelChannel = unsigned char; using TextureFormat = vk::Format; // TODO: Change using Index = uint32_t; @@ -71,7 +76,7 @@ namespace SHADE \brief Adds a texture to the Texture Library. But this does not mean that the - textures have been added yet. A call to "BuildImages()" is required to + textures have been added yet. A call to "BuildTextures()" is required to transfer all textures into the GPU. \param pixelCount @@ -88,13 +93,15 @@ namespace SHADE */ /*******************************************************************************/ - Handle Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, SHTexture::TextureFormat format, uint32_t mipLevels); + + Handle Add(const SHTextureAsset& texAsset, Handle sampler); + Handle Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, uint32_t width, uint32_t height, SHTexture::TextureFormat format, std::vector mipOffsets, Handle sampler); /*******************************************************************************/ /*! \brief Removes a mesh from the Texture Library. But this does not mean that the - textures have been removed yet. A call to "BuildImages()" is required to + textures have been removed yet. A call to "BuildTextures()" is required to finalise all changes. \param mesh @@ -118,12 +125,12 @@ namespace SHADE queue. */ /***************************************************************************/ - void BuildImages(Handle device, Handle cmdBuffer, Handle graphicsQueue, Handle descPool, Handle descLayout); + void BuildTextures(Handle device, Handle cmdBuffer, Handle graphicsQueue, Handle descPool); /*-----------------------------------------------------------------------------*/ /* Getter Functions */ /*-----------------------------------------------------------------------------*/ - Handle GetTextureBuffer() const noexcept { return texStorageBuffer; } + Handle GetTextureDescriptorSetGroup() const noexcept { return texDescriptors; } private: /*-----------------------------------------------------------------------------*/ @@ -134,9 +141,12 @@ namespace SHADE uint32_t PixelCount = 0; const SHTexture::PixelChannel* PixelData = nullptr; SHTexture::TextureFormat TextureFormat = {}; - uint32_t MipLevels = 0; + Handle Sampler; + std::vector MipOffsets; + uint32_t Width; + uint32_t Height; + Handle TextureHandle; Handle Image; - Handle Handle; }; /*-----------------------------------------------------------------------------*/ @@ -149,9 +159,9 @@ namespace SHADE ResourceManager resourceManager; std::vector> texOrder; // CPU Storage - std::vector texStorage; + std::vector, Handle, vk::ImageLayout>> combinedImageSamplers; // GPU Storage - Handle texStorageBuffer{}; + Handle texDescriptors; // Flags bool isDirty = true; @@ -159,5 +169,6 @@ namespace SHADE /* Helper Functions */ /*-----------------------------------------------------------------------------*/ void preparePipelineBarriers(vk::ImageLayout oldLayout, vk::ImageLayout newLayout, vk::PipelineStageFlagBits& srcStage, vk::PipelineStageFlagBits& dstStage, std::vector& barriers); + vk::Format ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear); }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHVkSamplerCache.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHVkSamplerCache.cpp new file mode 100644 index 00000000..6938dae5 --- /dev/null +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHVkSamplerCache.cpp @@ -0,0 +1,75 @@ +/************************************************************************************//*! +\file SHVkSamplerCache.cpp +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Mar 16, 2022 +\brief Contains the implementation for the SHVkSamplerCache class. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#include "SHpch.h" +#include "SHVkSamplerCache.h" + +// Standard Library +#include +// Project Header +#include "Graphics/Images/SHVkSampler.h" +#include "Graphics/Devices/SHVkLogicalDevice.h" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Utility Functions */ + /*---------------------------------------------------------------------------------*/ + void SHSamplerCache::Clear() + { + samplersMap.clear(); + } + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + Handle SHSamplerCache::GetSampler(Handle device, const SHVkSamplerParams& params) + { + // Get the hash to check if it was cached + const RawSamplerHash HASH = calcHash + ( + params.minFilter, + params.magFilter, + params.addressMode, + params.mipmapMode, + params.minLod, + params.maxLod + ); + + // Check if it was cached + auto sampler = samplersMap.find(HASH); + if (sampler == samplersMap.end()) + { + const auto BUILD_RESULT = samplersMap.emplace(HASH, device->CreateSampler(params)); + sampler = BUILD_RESULT.first; + } + + return sampler->second; + } + + /*---------------------------------------------------------------------------------*/ + /* Helper Functions */ + /*---------------------------------------------------------------------------------*/ + SHSamplerCache::RawSamplerHash SHSamplerCache::calcHash(vk::Filter minFilter, vk::Filter magFilter, vk::SamplerAddressMode addressMode, vk::SamplerMipmapMode mipmapMode, float minLod, float maxLod) + { + static auto charHasher = std::hash{}; + static auto floatHasher = std::hash{}; + + const RawSamplerHash H1 = charHasher(static_cast(minFilter)); + const RawSamplerHash H2 = charHasher(static_cast(magFilter)); + const RawSamplerHash H3 = charHasher(static_cast(addressMode)); + const RawSamplerHash H4 = charHasher(static_cast(mipmapMode)); + const RawSamplerHash H5 = floatHasher(minLod); + const RawSamplerHash H6 = floatHasher(maxLod); + + return H1 ^ (H2 << 1) ^ (H3 << 2) ^ (H4 << 3) ^ (H5 << 4) ^ (H6 << 5); + } +} diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHVkSamplerCache.h b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHVkSamplerCache.h new file mode 100644 index 00000000..c1529577 --- /dev/null +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHVkSamplerCache.h @@ -0,0 +1,80 @@ +/************************************************************************************//*! +\file SHSamplerCache.h +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Mar 16, 2022 +\brief Contains the interface for the SHSamplerCache class. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +// Standard Libraries +#include +// External Dependencies +#include "Graphics/SHVulkanIncludes.h" +// Project Includes +#include "Resource/Handle.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Forward Declarations */ + /*-----------------------------------------------------------------------------------*/ + class SHVkLogicalDevice; + class SHVkSampler; + struct SHVkSamplerParams; + + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + /*************************************************************************************/ + /*! + \brief + Class that is responsible for caching and providing Samplers to the user for + sampling textures. + */ + /*************************************************************************************/ + class SHSamplerCache + { + public: + /*---------------------------------------------------------------------------------*/ + /* Utility Functions */ + /*---------------------------------------------------------------------------------*/ + /// + /// Clears the cache, destroying all created samplers. + /// + void Clear(); + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + /// + /// Retrieves a Vulkan Sampler of the specified type. If this was retrieved + /// before, a cached copy of the Vulkan Sampler will be provided. + /// + /// Logical device to create the sampler with if needed. + /// Describes the parameters for the sampler. + /// Handle to the SHVkSampler object specified. + Handle GetSampler(Handle device, const SHVkSamplerParams& params); + + private: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + using RawSamplerHash = size_t; + + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + // Resources + std::unordered_map> samplersMap; + + /*---------------------------------------------------------------------------------*/ + /* Helper Functions */ + /*---------------------------------------------------------------------------------*/ + static RawSamplerHash calcHash(vk::Filter minFilter, vk::Filter magFilter, vk::SamplerAddressMode addressMode, vk::SamplerMipmapMode mipmapMode, float minLod, float maxLod); + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp index 25be112e..7a76447d 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp +++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp @@ -216,10 +216,13 @@ namespace SHADE /***************************************************************************/ void SHVkPipelineLayout::PrepareVkDescriptorSetLayouts(void) noexcept { + descriptorSetLayoutsPipeline.reserve(descriptorSetLayoutsAllocate.size() + descriptorSetLayoutsGlobal.size()); + // Settle allocate layouts first vkDescriptorSetLayoutsAllocate.reserve(descriptorSetLayoutsAllocate.size()); for (auto const& layout : descriptorSetLayoutsAllocate) { + descriptorSetLayoutsPipeline.emplace_back(layout); vkDescriptorSetLayoutsAllocate.emplace_back(layout->GetVkHandle()); } @@ -228,7 +231,10 @@ namespace SHADE // First we insert the global layouts for (auto const& layout : descriptorSetLayoutsGlobal) + { + descriptorSetLayoutsPipeline.emplace_back(layout); vkDescriptorSetLayoutsPipeline.emplace_back(layout->GetVkHandle()); + } // Then we append layouts for allocation at the back of the vector std::copy(vkDescriptorSetLayoutsAllocate.begin(), vkDescriptorSetLayoutsAllocate.end(), std::back_inserter(vkDescriptorSetLayoutsPipeline)); @@ -435,6 +441,16 @@ namespace SHADE return {}; } + std::vector> SHVkPipelineLayout::GetDescriptorSetLayoutsPipeline(void) const noexcept + { + return descriptorSetLayoutsPipeline; + } + + std::vector> SHVkPipelineLayout::GetDescriptorSetLayoutsAllocate(void) const noexcept + { + return descriptorSetLayoutsAllocate; + } + SHVkPipelineLayout& SHVkPipelineLayout::operator=(SHVkPipelineLayout&& rhs) noexcept { if (&rhs == this) diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h index e43ceb73..f5d363fa 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h +++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h @@ -42,6 +42,9 @@ namespace SHADE //! We want to store this also because we need to allocate later std::vector vkDescriptorSetLayoutsAllocate; + //! Store for descriptor set group creation + std::vector> descriptorSetLayoutsPipeline; + //! Store for pipeline layout recreation std::vector vkDescriptorSetLayoutsPipeline; @@ -71,10 +74,12 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ /*-----------------------------------------------------------------------*/ - std::vector> const& GetShaderModules (void) const noexcept; - vk::PipelineLayout GetVkPipelineLayout (void) const noexcept; - SHPushConstantInterface const& GetPushConstantInterface (void) const noexcept; - Handle GetShaderBlockInterface (uint32_t set, uint32_t binding, vk::ShaderStageFlagBits shaderStage) const noexcept; + std::vector> const& GetShaderModules (void) const noexcept; + vk::PipelineLayout GetVkPipelineLayout (void) const noexcept; + SHPushConstantInterface const& GetPushConstantInterface (void) const noexcept; + Handle GetShaderBlockInterface (uint32_t set, uint32_t binding, vk::ShaderStageFlagBits shaderStage) const noexcept; + std::vector> GetDescriptorSetLayoutsPipeline(void) const noexcept; + std::vector> GetDescriptorSetLayoutsAllocate(void) const noexcept; }; } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h b/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h new file mode 100644 index 00000000..dc21fa37 --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h @@ -0,0 +1,14 @@ +#pragma once + +namespace SHADE +{ + // Used for attachment description creation for renderpass node + enum class SH_ATT_DESC_TYPE + { + COLOR, + COLOR_PRESENT, + DEPTH, + STENCIL, + DEPTH_STENCIL, + }; +} diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp index 3f5641c0..828a83f1 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp @@ -11,655 +11,7 @@ namespace SHADE { - /***************************************************************************/ - /*! - - \brief - Non-default ctor for the resource. Using the type of the resource, we - decide whether or not we create a resource or link with a swapchain - resource (image). - - \param logicalDevice - Logical device required to create an image resource if the type is NOT - SH_ATT_DESC_TYPE::COLOR_PRESENT. - - \param swapchain - Swapchain required to get swapchain image if the type IS - SH_ATT_DESC_TYPE::COLOR_PRESENT. - - \param type - Type of the image resource. - - \param format - Format of the image resource. - - \param w - Width of the image resource. - - \param h - Height of the image resource. - - \param levels - Number of mipmap levels of the image resource. - - \param createFlags - Create flags used when an image resource needs to be created. - - */ - /***************************************************************************/ - SHRenderGraphResource::SHRenderGraphResource(Handle const& logicalDevice, Handle const& swapchain, std::string const& name, SH_ATT_DESC_TYPE type, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageCreateFlagBits createFlags) noexcept - : resourceType{ type } - , resourceFormat{ format } - , images{} - , imageViews{} - , width{ w } - , height{ h } - , mipLevels{ levels } - , resourceName{ name } - { - // If the resource type is an arbitrary image and not swapchain image - if (type != SH_ATT_DESC_TYPE::COLOR_PRESENT) - { - vk::ImageAspectFlags imageAspectFlags; - vk::ImageUsageFlags usage = {}; - - // Check the resource type and set image usage flags and image aspect flags accordingly - switch (resourceType) - { - case SH_ATT_DESC_TYPE::COLOR: - usage |= vk::ImageUsageFlagBits::eColorAttachment; - imageAspectFlags |= vk::ImageAspectFlagBits::eColor; - break; - case SH_ATT_DESC_TYPE::DEPTH: - usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; - imageAspectFlags |= vk::ImageAspectFlagBits::eDepth; - break; - case SH_ATT_DESC_TYPE::STENCIL: - usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; - imageAspectFlags |= vk::ImageAspectFlagBits::eStencil; - break; - case SH_ATT_DESC_TYPE::DEPTH_STENCIL: - usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; - imageAspectFlags |= vk::ImageAspectFlagBits::eStencil | vk::ImageAspectFlagBits::eDepth; - break; - } - - // The resource is not a swapchain image, just use the first slot of the vector - images.push_back(logicalDevice->CreateImage(width, height, mipLevels, resourceFormat, usage, createFlags)); - - // prepare image view details - SHImageViewDetails viewDetails - { - .viewType = vk::ImageViewType::e2D, - .format = images[0]->GetImageFormat(), - .imageAspectFlags = imageAspectFlags, - .baseMipLevel = 0, - .mipLevelCount = mipLevels, - .baseArrayLayer = 0, - .layerCount = 1, - }; - - // just 1 image view created - imageViews.push_back(images[0]->CreateImageView(logicalDevice, images[0], viewDetails)); - } - else // if swapchain image resource - { - // Prepare image view details - SHImageViewDetails viewDetails - { - .viewType = vk::ImageViewType::e2D, - .format = swapchain->GetSurfaceFormatKHR().format, - .imageAspectFlags = vk::ImageAspectFlagBits::eColor, - .baseMipLevel = 0, - .mipLevelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1, - }; - - // We want an image handle for every swapchain image - images.resize(swapchain->GetNumImages()); - imageViews.resize(swapchain->GetNumImages()); - - for (uint32_t i = 0; i < swapchain->GetNumImages(); ++i) - { - images[i] = swapchain->GetSwapchainImage(i); - imageViews[i] = images[i]->CreateImageView(logicalDevice, images[i], viewDetails); - } - } - } - - /***************************************************************************/ - /*! - - \brief - Move ctor for resource. - - \param rhs - The other resource. - - */ - /***************************************************************************/ - SHRenderGraphResource::SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept - : resourceName{ std::move(rhs.resourceName) } - , resourceType{ std::move(rhs.resourceType) } - , images{ std::move(rhs.images) } - , imageViews{ std::move(rhs.imageViews) } - , resourceFormat{ std::move(rhs.resourceFormat) } - , width{ rhs.width } - , height{ rhs.height } - , mipLevels{ rhs.mipLevels } - { - - } - - /***************************************************************************/ - /*! - - \brief - Move assignment operator. - - \param rhs - The other resource. - - \return - - */ - /***************************************************************************/ - SHRenderGraphResource& SHRenderGraphResource::operator=(SHRenderGraphResource&& rhs) noexcept - { - if (this == &rhs) - return *this; - - resourceName = std::move(rhs.resourceName); - resourceType = std::move(rhs.resourceType); - images = std::move(rhs.images); - imageViews = std::move(rhs.imageViews); - resourceFormat = std::move(rhs.resourceFormat); - width = rhs.width; - height = rhs.height; - mipLevels = rhs.mipLevels; - - return *this; - } - - /***************************************************************************/ - /*! - - \brief - Destructor for resource. - - */ - /***************************************************************************/ - SHRenderGraphResource::~SHRenderGraphResource(void) noexcept - { - - } - - /***************************************************************************/ - /*! - - \brief - Subpass non-default constructor. Simply initializes variables. - - \param mapping - Mapping from a resource handle to an attachment reference referencing - the resource. - - \param resources - A mapping from string to render graph resource. - - */ - /***************************************************************************/ - SHSubpass::SHSubpass(ResourceManager& rm, Handle const& parent, uint32_t index, std::unordered_map const* mapping, std::unordered_map> const* resources) noexcept - : resourceAttachmentMapping{ mapping } - , ptrToResources{ resources } - , parentNode{ parent } - , subpassIndex{ index } - , superBatch{} - , colorReferences{} - , depthReferences{} - , inputReferences{} - { - } - - /***************************************************************************/ - /*! - - \brief - Move constructor for subpass. - - \param rhs - The subpass the move from. - - */ - /***************************************************************************/ - SHSubpass::SHSubpass(SHSubpass&& rhs) noexcept - : subpassIndex{ std::move(rhs.subpassIndex) } - , parentNode{ std::move(rhs.parentNode) } - , superBatch{ std::move(rhs.superBatch) } - , colorReferences{ std::move(rhs.colorReferences) } - , depthReferences{ std::move(rhs.depthReferences) } - , inputReferences{ std::move(rhs.inputReferences) } - , resourceAttachmentMapping{ rhs.resourceAttachmentMapping } - , ptrToResources{ rhs.ptrToResources } - { - - } - - /***************************************************************************/ - /*! - - \brief - Move assignment operator for subpass. - - \param rhs - subpass to move from. - - */ - /***************************************************************************/ - SHSubpass& SHSubpass::operator=(SHSubpass&& rhs) noexcept - { - if (this == &rhs) - return *this; - - subpassIndex = std::move(rhs.subpassIndex); - parentNode = std::move(rhs.parentNode); - superBatch = std::move(rhs.superBatch); - colorReferences = std::move(rhs.colorReferences); - depthReferences = std::move(rhs.depthReferences); - inputReferences = std::move(rhs.inputReferences); - resourceAttachmentMapping = rhs.resourceAttachmentMapping; - ptrToResources = rhs.ptrToResources; - - return *this; - } - - /***************************************************************************/ - /*! - - \brief - Adds a color output to a subpass. Takes in a string and finds the - attachment index to create the vk::SubpassReference. - - \param resourceToReference - Resource name to find resource to attach. - - */ - /***************************************************************************/ - void SHSubpass::AddColorOutput(std::string resourceToReference) noexcept - { - colorReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eColorAttachmentOptimal }); - } - - /***************************************************************************/ - /*! - - \brief - Adds a depth output to a subpass. Takes in a string and finds the - attachment index to create the vk::SubpassReference. - - \param resourceToReference - Resource name to find resource to attach. - - \param attachmentDescriptionType - Depending on the type of the resource, initialize the image layout - appropriately. - - */ - /***************************************************************************/ - void SHSubpass::AddDepthOutput(std::string resourceToReference, SH_ATT_DESC_TYPE attachmentDescriptionType) noexcept - { - vk::ImageLayout imageLayout; - switch (attachmentDescriptionType) - { - case SH_ATT_DESC_TYPE::DEPTH: - imageLayout = vk::ImageLayout::eDepthAttachmentOptimal; - break; - case SH_ATT_DESC_TYPE::STENCIL: - imageLayout = vk::ImageLayout::eStencilAttachmentOptimal; - break; - case SH_ATT_DESC_TYPE::DEPTH_STENCIL: - imageLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal; - break; - default: - //Invalid - return; - } - depthReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), imageLayout }); - } - - /***************************************************************************/ - /*! - - \brief - Adds a input output to a subpass. Takes in a string and finds the - attachment index to create the vk::SubpassReference. - - \param resourceToReference - Resource name to find resource to attach. - - */ - /***************************************************************************/ - void SHSubpass::AddInput(std::string resourceToReference) noexcept - { - inputReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eShaderReadOnlyOptimal }); - } - - void SHSubpass::Execute(Handle& commandBuffer, uint32_t frameIndex) noexcept - { - // Ensure correct transforms are provided - superBatch->UpdateBuffers(frameIndex); - - // Draw all the batches - superBatch->Draw(commandBuffer, frameIndex); - - // Draw all the exterior draw calls - for (auto& drawCall : exteriorDrawCalls) - { - drawCall(commandBuffer); - } - } - - void SHSubpass::AddExteriorDrawCalls(std::function&)> const& newDrawCall) noexcept - { - exteriorDrawCalls.push_back(newDrawCall); - } - - void SHSubpass::Init(ResourceManager& resourceManager) noexcept - { - superBatch = resourceManager.Create(GetHandle()); - - } - - /***************************************************************************/ - /*! - - \brief - Getter for parent renderpass. - - \return - Returns the parent renderpass the subpass belongs to. - - */ - /***************************************************************************/ - Handle const& SHSubpass::GetParentNode(void) const noexcept - { - return parentNode; - } - - SHADE::SHSubPassIndex SHSubpass::GetIndex() const noexcept - { - return subpassIndex; - } - - Handle SHSubpass::GetSuperBatch(void) const noexcept - { - return superBatch; - } - - /***************************************************************************/ - /*! - - \brief - Creates a renderpass for the node. Uses subpass and attachment - descriptions already configured beforehand in the render graph. - - */ - /***************************************************************************/ - void SHRenderGraphNode::CreateRenderpass(void) noexcept - { - renderpass = logicalDeviceHdl->CreateRenderpass(attachmentDescriptions, spDescs, spDeps); - } - - /***************************************************************************/ - /*! - - \brief - Creates a framebuffer from the images used in the renderpass. - - */ - /***************************************************************************/ - void SHRenderGraphNode::CreateFramebuffer(void) noexcept - { - for (uint32_t i = 0; i < framebuffers.size(); ++i) - { - std::vector> imageViews(attResources.size()); - uint32_t fbWidth = std::numeric_limits::max(); - uint32_t fbHeight = std::numeric_limits::max(); - - for (uint32_t j = 0; j < attResources.size(); ++j) - { - uint32_t imageViewIndex = (attResources[j]->resourceType == SH_ATT_DESC_TYPE::COLOR_PRESENT) ? i : 0; - imageViews[j] = attResources[j]->imageViews[imageViewIndex]; - - // We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's - if (fbWidth > attResources[j]->width) - fbWidth = attResources[j]->width; - if (fbHeight > attResources[j]->height) - fbHeight = attResources[j]->height; - } - - - framebuffers[i] = logicalDeviceHdl->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight); - } - } - - /***************************************************************************/ - /*! - - \brief - Render Graph node constructor. Note that we do not create the renderpass - yet. This is because layouts of attachment descriptions facilitate image - transitions and we cannot know guarantee layouts until we've seen all - renderpasses and their subpasses in the graph. - - \param swapchain - Swapchain required to query number of images as parameters for number - of framebuffers to create. - - \param attachmentDescriptionTypes - - - \return - - */ - /***************************************************************************/ - SHRenderGraphNode::SHRenderGraphNode(ResourceManager& rm, Handle const& logicalDevice, Handle const& swapchain, std::vector> attRes, std::vector> predecessors, std::unordered_map> const* resources, Handle globalData) noexcept - : logicalDeviceHdl{ logicalDevice } - , renderpass{} - , framebuffers{} - , prereqNodes{ std::move(predecessors) } - , attachmentDescriptions{} - , resourceAttachmentMapping{} - , attResources{ std::move(attRes) } - , subpasses{} - , executed{ false } - , configured{ false } - , resourceManager{ rm } - , ptrToResources{ resources } - { - // pipeline library initialization - pipelineLibrary.Init(logicalDeviceHdl, globalData); - - attachmentDescriptions.resize(attResources.size()); - - bool containsSwapchainImage = false; - for (uint32_t i = 0; i < attResources.size(); ++i) - { - // As mentioned above we don't initialize much here because it's dependent on how other renderpasses are configured. - vk::AttachmentDescription& newDesc = attachmentDescriptions[i]; - newDesc.samples = vk::SampleCountFlagBits::e1; - - // We set this to clear first. If later we find out that some predecessor is writing to the same attachment, - // we set the pred's storeOp to eStore and "this" loadOp to eLoad. - newDesc.loadOp = vk::AttachmentLoadOp::eClear; - newDesc.storeOp = vk::AttachmentStoreOp::eStore; - - newDesc.stencilLoadOp = vk::AttachmentLoadOp::eClear; - newDesc.stencilStoreOp = vk::AttachmentStoreOp::eStore; - - newDesc.format = attResources[i]->resourceFormat; - - if (attResources[i]->resourceType == SH_ATT_DESC_TYPE::COLOR_PRESENT) - containsSwapchainImage = true; - - resourceAttachmentMapping.try_emplace(attResources[i].GetId().Raw, i); - } - - if (!containsSwapchainImage) - framebuffers.resize(1); - else - framebuffers.resize(swapchain->GetNumImages()); - - // At this point, we could configure framebuffers if we had the renderpass object but we don't so their creation has to be - // deferred to when renderpasses are also created. - } - - SHRenderGraphNode::SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept - : resourceManager{ rhs.resourceManager } - , logicalDeviceHdl{ rhs.logicalDeviceHdl } - , renderpass{ rhs.renderpass } - , framebuffers{ std::move(rhs.framebuffers) } - , prereqNodes{ std::move(rhs.prereqNodes) } - , attachmentDescriptions{ std::move(rhs.attachmentDescriptions) } - , attResources{ std::move(rhs.attResources) } - , subpasses{ std::move(rhs.subpasses) } - , resourceAttachmentMapping{ std::move(rhs.resourceAttachmentMapping) } - , subpassIndexing{ std::move(rhs.subpassIndexing) } - , configured{ rhs.configured } - , executed{ rhs.executed } - , ptrToResources{ rhs.ptrToResources } - , pipelineLibrary{ std::move(rhs.pipelineLibrary) } - , batcher { std::move(rhs.batcher) } - - { - rhs.renderpass = {}; - } - - SHRenderGraphNode& SHRenderGraphNode::operator=(SHRenderGraphNode&& rhs) noexcept - { - if (&rhs == this) - return *this; - - resourceManager = rhs.resourceManager; - logicalDeviceHdl = rhs.logicalDeviceHdl; - renderpass = rhs.renderpass; - framebuffers = std::move(rhs.framebuffers); - prereqNodes = std::move(rhs.prereqNodes); - attachmentDescriptions = std::move(rhs.attachmentDescriptions); - attResources = std::move(rhs.attResources); - subpasses = std::move(rhs.subpasses); - resourceAttachmentMapping = std::move(rhs.resourceAttachmentMapping); - subpassIndexing = std::move(rhs.subpassIndexing); - ptrToResources = std::move(rhs.ptrToResources); - pipelineLibrary = std::move(rhs.pipelineLibrary); - batcher = std::move(rhs.batcher); - - rhs.renderpass = {}; - - return *this; - } - - /***************************************************************************/ - /*! - - \brief - Add subpasses to the renderpass and returns a reference to it. - - \param subpassName - Name of the subpass. - - \return - Handle to the new subpass. - - */ - /***************************************************************************/ - Handle SHRenderGraphNode::AddSubpass(std::string subpassName) noexcept - { - // if subpass already exists, don't add. - if (subpassIndexing.contains(subpassName)) - { - SHLOG_ERROR("Subpass already exists."); - return{}; - } - - // Add subpass to container and create mapping for it - subpasses.emplace_back(resourceManager.Create(resourceManager, GetHandle(), subpasses.size(), &resourceAttachmentMapping, ptrToResources)); - subpassIndexing.try_emplace(subpassName, static_cast(subpasses.size()) - 1u); - Handle subpass = subpasses.back(); - subpass->Init(resourceManager); - - // Register the SuperBatch - batcher.RegisterSuperBatch(subpass->GetSuperBatch()); - - return subpass; - } - - void SHRenderGraphNode::Execute(Handle& commandBuffer, uint32_t frameIndex) noexcept - { - frameIndex = (framebuffers.size() > 1) ? frameIndex : 0; - commandBuffer->BeginRenderpass(renderpass, framebuffers[frameIndex]); - - for (uint32_t i = 0; i < subpasses.size(); ++i) - { - subpasses[i]->Execute(commandBuffer, frameIndex); - - // Go to next subpass if not last subpass - if (i != subpasses.size() - 1) - commandBuffer->NextSubpass(); - } - - commandBuffer->EndRenderpass(); - } - - Handle SHRenderGraphNode::GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept - { - // verify subpass exists - if (subpass->GetIndex() >= subpasses.size()) - { - SHLOG_ERROR("Subpass index passed in is not valid. RenderGraphNode does not have that many passes. "); - return {}; - } - - Handle pipeline = pipelineLibrary.GetDrawPipline(vsFsPair); - if (!pipeline) - { - pipeline = pipelineLibrary.CreateDrawPipeline - ( - vsFsPair, - renderpass, - subpass - ); - } - - return pipeline; - } - - void SHRenderGraphNode::FinaliseBatch(uint32_t frameIndex) - { - batcher.FinaliseBatches(logicalDeviceHdl, frameIndex); - } - - /***************************************************************************/ - /*! - - \brief - Get the renderpass from the node. - - \return - Handle to the renderpass. - - */ - /***************************************************************************/ - Handle SHRenderGraphNode::GetRenderpass(void) const noexcept - { - return renderpass; - } - - Handle SHRenderGraphNode::GetSubpass(std::string_view subpassName) const noexcept - { - return subpasses[subpassIndexing.at(subpassName.data())]; - } + /***************************************************************************/ /*! @@ -779,7 +131,7 @@ namespace SHADE attDesc.loadOp = vk::AttachmentLoadOp::eLoad; predAttDesc.storeOp = vk::AttachmentStoreOp::eStore; - // TODO: Stecil load and store + // TODO: Stencil load and store // When an image is done being used in a renderpass, the image layout will end up being the finalLayout // value of the attachment description. We want this to carry over to the next renderpass; specifically @@ -976,11 +328,10 @@ namespace SHADE */ /***************************************************************************/ - void SHRenderGraph::Init(Handle const& logicalDevice, Handle const& swapchain, Handle inGlobalData) noexcept + void SHRenderGraph::Init(Handle const& logicalDevice, Handle const& swapchain) noexcept { logicalDeviceHdl = logicalDevice; swapchainHdl = swapchain; - globalData = inGlobalData; } /***************************************************************************/ @@ -1012,7 +363,6 @@ namespace SHADE , nodes{ std::move(rhs.nodes) } , graphResources{ std::move(rhs.graphResources) } , resourceManager{ std::move(rhs.resourceManager) } - , globalData{ rhs.globalData } { } @@ -1028,7 +378,6 @@ namespace SHADE nodes = std::move(rhs.nodes); graphResources = std::move(rhs.graphResources); resourceManager = std::move(rhs.resourceManager); - globalData = rhs.globalData; return *this; } @@ -1086,7 +435,7 @@ namespace SHADE } } - nodes.emplace_back(resourceManager.Create(resourceManager, logicalDeviceHdl, swapchainHdl, std::move(resources), std::move(predecessors), &graphResources, globalData)); + nodes.emplace_back(resourceManager.Create(resourceManager, logicalDeviceHdl, swapchainHdl, std::move(resources), std::move(predecessors), &graphResources)); nodeIndexing.emplace(nodeName, static_cast(nodes.size()) - 1u); return nodes.at(nodeIndexing[nodeName]); } @@ -1114,20 +463,20 @@ namespace SHADE // TODO: The graph scope buffers were meant to bind vertex buffers and index buffers for meshes. Find a // better way to manage these - void SHRenderGraph::Execute(uint32_t frameIndex, Handle cmdBuffer) noexcept + void SHRenderGraph::Execute(uint32_t frameIndex, Handle cmdBuffer, Handle descPool) noexcept { // TODO: DON'T HARDCODE THIS cmdBuffer->SetViewportScissor(1920.0f, 1080.0f, 1920, 1080); for (auto& node : nodes) - node->Execute(cmdBuffer, frameIndex); + node->Execute(cmdBuffer, descPool, frameIndex); } - void SHRenderGraph::FinaliseBatch(uint32_t frameIndex) + void SHRenderGraph::FinaliseBatch(uint32_t frameIndex, Handle descPool) { for (auto& node : nodes) { - node->FinaliseBatch(frameIndex); + node->FinaliseBatch(frameIndex, descPool); } } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h index 91a2f1f5..8b5b2212 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h @@ -7,6 +7,12 @@ #include "Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h" #include "Graphics/MiddleEnd/Batching/SHSuperBatch.h" #include "../MiddleEnd/Batching/SHBatcher.h" +#include "SHRenderGraphNode.h" +#include "SHSubpass.h" +#include "SHRenderGraphResource.h" +#include "SHRenderGraphNode.h" +#include "SHSubpass.h" +#include "SHAttachmentDescriptionType.h" #include #include @@ -24,223 +30,6 @@ namespace SHADE class SHRenderGraphNode; class SHGraphicsGlobalData; - // Used for attachment description creation for renderpass node - enum class SH_ATT_DESC_TYPE - { - COLOR, - COLOR_PRESENT, - DEPTH, - STENCIL, - DEPTH_STENCIL, - }; - - - class SH_API SHRenderGraphResource - { - private: - /*-----------------------------------------------------------------------*/ - /* PRIVATE MEMBER VARIABLES */ - /*-----------------------------------------------------------------------*/ - //! Name of the resource - std::string resourceName; - - //! Used for initializing image layouts - SH_ATT_DESC_TYPE resourceType; - - //! The resource itself (this is a vector because if the resource happens - //! to be a swapchain image, then we need however many frames in flight). - //! However when it's not a swapchain image, we want this container to be size 1 - //! because writing to these images will not interfere with images in the previous - //! frame, unlike the swapchain image. - std::vector> images; - - //! Views to resources (vector because same rationale as images. see above). - std::vector> imageViews; - - //! Image format - vk::Format resourceFormat; - - //! width of the resource - uint32_t width; - - //! Height of the resource - uint32_t height; - - //! Number of mipmap levels - uint8_t mipLevels; - public: - /*-----------------------------------------------------------------------*/ - /* CTORS AND DTORS */ - /*-----------------------------------------------------------------------*/ - SHRenderGraphResource(Handle const& logicalDevice, Handle const& swapchain, std::string const& name, SH_ATT_DESC_TYPE type, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageCreateFlagBits createFlags) noexcept; - SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept; - SHRenderGraphResource& operator=(SHRenderGraphResource&& rhs) noexcept; - ~SHRenderGraphResource(void) noexcept; - - friend class SHRenderGraphNode; - friend class SHRenderGraph; - }; - - - class SH_API SHSubpass : public ISelfHandle - { - private: - /*---------------------------------------------------------------------*/ - /* PRIVATE MEMBER VARIABLES */ - /*---------------------------------------------------------------------*/ - //! The index of the subpass in the render graph - uint32_t subpassIndex; - - //! The parent renderpass that this subpass belongs to - Handle parentNode; - - //! - Handle superBatch; - - //! Color attachments - std::vector colorReferences; - - //! Depth attachments - std::vector depthReferences; - - //! Input attachments - std::vector inputReferences; - - //! For getting attachment reference indices using handles - std::unordered_map const* resourceAttachmentMapping; - - //! Pointer to resources in the render graph (for getting handle IDs) - std::unordered_map> const* ptrToResources; - - //! Sometimes there exists entities that we want to render onto a render target - //! but don't want it to come from the batching system. An example would be ImGUI. - //! For these entities we want to link a function from the outside and draw them - //! after we draw everything from the batch. Because of this, these draw calls - //! are always the last things drawn, so DO NOT USE THIS FUNCTIONALITY FOR ANYTHING - //! COMPLEX. - std::vector&)>> exteriorDrawCalls; - - public: - /*-----------------------------------------------------------------------*/ - /* CTORS AND DTORS */ - /*-----------------------------------------------------------------------*/ - SHSubpass(ResourceManager& rm, Handle const& parent, uint32_t index, std::unordered_map const* mapping, std::unordered_map> const* ptrToResources) noexcept; - SHSubpass(SHSubpass&& rhs) noexcept; - SHSubpass& operator=(SHSubpass&& rhs) noexcept; - - /*-----------------------------------------------------------------------*/ - /* PUBLIC MEMBER FUNCTIONS */ - /*-----------------------------------------------------------------------*/ - // Preparation functions - void AddColorOutput(std::string resourceToReference) noexcept; - void AddDepthOutput(std::string resourceToReference, SH_ATT_DESC_TYPE attachmentDescriptionType = SH_ATT_DESC_TYPE::DEPTH_STENCIL) noexcept; - void AddInput(std::string resourceToReference) noexcept; - - // Runtime functions - void Execute(Handle& commandBuffer, uint32_t frameIndex) noexcept; - void AddExteriorDrawCalls(std::function&)> const& newDrawCall) noexcept; - - void Init (ResourceManager& resourceManager) noexcept; - - /*-----------------------------------------------------------------------*/ - /* GETTERS AND SETTERS */ - /*-----------------------------------------------------------------------*/ - Handle const& GetParentNode(void) const noexcept; - SHSubPassIndex GetIndex() const noexcept; - Handle GetSuperBatch (void) const noexcept; - - - friend class SHRenderGraphNode; - friend class SHRenderGraph; - }; - - class SH_API SHRenderGraphNode : public ISelfHandle - { - private: - /*-----------------------------------------------------------------------*/ - /* PRIVATE MEMBER VARIABLES */ - /*-----------------------------------------------------------------------*/ - ResourceManager& resourceManager; - - //! For Vulkan object creation - Handle logicalDeviceHdl; - - //! Each node will have a renderpass and each renderpass will have its own subpasses. - //! These subpasses will execute sequentially. - Handle renderpass; - - //! Framebuffers used in this renderpass. If renderpass contains usage of a swapchain image - //! used for presenting, then we cannot use just 1 framebuffer, we need to have 1 for however many frames in flight. - std::vector> framebuffers; - - //! Nodes that must finish execution before this node is executed will be in this container - std::vector> prereqNodes; - - //! Container of Attachment descriptions - std::vector attachmentDescriptions; - - //! Resources used in this renderpass - std::vector> attResources; - - //! Vector of subpasses - std::vector> subpasses; - - //! Descriptions to pass to renderpass for renderpass creation. We want to keep this here because - std::vector spDescs; - - //! Subpass dependencies for renderpass creation - std::vector spDeps; - - //! For indexing resources fast - std::unordered_map resourceAttachmentMapping; - - //! For indexing subpasses - std::map subpassIndexing; - - //! Pointer to resources in the render graph (for getting handle IDs) - std::unordered_map> const* ptrToResources; - - //! Every renderpass will require a pipeline library that will contain pipelines compatible with this renderpass - SHPipelineLibrary pipelineLibrary; - - //! Whether or not the node has finished execution - bool executed; - - //! Whether or not the node has been configured already or not - bool configured; - - SHBatcher batcher; - - /*-----------------------------------------------------------------------*/ - /* PRIVATE MEMBER FUNCTIONS */ - /*-----------------------------------------------------------------------*/ - void CreateRenderpass (void) noexcept; - void CreateFramebuffer(void) noexcept; - - public: - /*-----------------------------------------------------------------------*/ - /* CTORS AND DTORS */ - /*-----------------------------------------------------------------------*/ - SHRenderGraphNode (ResourceManager& rm, Handle const& logicalDevice, Handle const& swapchain, std::vector> attRes, std::vector> predecessors, std::unordered_map> const* resources, Handle globalData) noexcept; - SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept; - SHRenderGraphNode& operator= (SHRenderGraphNode&& rhs) noexcept; - - /*-----------------------------------------------------------------------*/ - /* PUBLIC MEMBER FUNCTIONS */ - /*-----------------------------------------------------------------------*/ - Handle AddSubpass (std::string subpassName) noexcept; - // TODO: RemoveSubpass() - void Execute (Handle& commandBuffer, uint32_t frameIndex) noexcept; - Handle GetOrCreatePipeline (std::pair, Handle> const& vsFsPair, Handle subpass) noexcept; - void FinaliseBatch(uint32_t frameIndex); - - /*-----------------------------------------------------------------------*/ - /* SETTERS AND GETTERS */ - /*-----------------------------------------------------------------------*/ - Handle GetRenderpass (void) const noexcept; - Handle GetSubpass(std::string_view subpassName) const noexcept; - friend class SHRenderGraph; - }; class SH_API SHRenderGraph { @@ -272,9 +61,6 @@ namespace SHADE //! Resource library for graph handles ResourceManager resourceManager; - - //! Handle to global data - Handle globalData; public: /*-----------------------------------------------------------------------*/ @@ -288,12 +74,12 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ - void Init (Handle const& logicalDevice, Handle const& swapchain, Handle inGlobalData) noexcept; + void Init (Handle const& logicalDevice, Handle const& swapchain) noexcept; void AddResource (std::string resourceName, SH_ATT_DESC_TYPE type, uint32_t w = static_cast(-1), uint32_t h = static_cast(-1), vk::Format format = vk::Format::eB8G8R8A8Unorm, uint8_t levels = 1, vk::ImageCreateFlagBits createFlags = {}); Handle AddNode (std::string nodeName, std::initializer_list resourceNames, std::initializer_list predecessorNodes) noexcept; void Generate (void) noexcept; - void Execute (uint32_t frameIndex, Handle cmdBuffer) noexcept; - void FinaliseBatch(uint32_t frameIndex); + void Execute (uint32_t frameIndex, Handle cmdBuffer, Handle descPool) noexcept; + void FinaliseBatch(uint32_t frameIndex, Handle descPool); /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp new file mode 100644 index 00000000..b981225a --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp @@ -0,0 +1,276 @@ +#include "SHpch.h" +#include "SHRenderGraphNode.h" +#include "Graphics/Devices/SHVkLogicalDevice.h" +#include "Graphics/Images/SHVkImageView.h" +#include "Graphics/Swapchain/SHVkSwapchain.h" +#include "SHRenderGraphResource.h" +#include "SHSubpass.h" + +namespace SHADE +{ + + /***************************************************************************/ + /*! + + \brief + Creates a renderpass for the node. Uses subpass and attachment + descriptions already configured beforehand in the render graph. + + */ + /***************************************************************************/ + void SHRenderGraphNode::CreateRenderpass(void) noexcept + { + renderpass = logicalDeviceHdl->CreateRenderpass(attachmentDescriptions, spDescs, spDeps); + } + + /***************************************************************************/ + /*! + + \brief + Creates a framebuffer from the images used in the renderpass. + + */ + /***************************************************************************/ + void SHRenderGraphNode::CreateFramebuffer(void) noexcept + { + for (uint32_t i = 0; i < framebuffers.size(); ++i) + { + std::vector> imageViews(attResources.size()); + uint32_t fbWidth = std::numeric_limits::max(); + uint32_t fbHeight = std::numeric_limits::max(); + + for (uint32_t j = 0; j < attResources.size(); ++j) + { + uint32_t imageViewIndex = (attResources[j]->resourceType == SH_ATT_DESC_TYPE::COLOR_PRESENT) ? i : 0; + imageViews[j] = attResources[j]->imageViews[imageViewIndex]; + + // We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's + if (fbWidth > attResources[j]->width) + fbWidth = attResources[j]->width; + if (fbHeight > attResources[j]->height) + fbHeight = attResources[j]->height; + } + + + framebuffers[i] = logicalDeviceHdl->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight); + } + } + + /***************************************************************************/ + /*! + + \brief + Render Graph node constructor. Note that we do not create the renderpass + yet. This is because layouts of attachment descriptions facilitate image + transitions and we cannot know guarantee layouts until we've seen all + renderpasses and their subpasses in the graph. + + \param swapchain + Swapchain required to query number of images as parameters for number + of framebuffers to create. + + \param attachmentDescriptionTypes + + + \return + + */ + /***************************************************************************/ + SHRenderGraphNode::SHRenderGraphNode(ResourceManager& rm, Handle const& logicalDevice, Handle const& swapchain, std::vector> attRes, std::vector> predecessors, std::unordered_map> const* resources) noexcept + : logicalDeviceHdl{ logicalDevice } + , renderpass{} + , framebuffers{} + , prereqNodes{ std::move(predecessors) } + , attachmentDescriptions{} + , resourceAttachmentMapping{} + , attResources{ std::move(attRes) } + , subpasses{} + , executed{ false } + , configured{ false } + , resourceManager{ rm } + , ptrToResources{ resources } + { + // pipeline library initialization + pipelineLibrary.Init(logicalDeviceHdl); + + attachmentDescriptions.resize(attResources.size()); + + bool containsSwapchainImage = false; + for (uint32_t i = 0; i < attResources.size(); ++i) + { + // As mentioned above we don't initialize much here because it's dependent on how other renderpasses are configured. + vk::AttachmentDescription& newDesc = attachmentDescriptions[i]; + newDesc.samples = vk::SampleCountFlagBits::e1; + + // We set this to clear first. If later we find out that some predecessor is writing to the same attachment, + // we set the pred's storeOp to eStore and "this" loadOp to eLoad. + newDesc.loadOp = vk::AttachmentLoadOp::eClear; + newDesc.storeOp = vk::AttachmentStoreOp::eStore; + + newDesc.stencilLoadOp = vk::AttachmentLoadOp::eClear; + newDesc.stencilStoreOp = vk::AttachmentStoreOp::eStore; + + newDesc.format = attResources[i]->resourceFormat; + + if (attResources[i]->resourceType == SH_ATT_DESC_TYPE::COLOR_PRESENT) + containsSwapchainImage = true; + + resourceAttachmentMapping.try_emplace(attResources[i].GetId().Raw, i); + } + + if (!containsSwapchainImage) + framebuffers.resize(1); + else + framebuffers.resize(swapchain->GetNumImages()); + + // At this point, we could configure framebuffers if we had the renderpass object but we don't so their creation has to be + // deferred to when renderpasses are also created. + } + + SHRenderGraphNode::SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept + : resourceManager{ rhs.resourceManager } + , logicalDeviceHdl{ rhs.logicalDeviceHdl } + , renderpass{ rhs.renderpass } + , framebuffers{ std::move(rhs.framebuffers) } + , prereqNodes{ std::move(rhs.prereqNodes) } + , attachmentDescriptions{ std::move(rhs.attachmentDescriptions) } + , attResources{ std::move(rhs.attResources) } + , subpasses{ std::move(rhs.subpasses) } + , resourceAttachmentMapping{ std::move(rhs.resourceAttachmentMapping) } + , subpassIndexing{ std::move(rhs.subpassIndexing) } + , configured{ rhs.configured } + , executed{ rhs.executed } + , ptrToResources{ rhs.ptrToResources } + , pipelineLibrary{ std::move(rhs.pipelineLibrary) } + , batcher{ std::move(rhs.batcher) } + + { + rhs.renderpass = {}; + } + + SHRenderGraphNode& SHRenderGraphNode::operator=(SHRenderGraphNode&& rhs) noexcept + { + if (&rhs == this) + return *this; + + resourceManager = rhs.resourceManager; + logicalDeviceHdl = rhs.logicalDeviceHdl; + renderpass = rhs.renderpass; + framebuffers = std::move(rhs.framebuffers); + prereqNodes = std::move(rhs.prereqNodes); + attachmentDescriptions = std::move(rhs.attachmentDescriptions); + attResources = std::move(rhs.attResources); + subpasses = std::move(rhs.subpasses); + resourceAttachmentMapping = std::move(rhs.resourceAttachmentMapping); + subpassIndexing = std::move(rhs.subpassIndexing); + ptrToResources = std::move(rhs.ptrToResources); + pipelineLibrary = std::move(rhs.pipelineLibrary); + batcher = std::move(rhs.batcher); + + rhs.renderpass = {}; + + return *this; + } + + /***************************************************************************/ + /*! + + \brief + Add subpasses to the renderpass and returns a reference to it. + + \param subpassName + Name of the subpass. + + \return + Handle to the new subpass. + + */ + /***************************************************************************/ + Handle SHRenderGraphNode::AddSubpass(std::string subpassName) noexcept + { + // if subpass already exists, don't add. + if (subpassIndexing.contains(subpassName)) + { + SHLOG_ERROR("Subpass already exists."); + return{}; + } + + // Add subpass to container and create mapping for it + subpasses.emplace_back(resourceManager.Create(resourceManager, GetHandle(), subpasses.size(), &resourceAttachmentMapping, ptrToResources)); + subpassIndexing.try_emplace(subpassName, static_cast(subpasses.size()) - 1u); + Handle subpass = subpasses.back(); + subpass->Init(resourceManager); + + // Register the SuperBatch + batcher.RegisterSuperBatch(subpass->GetSuperBatch()); + + return subpass; + } + + void SHRenderGraphNode::Execute(Handle& commandBuffer, Handle descPool, uint32_t frameIndex) noexcept + { + frameIndex = (framebuffers.size() > 1) ? frameIndex : 0; + commandBuffer->BeginRenderpass(renderpass, framebuffers[frameIndex]); + + for (uint32_t i = 0; i < subpasses.size(); ++i) + { + subpasses[i]->Execute(commandBuffer, descPool, frameIndex); + + // Go to next subpass if not last subpass + if (i != subpasses.size() - 1) + commandBuffer->NextSubpass(); + } + + commandBuffer->EndRenderpass(); + } + + Handle SHRenderGraphNode::GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept + { + // verify subpass exists + if (subpass->GetIndex() >= subpasses.size()) + { + SHLOG_ERROR("Subpass index passed in is not valid. RenderGraphNode does not have that many passes. "); + return {}; + } + + Handle pipeline = pipelineLibrary.GetDrawPipline(vsFsPair); + if (!pipeline) + { + pipeline = pipelineLibrary.CreateDrawPipeline + ( + vsFsPair, + renderpass, + subpass + ); + } + + return pipeline; + } + + void SHRenderGraphNode::FinaliseBatch(uint32_t frameIndex, Handle descPool) + { + batcher.FinaliseBatches(logicalDeviceHdl, descPool, frameIndex); + } + + /***************************************************************************/ + /*! + + \brief + Get the renderpass from the node. + + \return + Handle to the renderpass. + + */ + /***************************************************************************/ + Handle SHRenderGraphNode::GetRenderpass(void) const noexcept + { + return renderpass; + } + + Handle SHRenderGraphNode::GetSubpass(std::string_view subpassName) const noexcept + { + return subpasses[subpassIndexing.at(subpassName.data())]; + } + +} \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h new file mode 100644 index 00000000..59b20271 --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h @@ -0,0 +1,110 @@ +#pragma once + +#include +#include +#include +#include +#include "SHAttachmentDescriptionType.h" +#include "Graphics/SHVulkanIncludes.h" +#include "SH_API.h" +#include "Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h" +#include "Graphics/MiddleEnd/Batching/SHBatcher.h" + +namespace SHADE +{ + class ResourceManager; + class SHVkFramebuffer; + class SHRenderGraphResource; + class SHVkLogicalDevice; + class SHVkRenderpass; + class SHVkDescriptorPool; + + class SH_API SHRenderGraphNode : public ISelfHandle + { + private: + /*-----------------------------------------------------------------------*/ + /* PRIVATE MEMBER VARIABLES */ + /*-----------------------------------------------------------------------*/ + ResourceManager& resourceManager; + + //! For Vulkan object creation + Handle logicalDeviceHdl; + + //! Each node will have a renderpass and each renderpass will have its own subpasses. + //! These subpasses will execute sequentially. + Handle renderpass; + + //! Framebuffers used in this renderpass. If renderpass contains usage of a swapchain image + //! used for presenting, then we cannot use just 1 framebuffer, we need to have 1 for however many frames in flight. + std::vector> framebuffers; + + //! Nodes that must finish execution before this node is executed will be in this container + std::vector> prereqNodes; + + //! Container of Attachment descriptions + std::vector attachmentDescriptions; + + //! Resources used in this renderpass + std::vector> attResources; + + //! Vector of subpasses + std::vector> subpasses; + + //! Descriptions to pass to renderpass for renderpass creation. We want to keep this here because + std::vector spDescs; + + //! Subpass dependencies for renderpass creation + std::vector spDeps; + + //! For indexing resources fast + std::unordered_map resourceAttachmentMapping; + + //! For indexing subpasses + std::map subpassIndexing; + + //! Pointer to resources in the render graph (for getting handle IDs) + std::unordered_map> const* ptrToResources; + + //! Every renderpass will require a pipeline library that will contain pipelines compatible with this renderpass + SHPipelineLibrary pipelineLibrary; + + //! Whether or not the node has finished execution + bool executed; + + //! Whether or not the node has been configured already or not + bool configured; + + SHBatcher batcher; + + /*-----------------------------------------------------------------------*/ + /* PRIVATE MEMBER FUNCTIONS */ + /*-----------------------------------------------------------------------*/ + void CreateRenderpass(void) noexcept; + void CreateFramebuffer(void) noexcept; + + public: + /*-----------------------------------------------------------------------*/ + /* CTORS AND DTORS */ + /*-----------------------------------------------------------------------*/ + SHRenderGraphNode(ResourceManager& rm, Handle const& logicalDevice, Handle const& swapchain, std::vector> attRes, std::vector> predecessors, std::unordered_map> const* resources) noexcept; + SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept; + SHRenderGraphNode& operator= (SHRenderGraphNode&& rhs) noexcept; + + /*-----------------------------------------------------------------------*/ + /* PUBLIC MEMBER FUNCTIONS */ + /*-----------------------------------------------------------------------*/ + Handle AddSubpass(std::string subpassName) noexcept; + // TODO: RemoveSubpass() + void Execute(Handle& commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; + Handle GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept; + void FinaliseBatch(uint32_t frameIndex, Handle descPool); + + /*-----------------------------------------------------------------------*/ + /* SETTERS AND GETTERS */ + /*-----------------------------------------------------------------------*/ + Handle GetRenderpass(void) const noexcept; + Handle GetSubpass(std::string_view subpassName) const noexcept; + friend class SHRenderGraph; + }; + +} diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp new file mode 100644 index 00000000..eb873b16 --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp @@ -0,0 +1,192 @@ +#include "SHpch.h" +#include "SHRenderGraphResource.h" +#include "Graphics/Devices/SHVkLogicalDevice.h" +#include "Graphics/Swapchain/SHVkSwapchain.h" + +namespace SHADE +{ + /***************************************************************************/ + /*! + + \brief + Non-default ctor for the resource. Using the type of the resource, we + decide whether or not we create a resource or link with a swapchain + resource (image). + + \param logicalDevice + Logical device required to create an image resource if the type is NOT + SH_ATT_DESC_TYPE::COLOR_PRESENT. + + \param swapchain + Swapchain required to get swapchain image if the type IS + SH_ATT_DESC_TYPE::COLOR_PRESENT. + + \param type + Type of the image resource. + + \param format + Format of the image resource. + + \param w + Width of the image resource. + + \param h + Height of the image resource. + + \param levels + Number of mipmap levels of the image resource. + + \param createFlags + Create flags used when an image resource needs to be created. + + */ + /***************************************************************************/ + SHRenderGraphResource::SHRenderGraphResource(Handle const& logicalDevice, Handle const& swapchain, std::string const& name, SH_ATT_DESC_TYPE type, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageCreateFlagBits createFlags) noexcept + : resourceType{ type } + , resourceFormat{ format } + , images{} + , imageViews{} + , width{ w } + , height{ h } + , mipLevels{ levels } + , resourceName{ name } + { + // If the resource type is an arbitrary image and not swapchain image + if (type != SH_ATT_DESC_TYPE::COLOR_PRESENT) + { + vk::ImageAspectFlags imageAspectFlags; + vk::ImageUsageFlags usage = {}; + + // Check the resource type and set image usage flags and image aspect flags accordingly + switch (resourceType) + { + case SH_ATT_DESC_TYPE::COLOR: + usage |= vk::ImageUsageFlagBits::eColorAttachment; + imageAspectFlags |= vk::ImageAspectFlagBits::eColor; + break; + case SH_ATT_DESC_TYPE::DEPTH: + usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; + imageAspectFlags |= vk::ImageAspectFlagBits::eDepth; + break; + case SH_ATT_DESC_TYPE::STENCIL: + usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; + imageAspectFlags |= vk::ImageAspectFlagBits::eStencil; + break; + case SH_ATT_DESC_TYPE::DEPTH_STENCIL: + usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; + imageAspectFlags |= vk::ImageAspectFlagBits::eStencil | vk::ImageAspectFlagBits::eDepth; + break; + } + + // The resource is not a swapchain image, just use the first slot of the vector + images.push_back(logicalDevice->CreateImage(width, height, mipLevels, resourceFormat, usage, createFlags)); + + // prepare image view details + SHImageViewDetails viewDetails + { + .viewType = vk::ImageViewType::e2D, + .format = images[0]->GetImageFormat(), + .imageAspectFlags = imageAspectFlags, + .baseMipLevel = 0, + .mipLevelCount = mipLevels, + .baseArrayLayer = 0, + .layerCount = 1, + }; + + // just 1 image view created + imageViews.push_back(images[0]->CreateImageView(logicalDevice, images[0], viewDetails)); + } + else // if swapchain image resource + { + // Prepare image view details + SHImageViewDetails viewDetails + { + .viewType = vk::ImageViewType::e2D, + .format = swapchain->GetSurfaceFormatKHR().format, + .imageAspectFlags = vk::ImageAspectFlagBits::eColor, + .baseMipLevel = 0, + .mipLevelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }; + + // We want an image handle for every swapchain image + images.resize(swapchain->GetNumImages()); + imageViews.resize(swapchain->GetNumImages()); + + for (uint32_t i = 0; i < swapchain->GetNumImages(); ++i) + { + images[i] = swapchain->GetSwapchainImage(i); + imageViews[i] = images[i]->CreateImageView(logicalDevice, images[i], viewDetails); + } + } + } + + /***************************************************************************/ + /*! + + \brief + Move ctor for resource. + + \param rhs + The other resource. + + */ + /***************************************************************************/ + SHRenderGraphResource::SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept + : resourceName{ std::move(rhs.resourceName) } + , resourceType{ std::move(rhs.resourceType) } + , images{ std::move(rhs.images) } + , imageViews{ std::move(rhs.imageViews) } + , resourceFormat{ std::move(rhs.resourceFormat) } + , width{ rhs.width } + , height{ rhs.height } + , mipLevels{ rhs.mipLevels } + { + + } + + /***************************************************************************/ + /*! + + \brief + Move assignment operator. + + \param rhs + The other resource. + + \return + + */ + /***************************************************************************/ + SHRenderGraphResource& SHRenderGraphResource::operator=(SHRenderGraphResource&& rhs) noexcept + { + if (this == &rhs) + return *this; + + resourceName = std::move(rhs.resourceName); + resourceType = std::move(rhs.resourceType); + images = std::move(rhs.images); + imageViews = std::move(rhs.imageViews); + resourceFormat = std::move(rhs.resourceFormat); + width = rhs.width; + height = rhs.height; + mipLevels = rhs.mipLevels; + + return *this; + } + + /***************************************************************************/ + /*! + + \brief + Destructor for resource. + + */ + /***************************************************************************/ + SHRenderGraphResource::~SHRenderGraphResource(void) noexcept + { + + } + +} \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h new file mode 100644 index 00000000..fcb16601 --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h @@ -0,0 +1,62 @@ +#pragma once + +#include +#include "SHAttachmentDescriptionType.h" +#include +#include "Resource/Handle.h" +#include "Graphics/SHVulkanIncludes.h" +#include "SH_API.h" + +namespace SHADE +{ + class SHVkImage; + class SHVkImageView; + class SHVkLogicalDevice; + class SHVkSwapchain; + + class SH_API SHRenderGraphResource + { + private: + /*-----------------------------------------------------------------------*/ + /* PRIVATE MEMBER VARIABLES */ + /*-----------------------------------------------------------------------*/ + //! Name of the resource + std::string resourceName; + + //! Used for initializing image layouts + SH_ATT_DESC_TYPE resourceType; + + //! The resource itself (this is a vector because if the resource happens + //! to be a swapchain image, then we need however many frames in flight). + //! However when it's not a swapchain image, we want this container to be size 1 + //! because writing to these images will not interfere with images in the previous + //! frame, unlike the swapchain image. + std::vector> images; + + //! Views to resources (vector because same rationale as images. see above). + std::vector> imageViews; + + //! Image format + vk::Format resourceFormat; + + //! width of the resource + uint32_t width; + + //! Height of the resource + uint32_t height; + + //! Number of mipmap levels + uint8_t mipLevels; + public: + /*-----------------------------------------------------------------------*/ + /* CTORS AND DTORS */ + /*-----------------------------------------------------------------------*/ + SHRenderGraphResource(Handle const& logicalDevice, Handle const& swapchain, std::string const& name, SH_ATT_DESC_TYPE type, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageCreateFlagBits createFlags) noexcept; + SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept; + SHRenderGraphResource& operator=(SHRenderGraphResource&& rhs) noexcept; + ~SHRenderGraphResource(void) noexcept; + + friend class SHRenderGraphNode; + friend class SHRenderGraph; + }; +} diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp new file mode 100644 index 00000000..007502dd --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp @@ -0,0 +1,210 @@ +#include "SHpch.h" +#include "SHSubpass.h" +#include "Graphics/MiddleEnd/Batching/SHSuperBatch.h" +#include "Graphics/Devices/SHVkLogicalDevice.h" + +namespace SHADE +{ + + /***************************************************************************/ + /*! + + \brief + Subpass non-default constructor. Simply initializes variables. + + \param mapping + Mapping from a resource handle to an attachment reference referencing + the resource. + + \param resources + A mapping from string to render graph resource. + + */ + /***************************************************************************/ + SHSubpass::SHSubpass(ResourceManager& rm, Handle const& parent, uint32_t index, std::unordered_map const* mapping, std::unordered_map> const* resources) noexcept + : resourceAttachmentMapping{ mapping } + , ptrToResources{ resources } + , parentNode{ parent } + , subpassIndex{ index } + , superBatch{} + , colorReferences{} + , depthReferences{} + , inputReferences{} + { + } + + /***************************************************************************/ + /*! + + \brief + Move constructor for subpass. + + \param rhs + The subpass the move from. + + */ + /***************************************************************************/ + SHSubpass::SHSubpass(SHSubpass&& rhs) noexcept + : subpassIndex{ std::move(rhs.subpassIndex) } + , parentNode{ std::move(rhs.parentNode) } + , superBatch{ std::move(rhs.superBatch) } + , colorReferences{ std::move(rhs.colorReferences) } + , depthReferences{ std::move(rhs.depthReferences) } + , inputReferences{ std::move(rhs.inputReferences) } + , resourceAttachmentMapping{ rhs.resourceAttachmentMapping } + , ptrToResources{ rhs.ptrToResources } + { + + } + + /***************************************************************************/ + /*! + + \brief + Move assignment operator for subpass. + + \param rhs + subpass to move from. + + */ + /***************************************************************************/ + SHSubpass& SHSubpass::operator=(SHSubpass&& rhs) noexcept + { + if (this == &rhs) + return *this; + + subpassIndex = std::move(rhs.subpassIndex); + parentNode = std::move(rhs.parentNode); + superBatch = std::move(rhs.superBatch); + colorReferences = std::move(rhs.colorReferences); + depthReferences = std::move(rhs.depthReferences); + inputReferences = std::move(rhs.inputReferences); + resourceAttachmentMapping = rhs.resourceAttachmentMapping; + ptrToResources = rhs.ptrToResources; + + return *this; + } + + /***************************************************************************/ + /*! + + \brief + Adds a color output to a subpass. Takes in a string and finds the + attachment index to create the vk::SubpassReference. + + \param resourceToReference + Resource name to find resource to attach. + + */ + /***************************************************************************/ + void SHSubpass::AddColorOutput(std::string resourceToReference) noexcept + { + colorReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eColorAttachmentOptimal }); + } + + /***************************************************************************/ + /*! + + \brief + Adds a depth output to a subpass. Takes in a string and finds the + attachment index to create the vk::SubpassReference. + + \param resourceToReference + Resource name to find resource to attach. + + \param attachmentDescriptionType + Depending on the type of the resource, initialize the image layout + appropriately. + + */ + /***************************************************************************/ + void SHSubpass::AddDepthOutput(std::string resourceToReference, SH_ATT_DESC_TYPE attachmentDescriptionType) noexcept + { + vk::ImageLayout imageLayout; + switch (attachmentDescriptionType) + { + case SH_ATT_DESC_TYPE::DEPTH: + imageLayout = vk::ImageLayout::eDepthAttachmentOptimal; + break; + case SH_ATT_DESC_TYPE::STENCIL: + imageLayout = vk::ImageLayout::eStencilAttachmentOptimal; + break; + case SH_ATT_DESC_TYPE::DEPTH_STENCIL: + imageLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal; + break; + default: + //Invalid + return; + } + depthReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), imageLayout }); + } + + /***************************************************************************/ + /*! + + \brief + Adds a input output to a subpass. Takes in a string and finds the + attachment index to create the vk::SubpassReference. + + \param resourceToReference + Resource name to find resource to attach. + + */ + /***************************************************************************/ + void SHSubpass::AddInput(std::string resourceToReference) noexcept + { + inputReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eShaderReadOnlyOptimal }); + } + + void SHSubpass::Execute(Handle& commandBuffer, Handle descPool, uint32_t frameIndex) noexcept + { + // Ensure correct transforms are provided + superBatch->UpdateBuffers(frameIndex, descPool); + + // Draw all the batches + superBatch->Draw(commandBuffer, frameIndex); + + // Draw all the exterior draw calls + for (auto& drawCall : exteriorDrawCalls) + { + drawCall(commandBuffer); + } + } + + void SHSubpass::AddExteriorDrawCalls(std::function&)> const& newDrawCall) noexcept + { + exteriorDrawCalls.push_back(newDrawCall); + } + + void SHSubpass::Init(ResourceManager& resourceManager) noexcept + { + superBatch = resourceManager.Create(GetHandle()); + + } + + /***************************************************************************/ + /*! + + \brief + Getter for parent renderpass. + + \return + Returns the parent renderpass the subpass belongs to. + + */ + /***************************************************************************/ + Handle const& SHSubpass::GetParentNode(void) const noexcept + { + return parentNode; + } + + SHADE::SHSubPassIndex SHSubpass::GetIndex() const noexcept + { + return subpassIndex; + } + + Handle SHSubpass::GetSuperBatch(void) const noexcept + { + return superBatch; + } +} \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h new file mode 100644 index 00000000..b8b8717f --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h @@ -0,0 +1,94 @@ +#pragma once + +#include "SHAttachmentDescriptionType.h" +#include +#include "SH_API.h" +#include "Resource/Handle.h" +#include "Graphics/SHVulkanIncludes.h" + + +namespace SHADE +{ + class SHRenderGraphNode; + class SHSuperBatch; + class SHRenderGraphResource; + class SHVkCommandBuffer; + class SHVkDescriptorSetLayout; + class SHVkDescriptorPool; + + class SH_API SHSubpass : public ISelfHandle + { + private: + /*---------------------------------------------------------------------*/ + /* PRIVATE MEMBER VARIABLES */ + /*---------------------------------------------------------------------*/ + //! The index of the subpass in the render graph + uint32_t subpassIndex; + + //! The parent renderpass that this subpass belongs to + Handle parentNode; + + //! + Handle superBatch; + + //! Descriptor set layout to hold attachments + Handle descriptorSetLayout; + + //! Color attachments + std::vector colorReferences; + + //! Depth attachments + std::vector depthReferences; + + //! Input attachments + std::vector inputReferences; + + //! For getting attachment reference indices using handles + std::unordered_map const* resourceAttachmentMapping; + + //! Pointer to resources in the render graph (for getting handle IDs) + std::unordered_map> const* ptrToResources; + + //! Sometimes there exists entities that we want to render onto a render target + //! but don't want it to come from the batching system. An example would be ImGUI. + //! For these entities we want to link a function from the outside and draw them + //! after we draw everything from the batch. Because of this, these draw calls + //! are always the last things drawn, so DO NOT USE THIS FUNCTIONALITY FOR ANYTHING + //! COMPLEX. + std::vector&)>> exteriorDrawCalls; + + + public: + /*-----------------------------------------------------------------------*/ + /* CTORS AND DTORS */ + /*-----------------------------------------------------------------------*/ + SHSubpass(ResourceManager& rm, Handle const& parent, uint32_t index, std::unordered_map const* mapping, std::unordered_map> const* ptrToResources) noexcept; + SHSubpass(SHSubpass&& rhs) noexcept; + SHSubpass& operator=(SHSubpass&& rhs) noexcept; + + /*-----------------------------------------------------------------------*/ + /* PUBLIC MEMBER FUNCTIONS */ + /*-----------------------------------------------------------------------*/ + // Preparation functions + void AddColorOutput(std::string resourceToReference) noexcept; + void AddDepthOutput(std::string resourceToReference, SH_ATT_DESC_TYPE attachmentDescriptionType = SH_ATT_DESC_TYPE::DEPTH_STENCIL) noexcept; + void AddInput(std::string resourceToReference) noexcept; + + // Runtime functions + void Execute(Handle& commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; + void AddExteriorDrawCalls(std::function&)> const& newDrawCall) noexcept; + + void Init(ResourceManager& resourceManager) noexcept; + + /*-----------------------------------------------------------------------*/ + /* GETTERS AND SETTERS */ + /*-----------------------------------------------------------------------*/ + Handle const& GetParentNode(void) const noexcept; + SHSubPassIndex GetIndex() const noexcept; + Handle GetSuperBatch(void) const noexcept; + + + friend class SHRenderGraphNode; + friend class SHRenderGraph; + }; +} diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.cpp new file mode 100644 index 00000000..ccd0e6c3 --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.cpp @@ -0,0 +1,23 @@ +#include "SHpch.h" +#include "SHSubpassCompute.h" +#include "Graphics/Pipeline/SHVkPipeline.h" +#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" +#include "Graphics/Descriptors/SHVkDescriptorPool.h" + +namespace SHADE +{ + SHSubpassCompute::SHSubpassCompute(Handle inPipeline, Handle descPool) noexcept + : pipeline {inPipeline} + { + // Get the descriptor set layouts required to allocate. we will bind a different pipeline layout, one that includes the layout for global. + auto const& layouts = pipeline->GetPipelineLayout()->GetDescriptorSetLayoutsAllocate(); + + // Variable counts for the descriptor sets (all should be 1). + std::vector variableCounts{static_cast(layouts.size())}; + std::fill (variableCounts.begin(), variableCounts.end(), 0); + + // Allocate descriptor sets to hold the images for reading (STORAGE_IMAGE) + descPool->Allocate(layouts, variableCounts); + } + +} diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.h b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.h new file mode 100644 index 00000000..3ebc5676 --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +namespace SHADE +{ + class SHVkPipeline; + class SHVkDescriptorSetGroup; + class SHVkDescriptorPool; + + class SHSubpassCompute + { + private: + //! To run the dispatch command + Handle pipeline; + + //! Descriptor set group + Handle descSetGroup; + + public: + SHSubpassCompute (Handle inPipeline, Handle descPool) noexcept; + + }; +} + diff --git a/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.h b/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.h index afed0736..b0ae7445 100644 --- a/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.h +++ b/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.h @@ -10,10 +10,6 @@ namespace SHADE { class SHVkLogicalDevice; class SHVkFramebuffer; - /*-----------------------------------------------------------------------*/ - /* TYPE DEFINTIIONS */ - /*-----------------------------------------------------------------------*/ - using SHSubPassIndex = uint32_t; class SHVkRenderpass { diff --git a/SHADE_Engine/src/Graphics/SHVulkanDefines.h b/SHADE_Engine/src/Graphics/SHVulkanDefines.h index 2f625f7e..1cbcae0f 100644 --- a/SHADE_Engine/src/Graphics/SHVulkanDefines.h +++ b/SHADE_Engine/src/Graphics/SHVulkanDefines.h @@ -5,9 +5,13 @@ namespace SHADE { + /*-----------------------------------------------------------------------*/ + /* TYPE DEFINTIIONS */ + /*-----------------------------------------------------------------------*/ using SHQueueFamilyIndex = uint32_t; using BindingAndSetHash = uint64_t; using SetIndex = uint32_t; + using SHSubPassIndex = uint32_t; } diff --git a/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.cpp b/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.cpp index 7ed50c59..75ede865 100644 --- a/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.cpp +++ b/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.cpp @@ -27,7 +27,7 @@ namespace SHADE SHADE::SHShaderBlockInterface::Variable const* const SHShaderBlockInterface::GetVariable(uint32_t index) const noexcept { - if (variableIndexing.size() < index) + if (index < variableIndexing.size()) return &variables.at(index); return nullptr; diff --git a/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.h b/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.h index ee7e7726..e546b452 100644 --- a/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.h +++ b/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.h @@ -2,10 +2,12 @@ #include +#include "SH_API.h" + namespace SHADE { - class SHShaderBlockInterface + class SH_API SHShaderBlockInterface { public: struct Variable diff --git a/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp b/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp index 1e5fb074..41327988 100644 --- a/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp +++ b/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp @@ -111,6 +111,7 @@ namespace SHADE biggestAlignment = std::max(biggestAlignment, 4u); break; case SpvOp::SpvOpTypeStruct: + case SpvOp::SpvOpTypeRuntimeArray: recurseForInfo(&member, interfaceHdl, member.offset, biggestAlignment, parentVarName + std::string(member.name) + "."); break; } diff --git a/SHADE_Engine/src/Resource/Handle.h b/SHADE_Engine/src/Resource/Handle.h index a0272290..9579063c 100644 --- a/SHADE_Engine/src/Resource/Handle.h +++ b/SHADE_Engine/src/Resource/Handle.h @@ -54,7 +54,7 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Usage Functions */ /*-----------------------------------------------------------------------------*/ - inline Id GetId() const; + inline Id GetId() const noexcept; /*-----------------------------------------------------------------------------*/ /* Overloaded Operators */ @@ -62,7 +62,7 @@ namespace SHADE /// /// Converts to true if this is a valid Handle. /// - inline operator bool() const; + inline operator bool() const noexcept; protected: /*-----------------------------------------------------------------------------*/ @@ -101,6 +101,7 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Overloaded Operators */ /*-----------------------------------------------------------------------------*/ + inline bool operator==(const Handle& rhs) const noexcept; /// /// Returns the underlying object pointed to by the Handle. /// diff --git a/SHADE_Engine/src/Resource/Handle.hpp b/SHADE_Engine/src/Resource/Handle.hpp index 27cdd1cd..45468ec1 100644 --- a/SHADE_Engine/src/Resource/Handle.hpp +++ b/SHADE_Engine/src/Resource/Handle.hpp @@ -8,15 +8,15 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* HandleBase - Usage Functions */ /*---------------------------------------------------------------------------------*/ - inline HandleBase::Id HandleBase::GetId() const + inline HandleBase::Id HandleBase::GetId() const noexcept { return id; } /*---------------------------------------------------------------------------------*/ /* HandleBase - Overloaded Operators */ - inline HandleBase::operator bool() const /*---------------------------------------------------------------------------------*/ + inline HandleBase::operator bool() const noexcept { return id.Raw != INVALID_ID.Raw; } @@ -33,6 +33,12 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* Handle - Overloaded Operators */ /*---------------------------------------------------------------------------------*/ + template + bool SHADE::Handle::operator==(const Handle& rhs) const noexcept + { + return id.Raw == rhs.id.Raw && library == rhs.library; + } + template T& Handle::operator*() { diff --git a/TempShaderFolder/TestCubeFs.glsl b/TempShaderFolder/TestCubeFs.glsl index 7d49eda4..3a25ad71 100644 --- a/TempShaderFolder/TestCubeFs.glsl +++ b/TempShaderFolder/TestCubeFs.glsl @@ -1,72 +1,44 @@ #version 450 #extension GL_ARB_separate_shader_objects : enable #extension GL_ARB_shading_language_420pack : enable +#extension GL_EXT_nonuniform_qualifier : require + +struct MatPropData +{ + vec4 color; + int textureIndex; + float alpha; + vec3 beta; +}; layout(location = 0) in struct { - //mat3 BTN; vec4 vertColor; - //vec3 localSpacePosition; - //vec2 uv; - //vec3 localLightPosition; - //vec3 localEyePosition; + vec2 uv; } In; -//layout(std140, push_constant) uniform TestPushConstant -//{ -// mat4 pvMat; -// vec4 lightPosition; -// vec4 eyePosition; -// vec4 ambientColor; -// vec4 lightColor; -// -//} testPushConstant; +// material stuff +layout(location = 2) flat in struct +{ + int materialIndex; +} In2; + +//layout (set = 0, binding = ) + +layout (set = 0, binding = 1) uniform sampler2D textures[]; // for textures (global) +layout (set = 3, binding = 0) buffer MaterialProperties // For materials +{ + MatPropData data[]; +} MatProp; layout(location = 0) out vec4 outColor; -//layout(binding = 0) uniform sampler2D diffuseMap; -//layout(binding = 1) uniform sampler2D normalMap; -//layout(binding = 2) uniform sampler2D aoMap; -//layout(binding = 3) uniform sampler2D glossinessMap; -//layout(binding = 4) uniform sampler2D samplerRoughnessMap; - void main() { - //vec3 normal; - //// Get the tangent space normal from normal map. It is a BC5 texture and therefore only use red and green - //normal.xy = (texture (normalMap, In.uv).gr * 2.0f) - 1.0f; + outColor = texture(textures[nonuniformEXT(MatProp.data[In2.materialIndex].textureIndex)], In.uv) + + MatProp.data[In2.materialIndex].color / MatProp.data[In2.materialIndex].alpha; - //// z value is derived (TODO: Find out what this does) - //normal.z = sqrt(1.0f - dot(normal.xy, normal.xy)); - - //// Transform the normal from tangent space to local space - //normal = In.BTN * normal; - - //// Get the vector from fragment to light - //vec3 localLightDir = normalize(In.localLightPosition - In.localSpacePosition); - - //// get the value of dot between normal from texture and frag to light - //float diffuse = max(0, dot(normal, localLightDir)); - - //// sample the diffuse texture - //vec4 diffuseColor = texture (diffuseMap, In.uv) * In.vertColor; - - //vec3 eyeDirection = normalize(In.localSpacePosition - In.localEyePosition); - - //const float shininess = mix(1, 100, 1 - texture (samplerRoughnessMap, In.uv).r); - - //float specular = pow(max(0, dot(normal, normalize(localLightDir - eyeDirection))), shininess); - - //outColor.rgb = testPushConstant.ambientColor.rgb * diffuseColor.rgb * texture (aoMap, In.uv).rgb; - - //outColor.rgb += testPushConstant.lightColor.rgb * (specular.rrr * 0.4 + diffuse.rrr * diffuseColor.rgb); - - //const float gamma = testPushConstant.eyePosition.w; - //outColor.rgb = pow(outColor.rgb, vec3(1.0f / gamma)); - //outColor.a = diffuseColor.a; - - - outColor = vec4 (1.0f); + //outColor = vec4 (1.0f); } \ No newline at end of file diff --git a/TempShaderFolder/TestCubeFs.spv b/TempShaderFolder/TestCubeFs.spv index 669dc8b8..07f67a45 100644 Binary files a/TempShaderFolder/TestCubeFs.spv and b/TempShaderFolder/TestCubeFs.spv differ diff --git a/TempShaderFolder/TestCubeVs.glsl b/TempShaderFolder/TestCubeVs.glsl index b2d52104..eb5b2dff 100644 --- a/TempShaderFolder/TestCubeVs.glsl +++ b/TempShaderFolder/TestCubeVs.glsl @@ -9,27 +9,20 @@ layout(location = 2) in vec3 aNormal; layout(location = 3) in vec3 aTangent; layout(location = 4) in mat4 worldTransform; -//layout(std140, push_constant) uniform TestPushConstant -//{ -// mat4 pvMat; -// vec4 lightPosition; -// vec4 eyePosition; -// vec4 ambientColor; -// vec4 lightColor; -// -//} testPushConstant; layout(location = 0) out struct { - //mat3 BTN; - vec4 vertColor; - //vec3 localSpacePosition; - //vec2 uv; - //vec3 localLightPosition; - //vec3 localEyePosition; + vec4 vertColor; // location 0 + vec2 uv; // location = 1 } Out; +// material stuff +layout(location = 2) out struct +{ + int materialIndex; +} Out2; + layout(set = 2, binding = 0) uniform CameraData { vec4 position; @@ -38,25 +31,8 @@ layout(set = 2, binding = 0) uniform CameraData void main() { - //const float gamma = testPushConstant.eyePosition.w; - //mat4 W2L = inverse(worldTransform); - - //// Since attributes are instanced we want the local positions of light and eye (camera) - //Out.localLightPosition = vec3(W2L * vec4(testPushConstant.lightPosition.xyz, 1.0f)); - //Out.localEyePosition = vec3(W2L * vec4(testPushConstant.eyePosition.xyz, 1.0f)); - - //vec3 biTangent = normalize(cross(aNormal, aTangent)); - - //gl_Position = testPushConstant.pvMat * worldTransform * vec4(aVertexPos, 1.0); - - //// Since the normal we are sampling is in tangent space, we want to later convert them to local space - //// so we need this matrix to multiply with the sampled texel of the normal map. - //Out.BTN = mat3(aTangent, biTangent, aNormal); - //Out.localSpacePosition = aVertexPos; - //Out.uv = aUV; - - // render NDC first - //gl_Position = vec4(aVertexPos, 1.0f); + Out.uv = aUV; + Out2.materialIndex = gl_InstanceIndex; gl_Position = cameraData.vpMat * worldTransform * vec4 (aVertexPos, 1.0f); Out.vertColor = vec4 (aVertexPos, 1.0f); } \ No newline at end of file diff --git a/TempShaderFolder/TestCubeVs.spv b/TempShaderFolder/TestCubeVs.spv index eb9a1209..dfc9eda1 100644 Binary files a/TempShaderFolder/TestCubeVs.spv and b/TempShaderFolder/TestCubeVs.spv differ