Rendering merge #65

Merged
Xenosas1337 merged 33 commits from SP3-1-Rendering into main 2022-09-28 20:42:03 +08:00
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/RaccoonBag_Color_Ver4.dds");
SHADE::SHAssetManager::LoadDataTemp("../../Assets/RaccoonPreTexturedVer1_Base9.dds");
SHADE::SHAssetManager::LoadDataTemp("../../Assets/TD_Checker_Base_Color.dds");
//TODO: REMOVE AFTER PRESENTATION
//SHADE::SHSystemManager::RegisterRoutine<SHADE::SHAudioSystem, SHADE::SHAudioSystem::AudioRoutine>();

View File

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

View File

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

View File

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

View File

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

View File

@ -39,8 +39,10 @@ namespace SHADE
std::vector<vk::DescriptorPoolSize> Limits =
{
{ vk::DescriptorType::eCombinedImageSampler, 100 },
{ vk::DescriptorType::eUniformBuffer, 100 },
{ vk::DescriptorType::eUniformBufferDynamic, 100 }
{ vk::DescriptorType::eUniformBuffer, 100 },
{ vk::DescriptorType::eUniformBufferDynamic, 100 },
{ vk::DescriptorType::eStorageImage, 100},
{ vk::DescriptorType::eStorageBufferDynamic, 100 }
};
/// <summary>
/// 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
BindingAndSetHash writeHash = binding;
@ -170,9 +170,10 @@ namespace SHADE
for (uint32_t i = 0; i < imageViewsAndSamplers.size(); ++i)
{
// write sampler and image view
auto& ivs = imageViewsAndSamplers[i];
writeInfo.descImageInfos[i].imageView = ivs.first->GetImageView();
writeInfo.descImageInfos[i].sampler = ivs.second->GetVkSampler();
auto& [view, sampler, layout] = imageViewsAndSamplers[i];
writeInfo.descImageInfos[i].imageView = view->GetImageView();
writeInfo.descImageInfos[i].sampler = sampler->GetVkSampler();
writeInfo.descImageInfos[i].imageLayout = layout;
}
}

View File

@ -1,5 +1,7 @@
#pragma once
#include <tuple>
// Project Includes
#include "Graphics/SHVulkanIncludes.h"
#include "Resource/Handle.h"
@ -63,7 +65,7 @@ namespace SHADE
void UpdateDescriptorSetImages(uint32_t set, uint32_t binding) noexcept;
void UpdateDescriptorSetBuffer(uint32_t set, uint32_t binding) noexcept;
void ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span<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;

View File

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

View File

