Merge pull request #65 from SHADE-DP/SP3-1-Rendering

Rendering merge
This commit is contained in:
XiaoQiDigipen 2022-09-28 20:42:03 +08:00 committed by GitHub
commit c963f1d978
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
62 changed files with 2000 additions and 1207 deletions

Binary file not shown.

View File

@ -84,6 +84,7 @@ namespace Sandbox
SHADE::SHAssetManager::LoadDataTemp("../../Assets/racoon.gltf"); SHADE::SHAssetManager::LoadDataTemp("../../Assets/racoon.gltf");
SHADE::SHAssetManager::LoadDataTemp("../../Assets/RaccoonBag_Color_Ver4.dds"); SHADE::SHAssetManager::LoadDataTemp("../../Assets/RaccoonBag_Color_Ver4.dds");
SHADE::SHAssetManager::LoadDataTemp("../../Assets/RaccoonPreTexturedVer1_Base9.dds"); SHADE::SHAssetManager::LoadDataTemp("../../Assets/RaccoonPreTexturedVer1_Base9.dds");
SHADE::SHAssetManager::LoadDataTemp("../../Assets/TD_Checker_Base_Color.dds");
//TODO: REMOVE AFTER PRESENTATION //TODO: REMOVE AFTER PRESENTATION
//SHADE::SHSystemManager::RegisterRoutine<SHADE::SHAudioSystem, SHADE::SHAudioSystem::AudioRoutine>(); //SHADE::SHSystemManager::RegisterRoutine<SHADE::SHAudioSystem, SHADE::SHAudioSystem::AudioRoutine>();

View File

@ -9,6 +9,7 @@
#include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h" #include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h"
#include "Scripting/SHScriptEngine.h" #include "Scripting/SHScriptEngine.h"
#include "Math/Transform/SHTransformComponent.h" #include "Math/Transform/SHTransformComponent.h"
#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h"
#include "Assets/SHAssetManager.h" #include "Assets/SHAssetManager.h"
@ -57,70 +58,103 @@ namespace Sandbox
} }
graphicsSystem->BuildMeshBuffers(); graphicsSystem->BuildMeshBuffers();
//Test Textures // Load Textures
auto textures{ SHADE::SHAssetManager::GetAllTextures() }; auto textures = SHADE::SHAssetManager::GetAllTextures();
std::vector<Handle<SHTexture>> texHandles;
for (const auto& tex : textures)
{
auto texture = graphicsSystem->Add(tex);
texHandles.push_back(texture);
}
graphicsSystem->BuildTextures();
// Create Materials // Create Materials
auto matInst = graphicsSystem->AddOrGetBaseMaterialInstance(); 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 // Create Stress Test Objects
static const SHVec3 TEST_OBJ_SCALE = { 0.2f, 0.2f, 0.2f }; static const SHVec3 TEST_OBJ_SCALE = { 0.05f, 0.05f, 0.05f };
constexpr int NUM_ROWS = 1; constexpr int NUM_ROWS = 100;
constexpr int NUM_COLS = 1; constexpr int NUM_COLS = 100;
static const SHVec3 TEST_OBJ_SPACING = { 1.0f, 1.0f, 1.0f }; 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 ), 0.0f, 0.0f }; static const SHVec3 TEST_OBJ_START_POS = { - (NUM_COLS / 2 * TEST_OBJ_SPACING.x ) + 1.0f, -2.0f, -1.0f };
//for (int z = 0; z < NUM_ROWS; ++z)
//for (int x = 0; x < NUM_COLS; ++x)
//{
// auto entity = SHEntityManager::CreateEntity<SHRenderable, SHTransformComponent>();
// auto& renderable = *SHComponentManager::GetComponent_s<SHRenderable>(entity);
// auto& transform = *SHComponentManager::GetComponent_s<SHTransformComponent>(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);
//}
for (int y = 0; y < NUM_ROWS; ++y)
for (int x = 0; x < NUM_COLS; ++x)
{
auto entity = SHEntityManager::CreateEntity<SHRenderable, SHTransformComponent>(); auto entity = SHEntityManager::CreateEntity<SHRenderable, SHTransformComponent>();
auto& renderable = *SHComponentManager::GetComponent_s<SHRenderable>(entity); auto& renderable = *SHComponentManager::GetComponent_s<SHRenderable>(entity);
auto& transform = *SHComponentManager::GetComponent_s<SHTransformComponent>(entity); auto& transform = *SHComponentManager::GetComponent_s<SHTransformComponent>(entity);
renderable.Mesh = handles.front(); 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); stressTestObjects.emplace_back(entity);
}
auto entity = SHEntityManager::CreateEntity<SHRenderable, SHTransformComponent>();
auto& renderable = *SHComponentManager::GetComponent_s<SHRenderable>(entity);
auto& transform = *SHComponentManager::GetComponent_s<SHTransformComponent>(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<SHRenderable, SHTransformComponent>();
//auto& renderable = *SHComponentManager::GetComponent_s<SHRenderable>(entity);
//auto& transform = *SHComponentManager::GetComponent_s<SHTransformComponent>(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 // Create blank entity with a script
testObj = SHADE::SHEntityManager::CreateEntity(); //testObj = SHADE::SHEntityManager::CreateEntity<SHRenderable, SHTransformComponent>();
//auto& testObjRenderable = *SHComponentManager::GetComponent_s<SHRenderable>(testObj);
//testObjRenderable.Mesh = CUBE_MESH;
//testObjRenderable.SetMaterial(matInst);
SHADE::SHScriptEngine* scriptEngine = static_cast<SHADE::SHScriptEngine*>(SHADE::SHSystemManager::GetSystem<SHADE::SHScriptEngine>()); SHADE::SHScriptEngine* scriptEngine = static_cast<SHADE::SHScriptEngine*>(SHADE::SHSystemManager::GetSystem<SHADE::SHScriptEngine>());
scriptEngine->AddScript(testObj, "TestScript"); scriptEngine->AddScript(testObj, "TestScript");
} }
void SBTestScene::Update(float dt) void SBTestScene::Update(float dt)
{ {
/*static float rotation = 0.0f; static float rotation = 0.0f;
auto& transform = *SHADE::SHComponentManager::GetComponent_s<SHADE::SHTransformComponent>(testObj); //auto& transform = *SHADE::SHComponentManager::GetComponent_s<SHADE::SHTransformComponent>(testObj);
transform.SetLocalRotation(rotation, 0.0f, 0.0f); //transform.SetWorldPosition({1.0f, 1.0f, -1.0f});
rotation += dt * 10.0f;*/ //transform.SetWorldRotation(0.0f, 0.0f + rotation, 0.0f);
/*static float rotation = 0.0f; //rotation += dt * 0.2f;
auto& transform = *SHADE::SHComponentManager::GetComponent_s<SHADE::SHTransformComponent>(stressTestObjects[0]);
transform.SetWorldPosition({rotation, 0.0f, 0.0f});
rotation += dt * 10.0f;*/
// Destroy entity if space is pressed // Destroy entity if space is pressed
if (GetKeyState(VK_SPACE) & 0x8000) if (GetKeyState(VK_SPACE) & 0x8000)
{ {
rotation = 0.0f;
SHADE::SHScriptEngine* scriptEngine = static_cast<SHADE::SHScriptEngine*>(SHADE::SHSystemManager::GetSystem<SHADE::SHScriptEngine>()); SHADE::SHScriptEngine* scriptEngine = static_cast<SHADE::SHScriptEngine*>(SHADE::SHSystemManager::GetSystem<SHADE::SHScriptEngine>());
scriptEngine->RemoveAllScripts(testObj); scriptEngine->RemoveAllScripts(testObj);
} }
@ -128,6 +162,7 @@ namespace Sandbox
void SBTestScene::Render() void SBTestScene::Render()
{ {
} }
void SBTestScene::Unload() void SBTestScene::Unload()

View File

@ -133,6 +133,9 @@ project "SHADE_Engine"
"xcopy /r /y /q \"%{IncludeDir.fmod}\\lib\\fmodstudio.dll\" \"$(OutDir)\"" "xcopy /r /y /q \"%{IncludeDir.fmod}\\lib\\fmodstudio.dll\" \"$(OutDir)\""
} }
filter "configurations:Publish"
postbuildcommands {"xcopy /r /y /q \"%{IncludeDir.assimp}\\bin\\Release\\assimp-vc142-mt.dll\" \"$(OutDir)\""}
warnings 'Extra' warnings 'Extra'
filter "configurations:Debug" filter "configurations:Debug"

View File

@ -2,16 +2,17 @@
#include <vector> #include <vector>
#include "Math/SHMath.h" #include "Math/SHMath.h"
#include "SH_API.h"
namespace SHADE namespace SHADE
{ {
struct SHMeshAssetHeader struct SH_API SHMeshAssetHeader
{ {
uint32_t vertexCount; uint32_t vertexCount;
uint32_t indexCount; uint32_t indexCount;
}; };
struct SHMeshAsset struct SH_API SHMeshAsset
{ {
bool compiled; bool compiled;
bool changed; bool changed;

View File

@ -74,12 +74,12 @@ namespace SHADE
for (auto i{0}; i < file.GetMipCount(); ++i) for (auto i{0}; i < file.GetMipCount(); ++i)
{ {
mipOff.push_back(totalBytes); mipOff[i] = totalBytes;
totalBytes += file.GetImageData(i, 0)->m_memSlicePitch; totalBytes += file.GetImageData(i, 0)->m_memSlicePitch;
} }
SHTexture::PixelChannel* pixel = new SHTexture::PixelChannel[totalBytes]; 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<SHTexture::PixelChannel const*>(file.GetDDSData())); //pixel = std::move(reinterpret_cast<SHTexture::PixelChannel const*>(file.GetDDSData()));
asset.numBytes = totalBytes; asset.numBytes = totalBytes;

View File

@ -39,8 +39,10 @@ namespace SHADE
std::vector<vk::DescriptorPoolSize> Limits = std::vector<vk::DescriptorPoolSize> Limits =
{ {
{ vk::DescriptorType::eCombinedImageSampler, 100 }, { vk::DescriptorType::eCombinedImageSampler, 100 },
{ vk::DescriptorType::eUniformBuffer, 100 }, { vk::DescriptorType::eUniformBuffer, 100 },
{ vk::DescriptorType::eUniformBufferDynamic, 100 } { vk::DescriptorType::eUniformBufferDynamic, 100 },
{ vk::DescriptorType::eStorageImage, 100},
{ vk::DescriptorType::eStorageBufferDynamic, 100 }
}; };
/// <summary> /// <summary>
/// Maximum number of descriptor sets allowed /// Maximum number of descriptor sets allowed

View File

@ -155,7 +155,7 @@ namespace SHADE
*/ */
/***************************************************************************/ /***************************************************************************/
void SHVkDescriptorSetGroup::ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span<std::pair<Handle<SHVkImageView>, Handle<SHVkSampler>>> const& imageViewsAndSamplers) noexcept void SHVkDescriptorSetGroup::ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span<std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, vk::ImageLayout>> const& imageViewsAndSamplers) noexcept
{ {
// Find the target writeDescSet // Find the target writeDescSet
BindingAndSetHash writeHash = binding; BindingAndSetHash writeHash = binding;
@ -170,9 +170,10 @@ namespace SHADE
for (uint32_t i = 0; i < imageViewsAndSamplers.size(); ++i) for (uint32_t i = 0; i < imageViewsAndSamplers.size(); ++i)
{ {
// write sampler and image view // write sampler and image view
auto& ivs = imageViewsAndSamplers[i]; auto& [view, sampler, layout] = imageViewsAndSamplers[i];
writeInfo.descImageInfos[i].imageView = ivs.first->GetImageView(); writeInfo.descImageInfos[i].imageView = view->GetImageView();
writeInfo.descImageInfos[i].sampler = ivs.second->GetVkSampler(); writeInfo.descImageInfos[i].sampler = sampler->GetVkSampler();
writeInfo.descImageInfos[i].imageLayout = layout;
} }
} }

View File

@ -1,5 +1,7 @@
#pragma once #pragma once
#include <tuple>
// Project Includes // Project Includes
#include "Graphics/SHVulkanIncludes.h" #include "Graphics/SHVulkanIncludes.h"
#include "Resource/Handle.h" #include "Resource/Handle.h"
@ -63,7 +65,7 @@ namespace SHADE
void UpdateDescriptorSetImages(uint32_t set, uint32_t binding) noexcept; void UpdateDescriptorSetImages(uint32_t set, uint32_t binding) noexcept;
void UpdateDescriptorSetBuffer(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<std::pair<Handle<SHVkImageView>, Handle<SHVkSampler>>> const& imageViewsAndSamplers) noexcept; void ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span<std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, vk::ImageLayout>> const& imageViewsAndSamplers) noexcept;
void ModifyWriteDescBuffer (uint32_t set, uint32_t binding, std::span<Handle<SHVkBuffer>> const& buffers, uint32_t offset, uint32_t range) noexcept; void ModifyWriteDescBuffer (uint32_t set, uint32_t binding, std::span<Handle<SHVkBuffer>> const& buffers, uint32_t offset, uint32_t range) noexcept;

View File