@ -21,7 +21,6 @@
#include "Graphics/Descriptors/SHVkDescriptorSetLayout.h"
#include "Graphics/Images/SHVkImage.h"
namespace SHADE
{
/*-----------------------------------------------------------------------*/
@ -41,6 +40,8 @@ namespace SHADE
class SHShaderBlockInterface;
class SHVkDescriptorSetGroup;
class SHSubpass;
class SHVkSampler;
struct SHVkSamplerParams;
/***************************************************************************/
/*!
@ -102,6 +103,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
void InitializeVMA (void) noexcept;
void InitializeQueues (std::initializer_list<SHQueueParams> queueCreateParams) noexcept;
uint32_t ComputeAlignedBufferSize(uint32_t originalSize, size_t typeSize) const noexcept;
public:
/*-----------------------------------------------------------------------*/
@ -121,7 +123,8 @@ namespace SHADE
// Miscellaneous functions
void WaitIdle (void) noexcept;
uint32_t FindMemoryType (uint32_t typeFilter, vk::MemoryPropertyFlags properties);
uint32_t PadUBOSize (uint32_t originalSize) const noexcept;
uint32_t PadUBOSize(uint32_t originalSize) const noexcept;
uint32_t PadSSBOSize(uint32_t originalSize) const noexcept;
// creation functions
Handle<SHVkSurface> CreateSurface (HWND const& windowHandle) const noexcept;
@ -178,6 +181,7 @@ namespace SHADE
Handle<SHVkRenderpass> const& renderpassHdl,
Handle<SHSubpass> subpass
) 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::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
vk::BufferCreateInfo bufferInfo{};
@ -70,7 +70,7 @@ namespace SHADE
vmaMapMemory(*vmaAllocator, stagingAlloc, &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 sizes = srcSize;
@ -82,7 +82,7 @@ namespace SHADE
SHVkImage::SHVkImage(
VmaAllocator const* allocator,
SHImageCreateParams const& imageDetails,
unsigned char* data,
const unsigned char* data,
uint32_t dataSize,
std::span<uint32_t> inMipOffsets,
VmaMemoryUsage memUsage,

View File

@ -107,7 +107,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
void PrepStagingBuffer(void* data, uint32_t srcSize) noexcept;
void PrepStagingBuffer(const void* data, uint32_t srcSize) noexcept;
public:
@ -119,7 +119,7 @@ namespace SHADE
SHVkImage(
VmaAllocator const* allocator,
SHImageCreateParams const& imageDetails,
unsigned char* data,
const unsigned char* data,
uint32_t dataSize,
std::span<uint32_t> inMipOffsets,
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 "SHVkSampler.h"
#include "Graphics/Devices/SHVkLogicalDevice.h"
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
// STL Includes
#include <vector>
// Project Includes
#include "Graphics/SHVulkanIncludes.h"
#include "Resource/Handle.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Forward Declarations */
/*-----------------------------------------------------------------------------------*/
class SHVkLogicalDevice;
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
/*************************************************************************************/
/*!
\brief
Holds parameters for constructing the SHVkSampler.
*/
/*************************************************************************************/
struct SHVkSamplerParams
{
vk::Filter minFilter;
vk::Filter maxFilter;
//vk::Filter maxFilter;
vk::Filter minFilter = vk::Filter::eLinear;
vk::Filter magFilter = vk::Filter::eLinear;
vk::SamplerAddressMode addressMode = vk::SamplerAddressMode::eClampToEdge;
vk::SamplerMipmapMode mipmapMode = vk::SamplerMipmapMode::eLinear;
float minLod = 0;
float maxLod = 0;
};
/*************************************************************************************/
/*!
\brief
Wrapper for a VkSampler.
*/
/*************************************************************************************/
class SHVkSampler
{
private:
//! The vulkan sampler handler
vk::Sampler vkSampler;
public:
SHVkSampler () noexcept;
SHVkSampler (SHVkSampler&& rhs) noexcept;
SHVkSampler&& operator=(SHVkSampler&& rhs) noexcept;
public:
/*---------------------------------------------------------------------------------*/
/* Constructors */
/*---------------------------------------------------------------------------------*/
SHVkSampler(Handle<SHVkLogicalDevice> logicalDevice, const SHVkSamplerParams& params = {}) noexcept;
SHVkSampler(SHVkSampler&& rhs) noexcept;
~SHVkSampler() noexcept;
vk::Sampler GetVkSampler (void) const noexcept;
/*---------------------------------------------------------------------------------*/
/* Overloaded Operators */
/*---------------------------------------------------------------------------------*/
SHVkSampler& operator=(SHVkSampler&& rhs) noexcept;
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
vk::Sampler GetVkSampler(void) const noexcept { return vkSampler; }
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
vk::Sampler vkSampler; //! The Vulkan sampler handler
Handle<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/MiddleEnd/Interface/SHGraphicsConstants.h"
#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "ECS_Base/Managers/SHComponentManager.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h"
#include "Graphics/Descriptors/SHVkDescriptorPool.h"
namespace SHADE
{
@ -120,7 +123,7 @@ namespace SHADE
}
}
void SHBatch::UpdateMaterialBuffer(uint32_t frameIndex)
void SHBatch::UpdateMaterialBuffer(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{
@ -154,21 +157,17 @@ namespace SHADE
if (!matBufferDirty[frameIndex])
return;
// Build CPI Buffer
// Build CPU Buffer
char* propsCurrPtr = matPropsData.get();
for (auto& subBatch : subBatches)
for (const SHRenderable* renderable : subBatch.Renderables)
{
renderable->GetMaterial()->ExportProperties(propsCurrPtr);
propsCurrPtr += singleMatPropSize;
propsCurrPtr += singleMatPropAlignedSize;
}
// Transfer to GPU
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast<uint32_t>(matPropsDataSize),
vk::BufferUsageFlagBits::eStorageBuffer
);
rebuildMaterialBuffers(frameIndex, descPool);
// This frame is updated
matBufferDirty[frameIndex] = false;
@ -207,7 +206,7 @@ namespace SHADE
transformDataBuffer[frameIndex]->WriteToMemory(transformData.data(), static_cast<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)
{
@ -215,6 +214,9 @@ namespace SHADE
return;
}
// Save logical device
device = _device;
// No need to build as there are no changes
if (!isDirty[frameIndex])
return;
@ -247,7 +249,8 @@ namespace SHADE
if (!EMPTY_MAT_PROPS)
{
singleMatPropSize = SHADER_INFO->GetBytesRequired();
matPropTotalBytes = drawData.size() * singleMatPropSize;
singleMatPropAlignedSize = device->PadSSBOSize(singleMatPropSize);
matPropTotalBytes = numTotalElements * singleMatPropAlignedSize;
if (matPropsDataSize < matPropTotalBytes)
{
matPropsData.reset(new char[matPropTotalBytes]);
@ -267,7 +270,7 @@ namespace SHADE
.instanceCount = static_cast<uint32_t>(subBatch.Renderables.size()),
.firstIndex = subBatch.Mesh->FirstIndex,
.vertexOffset = subBatch.Mesh->FirstVertex,
.firstInstance = nextInstanceIndex
.firstInstance = nextInstanceIndex++
});
// Fill in buffers (CPU)
@ -289,7 +292,7 @@ namespace SHADE
if (!EMPTY_MAT_PROPS)
{
renderable->GetMaterial()->ExportProperties(propsCurrPtr);
propsCurrPtr += singleMatPropSize;
propsCurrPtr += singleMatPropAlignedSize;
}
}
}
@ -304,30 +307,21 @@ namespace SHADE
const uint32_t DRAW_DATA_BYTES = static_cast<uint32_t>(drawData.size() * sizeof(vk::DrawIndexedIndirectCommand));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
_device, drawDataBuffer[frameIndex], drawData.data(), DRAW_DATA_BYTES,
device, drawDataBuffer[frameIndex], drawData.data(), DRAW_DATA_BYTES,
BuffUsage::eIndirectBuffer
);
// - Transform Buffer
const uint32_t TF_DATA_BYTES = static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
_device, transformDataBuffer[frameIndex], transformData.data(), TF_DATA_BYTES,
device, transformDataBuffer[frameIndex], transformData.data(), TF_DATA_BYTES,
BuffUsage::eVertexBuffer
);
// - Material Properties Buffer
if (matPropsData)
{
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
_device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast<uint32_t>(matPropsDataSize),
BuffUsage::eStorageBuffer
);
}
rebuildMaterialBuffers(frameIndex, descPool);
// Mark this frame as no longer dirty
isDirty[frameIndex] = false;
// Save logical device
this->device = _device;
}
/*---------------------------------------------------------------------------------*/
@ -341,8 +335,20 @@ namespace SHADE
return;
}
// Bind all required objects before drawing
static std::array<uint32_t, 1> dynamicOffset { 0 };
cmdBuffer->BindPipeline(pipeline);
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRANSFORM, transformDataBuffer[frameIndex], 0);
if (matPropsDescSet[frameIndex])
{
cmdBuffer->BindDescriptorSet
(
matPropsDescSet[frameIndex],
vk::PipelineBindPoint::eGraphics,
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
dynamicOffset
);
}
cmdBuffer->DrawMultiIndirect(drawDataBuffer[frameIndex], static_cast<uint32_t>(drawData.size()));
}
@ -355,4 +361,39 @@ namespace SHADE
dirt = 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 SHVkLogicalDevice;
class SHMaterialInstance;
class SHVkDescriptorSetGroup;
class SHVkDescriptorPool;
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
@ -74,9 +76,9 @@ namespace SHADE
void Add(const SHRenderable* renderable);
void Remove(const SHRenderable* renderable);
void Clear();
void UpdateMaterialBuffer(uint32_t frameIndex);
void UpdateMaterialBuffer(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
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);
/*-----------------------------------------------------------------------------*/
@ -84,34 +86,44 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/
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 */
/*-----------------------------------------------------------------------------*/
// Resources
Handle<SHVkLogicalDevice> device;
Handle<SHVkLogicalDevice> device;
// Batch Properties
Handle<SHVkPipeline> pipeline;
Handle<SHVkPipeline> pipeline;
std::unordered_set<Handle<SHMaterialInstance>> referencedMatInstances;
std::array<bool, SHGraphicsConstants::NUM_FRAME_BUFFERS> matBufferDirty;
TripleBool matBufferDirty;
// Batch Tree
std::vector<SHSubBatch> subBatches;
std::array<bool, SHGraphicsConstants::NUM_FRAME_BUFFERS> isDirty;
// CPU Buffers
std::vector<vk::DrawIndexedIndirectCommand> drawData;
std::vector<SHMatrix> transformData;
std::unique_ptr<char> matPropsData;
Byte matPropsDataSize = 0;
Byte singleMatPropSize = 0;
bool isCPUBuffersDirty = true;
// GPU Buffers
std::array<Handle<SHVkBuffer>, SHGraphicsConstants::NUM_FRAME_BUFFERS> drawDataBuffer;
std::array<Handle<SHVkBuffer>, SHGraphicsConstants::NUM_FRAME_BUFFERS> transformDataBuffer;
std::array<Handle<SHVkBuffer>, SHGraphicsConstants::NUM_FRAME_BUFFERS> matPropsBuffer;
std::vector<SHSubBatch> subBatches;
TripleBool isDirty;
// CPU Buffers
std::vector<vk::DrawIndexedIndirectCommand> drawData;
std::vector<SHMatrix> transformData;
std::unique_ptr<char> matPropsData;
Byte matPropsDataSize = 0;
Byte singleMatPropAlignedSize = 0;
Byte singleMatPropSize = 0;
bool isCPUBuffersDirty = true;
// GPU Buffers
TripleBuffer drawDataBuffer;
TripleBuffer transformDataBuffer;
TripleBuffer matPropsBuffer;
TripleDescSet matPropsDescSet;
/*-----------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------*/
void setAllDirtyFlags();
void rebuildMaterialBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
};
}