@ -16,6 +16,7 @@
#include "Graphics/Framebuffer/SHVkFramebuffer.h" #include "Graphics/Framebuffer/SHVkFramebuffer.h"
#include "Graphics/Images/SHVkImageView.h" #include "Graphics/Images/SHVkImageView.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" #include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "Graphics/Images/SHVkSampler.h"
namespace SHADE 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 // point and lines fill mode
features.fillModeNonSolid = true; features.fillModeNonSolid = true;
features.samplerAnisotropy = VK_TRUE; features.samplerAnisotropy = VK_TRUE;
features.multiDrawIndirect = true;
// for wide lines // for wide lines
features.wideLines = true; features.wideLines = true;
@ -288,13 +301,12 @@ namespace SHADE
uint32_t SHVkLogicalDevice::PadUBOSize(uint32_t originalSize) const noexcept uint32_t SHVkLogicalDevice::PadUBOSize(uint32_t originalSize) const noexcept
{ {
uint32_t alignedSize = originalSize; return ComputeAlignedBufferSize(originalSize, uboBufferMemoryAlignment);
//uint32_t minBuffer }
if (uboBufferMemoryAlignment > 0)
{ uint32_t SHVkLogicalDevice::PadSSBOSize(uint32_t originalSize) const noexcept
alignedSize = (alignedSize + uboBufferMemoryAlignment - 1) & ~(uboBufferMemoryAlignment - 1); {
} return ComputeAlignedBufferSize(originalSize, ssboBufferMemoryAlignment);
return alignedSize;
} }
/***************************************************************************/ /***************************************************************************/
@ -499,6 +511,11 @@ namespace SHADE
} }
Handle<SHVkSampler> SHVkLogicalDevice::CreateSampler(const SHVkSamplerParams& params) noexcept
{
return SHVkInstance::GetResourceManager().Create <SHVkSampler>(GetHandle(), params);
}
Handle<SHVkRenderpass> SHVkLogicalDevice::CreateRenderpass(std::span<vk::AttachmentDescription> const vkDescriptions, std::vector<SHVkSubpassParams> const& subpasses) noexcept Handle<SHVkRenderpass> SHVkLogicalDevice::CreateRenderpass(std::span<vk::AttachmentDescription> const vkDescriptions, std::vector<SHVkSubpassParams> const& subpasses) noexcept
{ {
return SHVkInstance::GetResourceManager().Create <SHVkRenderpass>(GetHandle(), vkDescriptions, subpasses); return SHVkInstance::GetResourceManager().Create <SHVkRenderpass>(GetHandle(), vkDescriptions, subpasses);

View File

@ -21,7 +21,6 @@
#include "Graphics/Descriptors/SHVkDescriptorSetLayout.h" #include "Graphics/Descriptors/SHVkDescriptorSetLayout.h"
#include "Graphics/Images/SHVkImage.h" #include "Graphics/Images/SHVkImage.h"
namespace SHADE namespace SHADE
{ {
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@ -41,6 +40,8 @@ namespace SHADE
class SHShaderBlockInterface; class SHShaderBlockInterface;
class SHVkDescriptorSetGroup; class SHVkDescriptorSetGroup;
class SHSubpass; class SHSubpass;
class SHVkSampler;
struct SHVkSamplerParams;
/***************************************************************************/ /***************************************************************************/
/*! /*!
@ -102,6 +103,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
void InitializeVMA (void) noexcept; void InitializeVMA (void) noexcept;
void InitializeQueues (std::initializer_list<SHQueueParams> queueCreateParams) noexcept; void InitializeQueues (std::initializer_list<SHQueueParams> queueCreateParams) noexcept;
uint32_t ComputeAlignedBufferSize(uint32_t originalSize, size_t typeSize) const noexcept;
public: public:
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@ -121,7 +123,8 @@ namespace SHADE
// Miscellaneous functions // Miscellaneous functions
void WaitIdle (void) noexcept; void WaitIdle (void) noexcept;
uint32_t FindMemoryType (uint32_t typeFilter, vk::MemoryPropertyFlags properties); 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 // creation functions
Handle<SHVkSurface> CreateSurface (HWND const& windowHandle) const noexcept; Handle<SHVkSurface> CreateSurface (HWND const& windowHandle) const noexcept;
@ -178,6 +181,7 @@ namespace SHADE
Handle<SHVkRenderpass> const& renderpassHdl, Handle<SHVkRenderpass> const& renderpassHdl,
Handle<SHSubpass> subpass Handle<SHSubpass> subpass
) noexcept; ) noexcept;
Handle<SHVkSampler> CreateSampler (const SHVkSamplerParams& params) noexcept;
Handle<SHVkRenderpass> CreateRenderpass (std::span<vk::AttachmentDescription> const vkDescriptions, std::vector<SHVkSubpassParams> const& subpasses) noexcept; Handle<SHVkRenderpass> CreateRenderpass (std::span<vk::AttachmentDescription> const vkDescriptions, std::vector<SHVkSubpassParams> const& subpasses) noexcept;
Handle<SHVkRenderpass> CreateRenderpass (std::span<vk::AttachmentDescription> const vkDescriptions, std::span<vk::SubpassDescription> const spDescs, std::span<vk::SubpassDependency> const spDeps) noexcept; Handle<SHVkRenderpass> CreateRenderpass (std::span<vk::AttachmentDescription> const vkDescriptions, std::span<vk::SubpassDescription> const spDescs, std::span<vk::SubpassDependency> const spDeps) noexcept;

View File

@ -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 // For creation of buffer
vk::BufferCreateInfo bufferInfo{}; vk::BufferCreateInfo bufferInfo{};
@ -70,7 +70,7 @@ namespace SHADE
vmaMapMemory(*vmaAllocator, stagingAlloc, &stagingBufferMappedPtr); vmaMapMemory(*vmaAllocator, stagingAlloc, &stagingBufferMappedPtr);
if (stagingBufferMappedPtr) if (stagingBufferMappedPtr)
std::memcpy(static_cast<uint8_t*>(stagingBufferMappedPtr), static_cast<uint8_t*>(data), srcSize); std::memcpy(static_cast<uint8_t*>(stagingBufferMappedPtr), static_cast<const uint8_t*>(data), srcSize);
const VkDeviceSize offsets = 0; const VkDeviceSize offsets = 0;
const VkDeviceSize sizes = srcSize; const VkDeviceSize sizes = srcSize;
@ -82,7 +82,7 @@ namespace SHADE
SHVkImage::SHVkImage( SHVkImage::SHVkImage(
VmaAllocator const* allocator, VmaAllocator const* allocator,
SHImageCreateParams const& imageDetails, SHImageCreateParams const& imageDetails,
unsigned char* data, const unsigned char* data,
uint32_t dataSize, uint32_t dataSize,
std::span<uint32_t> inMipOffsets, std::span<uint32_t> inMipOffsets,
VmaMemoryUsage memUsage, VmaMemoryUsage memUsage,

View File

@ -107,7 +107,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER FUNCTIONS */ /* PRIVATE MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
void PrepStagingBuffer(void* data, uint32_t srcSize) noexcept; void PrepStagingBuffer(const void* data, uint32_t srcSize) noexcept;
public: public:
@ -119,7 +119,7 @@ namespace SHADE
SHVkImage( SHVkImage(
VmaAllocator const* allocator, VmaAllocator const* allocator,
SHImageCreateParams const& imageDetails, SHImageCreateParams const& imageDetails,
unsigned char* data, const unsigned char* data,
uint32_t dataSize, uint32_t dataSize,
std::span<uint32_t> inMipOffsets, std::span<uint32_t> inMipOffsets,
VmaMemoryUsage memUsage, VmaMemoryUsage memUsage,

View File

@ -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 "SHpch.h"
#include "SHVkSampler.h" #include "SHVkSampler.h"
#include "Graphics/Devices/SHVkLogicalDevice.h"
namespace SHADE namespace SHADE
{ {
/*-----------------------------------------------------------------------------------*/
vk::Sampler SHVkSampler::GetVkSampler(void) const noexcept /* Constructors */
/*-----------------------------------------------------------------------------------*/
SHVkSampler::SHVkSampler(Handle<SHVkLogicalDevice> 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;
}
} }

View File

@ -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 #pragma once
// STL Includes
#include <vector>
// Project Includes
#include "Graphics/SHVulkanIncludes.h" #include "Graphics/SHVulkanIncludes.h"
#include "Resource/Handle.h"
namespace SHADE namespace SHADE
{ {
/*-----------------------------------------------------------------------------------*/
/* Forward Declarations */
/*-----------------------------------------------------------------------------------*/
class SHVkLogicalDevice;
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
/*************************************************************************************/
/*!
\brief
Holds parameters for constructing the SHVkSampler.
*/
/*************************************************************************************/
struct SHVkSamplerParams struct SHVkSamplerParams
{ {
vk::Filter minFilter; vk::Filter minFilter = vk::Filter::eLinear;
vk::Filter maxFilter; vk::Filter magFilter = vk::Filter::eLinear;
//vk::Filter maxFilter; 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 class SHVkSampler
{ {
private: public:
//! The vulkan sampler handler /*---------------------------------------------------------------------------------*/
vk::Sampler vkSampler; /* Constructors */
/*---------------------------------------------------------------------------------*/
SHVkSampler(Handle<SHVkLogicalDevice> logicalDevice, const SHVkSamplerParams& params = {}) noexcept;
SHVkSampler(SHVkSampler&& rhs) noexcept;
~SHVkSampler() noexcept;
public: /*---------------------------------------------------------------------------------*/
SHVkSampler () noexcept; /* Overloaded Operators */
SHVkSampler (SHVkSampler&& rhs) noexcept; /*---------------------------------------------------------------------------------*/
SHVkSampler&& operator=(SHVkSampler&& rhs) noexcept; SHVkSampler& operator=(SHVkSampler&& rhs) noexcept;
vk::Sampler GetVkSampler (void) const noexcept; /*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
vk::Sampler GetVkSampler(void) const noexcept { return vkSampler; }
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
vk::Sampler vkSampler; //! The Vulkan sampler handler
Handle<SHVkLogicalDevice> device; //! Stored device for deallocating the object
}; };
} }

View File

@ -22,8 +22,11 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/Pipeline/SHVkPipeline.h" #include "Graphics/Pipeline/SHVkPipeline.h"
#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" #include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "ECS_Base/Managers/SHComponentManager.h" #include "ECS_Base/Managers/SHComponentManager.h"
#include "Math/Transform/SHTransformComponent.h" #include "Math/Transform/SHTransformComponent.h"
#include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h"
#include "Graphics/Descriptors/SHVkDescriptorPool.h"
namespace SHADE namespace SHADE
{ {
@ -120,7 +123,7 @@ namespace SHADE
} }
} }
void SHBatch::UpdateMaterialBuffer(uint32_t frameIndex) void SHBatch::UpdateMaterialBuffer(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{ {
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{ {
@ -154,21 +157,17 @@ namespace SHADE
if (!matBufferDirty[frameIndex]) if (!matBufferDirty[frameIndex])
return; return;
// Build CPI Buffer // Build CPU Buffer
char* propsCurrPtr = matPropsData.get(); char* propsCurrPtr = matPropsData.get();
for (auto& subBatch : subBatches) for (auto& subBatch : subBatches)
for (const SHRenderable* renderable : subBatch.Renderables) for (const SHRenderable* renderable : subBatch.Renderables)
{ {
renderable->GetMaterial()->ExportProperties(propsCurrPtr); renderable->GetMaterial()->ExportProperties(propsCurrPtr);
propsCurrPtr += singleMatPropSize; propsCurrPtr += singleMatPropAlignedSize;
} }
// Transfer to GPU // Transfer to GPU
SHVkUtil::EnsureBufferAndCopyHostVisibleData rebuildMaterialBuffers(frameIndex, descPool);
(
device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast<uint32_t>(matPropsDataSize),
vk::BufferUsageFlagBits::eStorageBuffer
);
// This frame is updated // This frame is updated
matBufferDirty[frameIndex] = false; matBufferDirty[frameIndex] = false;
@ -207,7 +206,7 @@ namespace SHADE
transformDataBuffer[frameIndex]->WriteToMemory(transformData.data(), static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix)), 0, 0); transformDataBuffer[frameIndex]->WriteToMemory(transformData.data(), static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix)), 0, 0);
} }
void SHBatch::Build(Handle<SHVkLogicalDevice> _device, uint32_t frameIndex) void SHBatch::Build(Handle<SHVkLogicalDevice> _device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex)
{ {
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{ {
@ -215,6 +214,9 @@ namespace SHADE
return; return;
} }
// Save logical device
device = _device;
// No need to build as there are no changes // No need to build as there are no changes
if (!isDirty[frameIndex]) if (!isDirty[frameIndex])
return; return;
@ -247,7 +249,8 @@ namespace SHADE
if (!EMPTY_MAT_PROPS) if (!EMPTY_MAT_PROPS)
{ {
singleMatPropSize = SHADER_INFO->GetBytesRequired(); singleMatPropSize = SHADER_INFO->GetBytesRequired();
matPropTotalBytes = drawData.size() * singleMatPropSize; singleMatPropAlignedSize = device->PadSSBOSize(singleMatPropSize);
matPropTotalBytes = numTotalElements * singleMatPropAlignedSize;
if (matPropsDataSize < matPropTotalBytes) if (matPropsDataSize < matPropTotalBytes)
{ {
matPropsData.reset(new char[matPropTotalBytes]); matPropsData.reset(new char[matPropTotalBytes]);
@ -267,7 +270,7 @@ namespace SHADE
.instanceCount = static_cast<uint32_t>(subBatch.Renderables.size()), .instanceCount = static_cast<uint32_t>(subBatch.Renderables.size()),
.firstIndex = subBatch.Mesh->FirstIndex, .firstIndex = subBatch.Mesh->FirstIndex,
.vertexOffset = subBatch.Mesh->FirstVertex, .vertexOffset = subBatch.Mesh->FirstVertex,
.firstInstance = nextInstanceIndex .firstInstance = nextInstanceIndex++
}); });
// Fill in buffers (CPU) // Fill in buffers (CPU)
@ -289,7 +292,7 @@ namespace SHADE
if (!EMPTY_MAT_PROPS) if (!EMPTY_MAT_PROPS)
{ {
renderable->GetMaterial()->ExportProperties(propsCurrPtr); renderable->GetMaterial()->ExportProperties(propsCurrPtr);
propsCurrPtr += singleMatPropSize; propsCurrPtr += singleMatPropAlignedSize;
} }
} }
} }
@ -304,30 +307,21 @@ namespace SHADE
const uint32_t DRAW_DATA_BYTES = static_cast<uint32_t>(drawData.size() * sizeof(vk::DrawIndexedIndirectCommand)); const uint32_t DRAW_DATA_BYTES = static_cast<uint32_t>(drawData.size() * sizeof(vk::DrawIndexedIndirectCommand));
SHVkUtil::EnsureBufferAndCopyHostVisibleData SHVkUtil::EnsureBufferAndCopyHostVisibleData
( (
_device, drawDataBuffer[frameIndex], drawData.data(), DRAW_DATA_BYTES, device, drawDataBuffer[frameIndex], drawData.data(), DRAW_DATA_BYTES,
BuffUsage::eIndirectBuffer BuffUsage::eIndirectBuffer
); );
// - Transform Buffer // - Transform Buffer
const uint32_t TF_DATA_BYTES = static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix)); const uint32_t TF_DATA_BYTES = static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix));
SHVkUtil::EnsureBufferAndCopyHostVisibleData SHVkUtil::EnsureBufferAndCopyHostVisibleData
( (
_device, transformDataBuffer[frameIndex], transformData.data(), TF_DATA_BYTES, device, transformDataBuffer[frameIndex], transformData.data(), TF_DATA_BYTES,
BuffUsage::eVertexBuffer BuffUsage::eVertexBuffer
); );
// - Material Properties Buffer // - Material Properties Buffer
if (matPropsData) rebuildMaterialBuffers(frameIndex, descPool);
{
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
_device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast<uint32_t>(matPropsDataSize),
BuffUsage::eStorageBuffer
);
}
// Mark this frame as no longer dirty
isDirty[frameIndex] = false; isDirty[frameIndex] = false;
// Save logical device
this->device = _device;
} }
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -341,8 +335,20 @@ namespace SHADE
return; return;
} }
// Bind all required objects before drawing
static std::array<uint32_t, 1> dynamicOffset { 0 };
cmdBuffer->BindPipeline(pipeline); cmdBuffer->BindPipeline(pipeline);
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRANSFORM, transformDataBuffer[frameIndex], 0); 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<uint32_t>(drawData.size())); cmdBuffer->DrawMultiIndirect(drawDataBuffer[frameIndex], static_cast<uint32_t>(drawData.size()));
} }
@ -355,4 +361,39 @@ namespace SHADE
dirt = true; dirt = true;
isCPUBuffersDirty = true; isCPUBuffersDirty = true;
} }
void SHBatch::rebuildMaterialBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{
if (matPropsData)
{
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast<uint32_t>(matPropsDataSize),
vk::BufferUsageFlagBits::eStorageBuffer
);
if (!matPropsDescSet[frameIndex])
{
matPropsDescSet[frameIndex] = descPool->Allocate
(
{ SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE] },
{ 0 }
);
}
std::array<Handle<SHVkBuffer>, 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
);
}
}
} }

View File

@ -35,6 +35,8 @@ namespace SHADE
class SHRenderable; class SHRenderable;
class SHVkLogicalDevice; class SHVkLogicalDevice;
class SHMaterialInstance; class SHMaterialInstance;
class SHVkDescriptorSetGroup;
class SHVkDescriptorPool;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Type Definitions */ /* Type Definitions */
@ -74,9 +76,9 @@ namespace SHADE
void Add(const SHRenderable* renderable); void Add(const SHRenderable* renderable);
void Remove(const SHRenderable* renderable); void Remove(const SHRenderable* renderable);
void Clear(); void Clear();
void UpdateMaterialBuffer(uint32_t frameIndex); void UpdateMaterialBuffer(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
void UpdateTransformBuffer(uint32_t frameIndex); void UpdateTransformBuffer(uint32_t frameIndex);
void Build(Handle<SHVkLogicalDevice> device, uint32_t frameIndex); void Build(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) ;
void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex); void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex);
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
@ -84,34 +86,44 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
Handle<SHVkPipeline> GetPipeline() const noexcept { return pipeline; }; Handle<SHVkPipeline> GetPipeline() const noexcept { return pipeline; };
private: private:
/*-----------------------------------------------------------------------------*/
/* Type Definition */
/*-----------------------------------------------------------------------------*/
using TripleBool = std::array<bool, SHGraphicsConstants::NUM_FRAME_BUFFERS>;
using TripleBuffer = std::array<Handle<SHVkBuffer>, SHGraphicsConstants::NUM_FRAME_BUFFERS>;
using TripleDescSet = std::array<Handle<SHVkDescriptorSetGroup>, SHGraphicsConstants::NUM_FRAME_BUFFERS>;
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Data Members */ /* Data Members */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
// Resources // Resources
Handle<SHVkLogicalDevice> device; Handle<SHVkLogicalDevice> device;
// Batch Properties // Batch Properties
Handle<SHVkPipeline> pipeline; Handle<SHVkPipeline> pipeline;
std::unordered_set<Handle<SHMaterialInstance>> referencedMatInstances; std::unordered_set<Handle<SHMaterialInstance>> referencedMatInstances;
std::array<bool, SHGraphicsConstants::NUM_FRAME_BUFFERS> matBufferDirty; TripleBool matBufferDirty;
// Batch Tree // Batch Tree
std::vector<SHSubBatch> subBatches; std::vector<SHSubBatch> subBatches;
std::array<bool, SHGraphicsConstants::NUM_FRAME_BUFFERS> isDirty; TripleBool isDirty;
// CPU Buffers // CPU Buffers
std::vector<vk::DrawIndexedIndirectCommand> drawData; std::vector<vk::DrawIndexedIndirectCommand> drawData;
std::vector<SHMatrix> transformData; std::vector<SHMatrix> transformData;
std::unique_ptr<char> matPropsData; std::unique_ptr<char> matPropsData;
Byte matPropsDataSize = 0; Byte matPropsDataSize = 0;
Byte singleMatPropSize = 0; Byte singleMatPropAlignedSize = 0;
bool isCPUBuffersDirty = true; Byte singleMatPropSize = 0;
bool isCPUBuffersDirty = true;
// GPU Buffers // GPU Buffers
std::array<Handle<SHVkBuffer>, SHGraphicsConstants::NUM_FRAME_BUFFERS> drawDataBuffer; TripleBuffer drawDataBuffer;
std::array<Handle<SHVkBuffer>, SHGraphicsConstants::NUM_FRAME_BUFFERS> transformDataBuffer; TripleBuffer transformDataBuffer;
std::array<Handle<SHVkBuffer>, SHGraphicsConstants::NUM_FRAME_BUFFERS> matPropsBuffer; TripleBuffer matPropsBuffer;
TripleDescSet matPropsDescSet;
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Helper Functions */ /* Helper Functions */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
void setAllDirtyFlags(); void setAllDirtyFlags();
void rebuildMaterialBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
}; };
} }

View File

@ -91,12 +91,12 @@ namespace SHADE
(*superBatch)->Remove(renderable); (*superBatch)->Remove(renderable);
} }
void SHBatcher::FinaliseBatches(Handle<SHVkLogicalDevice> device, uint32_t frameIndex) void SHBatcher::FinaliseBatches(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex)
{ {
// Build SuperBatches // Build SuperBatches
for (auto& batch : superBatches) for (auto& batch : superBatches)
{ {
batch->Build(device, frameIndex); batch->Build(device, descPool, frameIndex);
} }
} }
@ -109,11 +109,11 @@ namespace SHADE
superBatches.clear(); superBatches.clear();
} }
void SHBatcher::UpdateBuffers(uint32_t frameIndex) void SHBatcher::UpdateBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{ {
for (auto& batch : superBatches) for (auto& batch : superBatches)
{ {
batch->UpdateBuffers(frameIndex); batch->UpdateBuffers(frameIndex, descPool);
} }
} }

View File

@ -27,6 +27,7 @@ namespace SHADE
class SHSuperBatch; class SHSuperBatch;
class SHVkLogicalDevice; class SHVkLogicalDevice;
class SHVkCommandBuffer; class SHVkCommandBuffer;
class SHVkDescriptorPool;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Type Definitions */ /* Type Definitions */
@ -51,9 +52,9 @@ namespace SHADE
void PrepareBatches(); void PrepareBatches();
void AddToBatch(SHRenderable const* renderable); void AddToBatch(SHRenderable const* renderable);
void RemoveFromBatch(SHRenderable const* renderable); void RemoveFromBatch(SHRenderable const* renderable);
void FinaliseBatches(Handle<SHVkLogicalDevice> device, uint32_t frameIndex); void FinaliseBatches(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex);
void ClearBatches(); void ClearBatches();
void UpdateBuffers(uint32_t frameIndex); void UpdateBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
void RegisterSuperBatch(Handle<SHSuperBatch> superBatch); void RegisterSuperBatch(Handle<SHSuperBatch> superBatch);
void DeregisterSuperBatch(Handle<SHSuperBatch> superBatch); void DeregisterSuperBatch(Handle<SHSuperBatch> superBatch);

View File

@ -16,6 +16,7 @@ of DigiPen Institute of Technology is prohibited.
#include "SHBatch.h" #include "SHBatch.h"
#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h"
#include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Graphics/MiddleEnd/Interface/SHRenderable.h"
#include "Graphics/Descriptors/SHVkDescriptorPool.h"
namespace SHADE namespace SHADE
{ {
@ -78,21 +79,21 @@ namespace SHADE
batches.clear(); batches.clear();
} }
void SHSuperBatch::UpdateBuffers(uint32_t frameIndex) void SHSuperBatch::UpdateBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{ {
for (auto& batch : batches) for (auto& batch : batches)
{ {
batch.UpdateMaterialBuffer(frameIndex); batch.UpdateMaterialBuffer(frameIndex, descPool);
batch.UpdateTransformBuffer(frameIndex); batch.UpdateTransformBuffer(frameIndex);
} }
} }
void SHSuperBatch::Build(Handle<SHVkLogicalDevice> device, uint32_t frameIndex) noexcept void SHSuperBatch::Build(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept
{ {
// Build all batches // Build all batches
for (auto& batch : batches) for (auto& batch : batches)
{ {
batch.Build(device, frameIndex); batch.Build(device, descPool, frameIndex);
} }
} }

View File

@ -55,8 +55,8 @@ namespace SHADE
void Add(const SHRenderable* renderable) noexcept; void Add(const SHRenderable* renderable) noexcept;
void Remove(const SHRenderable* renderable) noexcept; void Remove(const SHRenderable* renderable) noexcept;
void Clear() noexcept; void Clear() noexcept;
void UpdateBuffers(uint32_t frameIndex); void UpdateBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
void Build(Handle<SHVkLogicalDevice> device, uint32_t frameIndex) noexcept; void Build(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept;
void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept; void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/

View File

@ -7,7 +7,22 @@
namespace SHADE namespace SHADE
{ {
/*-----------------------------------------------------------------------------------*/
/* Static Definitions */
/*-----------------------------------------------------------------------------------*/
std::vector<Handle<SHVkDescriptorSetLayout>> SHGraphicsGlobalData::globalDescSetLayouts;
Handle<SHVkDescriptorSetGroup> SHGraphicsGlobalData::globalDescSets;
SHVertexInputState SHGraphicsGlobalData::defaultVertexInputState;
Handle<SHVkPipelineLayout> SHGraphicsGlobalData::dummyPipelineLayout;
void SHGraphicsGlobalData::InitHighFrequencyGlobalData(void) noexcept
{
}
/*-----------------------------------------------------------------------------------*/
/* Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHGraphicsGlobalData::InitDescSetLayouts(Handle<SHVkLogicalDevice> logicalDevice) noexcept void SHGraphicsGlobalData::InitDescSetLayouts(Handle<SHVkLogicalDevice> logicalDevice) noexcept
{ {
SHVkDescriptorSetLayout::Binding genericDataBinding SHVkDescriptorSetLayout::Binding genericDataBinding
@ -87,18 +102,18 @@ namespace SHADE
InitDefaultVertexInputState(); InitDefaultVertexInputState();
} }
std::vector<Handle<SHVkDescriptorSetLayout>> const& SHGraphicsGlobalData::GetDescSetLayouts(void) const noexcept std::vector<Handle<SHVkDescriptorSetLayout>> const& SHGraphicsGlobalData::GetDescSetLayouts(void) noexcept
{ {
return globalDescSetLayouts; return globalDescSetLayouts;
} }
SHVertexInputState const& SHGraphicsGlobalData::GetDefaultViState(void) const noexcept SHVertexInputState const& SHGraphicsGlobalData::GetDefaultViState(void) noexcept
{ {
return defaultVertexInputState; return defaultVertexInputState;
} }
Handle<SHVkPipelineLayout> SHGraphicsGlobalData::GetDummyPipelineLayout(void) const noexcept Handle<SHVkPipelineLayout> SHGraphicsGlobalData::GetDummyPipelineLayout(void) noexcept
{ {
return dummyPipelineLayout; return dummyPipelineLayout;
} }

View File

@ -15,31 +15,38 @@ namespace SHADE
{ {
private: private:
//! Global descriptor set layouts. Used to allocate descriptor sets //! Global descriptor set layouts. Used to allocate descriptor sets
std::vector<Handle<SHVkDescriptorSetLayout>> globalDescSetLayouts; static std::vector<Handle<SHVkDescriptorSetLayout>> globalDescSetLayouts;
//! Global Descriptor sets //! Global Descriptor sets
Handle<SHVkDescriptorSetGroup> globalDescSets; static Handle<SHVkDescriptorSetGroup> globalDescSets;
//! Default vertex input state (used by everything). //! 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, //! 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. //! we create a dummy pipeline layout to use it for binding.
Handle<SHVkPipelineLayout> dummyPipelineLayout; static Handle<SHVkPipelineLayout> dummyPipelineLayout;
static void InitHighFrequencyGlobalData (void) noexcept;
static void InitDescSetLayouts (Handle<SHVkLogicalDevice> logicalDevice) noexcept;
static void InitDefaultVertexInputState (void) noexcept;
void InitDescSetLayouts (Handle<SHVkLogicalDevice> logicalDevice) noexcept;
void InitDefaultVertexInputState(void) noexcept;
public: public:
/*-----------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------*/
SHGraphicsGlobalData() = delete;
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */ /* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
void Init (Handle<SHVkLogicalDevice> logicalDevice) noexcept; static void Init (Handle<SHVkLogicalDevice> logicalDevice) noexcept;
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */ /* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
std::vector<Handle<SHVkDescriptorSetLayout>> const& GetDescSetLayouts (void) const noexcept; static std::vector<Handle<SHVkDescriptorSetLayout>> const& GetDescSetLayouts (void) noexcept;
SHVertexInputState const& GetDefaultViState (void) const noexcept; static SHVertexInputState const& GetDefaultViState (void) noexcept;
Handle<SHVkPipelineLayout> GetDummyPipelineLayout (void) const noexcept; static Handle<SHVkPipelineLayout> GetDummyPipelineLayout (void) noexcept;
}; };
} }

View File

@ -23,21 +23,39 @@ namespace SHADE
{ {
SHVec3 view = target - pos; view = SHVec3::Normalise(view); SHVec3 view = target - pos; view = SHVec3::Normalise(view);
SHVec3 right = SHVec3::Cross(view, up); right = SHVec3::Normalise(right); 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 = SHMatrix::Identity;
viewMatrix(0, 0) = UP[0]; viewMatrix(0, 0) = right[0];
viewMatrix(1, 0) = UP[1]; viewMatrix(0, 1) = right[1];
viewMatrix(2, 0) = UP[2]; viewMatrix(0, 2) = right[2];
viewMatrix(0, 1) = right[0];
viewMatrix(1, 1) = right[1]; viewMatrix(1, 0) = UP[0];
viewMatrix(2, 1) = right[2]; viewMatrix(1, 1) = UP[1];
viewMatrix(0, 2) = view[0]; viewMatrix(1, 2) = UP[2];
viewMatrix(1, 2) = view[1];
viewMatrix(2, 2) = view[2]; viewMatrix(2, 0) = view[0];
viewMatrix(3, 0) = -UP.Dot(pos); viewMatrix(2, 1) = view[1];
viewMatrix(3, 1) = -right.Dot(pos); viewMatrix(2, 2) = view[2];
viewMatrix(3, 2) = -view.Dot(pos);
viewMatrix(0, 3) = -right.Dot(pos);
viewMatrix(1, 3) = -UP.Dot(pos);
viewMatrix(2, 3) = -view.Dot(pos);
isDirty = true; isDirty = true;
} }

View File

@ -30,6 +30,8 @@ of DigiPen Institute of Technology is prohibited.
#include "SHGraphicsConstants.h" #include "SHGraphicsConstants.h"
#include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h" #include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h"
#include "Graphics/Buffers/SHVkBuffer.h" #include "Graphics/Buffers/SHVkBuffer.h"
#include "Graphics/Images/SHVkSampler.h"
#include "Assets/Asset Types/SHTextureAsset.h"
namespace SHADE namespace SHADE
{ {
@ -91,8 +93,10 @@ namespace SHADE
descPool = device->CreateDescriptorPools(); descPool = device->CreateDescriptorPools();
// Create generic command buffer // Create generic command buffer
transferCmdPool = device->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::TRANSFER, SH_CMD_POOL_RESET::POOL_BASED, true); //transferCmdPool = device->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS, SH_CMD_POOL_RESET::POOL_BASED, true);
transferCmdBuffer = transferCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY); 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 - Global data
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
globalData = resourceManager.Create<SHGraphicsGlobalData>(); SHGraphicsGlobalData::Init(device);
globalData->Init(device);
// Set Up Cameras // Set Up Cameras
screenCamera = resourceManager.Create<SHCamera>(); screenCamera = resourceManager.Create<SHCamera>();
@ -115,7 +118,7 @@ namespace SHADE
screenCamera->SetOrthographic(static_cast<float>(windowDims.first), static_cast<float>(windowDims.second), 0.01f, 100.0f); screenCamera->SetOrthographic(static_cast<float>(windowDims.first), static_cast<float>(windowDims.second), 0.01f, 100.0f);
worldCamera = resourceManager.Create<SHCamera>(); worldCamera = resourceManager.Create<SHCamera>();
//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(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<float>(windowDims.first), static_cast<float>(windowDims.second), 0.0f, 100.0f); worldCamera->SetPerspective(90.0f, static_cast<float>(windowDims.first), static_cast<float>(windowDims.second), 0.0f, 100.0f);
// Create Default Viewport // Create Default Viewport
@ -131,18 +134,20 @@ namespace SHADE
} }
// Initialize world render graph // 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("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("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("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); 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 //First subpass to write to G-Buffer
auto gBufferWriteSubpass = node->AddSubpass("G-Buffer Write"); auto gBufferWriteSubpass = node->AddSubpass("G-Buffer Write");
//gBufferWriteSubpass->AddColorOutput("Scene"); //gBufferWriteSubpass->AddColorOutput("Scene");
gBufferWriteSubpass->AddColorOutput("Present"); gBufferWriteSubpass->AddColorOutput("Present");
gBufferWriteSubpass->AddDepthOutput ("Depth Buffer", SH_ATT_DESC_TYPE::DEPTH_STENCIL);
//writeSubpass->AddColorOutput("Normals"); //writeSubpass->AddColorOutput("Normals");
// //Second subpass to read from G-Buffer // //Second subpass to read from G-Buffer
@ -171,7 +176,7 @@ namespace SHADE
debugWorldRenderer->SetCamera(worldCamera);*/ debugWorldRenderer->SetCamera(worldCamera);*/
// Add world renderer to default viewport // 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); worldRenderer->SetCamera(worldCamera);
@ -184,8 +189,8 @@ namespace SHADE
shaderModuleLibrary.ImportFromSourceLibrary(device, shaderSourceLibrary); shaderModuleLibrary.ImportFromSourceLibrary(device, shaderSourceLibrary);
auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl"); auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl");
auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl"); auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl");
//triVS->Reflect(); cubeVS->Reflect();
//triFS->Reflect(); cubeFS->Reflect();
defaultMaterial = AddMaterial(cubeVS, cubeFS, gBufferWriteSubpass); defaultMaterial = AddMaterial(cubeVS, cubeFS, gBufferWriteSubpass);
} }
@ -224,6 +229,9 @@ namespace SHADE
renderContext.ResetFence(); renderContext.ResetFence();
// Bind textures
// For every viewport // For every viewport
for (int vpIndex = 0; vpIndex < static_cast<int>(viewports.size()); ++vpIndex) for (int vpIndex = 0; vpIndex < static_cast<int>(viewports.size()); ++vpIndex)
{ {
@ -241,7 +249,7 @@ namespace SHADE
// Begin recording the command buffer // Begin recording the command buffer
currentCmdBuffer->BeginRecording(); currentCmdBuffer->BeginRecording();
currentCmdBuffer->ForceSetPipelineLayout(globalData->GetDummyPipelineLayout()); currentCmdBuffer->ForceSetPipelineLayout(SHGraphicsGlobalData::GetDummyPipelineLayout());
// Bind all the buffers required for meshes // Bind all the buffers required for meshes
for (auto& [buffer, bindingPoint] : MESH_DATA) for (auto& [buffer, bindingPoint] : MESH_DATA)
@ -252,11 +260,26 @@ namespace SHADE
currentCmdBuffer->BindIndexBuffer(buffer, 0); currentCmdBuffer->BindIndexBuffer(buffer, 0);
} }
// Bind textures
auto textureDescSet = texLibrary.GetTextureDescriptorSetGroup();
if (textureDescSet)
{
std::array<uint32_t, 1> texDynamicOffset {0};
currentCmdBuffer->BindDescriptorSet
(
textureDescSet,
vk::PipelineBindPoint::eGraphics,
0,
texDynamicOffset
);
}
// bind camera data // bind camera data
renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex); renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex);
// Draw first // Draw first
renderers[renIndex]->Draw(frameIndex); renderers[renIndex]->Draw(frameIndex, descPool);
// End the command buffer recording // End the command buffer recording
currentCmdBuffer->EndRecording(); currentCmdBuffer->EndRecording();
@ -309,7 +332,7 @@ namespace SHADE
for (auto vp : viewports) for (auto vp : viewports)
for (auto renderer : vp->GetRenderers()) for (auto renderer : vp->GetRenderers())
{ {
renderer->GetRenderGraph()->FinaliseBatch(renderContext.GetCurrentFrame()); renderer->GetRenderGraph()->FinaliseBatch(renderContext.GetCurrentFrame(), descPool);
} }
// Resize // Resize
@ -455,7 +478,35 @@ namespace SHADE
transferCmdBuffer->BeginRecording(); transferCmdBuffer->BeginRecording();
meshLibrary.BuildBuffers(device, transferCmdBuffer); meshLibrary.BuildBuffers(device, transferCmdBuffer);
transferCmdBuffer->EndRecording(); transferCmdBuffer->EndRecording();
transferQueue->SubmitCommandBuffer({ transferCmdBuffer }); graphicsQueue->SubmitCommandBuffer({ transferCmdBuffer });
}
/*---------------------------------------------------------------------------------*/
/* Texture Registration Functions */
/*---------------------------------------------------------------------------------*/
Handle<SHTexture> SHGraphicsSystem::Add(const SHTextureAsset& texAsset)
{
auto sampler = samplerCache.GetSampler(device, SHVkSamplerParams { .maxLod = static_cast<float>(texAsset.mipOffsets.size()) });
return texLibrary.Add(texAsset, sampler);
}
SHADE::Handle<SHADE::SHTexture> SHGraphicsSystem::Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, uint32_t width, uint32_t height, SHTexture::TextureFormat format, std::vector<uint32_t> mipOffsets)
{
auto sampler = samplerCache.GetSampler(device, SHVkSamplerParams{ .maxLod = static_cast<float>(mipOffsets.size()) });
return texLibrary.Add(pixelCount, pixelData, width, height, format, mipOffsets, sampler);
}
void SHGraphicsSystem::Remove(Handle<SHTexture> tex)
{
texLibrary.Remove(tex);
}
void SHGraphicsSystem::BuildTextures()
{
texLibrary.BuildTextures
(
device, graphicsTexCmdBuffer, graphicsQueue, descPool
);
} }
void SHGraphicsSystem::SetWindow(SHWindow* wind) noexcept void SHGraphicsSystem::SetWindow(SHWindow* wind) noexcept
@ -493,9 +544,13 @@ namespace SHADE
oldSuperBatch->Remove(&renderable); oldSuperBatch->Remove(&renderable);
} }
// Add to new SuperBatch // Add to new SuperBatch if there is a material
Handle<SHSuperBatch> newSuperBatch = renderable.GetMaterial()->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch(); Handle<SHMaterialInstance> newMatInstance = renderable.GetMaterial();
newSuperBatch->Add(&renderable); if (newMatInstance)
{
Handle<SHSuperBatch> newSuperBatch = newMatInstance->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch();
newSuperBatch->Add(&renderable);
}
// Unset change flag // Unset change flag
renderable.ResetChangedFlag(); renderable.ResetChangedFlag();