View File

@ -91,12 +91,12 @@ namespace SHADE
(*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
for (auto& batch : superBatches)
{
batch->Build(device, frameIndex);
batch->Build(device, descPool, frameIndex);
}
}
@ -109,11 +109,11 @@ namespace SHADE
superBatches.clear();
}
void SHBatcher::UpdateBuffers(uint32_t frameIndex)
void SHBatcher::UpdateBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{
for (auto& batch : superBatches)
{
batch->UpdateBuffers(frameIndex);
batch->UpdateBuffers(frameIndex, descPool);
}
}

View File

@ -27,6 +27,7 @@ namespace SHADE
class SHSuperBatch;
class SHVkLogicalDevice;
class SHVkCommandBuffer;
class SHVkDescriptorPool;
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
@ -51,9 +52,9 @@ namespace SHADE
void PrepareBatches();
void AddToBatch(SHRenderable const* renderable);
void RemoveFromBatch(SHRenderable const* renderable);
void FinaliseBatches(Handle<SHVkLogicalDevice> device, uint32_t frameIndex);
void FinaliseBatches(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex);
void ClearBatches();
void UpdateBuffers(uint32_t frameIndex);
void UpdateBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
void RegisterSuperBatch(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 "Graphics/MiddleEnd/Interface/SHMaterialInstance.h"
#include "Graphics/MiddleEnd/Interface/SHRenderable.h"
#include "Graphics/Descriptors/SHVkDescriptorPool.h"
namespace SHADE
{
@ -78,21 +79,21 @@ namespace SHADE
batches.clear();
}
void SHSuperBatch::UpdateBuffers(uint32_t frameIndex)
void SHSuperBatch::UpdateBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{
for (auto& batch : batches)
{
batch.UpdateMaterialBuffer(frameIndex);
batch.UpdateMaterialBuffer(frameIndex, descPool);
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
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 Remove(const SHRenderable* renderable) noexcept;
void Clear() noexcept;
void UpdateBuffers(uint32_t frameIndex);
void Build(Handle<SHVkLogicalDevice> device, uint32_t frameIndex) noexcept;
void UpdateBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
void Build(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept;
void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
/*-----------------------------------------------------------------------------*/

View File

@ -7,7 +7,22 @@
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
{
SHVkDescriptorSetLayout::Binding genericDataBinding
@ -87,18 +102,18 @@ namespace SHADE
InitDefaultVertexInputState();
}
std::vector<Handle<SHVkDescriptorSetLayout>> const& SHGraphicsGlobalData::GetDescSetLayouts(void) const noexcept
std::vector<Handle<SHVkDescriptorSetLayout>> const& SHGraphicsGlobalData::GetDescSetLayouts(void) noexcept
{
return globalDescSetLayouts;
}
SHVertexInputState const& SHGraphicsGlobalData::GetDefaultViState(void) const noexcept
SHVertexInputState const& SHGraphicsGlobalData::GetDefaultViState(void) noexcept
{
return defaultVertexInputState;
}
Handle<SHVkPipelineLayout> SHGraphicsGlobalData::GetDummyPipelineLayout(void) const noexcept
Handle<SHVkPipelineLayout> SHGraphicsGlobalData::GetDummyPipelineLayout(void) noexcept
{
return dummyPipelineLayout;
}

View File

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

View File

@ -23,22 +23,40 @@ namespace SHADE
{
SHVec3 view = target - pos; view = SHVec3::Normalise(view);
SHVec3 right = SHVec3::Cross(view, up); right = SHVec3::Normalise(right);
const SHVec3 UP = SHVec3::Cross(right, view);
const SHVec3 UP = SHVec3::Cross(view, right);
//viewMatrix = SHMatrix::Identity;
//viewMatrix(0, 0) = UP[0];
//viewMatrix(1, 0) = UP[1];
//viewMatrix(2, 0) = UP[2];
//viewMatrix(0, 1) = right[0];
//viewMatrix(1, 1) = right[1];
//viewMatrix(2, 1) = right[2];
//viewMatrix(0, 2) = view[0];
//viewMatrix(1, 2) = view[1];
//viewMatrix(2, 2) = view[2];
//viewMatrix(3, 0) = -UP.Dot(pos);
//viewMatrix(3, 1) = -right.Dot(pos);
//viewMatrix(3, 2) = -view.Dot(pos);
viewMatrix = SHMatrix::Identity;
viewMatrix(0, 0) = UP[0];
viewMatrix(1, 0) = UP[1];
viewMatrix(2, 0) = UP[2];
viewMatrix(0, 1) = right[0];
viewMatrix(1, 1) = right[1];
viewMatrix(2, 1) = right[2];
viewMatrix(0, 2) = view[0];
viewMatrix(1, 2) = view[1];
viewMatrix(2, 2) = view[2];
viewMatrix(3, 0) = -UP.Dot(pos);
viewMatrix(3, 1) = -right.Dot(pos);
viewMatrix(3, 2) = -view.Dot(pos);
viewMatrix(0, 0) = right[0];
viewMatrix(0, 1) = right[1];
viewMatrix(0, 2) = right[2];
viewMatrix(1, 0) = UP[0];
viewMatrix(1, 1) = UP[1];
viewMatrix(1, 2) = UP[2];
viewMatrix(2, 0) = view[0];
viewMatrix(2, 1) = view[1];
viewMatrix(2, 2) = view[2];
viewMatrix(0, 3) = -right.Dot(pos);
viewMatrix(1, 3) = -UP.Dot(pos);
viewMatrix(2, 3) = -view.Dot(pos);
isDirty = true;
}

View File

@ -30,6 +30,8 @@ of DigiPen Institute of Technology is prohibited.
#include "SHGraphicsConstants.h"
#include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h"
#include "Graphics/Buffers/SHVkBuffer.h"
#include "Graphics/Images/SHVkSampler.h"
#include "Assets/Asset Types/SHTextureAsset.h"
namespace SHADE
{
@ -91,8 +93,10 @@ namespace SHADE
descPool = device->CreateDescriptorPools();
// Create generic command buffer
transferCmdPool = device->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::TRANSFER, SH_CMD_POOL_RESET::POOL_BASED, true);
transferCmdBuffer = transferCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
//transferCmdPool = device->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS, SH_CMD_POOL_RESET::POOL_BASED, true);
graphicsCmdPool = device->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS, SH_CMD_POOL_RESET::POOL_BASED, true);
transferCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
graphicsTexCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
@ -106,8 +110,7 @@ namespace SHADE
- Global data
/*-----------------------------------------------------------------------*/
globalData = resourceManager.Create<SHGraphicsGlobalData>();
globalData->Init(device);
SHGraphicsGlobalData::Init(device);
// Set Up Cameras
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);
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(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);
// Create Default Viewport
@ -131,18 +134,20 @@ namespace SHADE
}
// Initialize world render graph
worldRenderGraph->Init(device, swapchain, globalData);
worldRenderGraph->Init(device, swapchain);
worldRenderGraph->AddResource("Depth Buffer", SH_ATT_DESC_TYPE::DEPTH_STENCIL, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint);
//worldRenderGraph->AddResource("Position", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eR16G16B16A16Sfloat);
//worldRenderGraph->AddResource("Normals", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eR16G16B16A16Sfloat);
//worldRenderGraph->AddResource("Composite", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eR16G16B16A16Sfloat);
worldRenderGraph->AddResource("Scene", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eB8G8R8A8Unorm);
//worldRenderGraph->AddResource("Scene", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eB8G8R8A8Unorm);
worldRenderGraph->AddResource("Present", SH_ATT_DESC_TYPE::COLOR_PRESENT, windowDims.first, windowDims.second);
auto node = worldRenderGraph->AddNode("G-Buffer", { /*"Composite", "Position", */"Present" }, {}); // no predecessors
auto node = worldRenderGraph->AddNode("G-Buffer", { /*"Composite", "Position", */"Depth Buffer", "Present" }, {}); // no predecessors
//First subpass to write to G-Buffer
auto gBufferWriteSubpass = node->AddSubpass("G-Buffer Write");
//gBufferWriteSubpass->AddColorOutput("Scene");
gBufferWriteSubpass->AddColorOutput("Present");
gBufferWriteSubpass->AddDepthOutput ("Depth Buffer", SH_ATT_DESC_TYPE::DEPTH_STENCIL);
//writeSubpass->AddColorOutput("Normals");
// //Second subpass to read from G-Buffer
@ -171,7 +176,7 @@ namespace SHADE
debugWorldRenderer->SetCamera(worldCamera);*/
// Add world renderer to default viewport
worldRenderer = defaultViewport->AddRenderer(resourceManager, swapchain->GetNumImages(), renderContextCmdPools, descPool, globalData->GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS], worldRenderGraph);
worldRenderer = defaultViewport->AddRenderer(resourceManager, swapchain->GetNumImages(), renderContextCmdPools, descPool, SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS], worldRenderGraph);
worldRenderer->SetCamera(worldCamera);
@ -184,8 +189,8 @@ namespace SHADE
shaderModuleLibrary.ImportFromSourceLibrary(device, shaderSourceLibrary);
auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl");
auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl");
//triVS->Reflect();
//triFS->Reflect();
cubeVS->Reflect();
cubeFS->Reflect();
defaultMaterial = AddMaterial(cubeVS, cubeFS, gBufferWriteSubpass);
}
@ -224,6 +229,9 @@ namespace SHADE
renderContext.ResetFence();
// Bind textures
// For every viewport
for (int vpIndex = 0; vpIndex < static_cast<int>(viewports.size()); ++vpIndex)
{
@ -241,7 +249,7 @@ namespace SHADE
// Begin recording the command buffer
currentCmdBuffer->BeginRecording();
currentCmdBuffer->ForceSetPipelineLayout(globalData->GetDummyPipelineLayout());
currentCmdBuffer->ForceSetPipelineLayout(SHGraphicsGlobalData::GetDummyPipelineLayout());
// Bind all the buffers required for meshes
for (auto& [buffer, bindingPoint] : MESH_DATA)
@ -252,11 +260,26 @@ namespace SHADE
currentCmdBuffer->BindIndexBuffer(buffer, 0);
}
// Bind textures
auto textureDescSet = texLibrary.GetTextureDescriptorSetGroup();
if (textureDescSet)
{
std::array<uint32_t, 1> texDynamicOffset {0};
currentCmdBuffer->BindDescriptorSet
(
textureDescSet,
vk::PipelineBindPoint::eGraphics,
0,
texDynamicOffset
);
}
// bind camera data
renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex);
// Draw first
renderers[renIndex]->Draw(frameIndex);
renderers[renIndex]->Draw(frameIndex, descPool);
// End the command buffer recording
currentCmdBuffer->EndRecording();
@ -309,7 +332,7 @@ namespace SHADE
for (auto vp : viewports)
for (auto renderer : vp->GetRenderers())
{
renderer->GetRenderGraph()->FinaliseBatch(renderContext.GetCurrentFrame());
renderer->GetRenderGraph()->FinaliseBatch(renderContext.GetCurrentFrame(), descPool);
}
// Resize
@ -455,9 +478,37 @@ namespace SHADE
transferCmdBuffer->BeginRecording();
meshLibrary.BuildBuffers(device, transferCmdBuffer);
transferCmdBuffer->EndRecording();
transferQueue->SubmitCommandBuffer({ transferCmdBuffer });
graphicsQueue->SubmitCommandBuffer({ transferCmdBuffer });
}
/*---------------------------------------------------------------------------------*/
/* Texture Registration Functions */
/*---------------------------------------------------------------------------------*/
Handle<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
{
window = wind;
@ -493,9 +544,13 @@ namespace SHADE
oldSuperBatch->Remove(&renderable);
}
// Add to new SuperBatch
Handle<SHSuperBatch> newSuperBatch = renderable.GetMaterial()->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch();
newSuperBatch->Add(&renderable);
// Add to new SuperBatch if there is a material
Handle<SHMaterialInstance> newMatInstance = renderable.GetMaterial();
if (newMatInstance)
{
Handle<SHSuperBatch> newSuperBatch = newMatInstance->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch();
newSuperBatch->Add(&renderable);
}
// Unset change flag
renderable.ResetChangedFlag();