View File

@ -29,6 +29,8 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/MiddleEnd/Shaders/SHShaderModuleLibrary.h" #include "Graphics/MiddleEnd/Shaders/SHShaderModuleLibrary.h"
#include "SHMeshLibrary.h" #include "SHMeshLibrary.h"
#include "Graphics/MiddleEnd/Materials/SHMaterialInstanceCache.h" #include "Graphics/MiddleEnd/Materials/SHMaterialInstanceCache.h"
#include "../Textures/SHTextureLibrary.h"
#include "../Textures/SHVkSamplerCache.h"
namespace SHADE namespace SHADE
{ {
@ -188,6 +190,62 @@ namespace SHADE
/***************************************************************************/ /***************************************************************************/
void BuildMeshBuffers(); 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<SHTexture> Add(const SHTextureAsset& texAsset);
Handle<SHTexture> Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, uint32_t width, uint32_t height, SHTexture::TextureFormat format, std::vector<uint32_t> 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<SHTexture> 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 */ /* Setters */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
@ -220,19 +278,20 @@ namespace SHADE
Handle<SHVkQueue> graphicsQueue; Handle<SHVkQueue> graphicsQueue;
Handle<SHVkQueue> transferQueue; Handle<SHVkQueue> transferQueue;
Handle<SHVkDescriptorPool> descPool; Handle<SHVkDescriptorPool> descPool;
Handle<SHVkCommandPool> graphicsCmdPool;
Handle<SHVkCommandPool> transferCmdPool; Handle<SHVkCommandPool> transferCmdPool;
Handle<SHVkCommandBuffer> transferCmdBuffer; Handle<SHVkCommandBuffer> transferCmdBuffer;
Handle<SHVkCommandBuffer> graphicsTexCmdBuffer;
SHRenderContext renderContext; SHRenderContext renderContext;
std::array<Handle<SHVkSemaphore>, 2> graphSemaphores; std::array<Handle<SHVkSemaphore>, 2> graphSemaphores;
// Not Owned Resources // Not Owned Resources
SHWindow* window = nullptr; SHWindow* window = nullptr;
// global data (descriptor sets as well)
Handle<SHGraphicsGlobalData> globalData;
// Middle End Resources // Middle End Resources
ResourceManager resourceManager; ResourceManager resourceManager;
SHMeshLibrary meshLibrary; SHMeshLibrary meshLibrary;
SHTextureLibrary texLibrary;
SHSamplerCache samplerCache;
SHMaterialInstanceCache materialInstanceCache; SHMaterialInstanceCache materialInstanceCache;
// Viewports // Viewports
Handle<SHViewport> defaultViewport; // Whole screen Handle<SHViewport> defaultViewport; // Whole screen

View File

@ -40,8 +40,6 @@ namespace SHADE
void SHMaterialInstance::ExportProperties(void* dest) void SHMaterialInstance::ExportProperties(void* dest)
{ {
assert(dataStore != nullptr);
if (!baseMaterial) if (!baseMaterial)
throw std::runtime_error("[SHMaterialInstance] Attempted to set export a Material Instance with no base Material!"); throw std::runtime_error("[SHMaterialInstance] Attempted to set export a Material Instance with no base Material!");

View File

@ -15,6 +15,7 @@ of DigiPen Institute of Technology is prohibited.
// Project Includes // Project Includes
#include "Resource/Handle.h" #include "Resource/Handle.h"
#include "Graphics/Shaders/BlockInterface/SHShaderBlockInterface.h" #include "Graphics/Shaders/BlockInterface/SHShaderBlockInterface.h"
#include "SH_API.h"
namespace SHADE namespace SHADE
{ {
@ -34,7 +35,7 @@ namespace SHADE
a SHRenderable. a SHRenderable.
*/ */
/***********************************************************************************/ /***********************************************************************************/
class SHMaterialInstance class SH_API SHMaterialInstance
{ {
public: public:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/

View File

@ -48,7 +48,7 @@ namespace SHADE
} }
// Get offset and modify the memory directly // Get offset and modify the memory directly
T* dataPtr = dataStore.get() + od.StoredDataOffset; T* dataPtr = reinterpret_cast<T*>(dataStore.get() + od.StoredDataOffset);
*dataPtr = value; *dataPtr = value;
// Save the override data information // Save the override data information

View File

@ -81,7 +81,7 @@ namespace SHADE
if (!material) if (!material)
{ {
SHGraphicsSystem* gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>(); SHGraphicsSystem* gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>();
material = gfxSystem->AddOrGetBaseMaterialInstance(sharedMaterial->GetBaseMaterial()); material = gfxSystem->AddMaterialInstanceCopy(sharedMaterial);
} }
return material; return material;

View File

@ -60,9 +60,9 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Drawing Functions */ /* Drawing Functions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
void SHRenderer::Draw(uint32_t frameIndex) noexcept void SHRenderer::Draw(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool) noexcept
{ {
renderGraph->Execute(frameIndex, commandBuffers[frameIndex]); renderGraph->Execute(frameIndex, commandBuffers[frameIndex], descPool);
} }
void SHRenderer::UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept void SHRenderer::UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept

View File

@ -74,7 +74,7 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Drawing Functions */ /* Drawing Functions */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
void Draw(uint32_t frameIndex) noexcept; void Draw(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool) noexcept;
void UpdateDataAndBind (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept; void UpdateDataAndBind (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
void UpdateCameraDataToBuffer (void) noexcept; void UpdateCameraDataToBuffer (void) noexcept;

View File

@ -11,7 +11,7 @@ namespace SHADE
SHPipelineLayoutParams params SHPipelineLayoutParams params
{ {
.shaderModules = {vsFsPair.first, vsFsPair.second}, .shaderModules = {vsFsPair.first, vsFsPair.second},
.globalDescSetLayouts = globalData->GetDescSetLayouts() .globalDescSetLayouts = SHGraphicsGlobalData::GetDescSetLayouts()
}; };
// Create the pipeline layout // Create the pipeline layout
@ -19,7 +19,7 @@ namespace SHADE
// Create the pipeline and configure the default vertex input state // Create the pipeline and configure the default vertex input state
auto newPipeline = logicalDevice->CreateGraphicsPipeline(pipelineLayout, nullptr, renderpass, subpass); auto newPipeline = logicalDevice->CreateGraphicsPipeline(pipelineLayout, nullptr, renderpass, subpass);
newPipeline->GetPipelineState().SetVertexInputState(globalData->GetDefaultViState()); newPipeline->GetPipelineState().SetVertexInputState(SHGraphicsGlobalData::GetDefaultViState());
// Actually construct the pipeline // Actually construct the pipeline
newPipeline->ConstructPipeline(); newPipeline->ConstructPipeline();
@ -30,10 +30,9 @@ namespace SHADE
return newPipeline; return newPipeline;
} }
void SHPipelineLibrary::Init(Handle<SHVkLogicalDevice> device, Handle<SHGraphicsGlobalData> inGlobalData) noexcept void SHPipelineLibrary::Init(Handle<SHVkLogicalDevice> device) noexcept
{ {
logicalDevice = device; logicalDevice = device;
globalData = inGlobalData;
} }
Handle<SHVkPipeline> SHPipelineLibrary::GetDrawPipline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept Handle<SHVkPipeline> SHPipelineLibrary::GetDrawPipline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept

View File

@ -25,13 +25,8 @@ namespace SHADE
//! a map of pipelines that are hashed using a pair of shader module handles //! a map of pipelines that are hashed using a pair of shader module handles
std::unordered_map<std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>>, Handle<SHVkPipeline>> pipelines; std::unordered_map<std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>>, Handle<SHVkPipeline>> pipelines;
// Global data
Handle<SHGraphicsGlobalData> globalData;
public: public:
void Init (Handle<SHVkLogicalDevice> device, Handle<SHGraphicsGlobalData> inGlobalData) noexcept; void Init (Handle<SHVkLogicalDevice> device) noexcept;
// Draw pipeline functions. used only when creating pipelines for drawing using a vertex and fragment shader // Draw pipeline functions. used only when creating pipelines for drawing using a vertex and fragment shader
Handle<SHVkPipeline> CreateDrawPipeline ( Handle<SHVkPipeline> CreateDrawPipeline (

View File

@ -20,18 +20,36 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/Commands/SHVkCommandBuffer.h" #include "Graphics/Commands/SHVkCommandBuffer.h"
#include "Graphics/SHVkUtil.h" #include "Graphics/SHVkUtil.h"
#include "Tools/SHLogger.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 namespace SHADE
{ {
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Usage Functions */ /* Usage Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
Handle<SHTexture> SHTextureLibrary::Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, SHTexture::TextureFormat format, uint32_t mipLevels) Handle<SHTexture> SHTextureLibrary::Add(const SHTextureAsset& texAsset, Handle<SHVkSampler> sampler)
{
return Add
(
texAsset.numBytes,
texAsset.pixelData,
texAsset.width, texAsset.height,
texAsset.format,
texAsset.mipOffsets,
sampler
);
}
Handle<SHTexture> SHTextureLibrary::Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, uint32_t width, uint32_t height, SHTexture::TextureFormat format, std::vector<uint32_t> mipOffsets, Handle<SHVkSampler> sampler)
{ {
isDirty = true; isDirty = true;
auto handle = resourceManager.Create<SHTexture>(); auto handle = resourceManager.Create<SHTexture>();
addJobs.emplace_back(AddJob { pixelCount, pixelData, format, mipLevels }); addJobs.emplace_back(AddJob { pixelCount, pixelData, format, sampler, mipOffsets, width, height, handle });
return handle; return handle;
} }
@ -44,22 +62,48 @@ namespace SHADE
isDirty = true; isDirty = true;
} }
void SHTextureLibrary::BuildImages(Handle<SHVkLogicalDevice> device, Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHVkQueue> graphicsQueue, Handle<SHVkDescriptorPool> descPool, Handle<SHVkDescriptorSetLayout> descLayout) void SHTextureLibrary::BuildTextures(Handle<SHVkLogicalDevice> device, Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHVkQueue> graphicsQueue, Handle<SHVkDescriptorPool> descPool)
{ {
// Don't do anything if there are no updates
if (!isDirty)
return;
/* Remove Textures */ /* Remove Textures */
std::vector<vk::ImageMemoryBarrier> pipelineBarriers(addJobs.size()); // TODO
/* Add Textures */ /* Add Textures */
// Transition // Load Textures - Transitions
std::vector<vk::ImageMemoryBarrier> pipelineBarriers(addJobs.size());
for (int i = 0; auto& job : addJobs) for (int i = 0; auto& job : addJobs)
{ {
job.Image = resourceManager.Create<SHVkImage>(); job.Image = resourceManager.Create<SHVkImage>
(
&device->GetVMAAllocator(),
SHImageCreateParams
{
.imageType = vk::ImageType::e2D,
.width = job.Width,
.height = job.Height,
.depth = 1,
.levels = static_cast<uint8_t>(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]); job.Image->PrepareImageTransitionInfo(vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, pipelineBarriers[i]);
++i; ++i;
} }
vk::PipelineStageFlagBits srcStage = vk::PipelineStageFlagBits::eTopOfPipe; vk::PipelineStageFlagBits srcStage = vk::PipelineStageFlagBits::eTopOfPipe;
vk::PipelineStageFlagBits dstStage = vk::PipelineStageFlagBits::eTopOfPipe; vk::PipelineStageFlagBits dstStage = vk::PipelineStageFlagBits::eTopOfPipe;
preparePipelineBarriers(vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, srcStage, dstStage, pipelineBarriers); preparePipelineBarriers(vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, srcStage, dstStage, pipelineBarriers);
cmdBuffer->BeginRecording();
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, pipelineBarriers); cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, pipelineBarriers);
// Copy // Copy
@ -73,13 +117,16 @@ namespace SHADE
{ {
// Transition // Transition
job.Image->PrepareImageTransitionInfo(vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal, pipelineBarriers[i]); job.Image->PrepareImageTransitionInfo(vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal, pipelineBarriers[i]);
++i;
} }
preparePipelineBarriers(vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal, srcStage, dstStage, pipelineBarriers); 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 // Execute Commands
cmdBuffer->EndRecording();
graphicsQueue->SubmitCommandBuffer({ cmdBuffer }); graphicsQueue->SubmitCommandBuffer({ cmdBuffer });
device->WaitIdle(); device->WaitIdle();
graphicsQueue->GetVkQueue().waitIdle();
// Create Image View // Create Image View
for (auto& job : addJobs) for (auto& job : addJobs)
@ -90,16 +137,45 @@ namespace SHADE
.format = job.TextureFormat, .format = job.TextureFormat,
.imageAspectFlags = vk::ImageAspectFlagBits::eColor, .imageAspectFlags = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0, .baseMipLevel = 0,
.mipLevelCount = job.MipLevels, .mipLevelCount = static_cast<uint32_t>(job.MipOffsets.size()),
.baseArrayLayer = 0, .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 // Add Textures
Handle<SHVkDescriptorSetGroup> descSetGroup = descPool->Allocate({ descLayout }, { 1 }); 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<uint32_t>(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; 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;
//
//}
}
} }

View File

@ -14,6 +14,8 @@ of DigiPen Institute of Technology is prohibited.
// STL Includes // STL Includes
#include <vector> #include <vector>
// External Dependencies
#include "tinyddsloader.h"
// Project Includes // Project Includes
#include "Resource/Handle.h" #include "Resource/Handle.h"
#include "Resource/ResourceLibrary.h" #include "Resource/ResourceLibrary.h"
@ -33,6 +35,9 @@ namespace SHADE
class SHVkQueue; class SHVkQueue;
class SHVkDescriptorPool; class SHVkDescriptorPool;
class SHVkDescriptorSetLayout; class SHVkDescriptorSetLayout;
class SHVkDescriptorSetGroup;
class SHVkSampler;
class SHTextureAsset;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Type Definitions */ /* Type Definitions */
@ -43,7 +48,7 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Type Definitions */ /* Type Definitions */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
using PixelChannel = float; using PixelChannel = unsigned char;
using TextureFormat = vk::Format; // TODO: Change using TextureFormat = vk::Format; // TODO: Change
using Index = uint32_t; using Index = uint32_t;
@ -71,7 +76,7 @@ namespace SHADE
\brief \brief
Adds a texture to the Texture Library. But this does not mean that the 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. transfer all textures into the GPU.
\param pixelCount \param pixelCount
@ -88,13 +93,15 @@ namespace SHADE
*/ */
/*******************************************************************************/ /*******************************************************************************/
Handle<SHTexture> Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, SHTexture::TextureFormat format, uint32_t mipLevels);
Handle<SHTexture> Add(const SHTextureAsset& texAsset, Handle<SHVkSampler> sampler);
Handle<SHTexture> Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, uint32_t width, uint32_t height, SHTexture::TextureFormat format, std::vector<uint32_t> mipOffsets, Handle<SHVkSampler> sampler);
/*******************************************************************************/ /*******************************************************************************/
/*! /*!
\brief \brief
Removes a mesh from the Texture Library. But this does not mean that the 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. finalise all changes.
\param mesh \param mesh
@ -118,12 +125,12 @@ namespace SHADE
queue. queue.
*/ */
/***************************************************************************/ /***************************************************************************/
void BuildImages(Handle<SHVkLogicalDevice> device, Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHVkQueue> graphicsQueue, Handle<SHVkDescriptorPool> descPool, Handle<SHVkDescriptorSetLayout> descLayout); void BuildTextures(Handle<SHVkLogicalDevice> device, Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHVkQueue> graphicsQueue, Handle<SHVkDescriptorPool> descPool);
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Getter Functions */ /* Getter Functions */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
Handle<SHVkBuffer> GetTextureBuffer() const noexcept { return texStorageBuffer; } Handle<SHVkDescriptorSetGroup> GetTextureDescriptorSetGroup() const noexcept { return texDescriptors; }
private: private:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
@ -134,9 +141,12 @@ namespace SHADE
uint32_t PixelCount = 0; uint32_t PixelCount = 0;
const SHTexture::PixelChannel* PixelData = nullptr; const SHTexture::PixelChannel* PixelData = nullptr;
SHTexture::TextureFormat TextureFormat = {}; SHTexture::TextureFormat TextureFormat = {};
uint32_t MipLevels = 0; Handle<SHVkSampler> Sampler;
std::vector<uint32_t> MipOffsets;
uint32_t Width;
uint32_t Height;
Handle<SHTexture> TextureHandle;
Handle<SHVkImage> Image; Handle<SHVkImage> Image;
Handle<SHTexture> Handle;
}; };
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
@ -149,9 +159,9 @@ namespace SHADE
ResourceManager resourceManager; ResourceManager resourceManager;
std::vector<Handle<SHTexture>> texOrder; std::vector<Handle<SHTexture>> texOrder;
// CPU Storage // CPU Storage
std::vector<SHTexture::PixelChannel> texStorage; std::vector<std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, vk::ImageLayout>> combinedImageSamplers;
// GPU Storage // GPU Storage
Handle<SHVkBuffer> texStorageBuffer{}; Handle<SHVkDescriptorSetGroup> texDescriptors;
// Flags // Flags
bool isDirty = true; bool isDirty = true;
@ -159,5 +169,6 @@ namespace SHADE
/* Helper Functions */ /* Helper Functions */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
void preparePipelineBarriers(vk::ImageLayout oldLayout, vk::ImageLayout newLayout, vk::PipelineStageFlagBits& srcStage, vk::PipelineStageFlagBits& dstStage, std::vector<vk::ImageMemoryBarrier>& barriers); void preparePipelineBarriers(vk::ImageLayout oldLayout, vk::ImageLayout newLayout, vk::PipelineStageFlagBits& srcStage, vk::PipelineStageFlagBits& dstStage, std::vector<vk::ImageMemoryBarrier>& barriers);
vk::Format ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear);
}; };
} }

View File

@ -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 <functional>
// Project Header
#include "Graphics/Images/SHVkSampler.h"
#include "Graphics/Devices/SHVkLogicalDevice.h"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Utility Functions */
/*---------------------------------------------------------------------------------*/
void SHSamplerCache::Clear()
{
samplersMap.clear();
}
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
Handle<SHVkSampler> SHSamplerCache::GetSampler(Handle<SHVkLogicalDevice> 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<uint8_t>{};
static auto floatHasher = std::hash<float>{};
const RawSamplerHash H1 = charHasher(static_cast<uint8_t>(minFilter));
const RawSamplerHash H2 = charHasher(static_cast<uint8_t>(magFilter));
const RawSamplerHash H3 = charHasher(static_cast<uint8_t>(addressMode));
const RawSamplerHash H4 = charHasher(static_cast<uint8_t>(mipmapMode));
const RawSamplerHash H5 = floatHasher(minLod);
const RawSamplerHash H6 = floatHasher(maxLod);
return H1 ^ (H2 << 1) ^ (H3 << 2) ^ (H4 << 3) ^ (H5 << 4) ^ (H6 << 5);
}
}

View File

@ -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 <unordered_map>
// 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 */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Clears the cache, destroying all created samplers.
/// </summary>
void Clear();
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Retrieves a Vulkan Sampler of the specified type. If this was retrieved
/// before, a cached copy of the Vulkan Sampler will be provided.
/// </summary>
/// <param name="device">Logical device to create the sampler with if needed.</param>
/// <param name="params">Describes the parameters for the sampler.</param>
/// <returns>Handle to the SHVkSampler object specified.</returns>
Handle<SHVkSampler> GetSampler(Handle<SHVkLogicalDevice> device, const SHVkSamplerParams& params);
private:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
using RawSamplerHash = size_t;
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
// Resources
std::unordered_map<RawSamplerHash, Handle<SHVkSampler>> samplersMap;
/*---------------------------------------------------------------------------------*/
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
static RawSamplerHash calcHash(vk::Filter minFilter, vk::Filter magFilter, vk::SamplerAddressMode addressMode, vk::SamplerMipmapMode mipmapMode, float minLod, float maxLod);
};
}

View File