View File

@ -29,6 +29,8 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/MiddleEnd/Shaders/SHShaderModuleLibrary.h"
#include "SHMeshLibrary.h"
#include "Graphics/MiddleEnd/Materials/SHMaterialInstanceCache.h"
#include "../Textures/SHTextureLibrary.h"
#include "../Textures/SHVkSamplerCache.h"
namespace SHADE
{
@ -188,6 +190,62 @@ namespace SHADE
/***************************************************************************/
void BuildMeshBuffers();
/*-----------------------------------------------------------------------------*/
/* Texture Registration Functions */
/*-----------------------------------------------------------------------------*/
/*******************************************************************************/
/*!
\brief
Adds a texture to the Texture Library. But this does not mean that the
textures have been added yet. A call to "BuildTextures()" is required to
transfer all textures into the GPU.
\param pixelCount
Number of pixels in this Mesh.
\param positions
Pointer to the first in a contiguous array of SHMathVec3s that define vertex
positions.
\param format
Format of the texture loaded in.
\return
Handle to the created Texture. This is not valid to be used until a call to
BuildImages().
*/
/*******************************************************************************/
Handle<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 */
/*-----------------------------------------------------------------------------*/
@ -220,19 +278,20 @@ namespace SHADE
Handle<SHVkQueue> graphicsQueue;
Handle<SHVkQueue> transferQueue;
Handle<SHVkDescriptorPool> descPool;
Handle<SHVkCommandPool> graphicsCmdPool;
Handle<SHVkCommandPool> transferCmdPool;
Handle<SHVkCommandBuffer> transferCmdBuffer;
Handle<SHVkCommandBuffer> graphicsTexCmdBuffer;
SHRenderContext renderContext;
std::array<Handle<SHVkSemaphore>, 2> graphSemaphores;
// Not Owned Resources
SHWindow* window = nullptr;
// global data (descriptor sets as well)
Handle<SHGraphicsGlobalData> globalData;
// Middle End Resources
ResourceManager resourceManager;
SHMeshLibrary meshLibrary;
SHTextureLibrary texLibrary;
SHSamplerCache samplerCache;
SHMaterialInstanceCache materialInstanceCache;
// Viewports
Handle<SHViewport> defaultViewport; // Whole screen

View File

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

View File

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

View File

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

View File

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

View File

@ -60,9 +60,9 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/
/* 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

View File

@ -74,7 +74,7 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/
/* 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 UpdateCameraDataToBuffer (void) noexcept;

View File

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

View File

@ -24,14 +24,9 @@ namespace SHADE
//! 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;
// Global data
Handle<SHGraphicsGlobalData> globalData;
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
Handle<SHVkPipeline> CreateDrawPipeline (

View File

@ -20,18 +20,36 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/Commands/SHVkCommandBuffer.h"
#include "Graphics/SHVkUtil.h"
#include "Tools/SHLogger.h"
#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "Graphics/Images/SHVkImage.h"
#include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h"
#include "Assets/Asset Types/SHTextureAsset.h"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Usage Functions */
/*---------------------------------------------------------------------------------*/
Handle<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;
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;
}
@ -44,22 +62,48 @@ namespace SHADE
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 */
std::vector<vk::ImageMemoryBarrier> pipelineBarriers(addJobs.size());
// TODO
/* Add Textures */
// Transition
// Load Textures - Transitions
std::vector<vk::ImageMemoryBarrier> pipelineBarriers(addJobs.size());
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]);
++i;
}
vk::PipelineStageFlagBits srcStage = vk::PipelineStageFlagBits::eTopOfPipe;
vk::PipelineStageFlagBits dstStage = vk::PipelineStageFlagBits::eTopOfPipe;
preparePipelineBarriers(vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, srcStage, dstStage, pipelineBarriers);
cmdBuffer->BeginRecording();
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, pipelineBarriers);
// Copy
@ -73,13 +117,16 @@ namespace SHADE
{
// Transition
job.Image->PrepareImageTransitionInfo(vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal, pipelineBarriers[i]);
++i;
}
preparePipelineBarriers(vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal, srcStage, dstStage, pipelineBarriers);
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, pipelineBarriers);
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {}, {}, {}, pipelineBarriers);
// Execute Commands
cmdBuffer->EndRecording();
graphicsQueue->SubmitCommandBuffer({ cmdBuffer });
device->WaitIdle();
graphicsQueue->GetVkQueue().waitIdle();
// Create Image View
for (auto& job : addJobs)
@ -90,16 +137,45 @@ namespace SHADE
.format = job.TextureFormat,
.imageAspectFlags = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.mipLevelCount = job.MipLevels,
.mipLevelCount = static_cast<uint32_t>(job.MipOffsets.size()),
.baseArrayLayer = 0,
.layerCount = 0
.layerCount = 1
};
job.Handle->ImageView = job.Image->CreateImageView(device, job.Image, DETAILS);
job.TextureHandle->ImageView = job.Image->CreateImageView(device, job.Image, DETAILS);
}
// Build Descriptor
Handle<SHVkDescriptorSetGroup> descSetGroup = descPool->Allocate({ descLayout }, { 1 });
// Add Textures
for (auto& job : addJobs)
{
texOrder.emplace_back(job.TextureHandle);
combinedImageSamplers.emplace_back(std::make_tuple(job.TextureHandle->ImageView, job.Sampler, vk::ImageLayout::eShaderReadOnlyOptimal));
job.TextureHandle->TextureArrayIndex = texOrder.size() - 1;
}
addJobs.clear();
/* Build Descriptor Set with all the Textures only if there are textures */
if (!texOrder.empty())
{
if (!texDescriptors)
{
texDescriptors = descPool->Allocate
(
{ SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::STATIC_GLOBALS] },
{ static_cast<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;
}
@ -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
#include <vector>
// External Dependencies
#include "tinyddsloader.h"
// Project Includes
#include "Resource/Handle.h"
#include "Resource/ResourceLibrary.h"
@ -33,6 +35,9 @@ namespace SHADE
class SHVkQueue;
class SHVkDescriptorPool;
class SHVkDescriptorSetLayout;
class SHVkDescriptorSetGroup;
class SHVkSampler;
class SHTextureAsset;
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
@ -43,7 +48,7 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------*/
using PixelChannel = float;
using PixelChannel = unsigned char;
using TextureFormat = vk::Format; // TODO: Change
using Index = uint32_t;
@ -71,7 +76,7 @@ namespace SHADE
\brief
Adds a texture to the Texture Library. But this does not mean that the
textures have been added yet. A call to "BuildImages()" is required to
textures have been added yet. A call to "BuildTextures()" is required to
transfer all textures into the GPU.
\param pixelCount
@ -88,13 +93,15 @@ namespace SHADE
*/
/*******************************************************************************/
Handle<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
Removes a mesh from the Texture Library. But this does not mean that the
textures have been removed yet. A call to "BuildImages()" is required to
textures have been removed yet. A call to "BuildTextures()" is required to
finalise all changes.
\param mesh
@ -118,12 +125,12 @@ namespace SHADE
queue.
*/
/***************************************************************************/
void BuildImages(Handle<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 */
/*-----------------------------------------------------------------------------*/
Handle<SHVkBuffer> GetTextureBuffer() const noexcept { return texStorageBuffer; }
Handle<SHVkDescriptorSetGroup> GetTextureDescriptorSetGroup() const noexcept { return texDescriptors; }
private:
/*-----------------------------------------------------------------------------*/
@ -134,9 +141,12 @@ namespace SHADE
uint32_t PixelCount = 0;
const SHTexture::PixelChannel* PixelData = nullptr;
SHTexture::TextureFormat TextureFormat = {};
uint32_t MipLevels = 0;
Handle<SHVkSampler> Sampler;
std::vector<uint32_t> MipOffsets;
uint32_t Width;
uint32_t Height;
Handle<SHTexture> TextureHandle;
Handle<SHVkImage> Image;
Handle<SHTexture> Handle;
};
/*-----------------------------------------------------------------------------*/
@ -149,9 +159,9 @@ namespace SHADE
ResourceManager resourceManager;
std::vector<Handle<SHTexture>> texOrder;
// CPU Storage
std::vector<SHTexture::PixelChannel> texStorage;
std::vector<std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, vk::ImageLayout>> combinedImageSamplers;
// GPU Storage
Handle<SHVkBuffer> texStorageBuffer{};
Handle<SHVkDescriptorSetGroup> texDescriptors;
// Flags
bool isDirty = true;
@ -159,5 +169,6 @@ namespace SHADE
/* Helper Functions */
/*-----------------------------------------------------------------------------*/
void preparePipelineBarriers(vk::ImageLayout oldLayout, vk::ImageLayout newLayout, vk::PipelineStageFlagBits& srcStage, vk::PipelineStageFlagBits& dstStage, std::vector<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
{
descriptorSetLayoutsPipeline.reserve(descriptorSetLayoutsAllocate.size() + descriptorSetLayoutsGlobal.size());
// Settle allocate layouts first
vkDescriptorSetLayoutsAllocate.reserve(descriptorSetLayoutsAllocate.size());
for (auto const& layout : descriptorSetLayoutsAllocate)
{
descriptorSetLayoutsPipeline.emplace_back(layout);
vkDescriptorSetLayoutsAllocate.emplace_back(layout->GetVkHandle());
}
@ -228,7 +231,10 @@ namespace SHADE
// First we insert the global layouts
for (auto const& layout : descriptorSetLayoutsGlobal)
{
descriptorSetLayoutsPipeline.emplace_back(layout);
vkDescriptorSetLayoutsPipeline.emplace_back(layout->GetVkHandle());
}
// Then we append layouts for allocation at the back of the vector
std::copy(vkDescriptorSetLayoutsAllocate.begin(), vkDescriptorSetLayoutsAllocate.end(), std::back_inserter(vkDescriptorSetLayoutsPipeline));
@ -435,6 +441,16 @@ namespace SHADE
return {};
}
std::vector<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
{
if (&rhs == this)

View File

@ -42,6 +42,9 @@ namespace SHADE
//! We want to store this also because we need to allocate later
std::vector<vk::DescriptorSetLayout> vkDescriptorSetLayoutsAllocate;
//! Store for descriptor set group creation
std::vector<Handle<SHVkDescriptorSetLayout>> descriptorSetLayoutsPipeline;
//! Store for pipeline layout recreation
std::vector<vk::DescriptorSetLayout> vkDescriptorSetLayoutsPipeline;
@ -71,10 +74,12 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/
std::vector<Handle<SHVkShaderModule>> const& GetShaderModules (void) const noexcept;
vk::PipelineLayout GetVkPipelineLayout (void) const noexcept;
SHPushConstantInterface const& GetPushConstantInterface (void) const noexcept;
Handle<SHShaderBlockInterface> GetShaderBlockInterface (uint32_t set, uint32_t binding, vk::ShaderStageFlagBits shaderStage) const noexcept;
std::vector<Handle<SHVkShaderModule>> const& GetShaderModules (void) const noexcept;
vk::PipelineLayout GetVkPipelineLayout (void) const noexcept;
SHPushConstantInterface const& GetPushConstantInterface (void) const noexcept;
Handle<SHShaderBlockInterface> GetShaderBlockInterface (uint32_t set, uint32_t binding, vk::ShaderStageFlagBits shaderStage) const noexcept;
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
{
/***************************************************************************/
/*!
\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;
predAttDesc.storeOp = vk::AttachmentStoreOp::eStore;
// TODO: Stecil load and store
// TODO: Stencil load and store
// When an image is done being used in a renderpass, the image layout will end up being the finalLayout
// value of the attachment description. We want this to carry over to the next renderpass; specifically
@ -976,11 +328,10 @@ namespace SHADE
*/
/***************************************************************************/
void SHRenderGraph::Init(Handle<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;
swapchainHdl = swapchain;
globalData = inGlobalData;
}
/***************************************************************************/
@ -1012,7 +363,6 @@ namespace SHADE
, nodes{ std::move(rhs.nodes) }
, graphResources{ std::move(rhs.graphResources) }
, resourceManager{ std::move(rhs.resourceManager) }
, globalData{ rhs.globalData }
{
}
@ -1028,7 +378,6 @@ namespace SHADE
nodes = std::move(rhs.nodes);
graphResources = std::move(rhs.graphResources);
resourceManager = std::move(rhs.resourceManager);
globalData = rhs.globalData;
return *this;
}
@ -1086,7 +435,7 @@ namespace SHADE
}
}
nodes.emplace_back(resourceManager.Create<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);
return nodes.at(nodeIndexing[nodeName]);
}
@ -1114,20 +463,20 @@ namespace SHADE
// TODO: The graph scope buffers were meant to bind vertex buffers and index buffers for meshes. Find a
// better way to manage these
void SHRenderGraph::Execute(uint32_t frameIndex, Handle<SHVkCommandBuffer> cmdBuffer) noexcept
void SHRenderGraph::Execute(uint32_t frameIndex, Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHVkDescriptorPool> descPool) noexcept
{
// TODO: DON'T HARDCODE THIS
cmdBuffer->SetViewportScissor(1920.0f, 1080.0f, 1920, 1080);
for (auto& node : nodes)
node->Execute(cmdBuffer, frameIndex);
node->Execute(cmdBuffer, descPool, frameIndex);
}
void SHRenderGraph::FinaliseBatch(uint32_t frameIndex)
void SHRenderGraph::FinaliseBatch(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{
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/Batching/SHSuperBatch.h"
#include "../MiddleEnd/Batching/SHBatcher.h"
#include "SHRenderGraphNode.h"
#include "SHSubpass.h"
#include "SHRenderGraphResource.h"
#include "SHRenderGraphNode.h"
#include "SHSubpass.h"
#include "SHAttachmentDescriptionType.h"
#include <string>
#include <map>
@ -24,223 +30,6 @@ namespace SHADE
class SHRenderGraphNode;
class SHGraphicsGlobalData;
// Used for attachment description creation for renderpass node
enum class SH_ATT_DESC_TYPE
{
COLOR,
COLOR_PRESENT,
DEPTH,
STENCIL,
DEPTH_STENCIL,
};
class SH_API SHRenderGraphResource
{
private:
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/
//! Name of the resource
std::string resourceName;
//! Used for initializing image layouts
SH_ATT_DESC_TYPE resourceType;
//! The resource itself (this is a vector because if the resource happens
//! to be a swapchain image, then we need however many frames in flight).
//! However when it's not a swapchain image, we want this container to be size 1
//! because writing to these images will not interfere with images in the previous
//! frame, unlike the swapchain image.
std::vector<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
{
@ -272,9 +61,6 @@ namespace SHADE
//! Resource library for graph handles
ResourceManager resourceManager;
//! Handle to global data
Handle<SHGraphicsGlobalData> globalData;
public:
/*-----------------------------------------------------------------------*/
@ -288,12 +74,12 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
/* 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 = {});
Handle<SHRenderGraphNode> AddNode (std::string nodeName, std::initializer_list<std::string> resourceNames, std::initializer_list<std::string> predecessorNodes) noexcept;
void Generate (void) noexcept;
void Execute (uint32_t frameIndex, Handle<SHVkCommandBuffer> cmdBuffer) noexcept;
void FinaliseBatch(uint32_t frameIndex);
void Execute (uint32_t frameIndex, Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHVkDescriptorPool> descPool) noexcept;
void FinaliseBatch(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
/*-----------------------------------------------------------------------*/
/* 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 SHVkFramebuffer;
/*-----------------------------------------------------------------------*/
/* TYPE DEFINTIIONS */
/*-----------------------------------------------------------------------*/
using SHSubPassIndex = uint32_t;
class SHVkRenderpass
{

View File

@ -5,9 +5,13 @@
namespace SHADE
{
/*-----------------------------------------------------------------------*/
/* TYPE DEFINTIIONS */
/*-----------------------------------------------------------------------*/
using SHQueueFamilyIndex = uint32_t;
using BindingAndSetHash = uint64_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
{
if (variableIndexing.size() < index)
if (index < variableIndexing.size())
return &variables.at(index);
return nullptr;

View File

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

View File

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

View File

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

View File

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

View File

@ -1,72 +1,44 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
#extension GL_EXT_nonuniform_qualifier : require
struct MatPropData
{
vec4 color;
int textureIndex;
float alpha;
vec3 beta;
};
layout(location = 0) in struct
{
//mat3 BTN;
vec4 vertColor;
//vec3 localSpacePosition;
//vec2 uv;
//vec3 localLightPosition;
//vec3 localEyePosition;
vec2 uv;
} In;
//layout(std140, push_constant) uniform TestPushConstant
//{
// mat4 pvMat;
// vec4 lightPosition;
// vec4 eyePosition;
// vec4 ambientColor;
// vec4 lightColor;
//
//} testPushConstant;
// material stuff
layout(location = 2) flat in struct
{
int materialIndex;
} In2;
//layout (set = 0, binding = )
layout (set = 0, binding = 1) uniform sampler2D textures[]; // for textures (global)
layout (set = 3, binding = 0) buffer MaterialProperties // For materials
{
MatPropData data[];
} MatProp;
layout(location = 0) out vec4 outColor;
//layout(binding = 0) uniform sampler2D diffuseMap;
//layout(binding = 1) uniform sampler2D normalMap;
//layout(binding = 2) uniform sampler2D aoMap;
//layout(binding = 3) uniform sampler2D glossinessMap;
//layout(binding = 4) uniform sampler2D samplerRoughnessMap;
void main()
{
//vec3 normal;
//// Get the tangent space normal from normal map. It is a BC5 texture and therefore only use red and green
//normal.xy = (texture (normalMap, In.uv).gr * 2.0f) - 1.0f;
outColor = texture(textures[nonuniformEXT(MatProp.data[In2.materialIndex].textureIndex)], In.uv) +
MatProp.data[In2.materialIndex].color / MatProp.data[In2.materialIndex].alpha;
//// z value is derived (TODO: Find out what this does)
//normal.z = sqrt(1.0f - dot(normal.xy, normal.xy));
//// Transform the normal from tangent space to local space
//normal = In.BTN * normal;
//// Get the vector from fragment to light
//vec3 localLightDir = normalize(In.localLightPosition - In.localSpacePosition);
//// get the value of dot between normal from texture and frag to light
//float diffuse = max(0, dot(normal, localLightDir));
//// sample the diffuse texture
//vec4 diffuseColor = texture (diffuseMap, In.uv) * In.vertColor;
//vec3 eyeDirection = normalize(In.localSpacePosition - In.localEyePosition);
//const float shininess = mix(1, 100, 1 - texture (samplerRoughnessMap, In.uv).r);
//float specular = pow(max(0, dot(normal, normalize(localLightDir - eyeDirection))), shininess);
//outColor.rgb = testPushConstant.ambientColor.rgb * diffuseColor.rgb * texture (aoMap, In.uv).rgb;
//outColor.rgb += testPushConstant.lightColor.rgb * (specular.rrr * 0.4 + diffuse.rrr * diffuseColor.rgb);
//const float gamma = testPushConstant.eyePosition.w;
//outColor.rgb = pow(outColor.rgb, vec3(1.0f / gamma));
//outColor.a = diffuseColor.a;
outColor = vec4 (1.0f);
//outColor = vec4 (1.0f);
}

Binary file not shown.

View File

@ -9,27 +9,20 @@ layout(location = 2) in vec3 aNormal;
layout(location = 3) in vec3 aTangent;
layout(location = 4) in mat4 worldTransform;
//layout(std140, push_constant) uniform TestPushConstant
//{
// mat4 pvMat;
// vec4 lightPosition;
// vec4 eyePosition;
// vec4 ambientColor;
// vec4 lightColor;
//
//} testPushConstant;
layout(location = 0) out struct
{
//mat3 BTN;
vec4 vertColor;
//vec3 localSpacePosition;
//vec2 uv;
//vec3 localLightPosition;
//vec3 localEyePosition;
vec4 vertColor; // location 0
vec2 uv; // location = 1
} Out;
// material stuff
layout(location = 2) out struct
{
int materialIndex;
} Out2;
layout(set = 2, binding = 0) uniform CameraData
{
vec4 position;
@ -38,25 +31,8 @@ layout(set = 2, binding = 0) uniform CameraData
void main()
{
//const float gamma = testPushConstant.eyePosition.w;
//mat4 W2L = inverse(worldTransform);
//// Since attributes are instanced we want the local positions of light and eye (camera)
//Out.localLightPosition = vec3(W2L * vec4(testPushConstant.lightPosition.xyz, 1.0f));
//Out.localEyePosition = vec3(W2L * vec4(testPushConstant.eyePosition.xyz, 1.0f));
//vec3 biTangent = normalize(cross(aNormal, aTangent));
//gl_Position = testPushConstant.pvMat * worldTransform * vec4(aVertexPos, 1.0);
//// Since the normal we are sampling is in tangent space, we want to later convert them to local space
//// so we need this matrix to multiply with the sampled texel of the normal map.
//Out.BTN = mat3(aTangent, biTangent, aNormal);
//Out.localSpacePosition = aVertexPos;
//Out.uv = aUV;
// render NDC first
//gl_Position = vec4(aVertexPos, 1.0f);
Out.uv = aUV;
Out2.materialIndex = gl_InstanceIndex;
gl_Position = cameraData.vpMat * worldTransform * vec4 (aVertexPos, 1.0f);
Out.vertColor = vec4 (aVertexPos, 1.0f);
}

Binary file not shown.