@ -216,10 +216,13 @@ namespace SHADE
/***************************************************************************/ /***************************************************************************/
void SHVkPipelineLayout::PrepareVkDescriptorSetLayouts(void) noexcept void SHVkPipelineLayout::PrepareVkDescriptorSetLayouts(void) noexcept
{ {
descriptorSetLayoutsPipeline.reserve(descriptorSetLayoutsAllocate.size() + descriptorSetLayoutsGlobal.size());
// Settle allocate layouts first // Settle allocate layouts first
vkDescriptorSetLayoutsAllocate.reserve(descriptorSetLayoutsAllocate.size()); vkDescriptorSetLayoutsAllocate.reserve(descriptorSetLayoutsAllocate.size());
for (auto const& layout : descriptorSetLayoutsAllocate) for (auto const& layout : descriptorSetLayoutsAllocate)
{ {
descriptorSetLayoutsPipeline.emplace_back(layout);
vkDescriptorSetLayoutsAllocate.emplace_back(layout->GetVkHandle()); vkDescriptorSetLayoutsAllocate.emplace_back(layout->GetVkHandle());
} }
@ -228,7 +231,10 @@ namespace SHADE
// First we insert the global layouts // First we insert the global layouts
for (auto const& layout : descriptorSetLayoutsGlobal) for (auto const& layout : descriptorSetLayoutsGlobal)
{
descriptorSetLayoutsPipeline.emplace_back(layout);
vkDescriptorSetLayoutsPipeline.emplace_back(layout->GetVkHandle()); vkDescriptorSetLayoutsPipeline.emplace_back(layout->GetVkHandle());
}
// Then we append layouts for allocation at the back of the vector // Then we append layouts for allocation at the back of the vector
std::copy(vkDescriptorSetLayoutsAllocate.begin(), vkDescriptorSetLayoutsAllocate.end(), std::back_inserter(vkDescriptorSetLayoutsPipeline)); std::copy(vkDescriptorSetLayoutsAllocate.begin(), vkDescriptorSetLayoutsAllocate.end(), std::back_inserter(vkDescriptorSetLayoutsPipeline));
@ -435,6 +441,16 @@ namespace SHADE
return {}; return {};
} }
std::vector<Handle<SHVkDescriptorSetLayout>> SHVkPipelineLayout::GetDescriptorSetLayoutsPipeline(void) const noexcept
{
return descriptorSetLayoutsPipeline;
}
std::vector<Handle<SHVkDescriptorSetLayout>> SHVkPipelineLayout::GetDescriptorSetLayoutsAllocate(void) const noexcept
{
return descriptorSetLayoutsAllocate;
}
SHVkPipelineLayout& SHVkPipelineLayout::operator=(SHVkPipelineLayout&& rhs) noexcept SHVkPipelineLayout& SHVkPipelineLayout::operator=(SHVkPipelineLayout&& rhs) noexcept
{ {
if (&rhs == this) if (&rhs == this)

View File

@ -42,6 +42,9 @@ namespace SHADE
//! We want to store this also because we need to allocate later //! We want to store this also because we need to allocate later
std::vector<vk::DescriptorSetLayout> vkDescriptorSetLayoutsAllocate; std::vector<vk::DescriptorSetLayout> vkDescriptorSetLayoutsAllocate;
//! Store for descriptor set group creation
std::vector<Handle<SHVkDescriptorSetLayout>> descriptorSetLayoutsPipeline;
//! Store for pipeline layout recreation //! Store for pipeline layout recreation
std::vector<vk::DescriptorSetLayout> vkDescriptorSetLayoutsPipeline; std::vector<vk::DescriptorSetLayout> vkDescriptorSetLayoutsPipeline;
@ -71,10 +74,12 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */ /* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
std::vector<Handle<SHVkShaderModule>> const& GetShaderModules (void) const noexcept; std::vector<Handle<SHVkShaderModule>> const& GetShaderModules (void) const noexcept;
vk::PipelineLayout GetVkPipelineLayout (void) const noexcept; vk::PipelineLayout GetVkPipelineLayout (void) const noexcept;
SHPushConstantInterface const& GetPushConstantInterface (void) const noexcept; SHPushConstantInterface const& GetPushConstantInterface (void) const noexcept;
Handle<SHShaderBlockInterface> GetShaderBlockInterface (uint32_t set, uint32_t binding, vk::ShaderStageFlagBits shaderStage) const noexcept; Handle<SHShaderBlockInterface> GetShaderBlockInterface (uint32_t set, uint32_t binding, vk::ShaderStageFlagBits shaderStage) const noexcept;
std::vector<Handle<SHVkDescriptorSetLayout>> GetDescriptorSetLayoutsPipeline(void) const noexcept;
std::vector<Handle<SHVkDescriptorSetLayout>> GetDescriptorSetLayoutsAllocate(void) const noexcept;
}; };
} }

View File

@ -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,
};
}

View File

@ -11,655 +11,7 @@
namespace SHADE namespace SHADE
{ {
/***************************************************************************/
/*!
\brief
Non-default ctor for the resource. Using the type of the resource, we
decide whether or not we create a resource or link with a swapchain
resource (image).
\param logicalDevice
Logical device required to create an image resource if the type is NOT
SH_ATT_DESC_TYPE::COLOR_PRESENT.
\param swapchain
Swapchain required to get swapchain image if the type IS
SH_ATT_DESC_TYPE::COLOR_PRESENT.
\param type
Type of the image resource.
\param format
Format of the image resource.
\param w
Width of the image resource.
\param h
Height of the image resource.
\param levels
Number of mipmap levels of the image resource.
\param createFlags
Create flags used when an image resource needs to be created.
*/
/***************************************************************************/
SHRenderGraphResource::SHRenderGraphResource(Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, std::string const& name, SH_ATT_DESC_TYPE type, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageCreateFlagBits createFlags) noexcept
: resourceType{ type }
, resourceFormat{ format }
, images{}
, imageViews{}
, width{ w }
, height{ h }
, mipLevels{ levels }
, resourceName{ name }
{
// If the resource type is an arbitrary image and not swapchain image
if (type != SH_ATT_DESC_TYPE::COLOR_PRESENT)
{
vk::ImageAspectFlags imageAspectFlags;
vk::ImageUsageFlags usage = {};
// Check the resource type and set image usage flags and image aspect flags accordingly
switch (resourceType)
{
case SH_ATT_DESC_TYPE::COLOR:
usage |= vk::ImageUsageFlagBits::eColorAttachment;
imageAspectFlags |= vk::ImageAspectFlagBits::eColor;
break;
case SH_ATT_DESC_TYPE::DEPTH:
usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment;
imageAspectFlags |= vk::ImageAspectFlagBits::eDepth;
break;
case SH_ATT_DESC_TYPE::STENCIL:
usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment;
imageAspectFlags |= vk::ImageAspectFlagBits::eStencil;
break;
case SH_ATT_DESC_TYPE::DEPTH_STENCIL:
usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment;
imageAspectFlags |= vk::ImageAspectFlagBits::eStencil | vk::ImageAspectFlagBits::eDepth;
break;
}
// The resource is not a swapchain image, just use the first slot of the vector
images.push_back(logicalDevice->CreateImage(width, height, mipLevels, resourceFormat, usage, createFlags));
// prepare image view details
SHImageViewDetails viewDetails
{
.viewType = vk::ImageViewType::e2D,
.format = images[0]->GetImageFormat(),
.imageAspectFlags = imageAspectFlags,
.baseMipLevel = 0,
.mipLevelCount = mipLevels,
.baseArrayLayer = 0,
.layerCount = 1,
};
// just 1 image view created
imageViews.push_back(images[0]->CreateImageView(logicalDevice, images[0], viewDetails));
}
else // if swapchain image resource
{
// Prepare image view details
SHImageViewDetails viewDetails
{
.viewType = vk::ImageViewType::e2D,
.format = swapchain->GetSurfaceFormatKHR().format,
.imageAspectFlags = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.mipLevelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
};
// We want an image handle for every swapchain image
images.resize(swapchain->GetNumImages());
imageViews.resize(swapchain->GetNumImages());
for (uint32_t i = 0; i < swapchain->GetNumImages(); ++i)
{
images[i] = swapchain->GetSwapchainImage(i);
imageViews[i] = images[i]->CreateImageView(logicalDevice, images[i], viewDetails);
}
}
}
/***************************************************************************/
/*!
\brief
Move ctor for resource.
\param rhs
The other resource.
*/
/***************************************************************************/
SHRenderGraphResource::SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept
: resourceName{ std::move(rhs.resourceName) }
, resourceType{ std::move(rhs.resourceType) }
, images{ std::move(rhs.images) }
, imageViews{ std::move(rhs.imageViews) }
, resourceFormat{ std::move(rhs.resourceFormat) }
, width{ rhs.width }
, height{ rhs.height }
, mipLevels{ rhs.mipLevels }
{
}
/***************************************************************************/
/*!
\brief
Move assignment operator.
\param rhs
The other resource.
\return
*/
/***************************************************************************/
SHRenderGraphResource& SHRenderGraphResource::operator=(SHRenderGraphResource&& rhs) noexcept
{
if (this == &rhs)
return *this;
resourceName = std::move(rhs.resourceName);
resourceType = std::move(rhs.resourceType);
images = std::move(rhs.images);
imageViews = std::move(rhs.imageViews);
resourceFormat = std::move(rhs.resourceFormat);
width = rhs.width;
height = rhs.height;
mipLevels = rhs.mipLevels;
return *this;
}
/***************************************************************************/
/*!
\brief
Destructor for resource.
*/
/***************************************************************************/
SHRenderGraphResource::~SHRenderGraphResource(void) noexcept
{
}
/***************************************************************************/
/*!
\brief
Subpass non-default constructor. Simply initializes variables.
\param mapping
Mapping from a resource handle to an attachment reference referencing
the resource.
\param resources
A mapping from string to render graph resource.
*/
/***************************************************************************/
SHSubpass::SHSubpass(ResourceManager& rm, Handle<SHRenderGraphNode> const& parent, uint32_t index, std::unordered_map<uint64_t, uint32_t> const* mapping, std::unordered_map<std::string, Handle<SHRenderGraphResource>> 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<SHVkCommandBuffer>& 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<void(Handle<SHVkCommandBuffer>&)> const& newDrawCall) noexcept
{
exteriorDrawCalls.push_back(newDrawCall);
}
void SHSubpass::Init(ResourceManager& resourceManager) noexcept
{
superBatch = resourceManager.Create<SHSuperBatch>(GetHandle());
}
/***************************************************************************/
/*!
\brief
Getter for parent renderpass.
\return
Returns the parent renderpass the subpass belongs to.
*/
/***************************************************************************/
Handle<SHRenderGraphNode> const& SHSubpass::GetParentNode(void) const noexcept
{
return parentNode;
}
SHADE::SHSubPassIndex SHSubpass::GetIndex() const noexcept
{
return subpassIndex;
}
Handle<SHSuperBatch> 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<Handle<SHVkImageView>> imageViews(attResources.size());
uint32_t fbWidth = std::numeric_limits<uint32_t>::max();
uint32_t fbHeight = std::numeric_limits<uint32_t>::max();
for (uint32_t j = 0; j < attResources.size(); ++j)
{
uint32_t imageViewIndex = (attResources[j]->resourceType == SH_ATT_DESC_TYPE::COLOR_PRESENT) ? i : 0;
imageViews[j] = attResources[j]->imageViews[imageViewIndex];
// We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's
if (fbWidth > attResources[j]->width)
fbWidth = attResources[j]->width;
if (fbHeight > attResources[j]->height)
fbHeight = attResources[j]->height;
}
framebuffers[i] = logicalDeviceHdl->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight);
}
}
/***************************************************************************/
/*!
\brief
Render Graph node constructor. Note that we do not create the renderpass
yet. This is because layouts of attachment descriptions facilitate image
transitions and we cannot know guarantee layouts until we've seen all
renderpasses and their subpasses in the graph.
\param swapchain
Swapchain required to query number of images as parameters for number
of framebuffers to create.
\param attachmentDescriptionTypes
\return
*/
/***************************************************************************/
SHRenderGraphNode::SHRenderGraphNode(ResourceManager& rm, Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, std::vector<Handle<SHRenderGraphResource>> attRes, std::vector<Handle<SHRenderGraphNode>> predecessors, std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* resources, Handle<SHGraphicsGlobalData> 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<SHSubpass> SHRenderGraphNode::AddSubpass(std::string subpassName) noexcept
{
// if subpass already exists, don't add.
if (subpassIndexing.contains(subpassName))
{
SHLOG_ERROR("Subpass already exists.");
return{};
}
// Add subpass to container and create mapping for it
subpasses.emplace_back(resourceManager.Create<SHSubpass>(resourceManager, GetHandle(), subpasses.size(), &resourceAttachmentMapping, ptrToResources));
subpassIndexing.try_emplace(subpassName, static_cast<uint32_t>(subpasses.size()) - 1u);
Handle<SHSubpass> subpass = subpasses.back();
subpass->Init(resourceManager);
// Register the SuperBatch
batcher.RegisterSuperBatch(subpass->GetSuperBatch());
return subpass;
}
void SHRenderGraphNode::Execute(Handle<SHVkCommandBuffer>& 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<SHVkPipeline> SHRenderGraphNode::GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> 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<SHVkPipeline> 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<SHVkRenderpass> SHRenderGraphNode::GetRenderpass(void) const noexcept
{
return renderpass;
}
Handle<SHSubpass> 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; attDesc.loadOp = vk::AttachmentLoadOp::eLoad;
predAttDesc.storeOp = vk::AttachmentStoreOp::eStore; 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 // 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 // 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<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, Handle<SHGraphicsGlobalData> inGlobalData) noexcept void SHRenderGraph::Init(Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain) noexcept
{ {
logicalDeviceHdl = logicalDevice; logicalDeviceHdl = logicalDevice;
swapchainHdl = swapchain; swapchainHdl = swapchain;
globalData = inGlobalData;
} }
/***************************************************************************/ /***************************************************************************/
@ -1012,7 +363,6 @@ namespace SHADE
, nodes{ std::move(rhs.nodes) } , nodes{ std::move(rhs.nodes) }
, graphResources{ std::move(rhs.graphResources) } , graphResources{ std::move(rhs.graphResources) }
, resourceManager{ std::move(rhs.resourceManager) } , resourceManager{ std::move(rhs.resourceManager) }
, globalData{ rhs.globalData }
{ {
} }
@ -1028,7 +378,6 @@ namespace SHADE
nodes = std::move(rhs.nodes); nodes = std::move(rhs.nodes);
graphResources = std::move(rhs.graphResources); graphResources = std::move(rhs.graphResources);
resourceManager = std::move(rhs.resourceManager); resourceManager = std::move(rhs.resourceManager);
globalData = rhs.globalData;
return *this; return *this;
} }
@ -1086,7 +435,7 @@ namespace SHADE
} }
} }
nodes.emplace_back(resourceManager.Create<SHRenderGraphNode>(resourceManager, logicalDeviceHdl, swapchainHdl, std::move(resources), std::move(predecessors), &graphResources, globalData)); nodes.emplace_back(resourceManager.Create<SHRenderGraphNode>(resourceManager, logicalDeviceHdl, swapchainHdl, std::move(resources), std::move(predecessors), &graphResources));
nodeIndexing.emplace(nodeName, static_cast<uint32_t>(nodes.size()) - 1u); nodeIndexing.emplace(nodeName, static_cast<uint32_t>(nodes.size()) - 1u);
return nodes.at(nodeIndexing[nodeName]); 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 // TODO: The graph scope buffers were meant to bind vertex buffers and index buffers for meshes. Find a
// better way to manage these // better way to manage these
void SHRenderGraph::Execute(uint32_t frameIndex, Handle<SHVkCommandBuffer> cmdBuffer) noexcept void SHRenderGraph::Execute(uint32_t frameIndex, Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHVkDescriptorPool> descPool) noexcept
{ {
// TODO: DON'T HARDCODE THIS // TODO: DON'T HARDCODE THIS
cmdBuffer->SetViewportScissor(1920.0f, 1080.0f, 1920, 1080); cmdBuffer->SetViewportScissor(1920.0f, 1080.0f, 1920, 1080);
for (auto& node : nodes) 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<SHVkDescriptorPool> descPool)
{ {
for (auto& node : nodes) for (auto& node : nodes)
{ {
node->FinaliseBatch(frameIndex); node->FinaliseBatch(frameIndex, descPool);
} }
} }

View File

@ -7,6 +7,12 @@
#include "Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h" #include "Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h"
#include "Graphics/MiddleEnd/Batching/SHSuperBatch.h" #include "Graphics/MiddleEnd/Batching/SHSuperBatch.h"
#include "../MiddleEnd/Batching/SHBatcher.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 <string> #include <string>
#include <map> #include <map>
@ -24,223 +30,6 @@ namespace SHADE
class SHRenderGraphNode; class SHRenderGraphNode;
class SHGraphicsGlobalData; 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<Handle<SHVkImage>> images;
//! Views to resources (vector because same rationale as images. see above).
std::vector<Handle<SHVkImageView>> imageViews;
//! Image format
vk::Format resourceFormat;
//! width of the resource
uint32_t width;
//! Height of the resource
uint32_t height;
//! Number of mipmap levels
uint8_t mipLevels;
public:
/*-----------------------------------------------------------------------*/
/* CTORS AND DTORS */
/*-----------------------------------------------------------------------*/
SHRenderGraphResource(Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, std::string const& name, SH_ATT_DESC_TYPE type, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageCreateFlagBits createFlags) noexcept;
SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept;
SHRenderGraphResource& operator=(SHRenderGraphResource&& rhs) noexcept;
~SHRenderGraphResource(void) noexcept;
friend class SHRenderGraphNode;
friend class SHRenderGraph;
};
class SH_API SHSubpass : public ISelfHandle<SHSubpass>
{
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<SHRenderGraphNode> parentNode;
//!
Handle<SHSuperBatch> superBatch;
//! Color attachments
std::vector<vk::AttachmentReference> colorReferences;
//! Depth attachments
std::vector<vk::AttachmentReference> depthReferences;
//! Input attachments
std::vector<vk::AttachmentReference> inputReferences;
//! For getting attachment reference indices using handles
std::unordered_map<uint64_t, uint32_t> const* resourceAttachmentMapping;
//! Pointer to resources in the render graph (for getting handle IDs)
std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* ptrToResources;
//! 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<std::function<void(Handle<SHVkCommandBuffer>&)>> exteriorDrawCalls;
public:
/*-----------------------------------------------------------------------*/
/* CTORS AND DTORS */
/*-----------------------------------------------------------------------*/
SHSubpass(ResourceManager& rm, Handle<SHRenderGraphNode> const& parent, uint32_t index, std::unordered_map<uint64_t, uint32_t> const* mapping, std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* ptrToResources) noexcept;
SHSubpass(SHSubpass&& rhs) noexcept;
SHSubpass& operator=(SHSubpass&& rhs) noexcept;
/*-----------------------------------------------------------------------*/
/* 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<SHVkCommandBuffer>& commandBuffer, uint32_t frameIndex) noexcept;
void AddExteriorDrawCalls(std::function<void(Handle<SHVkCommandBuffer>&)> const& newDrawCall) noexcept;
void Init (ResourceManager& resourceManager) noexcept;
/*-----------------------------------------------------------------------*/
/* GETTERS AND SETTERS */
/*-----------------------------------------------------------------------*/
Handle<SHRenderGraphNode> const& GetParentNode(void) const noexcept;
SHSubPassIndex GetIndex() const noexcept;
Handle<SHSuperBatch> GetSuperBatch (void) const noexcept;
friend class SHRenderGraphNode;
friend class SHRenderGraph;
};
class SH_API SHRenderGraphNode : public ISelfHandle<SHRenderGraphNode>
{
private:
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/
ResourceManager& resourceManager;
//! For Vulkan object creation
Handle<SHVkLogicalDevice> logicalDeviceHdl;
//! Each node will have a renderpass and each renderpass will have its own subpasses.
//! These subpasses will execute sequentially.
Handle<SHVkRenderpass> renderpass;
//! Framebuffers used in this renderpass. If renderpass contains usage of a swapchain image
//! used for presenting, then we cannot use just 1 framebuffer, we need to have 1 for however many frames in flight.
std::vector<Handle<SHVkFramebuffer>> framebuffers;
//! Nodes that must finish execution before this node is executed will be in this container
std::vector<Handle<SHRenderGraphNode>> prereqNodes;
//! Container of Attachment descriptions
std::vector<vk::AttachmentDescription> attachmentDescriptions;
//! Resources used in this renderpass
std::vector<Handle<SHRenderGraphResource>> attResources;
//! Vector of subpasses
std::vector<Handle<SHSubpass>> subpasses;
//! Descriptions to pass to renderpass for renderpass creation. We want to keep this here because
std::vector<vk::SubpassDescription> spDescs;
//! Subpass dependencies for renderpass creation
std::vector<vk::SubpassDependency> spDeps;
//! For indexing resources fast
std::unordered_map<uint64_t, uint32_t> resourceAttachmentMapping;
//! For indexing subpasses
std::map<std::string, uint32_t> subpassIndexing;
//! Pointer to resources in the render graph (for getting handle IDs)
std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* ptrToResources;
//! 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<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, std::vector<Handle<SHRenderGraphResource>> attRes, std::vector<Handle<SHRenderGraphNode>> predecessors, std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* resources, Handle<SHGraphicsGlobalData> globalData) noexcept;
SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept;
SHRenderGraphNode& operator= (SHRenderGraphNode&& rhs) noexcept;
/*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
Handle<SHSubpass> AddSubpass (std::string subpassName) noexcept;
// TODO: RemoveSubpass()
void Execute (Handle<SHVkCommandBuffer>& commandBuffer, uint32_t frameIndex) noexcept;
Handle<SHVkPipeline> GetOrCreatePipeline (std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> subpass) noexcept;
void FinaliseBatch(uint32_t frameIndex);
/*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/
Handle<SHVkRenderpass> GetRenderpass (void) const noexcept;
Handle<SHSubpass> GetSubpass(std::string_view subpassName) const noexcept;
friend class SHRenderGraph;
};
class SH_API SHRenderGraph class SH_API SHRenderGraph
{ {
@ -273,9 +62,6 @@ namespace SHADE
//! Resource library for graph handles //! Resource library for graph handles
ResourceManager resourceManager; ResourceManager resourceManager;
//! Handle to global data
Handle<SHGraphicsGlobalData> globalData;
public: public:
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* CTORS AND DTORS */ /* CTORS AND DTORS */
@ -288,12 +74,12 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */ /* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
void Init (Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, Handle<SHGraphicsGlobalData> inGlobalData) noexcept; void Init (Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain) noexcept;
void AddResource (std::string resourceName, SH_ATT_DESC_TYPE type, uint32_t w = static_cast<uint32_t>(-1), uint32_t h = static_cast<uint32_t>(-1), vk::Format format = vk::Format::eB8G8R8A8Unorm, uint8_t levels = 1, vk::ImageCreateFlagBits createFlags = {}); void AddResource (std::string resourceName, SH_ATT_DESC_TYPE type, uint32_t w = static_cast<uint32_t>(-1), uint32_t h = static_cast<uint32_t>(-1), vk::Format format = vk::Format::eB8G8R8A8Unorm, uint8_t levels = 1, vk::ImageCreateFlagBits createFlags = {});
Handle<SHRenderGraphNode> AddNode (std::string nodeName, std::initializer_list<std::string> resourceNames, std::initializer_list<std::string> predecessorNodes) noexcept; Handle<SHRenderGraphNode> AddNode (std::string nodeName, std::initializer_list<std::string> resourceNames, std::initializer_list<std::string> predecessorNodes) noexcept;
void Generate (void) noexcept; void Generate (void) noexcept;
void Execute (uint32_t frameIndex, Handle<SHVkCommandBuffer> cmdBuffer) noexcept; void Execute (uint32_t frameIndex, Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHVkDescriptorPool> descPool) noexcept;
void FinaliseBatch(uint32_t frameIndex); void FinaliseBatch(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */ /* SETTERS AND GETTERS */

View File

@ -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<Handle<SHVkImageView>> imageViews(attResources.size());
uint32_t fbWidth = std::numeric_limits<uint32_t>::max();
uint32_t fbHeight = std::numeric_limits<uint32_t>::max();
for (uint32_t j = 0; j < attResources.size(); ++j)
{
uint32_t imageViewIndex = (attResources[j]->resourceType == SH_ATT_DESC_TYPE::COLOR_PRESENT) ? i : 0;
imageViews[j] = attResources[j]->imageViews[imageViewIndex];
// We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's
if (fbWidth > attResources[j]->width)
fbWidth = attResources[j]->width;
if (fbHeight > attResources[j]->height)
fbHeight = attResources[j]->height;
}
framebuffers[i] = logicalDeviceHdl->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight);
}
}
/***************************************************************************/
/*!
\brief
Render Graph node constructor. Note that we do not create the renderpass
yet. This is because layouts of attachment descriptions facilitate image
transitions and we cannot know guarantee layouts until we've seen all
renderpasses and their subpasses in the graph.
\param swapchain
Swapchain required to query number of images as parameters for number
of framebuffers to create.
\param attachmentDescriptionTypes
\return
*/
/***************************************************************************/
SHRenderGraphNode::SHRenderGraphNode(ResourceManager& rm, Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, std::vector<Handle<SHRenderGraphResource>> attRes, std::vector<Handle<SHRenderGraphNode>> predecessors, std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* resources) noexcept
: logicalDeviceHdl{ logicalDevice }
, renderpass{}
, framebuffers{}
, prereqNodes{ std::move(predecessors) }
, attachmentDescriptions{}
, resourceAttachmentMapping{}
, attResources{ std::move(attRes) }
, subpasses{}
, executed{ false }
, configured{ false }
, resourceManager{ rm }
, ptrToResources{ resources }
{
// 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<SHSubpass> SHRenderGraphNode::AddSubpass(std::string subpassName) noexcept
{
// if subpass already exists, don't add.
if (subpassIndexing.contains(subpassName))
{
SHLOG_ERROR("Subpass already exists.");
return{};
}
// Add subpass to container and create mapping for it
subpasses.emplace_back(resourceManager.Create<SHSubpass>(resourceManager, GetHandle(), subpasses.size(), &resourceAttachmentMapping, ptrToResources));
subpassIndexing.try_emplace(subpassName, static_cast<uint32_t>(subpasses.size()) - 1u);
Handle<SHSubpass> subpass = subpasses.back();
subpass->Init(resourceManager);
// Register the SuperBatch
batcher.RegisterSuperBatch(subpass->GetSuperBatch());
return subpass;
}
void SHRenderGraphNode::Execute(Handle<SHVkCommandBuffer>& commandBuffer, Handle<SHVkDescriptorPool> 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<SHVkPipeline> SHRenderGraphNode::GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> 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<SHVkPipeline> pipeline = pipelineLibrary.GetDrawPipline(vsFsPair);
if (!pipeline)
{
pipeline = pipelineLibrary.CreateDrawPipeline
(
vsFsPair,
renderpass,
subpass
);
}
return pipeline;
}
void SHRenderGraphNode::FinaliseBatch(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{
batcher.FinaliseBatches(logicalDeviceHdl, descPool, frameIndex);
}
/***************************************************************************/
/*!
\brief
Get the renderpass from the node.
\return
Handle to the renderpass.
*/
/***************************************************************************/
Handle<SHVkRenderpass> SHRenderGraphNode::GetRenderpass(void) const noexcept
{
return renderpass;
}
Handle<SHSubpass> SHRenderGraphNode::GetSubpass(std::string_view subpassName) const noexcept
{
return subpasses[subpassIndexing.at(subpassName.data())];
}
}

View File

@ -0,0 +1,110 @@
#pragma once
#include <string>
#include <unordered_map>
#include <map>
#include <vector>
#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<SHRenderGraphNode>
{
private:
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/
ResourceManager& resourceManager;
//! For Vulkan object creation
Handle<SHVkLogicalDevice> logicalDeviceHdl;
//! Each node will have a renderpass and each renderpass will have its own subpasses.
//! These subpasses will execute sequentially.
Handle<SHVkRenderpass> renderpass;
//! Framebuffers used in this renderpass. If renderpass contains usage of a swapchain image
//! used for presenting, then we cannot use just 1 framebuffer, we need to have 1 for however many frames in flight.
std::vector<Handle<SHVkFramebuffer>> framebuffers;
//! Nodes that must finish execution before this node is executed will be in this container
std::vector<Handle<SHRenderGraphNode>> prereqNodes;
//! Container of Attachment descriptions
std::vector<vk::AttachmentDescription> attachmentDescriptions;
//! Resources used in this renderpass
std::vector<Handle<SHRenderGraphResource>> attResources;
//! Vector of subpasses
std::vector<Handle<SHSubpass>> subpasses;
//! Descriptions to pass to renderpass for renderpass creation. We want to keep this here because
std::vector<vk::SubpassDescription> spDescs;
//! Subpass dependencies for renderpass creation
std::vector<vk::SubpassDependency> spDeps;
//! For indexing resources fast
std::unordered_map<uint64_t, uint32_t> resourceAttachmentMapping;
//! For indexing subpasses
std::map<std::string, uint32_t> subpassIndexing;
//! Pointer to resources in the render graph (for getting handle IDs)
std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* ptrToResources;
//! 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<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, std::vector<Handle<SHRenderGraphResource>> attRes, std::vector<Handle<SHRenderGraphNode>> predecessors, std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* resources) noexcept;
SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept;
SHRenderGraphNode& operator= (SHRenderGraphNode&& rhs) noexcept;
/*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
Handle<SHSubpass> AddSubpass(std::string subpassName) noexcept;
// TODO: RemoveSubpass()
void Execute(Handle<SHVkCommandBuffer>& commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept;
Handle<SHVkPipeline> GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> subpass) noexcept;
void FinaliseBatch(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
/*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/
Handle<SHVkRenderpass> GetRenderpass(void) const noexcept;
Handle<SHSubpass> GetSubpass(std::string_view subpassName) const noexcept;
friend class SHRenderGraph;
};
}

View File

@ -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<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, std::string const& name, SH_ATT_DESC_TYPE type, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageCreateFlagBits createFlags) noexcept
: resourceType{ type }
, resourceFormat{ format }
, images{}
, imageViews{}
, width{ w }
, height{ h }
, mipLevels{ levels }
, resourceName{ name }
{
// If the resource type is an arbitrary image and not swapchain image
if (type != SH_ATT_DESC_TYPE::COLOR_PRESENT)
{
vk::ImageAspectFlags imageAspectFlags;
vk::ImageUsageFlags usage = {};
// Check the resource type and set image usage flags and image aspect flags accordingly
switch (resourceType)
{
case SH_ATT_DESC_TYPE::COLOR:
usage |= vk::ImageUsageFlagBits::eColorAttachment;
imageAspectFlags |= vk::ImageAspectFlagBits::eColor;
break;
case SH_ATT_DESC_TYPE::DEPTH:
usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment;
imageAspectFlags |= vk::ImageAspectFlagBits::eDepth;
break;
case SH_ATT_DESC_TYPE::STENCIL:
usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment;
imageAspectFlags |= vk::ImageAspectFlagBits::eStencil;
break;
case SH_ATT_DESC_TYPE::DEPTH_STENCIL:
usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment;
imageAspectFlags |= vk::ImageAspectFlagBits::eStencil | vk::ImageAspectFlagBits::eDepth;
break;
}
// The resource is not a swapchain image, just use the first slot of the vector
images.push_back(logicalDevice->CreateImage(width, height, mipLevels, resourceFormat, usage, createFlags));
// prepare image view details
SHImageViewDetails viewDetails
{
.viewType = vk::ImageViewType::e2D,
.format = images[0]->GetImageFormat(),
.imageAspectFlags = imageAspectFlags,
.baseMipLevel = 0,
.mipLevelCount = mipLevels,
.baseArrayLayer = 0,
.layerCount = 1,
};
// just 1 image view created
imageViews.push_back(images[0]->CreateImageView(logicalDevice, images[0], viewDetails));
}
else // if swapchain image resource
{
// Prepare image view details
SHImageViewDetails viewDetails
{
.viewType = vk::ImageViewType::e2D,
.format = swapchain->GetSurfaceFormatKHR().format,
.imageAspectFlags = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.mipLevelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
};
// We want an image handle for every swapchain image
images.resize(swapchain->GetNumImages());
imageViews.resize(swapchain->GetNumImages());
for (uint32_t i = 0; i < swapchain->GetNumImages(); ++i)
{
images[i] = swapchain->GetSwapchainImage(i);
imageViews[i] = images[i]->CreateImageView(logicalDevice, images[i], viewDetails);
}
}
}
/***************************************************************************/
/*!
\brief
Move ctor for resource.
\param rhs
The other resource.
*/
/***************************************************************************/
SHRenderGraphResource::SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept
: resourceName{ std::move(rhs.resourceName) }
, resourceType{ std::move(rhs.resourceType) }
, images{ std::move(rhs.images) }
, imageViews{ std::move(rhs.imageViews) }
, resourceFormat{ std::move(rhs.resourceFormat) }
, width{ rhs.width }
, height{ rhs.height }
, mipLevels{ rhs.mipLevels }
{
}
/***************************************************************************/
/*!
\brief
Move assignment operator.
\param rhs
The other resource.
\return
*/
/***************************************************************************/
SHRenderGraphResource& SHRenderGraphResource::operator=(SHRenderGraphResource&& rhs) noexcept
{
if (this == &rhs)
return *this;
resourceName = std::move(rhs.resourceName);
resourceType = std::move(rhs.resourceType);
images = std::move(rhs.images);
imageViews = std::move(rhs.imageViews);
resourceFormat = std::move(rhs.resourceFormat);
width = rhs.width;
height = rhs.height;
mipLevels = rhs.mipLevels;
return *this;
}
/***************************************************************************/
/*!
\brief
Destructor for resource.
*/
/***************************************************************************/
SHRenderGraphResource::~SHRenderGraphResource(void) noexcept
{
}
}

View File

@ -0,0 +1,62 @@
#pragma once
#include <string>
#include "SHAttachmentDescriptionType.h"
#include <vector>
#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<Handle<SHVkImage>> images;
//! Views to resources (vector because same rationale as images. see above).
std::vector<Handle<SHVkImageView>> imageViews;
//! Image format
vk::Format resourceFormat;
//! width of the resource
uint32_t width;
//! Height of the resource
uint32_t height;
//! Number of mipmap levels
uint8_t mipLevels;
public:
/*-----------------------------------------------------------------------*/
/* CTORS AND DTORS */
/*-----------------------------------------------------------------------*/
SHRenderGraphResource(Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, std::string const& name, SH_ATT_DESC_TYPE type, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageCreateFlagBits createFlags) noexcept;
SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept;
SHRenderGraphResource& operator=(SHRenderGraphResource&& rhs) noexcept;
~SHRenderGraphResource(void) noexcept;
friend class SHRenderGraphNode;
friend class SHRenderGraph;
};
}

View File

@ -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<SHRenderGraphNode> const& parent, uint32_t index, std::unordered_map<uint64_t, uint32_t> const* mapping, std::unordered_map<std::string, Handle<SHRenderGraphResource>> 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<SHVkCommandBuffer>& commandBuffer, Handle<SHVkDescriptorPool> 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<void(Handle<SHVkCommandBuffer>&)> const& newDrawCall) noexcept
{
exteriorDrawCalls.push_back(newDrawCall);
}
void SHSubpass::Init(ResourceManager& resourceManager) noexcept
{
superBatch = resourceManager.Create<SHSuperBatch>(GetHandle());
}
/***************************************************************************/
/*!
\brief
Getter for parent renderpass.
\return
Returns the parent renderpass the subpass belongs to.
*/
/***************************************************************************/
Handle<SHRenderGraphNode> const& SHSubpass::GetParentNode(void) const noexcept
{
return parentNode;
}
SHADE::SHSubPassIndex SHSubpass::GetIndex() const noexcept
{
return subpassIndex;
}
Handle<SHSuperBatch> SHSubpass::GetSuperBatch(void) const noexcept
{
return superBatch;
}
}

View File

@ -0,0 +1,94 @@
#pragma once
#include "SHAttachmentDescriptionType.h"
#include <string>
#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<SHSubpass>
{
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<SHRenderGraphNode> parentNode;
//!
Handle<SHSuperBatch> superBatch;
//! Descriptor set layout to hold attachments
Handle<SHVkDescriptorSetLayout> descriptorSetLayout;
//! Color attachments
std::vector<vk::AttachmentReference> colorReferences;
//! Depth attachments
std::vector<vk::AttachmentReference> depthReferences;
//! Input attachments
std::vector<vk::AttachmentReference> inputReferences;
//! For getting attachment reference indices using handles
std::unordered_map<uint64_t, uint32_t> const* resourceAttachmentMapping;
//! Pointer to resources in the render graph (for getting handle IDs)
std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* ptrToResources;
//! 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<std::function<void(Handle<SHVkCommandBuffer>&)>> exteriorDrawCalls;
public:
/*-----------------------------------------------------------------------*/
/* CTORS AND DTORS */
/*-----------------------------------------------------------------------*/
SHSubpass(ResourceManager& rm, Handle<SHRenderGraphNode> const& parent, uint32_t index, std::unordered_map<uint64_t, uint32_t> const* mapping, std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* ptrToResources) noexcept;
SHSubpass(SHSubpass&& rhs) noexcept;
SHSubpass& operator=(SHSubpass&& rhs) noexcept;
/*-----------------------------------------------------------------------*/
/* 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<SHVkCommandBuffer>& commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept;
void AddExteriorDrawCalls(std::function<void(Handle<SHVkCommandBuffer>&)> const& newDrawCall) noexcept;
void Init(ResourceManager& resourceManager) noexcept;
/*-----------------------------------------------------------------------*/
/* GETTERS AND SETTERS */
/*-----------------------------------------------------------------------*/
Handle<SHRenderGraphNode> const& GetParentNode(void) const noexcept;
SHSubPassIndex GetIndex() const noexcept;
Handle<SHSuperBatch> GetSuperBatch(void) const noexcept;
friend class SHRenderGraphNode;
friend class SHRenderGraph;
};
}

View File

@ -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<SHVkPipeline> inPipeline, Handle<SHVkDescriptorPool> 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<uint32_t> variableCounts{static_cast<uint32_t>(layouts.size())};
std::fill (variableCounts.begin(), variableCounts.end(), 0);
// Allocate descriptor sets to hold the images for reading (STORAGE_IMAGE)
descPool->Allocate(layouts, variableCounts);
}
}

View File

@ -0,0 +1,25 @@
#pragma once
#include <Resource/Handle.h>
namespace SHADE
{
class SHVkPipeline;
class SHVkDescriptorSetGroup;
class SHVkDescriptorPool;
class SHSubpassCompute
{
private:
//! To run the dispatch command
Handle<SHVkPipeline> pipeline;
//! Descriptor set group
Handle<SHVkDescriptorSetGroup> descSetGroup;
public:
SHSubpassCompute (Handle<SHVkPipeline> inPipeline, Handle<SHVkDescriptorPool> descPool) noexcept;
};
}

View File

@ -10,10 +10,6 @@ namespace SHADE
{ {
class SHVkLogicalDevice; class SHVkLogicalDevice;
class SHVkFramebuffer; class SHVkFramebuffer;
/*-----------------------------------------------------------------------*/
/* TYPE DEFINTIIONS */
/*-----------------------------------------------------------------------*/
using SHSubPassIndex = uint32_t;
class SHVkRenderpass class SHVkRenderpass
{ {

View File

@ -5,9 +5,13 @@
namespace SHADE namespace SHADE
{ {
/*-----------------------------------------------------------------------*/
/* TYPE DEFINTIIONS */
/*-----------------------------------------------------------------------*/
using SHQueueFamilyIndex = uint32_t; using SHQueueFamilyIndex = uint32_t;
using BindingAndSetHash = uint64_t; using BindingAndSetHash = uint64_t;
using SetIndex = uint32_t; using SetIndex = uint32_t;
using SHSubPassIndex = uint32_t;
} }

View File

@ -27,7 +27,7 @@ namespace SHADE
SHADE::SHShaderBlockInterface::Variable const* const SHShaderBlockInterface::GetVariable(uint32_t index) const noexcept 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 &variables.at(index);
return nullptr; return nullptr;

View File

@ -2,10 +2,12 @@
#include <unordered_map> #include <unordered_map>
#include "SH_API.h"
namespace SHADE namespace SHADE
{ {
class SHShaderBlockInterface class SH_API SHShaderBlockInterface
{ {
public: public:
struct Variable struct Variable

View File

@ -111,6 +111,7 @@ namespace SHADE
biggestAlignment = std::max(biggestAlignment, 4u); biggestAlignment = std::max(biggestAlignment, 4u);
break; break;
case SpvOp::SpvOpTypeStruct: case SpvOp::SpvOpTypeStruct:
case SpvOp::SpvOpTypeRuntimeArray:
recurseForInfo(&member, interfaceHdl, member.offset, biggestAlignment, parentVarName + std::string(member.name) + "."); recurseForInfo(&member, interfaceHdl, member.offset, biggestAlignment, parentVarName + std::string(member.name) + ".");
break; break;
} }

View File

@ -54,7 +54,7 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Usage Functions */ /* Usage Functions */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
inline Id GetId() const; inline Id GetId() const noexcept;
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Overloaded Operators */ /* Overloaded Operators */
@ -62,7 +62,7 @@ namespace SHADE
/// <summary> /// <summary>
/// Converts to true if this is a valid Handle. /// Converts to true if this is a valid Handle.
/// </summary> /// </summary>
inline operator bool() const; inline operator bool() const noexcept;
protected: protected:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
@ -101,6 +101,7 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Overloaded Operators */ /* Overloaded Operators */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
inline bool operator==(const Handle<T>& rhs) const noexcept;
/// <summary> /// <summary>
/// Returns the underlying object pointed to by the Handle. /// Returns the underlying object pointed to by the Handle.
/// </summary> /// </summary>

View File

@ -8,15 +8,15 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* HandleBase - Usage Functions */ /* HandleBase - Usage Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
inline HandleBase::Id HandleBase::GetId() const inline HandleBase::Id HandleBase::GetId() const noexcept
{ {
return id; return id;
} }
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* HandleBase - Overloaded Operators */ /* HandleBase - Overloaded Operators */
inline HandleBase::operator bool() const
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
inline HandleBase::operator bool() const noexcept
{ {
return id.Raw != INVALID_ID.Raw; return id.Raw != INVALID_ID.Raw;
} }
@ -33,6 +33,12 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Handle<T> - Overloaded Operators */ /* Handle<T> - Overloaded Operators */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
template<typename T>
bool SHADE::Handle<T>::operator==(const Handle<T>& rhs) const noexcept
{
return id.Raw == rhs.id.Raw && library == rhs.library;
}
template <typename T> template <typename T>
T& Handle<T>::operator*() T& Handle<T>::operator*()
{ {

View File

@ -1,72 +1,44 @@
#version 450 #version 450
#extension GL_ARB_separate_shader_objects : enable #extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : 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 layout(location = 0) in struct
{ {
//mat3 BTN;
vec4 vertColor; vec4 vertColor;
//vec3 localSpacePosition; vec2 uv;
//vec2 uv;
//vec3 localLightPosition;
//vec3 localEyePosition;
} In; } In;
//layout(std140, push_constant) uniform TestPushConstant // material stuff
//{ layout(location = 2) flat in struct
// mat4 pvMat; {
// vec4 lightPosition; int materialIndex;
// vec4 eyePosition; } In2;
// vec4 ambientColor;
// vec4 lightColor; //layout (set = 0, binding = )
//
//} testPushConstant; 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(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() void main()
{ {
//vec3 normal;
//// Get the tangent space normal from normal map. It is a BC5 texture and therefore only use red and green outColor = texture(textures[nonuniformEXT(MatProp.data[In2.materialIndex].textureIndex)], In.uv) +
//normal.xy = (texture (normalMap, In.uv).gr * 2.0f) - 1.0f; MatProp.data[In2.materialIndex].color / MatProp.data[In2.materialIndex].alpha;
//// z value is derived (TODO: Find out what this does) //outColor = vec4 (1.0f);
//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);
} }

Binary file not shown.

View File

@ -9,27 +9,20 @@ layout(location = 2) in vec3 aNormal;
layout(location = 3) in vec3 aTangent; layout(location = 3) in vec3 aTangent;
layout(location = 4) in mat4 worldTransform; 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 layout(location = 0) out struct
{ {
//mat3 BTN; vec4 vertColor; // location 0
vec4 vertColor; vec2 uv; // location = 1
//vec3 localSpacePosition;
//vec2 uv;
//vec3 localLightPosition;
//vec3 localEyePosition;
} Out; } Out;
// material stuff
layout(location = 2) out struct
{
int materialIndex;
} Out2;
layout(set = 2, binding = 0) uniform CameraData layout(set = 2, binding = 0) uniform CameraData
{ {
vec4 position; vec4 position;
@ -38,25 +31,8 @@ layout(set = 2, binding = 0) uniform CameraData
void main() void main()
{ {
//const float gamma = testPushConstant.eyePosition.w; Out.uv = aUV;
//mat4 W2L = inverse(worldTransform); Out2.materialIndex = gl_InstanceIndex;
//// 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);
gl_Position = cameraData.vpMat * worldTransform * vec4 (aVertexPos, 1.0f); gl_Position = cameraData.vpMat * worldTransform * vec4 (aVertexPos, 1.0f);
Out.vertColor = vec4 (aVertexPos, 1.0f); Out.vertColor = vec4 (aVertexPos, 1.0f);
} }

Binary file not shown.