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

Added customization for compute shader post processing after renderpass end 
Added customization for compute shader post processing after renderpass end
Added Input attachment descriptor set support (incomplete, still need to bind and handle resizing)
Command buffers now take in a pipeline type to specify bind point. They also now store bind point specific data such as pipeline layout
More descriptor type support
Fixed a bug in batches where the frame index was not correct
Fixed a bug in pipeline layout where the descriptor set layout order was wrong
Render Graph now has 1 extra function at the start of generate where it checks render graph nodes for node computes. If they exist, add another subpass to transition all images involved.
Kirsch node compute for testing is in Graphics System.
Added function in SHVkUtil to convert pipeline type to pipeline bind point
This commit is contained in:
XiaoQiDigipen 2022-10-23 16:57:15 +08:00 committed by GitHub
commit bf2baee144
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 1221 additions and 361 deletions

View File

@ -0,0 +1,54 @@
[Window][MainStatusBar]
Pos=0,1060
Size=1920,20
Collapsed=0
[Window][SHEditorMenuBar]
Pos=0,48
Size=1920,1012
Collapsed=0
[Window][Hierarchy Panel]
Pos=0,142
Size=387,918
Collapsed=0
DockId=0x00000004,0
[Window][Debug##Default]
Pos=60,60
Size=400,400
Collapsed=0
[Window][Inspector]
Pos=1649,48
Size=271,1012
Collapsed=0
DockId=0x00000006,0
[Window][Profiler]
Pos=0,48
Size=387,92
Collapsed=0
DockId=0x00000003,0
[Window][Viewport]
Pos=648,48
Size=2519,1319
Collapsed=0
DockId=0x00000002,0
[Window][ Viewport]
Pos=389,48
Size=1258,1012
Collapsed=0
DockId=0x00000002,0
[Docking][Data]
DockSpace ID=0xC5C9B8AB Window=0xBE4044E9 Pos=8,79 Size=1920,1012 Split=X
DockNode ID=0x00000005 Parent=0xC5C9B8AB SizeRef=1992,1036 Split=X
DockNode ID=0x00000001 Parent=0x00000005 SizeRef=387,1036 Split=Y Selected=0x1E6EB881
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=225,94 Selected=0x1E6EB881
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=225,940 Selected=0xE096E5AE
DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1258,1036 CentralNode=1 Selected=0xB41284E7
DockNode ID=0x00000006 Parent=0xC5C9B8AB SizeRef=271,1036 Selected=0xE7039252

View File

@ -93,6 +93,7 @@ namespace Sandbox
SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BeginRoutine>();
SHSystemManager::RegisterRoutine<SHCameraSystem, SHCameraSystem::EditorCameraUpdate>();
SHSystemManager::RegisterRoutine<SHCameraSystem, SHCameraSystem::CameraSystemUpdate>();
#ifdef SHEDITOR
SHSystemManager::RegisterRoutine<SHEditor, SHEditor::EditorRoutine>();

View File

@ -14,6 +14,7 @@
#include "Physics/Components/SHColliderComponent.h"
#include "Assets/SHAssetManager.h"
#include "Camera/SHCameraComponent.h"
#include "Resource/SHResourceManager.h"
using namespace SHADE;
@ -155,6 +156,10 @@ namespace Sandbox
transformShowcase.SetWorldPosition({ 3.0f, -1.0f, -1.0f });
transformShowcase.SetLocalScale({ 5.0f, 5.0f, 5.0f });
scriptEngine->AddScript(raccoonShowcase, "RaccoonShowcase");
SHComponentManager::AddComponent<SHCameraComponent>(0);
SHComponentManager::RemoveComponent <SHRigidBodyComponent>(0);
SHComponentManager::RemoveComponent <SHColliderComponent>(0);
}
void SBTestScene::Update(float dt)

View File

@ -69,7 +69,7 @@ namespace SHADE
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::A))
{
std::cout << "Camera movement: "<<right.x<<", " << right.y << std::endl;
//std::cout << "Camera movement: "<<right.x<<", " << right.y << std::endl;
camera.position -= right * dt * camera.movementSpeed;
camera.dirtyView = true;
}
@ -110,7 +110,7 @@ namespace SHADE
camera.dirtyView = true;
}
std::cout << "Camera position: " << camera.position.x << " " << camera.position.y << std::endl;
//std::cout << "Camera position: " << camera.position.x << " " << camera.position.y << std::endl;
system->UpdateCameraComponent(system->editorCamera);
}
@ -140,10 +140,11 @@ namespace SHADE
{
auto transform = SHComponentManager::GetComponent<SHTransformComponent>(camera.GetEID());
SHVec3 rotation = transform->GetWorldRotation();
camera.pitch = rotation.x;
camera.yaw = rotation.y;
camera.roll = rotation.z;
camera.pitch = SHMath::RadiansToDegrees(rotation.x);
camera.yaw = SHMath::RadiansToDegrees(rotation.y);
camera.roll = SHMath::RadiansToDegrees(rotation.z);
camera.position = transform->GetWorldPosition();
camera.dirtyView = true;
}

View File

@ -10,6 +10,7 @@
#include "Graphics/Buffers/SHVkBuffer.h"
#include "Graphics/Images/SHVkImage.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "Graphics/SHVkUtil.h"
namespace SHADE
@ -299,7 +300,7 @@ namespace SHADE
SHLOG_ERROR("Command buffer must have started recording before a pipeline can be bound. ");
return;
}
boundPipelineLayoutHdl = pipelineHdl->GetPipelineLayout();
bindPointData[static_cast<uint32_t>(pipelineHdl->GetPipelineType())].boundPipelineLayoutHdl = pipelineHdl->GetPipelineLayout();
vkCommandBuffer.bindPipeline(pipelineHdl->GetPipelineBindPoint(), pipelineHdl->GetVkPipeline());
}
@ -358,9 +359,10 @@ namespace SHADE
}
}
void SHVkCommandBuffer::BindDescriptorSet(Handle<SHVkDescriptorSetGroup> descSetGroup, vk::PipelineBindPoint bindPoint, uint32_t firstSet, std::span<uint32_t> dynamicOffsets)
void SHVkCommandBuffer::BindDescriptorSet(Handle<SHVkDescriptorSetGroup> descSetGroup, SH_PIPELINE_TYPE bindPoint, uint32_t firstSet, std::span<uint32_t> dynamicOffsets)
{
vkCommandBuffer.bindDescriptorSets(bindPoint, boundPipelineLayoutHdl->GetVkPipelineLayout(), firstSet, descSetGroup->GetVkHandle(), dynamicOffsets);
uint32_t bindPointIndex = static_cast<uint32_t>(bindPoint);
vkCommandBuffer.bindDescriptorSets(SHVkUtil::GetPipelineBindPointFromType(bindPoint), bindPointData[bindPointIndex].boundPipelineLayoutHdl->GetVkPipelineLayout(), firstSet, descSetGroup->GetVkHandle(), dynamicOffsets);
}
/***************************************************************************/
@ -452,6 +454,11 @@ namespace SHADE
vkCommandBuffer.drawIndexedIndirect(indirectDrawData->GetVkBuffer(), 0, drawCount, sizeof(vk::DrawIndexedIndirectCommand));
}
void SHVkCommandBuffer::ComputeDispatch(uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) noexcept
{
vkCommandBuffer.dispatch (groupCountX, groupCountY, groupCountZ);
}
void SHVkCommandBuffer::CopyBufferToImage(const vk::Buffer& src, const vk::Image& dst, const std::vector<vk::BufferImageCopy>& copyInfo)
{
vkCommandBuffer.copyBufferToImage
@ -500,9 +507,9 @@ namespace SHADE
// //vkCommandBuffer.pipelineBarrier()
//}
void SHVkCommandBuffer::ForceSetPipelineLayout(Handle<SHVkPipelineLayout> pipelineLayout) noexcept
void SHVkCommandBuffer::ForceSetPipelineLayout(Handle<SHVkPipelineLayout> pipelineLayout, SH_PIPELINE_TYPE pipelineType) noexcept
{
boundPipelineLayoutHdl = pipelineLayout;
bindPointData[static_cast<uint32_t>(pipelineType)].boundPipelineLayoutHdl = pipelineLayout;
}
/***************************************************************************/
@ -513,12 +520,13 @@ namespace SHADE
*/
/***************************************************************************/
void SHVkCommandBuffer::SubmitPushConstants(void) const noexcept
void SHVkCommandBuffer::SubmitPushConstants(SH_PIPELINE_TYPE bindPoint) const noexcept
{
vkCommandBuffer.pushConstants(boundPipelineLayoutHdl->GetVkPipelineLayout(),
boundPipelineLayoutHdl->GetPushConstantInterface().GetShaderStageFlags(),
auto layoutHdl = bindPointData[static_cast<uint32_t>(bindPoint)].boundPipelineLayoutHdl;
vkCommandBuffer.pushConstants(layoutHdl->GetVkPipelineLayout(),
layoutHdl->GetPushConstantInterface().GetShaderStageFlags(),
0,
boundPipelineLayoutHdl->GetPushConstantInterface().GetSize(), pushConstantData);
layoutHdl->GetPushConstantInterface().GetSize(), pushConstantData);
}
/***************************************************************************/
@ -695,7 +703,7 @@ namespace SHADE
, usageFlags{ rhs.usageFlags }
, commandBufferCount{ rhs.commandBufferCount }
, parentPool{ rhs.parentPool }
, boundPipelineLayoutHdl{ rhs.boundPipelineLayoutHdl }
, bindPointData{ std::move (rhs.bindPointData)}
{
memcpy(pushConstantData, rhs.pushConstantData, PUSH_CONSTANT_SIZE);
@ -728,7 +736,7 @@ namespace SHADE
usageFlags = rhs.usageFlags;
commandBufferCount = rhs.commandBufferCount;
parentPool = rhs.parentPool;
boundPipelineLayoutHdl = rhs.boundPipelineLayoutHdl;
bindPointData = std::move(rhs.bindPointData);
memcpy(pushConstantData, rhs.pushConstantData, PUSH_CONSTANT_SIZE);
rhs.vkCommandBuffer = VK_NULL_HANDLE;

View File

@ -6,6 +6,7 @@
#include "SHCommandPoolResetMode.h"
#include "Resource/SHResourceLibrary.h"
#include "Graphics/Pipeline/SHVkPipelineLayout.h"
#include "Graphics/Pipeline/SHPipelineType.h"
namespace SHADE
{
@ -39,7 +40,14 @@ namespace SHADE
friend class SHResourceLibrary<SHVkCommandBuffer>;
static constexpr uint16_t PUSH_CONSTANT_SIZE = 512;
private:
struct PipelineBindPointData
{
//! The currently bound pipeline
Handle<SHVkPipelineLayout> boundPipelineLayoutHdl;
};
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/
@ -66,8 +74,8 @@ namespace SHADE
//! The command pool that this command buffer belongs to
Handle<SHVkCommandPool> parentPool;
//! The currently bound pipeline
Handle<SHVkPipelineLayout> boundPipelineLayoutHdl;
//! Every command buffer will have a set of pipeline bind point specific data
std::array<PipelineBindPointData, static_cast<uint32_t>(SH_PIPELINE_TYPE::NUM_TYPES)> bindPointData;
//! The push constant data for the command buffer
uint8_t pushConstantData[PUSH_CONSTANT_SIZE];
@ -112,13 +120,16 @@ namespace SHADE
void BindPipeline (Handle<SHVkPipeline> const& pipelineHdl) noexcept;
void BindVertexBuffer (uint32_t bindingPoint, Handle<SHVkBuffer> const& buffer, vk::DeviceSize offset) noexcept;
void BindIndexBuffer (Handle<SHVkBuffer> const& buffer, uint32_t startingIndex) const noexcept;
void BindDescriptorSet (Handle<SHVkDescriptorSetGroup> descSetGroup, vk::PipelineBindPoint bindPoint, uint32_t firstSet, std::span<uint32_t> dynamicOffsets);
void BindDescriptorSet (Handle<SHVkDescriptorSetGroup> descSetGroup, SH_PIPELINE_TYPE bindPoint, uint32_t firstSet, std::span<uint32_t> dynamicOffsets);
// Draw Commands
void DrawArrays (uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) const noexcept;
void DrawIndexed (uint32_t indexCount, uint32_t firstIndex, uint32_t vertexOffset) const noexcept;
void DrawMultiIndirect (Handle<SHVkBuffer> indirectDrawData, uint32_t drawCount);
// Compute Commands
void ComputeDispatch (uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) noexcept;
// Buffer Copy
void CopyBufferToImage (const vk::Buffer& src, const vk::Image& dst, const std::vector<vk::BufferImageCopy>& copyInfo);
void CopyImageToBuffer (const vk::Image& src, const vk::Buffer& dst, const std::vector<vk::BufferImageCopy>& copyInfo);
@ -138,13 +149,13 @@ namespace SHADE
// Push Constant variable setting
template <typename T>
void SetPushConstantVariable(std::string variableName, T const& data) noexcept
void SetPushConstantVariable(std::string variableName, T const& data, SH_PIPELINE_TYPE bindPoint) noexcept
{
memcpy (static_cast<uint8_t*>(pushConstantData) + boundPipelineLayoutHdl->GetPushConstantInterface().GetOffset(variableName), &data, sizeof (T));
memcpy (static_cast<uint8_t*>(pushConstantData) + bindPointData[static_cast<uint32_t>(bindPoint)].boundPipelineLayoutHdl->GetPushConstantInterface().GetOffset(variableName), &data, sizeof (T));
};
void ForceSetPipelineLayout (Handle<SHVkPipelineLayout> pipelineLayout) noexcept;
void ForceSetPipelineLayout (Handle<SHVkPipelineLayout> pipelineLayout, SH_PIPELINE_TYPE pipelineType) noexcept;
void SubmitPushConstants (void) const noexcept;
void SubmitPushConstants (SH_PIPELINE_TYPE bindPoint) const noexcept;
/*-----------------------------------------------------------------------*/
/* GETTERS AND SETTERS */

View File

@ -25,7 +25,8 @@ namespace SHADE
}
SHVkDescriptorPool::SHVkDescriptorPool(SHVkDescriptorPool&& rhs) noexcept
: device{ rhs.device }
: ISelfHandle (rhs)
, device{ rhs.device }
, pool{ rhs.pool }
{
rhs.pool = VK_NULL_HANDLE;

View File

@ -91,7 +91,7 @@ namespace SHADE
// new write for the binding
updater.writeInfos.emplace_back();
updater.writeHashMap.try_emplace(writeHash, updater.writeInfos.size() - 1);
updater.writeHashMap.try_emplace(writeHash, static_cast<uint32_t>(updater.writeInfos.size()) - 1u);
auto& writeInfo = updater.writeInfos.back();
// Descriptor count for the write descriptor set. Usually this is set to 1, but if binding is variable sized, set to info passed in
@ -102,10 +102,10 @@ namespace SHADE
//case vk::DescriptorType::eSampler:
//case vk::DescriptorType::eSampledImage:
case vk::DescriptorType::eCombinedImageSampler:
case vk::DescriptorType::eStorageImage:
case vk::DescriptorType::eInputAttachment:
writeInfo.descImageInfos.resize(descriptorCount);
break;
//case vk::DescriptorType::eStorageImage:
// break;
case vk::DescriptorType::eUniformTexelBuffer:
case vk::DescriptorType::eStorageTexelBuffer:
case vk::DescriptorType::eUniformBuffer:
@ -165,6 +165,7 @@ namespace SHADE
if (imageViewsAndSamplers.size() > writeInfo.descImageInfos.size())
{
SHLOG_ERROR("Attempting write too many descriptors into descriptor set. Failed to write to vk::WriteDescriptorSet. ");
return;
}
for (uint32_t i = 0; i < imageViewsAndSamplers.size(); ++i)

View File

@ -31,6 +31,8 @@ namespace SHADE
class SHVkDescriptorSetGroup
{
public:
using viewSamplerLayout = std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, vk::ImageLayout>;
/*-----------------------------------------------------------------------------*/
/* Constructor/Destructors */
/*-----------------------------------------------------------------------------*/

View File

@ -233,6 +233,8 @@ namespace SHADE
, vmaAllocator{rhs.vmaAllocator}
, nonDedicatedBestIndex {0}
, parentPhysicalDeviceHdl {rhs.parentPhysicalDeviceHdl}
, uboBufferMemoryAlignment{ 0 }
, ssboBufferMemoryAlignment{ 0 }
{
rhs.vkLogicalDevice = VK_NULL_HANDLE;
}
@ -261,6 +263,8 @@ namespace SHADE
vmaAllocator = rhs.vmaAllocator;
nonDedicatedBestIndex = 0;
parentPhysicalDeviceHdl = rhs.parentPhysicalDeviceHdl;
uboBufferMemoryAlignment = rhs.uboBufferMemoryAlignment;
ssboBufferMemoryAlignment = rhs.ssboBufferMemoryAlignment;
rhs.vkLogicalDevice = VK_NULL_HANDLE;
@ -529,6 +533,11 @@ namespace SHADE
}
Handle<SHVkPipeline> SHVkLogicalDevice::CreateComputePipeline(Handle<SHVkPipelineLayout> const& pipelineLayoutHdl) noexcept
{
return SHVkInstance::GetResourceManager().Create <SHVkPipeline>(GetHandle(), pipelineLayoutHdl);
}
Handle<SHVkSampler> SHVkLogicalDevice::CreateSampler(const SHVkSamplerParams& params) noexcept
{
return SHVkInstance::GetResourceManager().Create <SHVkSampler>(GetHandle(), params);

View File

@ -181,6 +181,11 @@ namespace SHADE
Handle<SHVkRenderpass> const& renderpassHdl,
Handle<SHSubpass> subpass
) noexcept;
Handle<SHVkPipeline> CreateComputePipeline (
Handle<SHVkPipelineLayout> const& pipelineLayoutHdl
) noexcept;
Handle<SHVkSampler> CreateSampler (const SHVkSamplerParams& params) noexcept;
Handle<SHVkRenderpass> CreateRenderpass (std::span<vk::AttachmentDescription> const vkDescriptions, std::vector<SHVkSubpassParams> const& subpasses) noexcept;

View File

@ -385,7 +385,7 @@ namespace SHADE
cmdBuffer->BindDescriptorSet
(
matPropsDescSet[frameIndex],
vk::PipelineBindPoint::eGraphics,
SH_PIPELINE_TYPE::GRAPHICS,
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
dynamicOffset
);

View File

@ -63,6 +63,14 @@ namespace SHADE
*/
/***************************************************************************/
static constexpr uint32_t PER_INSTANCE = 3;
/***************************************************************************/
/*!
\brief
DescriptorSet Index for render graph resources.
*/
/***************************************************************************/
static constexpr uint32_t RENDERGRAPH_RESOURCE = 4;
};

View File

@ -115,6 +115,23 @@ namespace SHADE
graphicsCmdPool = device->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS, SH_CMD_POOL_RESET::POOL_BASED, true);
transferCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
graphicsTexCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
// TODO: This is VERY temporarily here until a more solid resource management system is implemented
shaderSourceLibrary.Init("../../TempShaderFolder/");
shaderSourceLibrary.LoadShader(0, "TestCubeVs.glsl", SH_SHADER_TYPE::VERTEX, true);
shaderSourceLibrary.LoadShader(1, "TestCubeFs.glsl", SH_SHADER_TYPE::FRAGMENT, true);
shaderSourceLibrary.LoadShader(2, "KirschCs.glsl", SH_SHADER_TYPE::COMPUTE, true);
shaderModuleLibrary.ImportFromSourceLibrary(device, shaderSourceLibrary);
auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl");
auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl");
auto greyscale = shaderModuleLibrary.GetShaderModule("KirschCs.glsl");
cubeVS->Reflect();
cubeFS->Reflect();
greyscale->Reflect();
}
void SHGraphicsSystem::InitSceneRenderGraph(void) noexcept
@ -130,6 +147,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
auto windowDims = window->GetWindowSize();
auto cameraSystem = SHSystemManager::GetSystem<SHCameraSystem>();
// Set Up Cameras
screenCamera = resourceManager.Create<SHCamera>();
@ -154,21 +172,21 @@ namespace SHADE
// Initialize world render graph
worldRenderGraph->Init(device, swapchain);
worldRenderGraph->AddResource("Scene", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT }, windowDims.first, windowDims.second);
worldRenderGraph->AddResource("Scene Pre-Process", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second);
worldRenderGraph->AddResource("Scene", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second);
worldRenderGraph->AddResource("Depth Buffer", { SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL }, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint);
worldRenderGraph->AddResource("Entity ID", { SH_ATT_DESC_TYPE_FLAGS::COLOR }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc);
auto node = worldRenderGraph->AddNode("G-Buffer", { "Entity ID", "Depth Buffer", "Scene"}, {}); // no predecessors
auto node = worldRenderGraph->AddNode("G-Buffer", { "Entity ID", "Depth Buffer", "Scene", "Scene Pre-Process"}, {}); // no predecessors
//First subpass to write to G-Buffer
auto gBufferWriteSubpass = node->AddSubpass("G-Buffer Write");
gBufferWriteSubpass->AddColorOutput("Scene");
gBufferWriteSubpass->AddColorOutput("Scene Pre-Process");
gBufferWriteSubpass->AddColorOutput("Entity ID");
gBufferWriteSubpass->AddDepthOutput("Depth Buffer", SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL);
// We do this to just transition our scene layout to shader read
auto sceneLayoutTransitionSubpass = node->AddSubpass("Scene Layout Transition");
sceneLayoutTransitionSubpass->AddInput("Scene");
auto greyscale = shaderModuleLibrary.GetShaderModule("KirschCs.glsl");
node->AddNodeCompute (greyscale, {"Scene Pre-Process", "Scene"});
// Generate world render graph
worldRenderGraph->Generate();
@ -177,20 +195,13 @@ namespace SHADE
worldRenderer = worldViewport->AddRenderer(resourceManager, swapchain->GetNumImages(), renderContextCmdPools, descPool, SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS], worldRenderGraph);
worldRenderer->SetCamera(worldCamera);
worldRenderer->SetCameraDirector(cameraSystem->CreateDirector());
// TODO: This is VERY temporarily here until a more solid resource management system is implemented
shaderSourceLibrary.Init("../../TempShaderFolder/");
shaderSourceLibrary.LoadShader(0, "TestCubeVs.glsl", SH_SHADER_TYPE::VERTEX, true);
shaderSourceLibrary.LoadShader(1, "TestCubeFs.glsl", SH_SHADER_TYPE::FRAGMENT, true);
shaderModuleLibrary.ImportFromSourceLibrary(device, shaderSourceLibrary);
auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl");
auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl");
cubeVS->Reflect();
cubeFS->Reflect();
defaultMaterial = AddMaterial(cubeVS, cubeFS, gBufferWriteSubpass);
}
void SHGraphicsSystem::InitMiddleEnd(void) noexcept
@ -323,21 +334,7 @@ namespace SHADE
auto cameraSystem = SHSystemManager::GetSystem<SHCameraSystem>();
#ifdef SHEDITOR
auto editorSystem = SHSystemManager::GetSystem<SHEditor>();
if (editorSystem->editorState != SHEditor::State::PLAY)
{
worldRenderer->SetViewProjectionMatrix(SHMatrix::Transpose(cameraSystem->GetEditorCamera()->GetProjMatrix() * cameraSystem->GetEditorCamera()->GetViewMatrix()));
}
else
{
// main camera
}
#else
// main camera
#endif
// For every viewport
for (int vpIndex = 0; vpIndex < static_cast<int>(viewports.size()); ++vpIndex)
@ -360,7 +357,7 @@ namespace SHADE
uint32_t h = static_cast<uint32_t>(viewports[vpIndex]->GetHeight());
currentCmdBuffer->SetViewportScissor (static_cast<float>(w), static_cast<float>(h), w, h);
currentCmdBuffer->ForceSetPipelineLayout(SHGraphicsGlobalData::GetDummyPipelineLayout());
currentCmdBuffer->ForceSetPipelineLayout(SHGraphicsGlobalData::GetDummyPipelineLayout(), SH_PIPELINE_TYPE::GRAPHICS);
// Bind all the buffers required for meshes
for (auto& [buffer, bindingPoint] : MESH_DATA)
@ -380,14 +377,29 @@ namespace SHADE
currentCmdBuffer->BindDescriptorSet
(
textureDescSet,
vk::PipelineBindPoint::eGraphics,
SH_PIPELINE_TYPE::GRAPHICS,
0,
texDynamicOffset
);
}
// bind camera data
//renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex);
#ifdef SHEDITOR
if (renderers[renIndex] == worldRenderer)
{
auto editorSystem = SHSystemManager::GetSystem<SHEditor>();
if (editorSystem->editorState != SHEditor::State::PLAY)
worldRenderer->UpdateDataAndBind(currentCmdBuffer, frameIndex, SHMatrix::Transpose(cameraSystem->GetEditorCamera()->GetProjMatrix() * cameraSystem->GetEditorCamera()->GetViewMatrix()));
else
renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex);
}
else
renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex);
#else
renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex);
#endif
// Draw first
renderers[renIndex]->Draw(frameIndex, descPool);
@ -726,8 +738,8 @@ namespace SHADE
auto cameraSystem = SHSystemManager::GetSystem<SHCameraSystem>();
#ifdef SHEDITOR
cameraSystem->GetEditorCamera()->SetWidth(resizeWidth);
cameraSystem->GetEditorCamera()->SetHeight(resizeHeight);
cameraSystem->GetEditorCamera()->SetWidth(static_cast<float>(resizeWidth));
cameraSystem->GetEditorCamera()->SetHeight(static_cast<float>(resizeHeight));
#else
#endif

View File

@ -68,7 +68,7 @@ namespace SHADE
{
std::vector combinedImageSampler
{
std::make_tuple(offscreenRender->GetImageView(), offscreenRenderSampler, vk::ImageLayout::eShaderReadOnlyOptimal),
std::make_tuple(offscreenRender->GetImageView(), offscreenRenderSampler, vk::ImageLayout::eGeneral),
};
// Register the image view and sampler with the descriptor set. Now whenever rendering to the offscreen image is done, the descriptor set will see the change

View File

@ -21,6 +21,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "Graphics/Buffers/SHVkBuffer.h"
#include "Camera/SHCameraDirector.h"
namespace SHADE
{
@ -65,6 +66,11 @@ namespace SHADE
camera = _camera;
}
void SHRenderer::SetCameraDirector(Handle<SHCameraDirector> director) noexcept
{
cameraDirector = director;
}
/*-----------------------------------------------------------------------------------*/
/* Drawing Functions */
/*-----------------------------------------------------------------------------------*/
@ -75,15 +81,22 @@ namespace SHADE
void SHRenderer::UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
{
if (camera)
if (camera && cameraDirector)
{
UpdateDataAndBind(cmdBuffer, frameIndex, SHMatrix::Transpose(cameraDirector->GetVPMatrix()));
}
}
void SHRenderer::UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, SHMatrix exteriorMatrix) noexcept
{
SetViewProjectionMatrix(exteriorMatrix);
//cpuCameraData.viewProjectionMatrix = camera->GetViewProjectionMatrix();
cameraBuffer->WriteToMemory(&cpuCameraData, sizeof(SHShaderCameraData), 0, cameraDataAlignedSize * frameIndex);
std::array<uint32_t, 1> dynamicOffsets{ frameIndex * cameraDataAlignedSize };
cmdBuffer->BindDescriptorSet(cameraDescriptorSet, vk::PipelineBindPoint::eGraphics, SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS, std::span{ dynamicOffsets.data(), 1 });
}
cmdBuffer->BindDescriptorSet(cameraDescriptorSet, SH_PIPELINE_TYPE::GRAPHICS, SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS, std::span{ dynamicOffsets.data(), 1 });
}
void SHRenderer::UpdateCameraDataToBuffer(void) noexcept

View File

@ -40,6 +40,7 @@ namespace SHADE
class SHGraphicsGlobalData;
class SHVkDescriptorPool;
class SHVkBuffer;
class SHCameraDirector;
struct SHShaderCameraData
{
@ -71,12 +72,14 @@ namespace SHADE
/* Camera Registration */
/*-----------------------------------------------------------------------------*/
void SetCamera(Handle<SHCamera> _camera);
void SetCameraDirector (Handle<SHCameraDirector> director) noexcept;
/*-----------------------------------------------------------------------------*/
/* Drawing Functions */
/*-----------------------------------------------------------------------------*/
void Draw(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool) noexcept;
void UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
void UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, SHMatrix exteriorMatrix) noexcept;
void UpdateCameraDataToBuffer (void) noexcept;
void SetViewProjectionMatrix (SHMatrix const& vpMatrix) noexcept;
@ -99,6 +102,8 @@ namespace SHADE
Handle<SHVkDescriptorSetGroup> cameraDescriptorSet;
Handle<SHVkBuffer> cameraBuffer;
Handle<SHCameraDirector> cameraDirector;
// we really only need 1 copy even though we need %swapchainImages copies for
// GPU.
SHShaderCameraData cpuCameraData;

View File

@ -8,7 +8,7 @@
namespace SHADE
{
Handle<SHVkPipeline> SHPipelineLibrary::CreateDrawPipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHVkRenderpass> renderpass, Handle<SHSubpass> subpass) noexcept
Handle<SHVkPipeline> SHPipelineLibrary::CreateGraphicsPipelines(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHVkRenderpass> renderpass, Handle<SHSubpass> subpass) noexcept
{
SHPipelineLayoutParams params
{
@ -52,7 +52,7 @@ namespace SHADE
newPipeline->ConstructPipeline();
// Emplace the new pipeline
pipelines.emplace (vsFsPair, newPipeline);
graphicsPipelines.emplace (vsFsPair, newPipeline);
return newPipeline;
}
@ -62,19 +62,19 @@ namespace SHADE
logicalDevice = device;
}
Handle<SHVkPipeline> SHPipelineLibrary::GetDrawPipline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept
Handle<SHVkPipeline> SHPipelineLibrary::GetGraphicsPipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept
{
// return the pipeline requested for
if (pipelines.contains(vsFsPair))
return pipelines.at(vsFsPair);
if (graphicsPipelines.contains(vsFsPair))
return graphicsPipelines.at(vsFsPair);
else
return {};
}
bool SHPipelineLibrary::CheckDrawPipelineExistence(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept
bool SHPipelineLibrary::CheckGraphicsPipelineExistence(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept
{
// Returns if a pipeline exists or not
return pipelines.contains(vsFsPair);
return graphicsPipelines.contains(vsFsPair);
}
}

View File

@ -23,19 +23,19 @@ namespace SHADE
Handle<SHVkLogicalDevice> logicalDevice;
//! a map of pipelines that are hashed using a pair of shader module handles
std::unordered_map<std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>>, Handle<SHVkPipeline>> pipelines;
std::unordered_map<std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>>, Handle<SHVkPipeline>> graphicsPipelines;
public:
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 (
Handle<SHVkPipeline> CreateGraphicsPipelines (
std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair,
Handle<SHVkRenderpass> renderpass,
Handle<SHSubpass> subpass
) noexcept;
Handle<SHVkPipeline> GetDrawPipline (std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept;
bool CheckDrawPipelineExistence (std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept;
Handle<SHVkPipeline> GetGraphicsPipeline (std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept;
bool CheckGraphicsPipelineExistence (std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept;
};
}

View File

@ -5,9 +5,13 @@ namespace SHADE
{
enum class SH_PIPELINE_TYPE
{
GRAPHICS,
GRAPHICS = 0,
COMPUTE,
RAY_TRACING,
NUM_TYPES,
};
}
#endif

View File

@ -4,6 +4,7 @@
#include "Graphics/Shaders/SHVkShaderModule.h"
#include "Graphics/Debugging/SHVulkanDebugUtil.h"
#include "Graphics/RenderGraph/SHRenderGraph.h"
#include "Graphics/SHVkUtil.h"
namespace SHADE
{
@ -171,6 +172,29 @@ namespace SHADE
void SHVkPipeline::CreateComputePipeline(void) noexcept
{
auto shaderModule = pipelineLayout->GetShaderModules()[0];
vk::PipelineShaderStageCreateInfo shaderStageCreateInfo
{
.stage = vk::ShaderStageFlagBits::eCompute,
.module = shaderModule->GetVkShaderModule(),
.pName = shaderModule->GetEntryPoint().c_str(),
};
vk::ComputePipelineCreateInfo cpCreateInfo
{
.flags = {},
.stage = shaderStageCreateInfo,
.layout = pipelineLayout->GetVkPipelineLayout(),
};
if (auto result = logicalDeviceHdl->GetVkLogicalDevice().createComputePipelines({}, 1, &cpCreateInfo, nullptr, &vkPipeline); result != vk::Result::eSuccess)
SHVulkanDebugUtil::ReportVkError(result, "Failed to create Compute Pipeline. ");
else
{
SHVulkanDebugUtil::ReportVkSuccess("Successfully created a Compute Pipeline. ");
created = true;
}
}
@ -245,7 +269,7 @@ namespace SHADE
, logicalDeviceHdl{ rhs.logicalDeviceHdl }
, pipelineLayout { rhs.pipelineLayout }
{
vkPipeline = VK_NULL_HANDLE;
rhs.vkPipeline = VK_NULL_HANDLE;
}
/***************************************************************************/
@ -285,6 +309,7 @@ namespace SHADE
/***************************************************************************/
SHVkPipeline::~SHVkPipeline(void) noexcept
{
if (vkPipeline)
logicalDeviceHdl->GetVkLogicalDevice().destroyPipeline(vkPipeline, nullptr);
}
@ -313,7 +338,7 @@ namespace SHADE
created = rhs.created;
logicalDeviceHdl = rhs.logicalDeviceHdl;
vkPipeline = VK_NULL_HANDLE;
rhs.vkPipeline = VK_NULL_HANDLE;
return *this;
}
@ -399,18 +424,7 @@ namespace SHADE
/***************************************************************************/
vk::PipelineBindPoint SHVkPipeline::GetPipelineBindPoint(void) const noexcept
{
switch (pipelineType)
{
case SH_PIPELINE_TYPE::GRAPHICS:
return vk::PipelineBindPoint::eGraphics;
case SH_PIPELINE_TYPE::COMPUTE:
return vk::PipelineBindPoint::eCompute;
break;
default:
return vk::PipelineBindPoint::eGraphics;
break;
}
return SHVkUtil::GetPipelineBindPointFromType(pipelineType);
}
/***************************************************************************/
@ -450,4 +464,9 @@ namespace SHADE
return pipelineLayout;
}
SH_PIPELINE_TYPE SHVkPipeline::GetPipelineType(void) const noexcept
{
return pipelineType;
}
}

View File

@ -77,6 +77,7 @@ namespace SHADE
vk::Pipeline GetVkPipeline (void) const noexcept;
bool GetIsCreated (void) const noexcept;
Handle<SHVkPipelineLayout> GetPipelineLayout (void) const noexcept;
SH_PIPELINE_TYPE GetPipelineType (void) const noexcept;
};
}

View File

@ -216,9 +216,18 @@ namespace SHADE
/***************************************************************************/
void SHVkPipelineLayout::PrepareVkDescriptorSetLayouts(void) noexcept
{
// pipeline layouts contain global layouts first, then layouts for allocation
descriptorSetLayoutsPipeline.reserve(descriptorSetLayoutsAllocate.size() + descriptorSetLayoutsGlobal.size());
vkDescriptorSetLayoutsPipeline.reserve(descriptorSetLayoutsAllocate.size() + descriptorSetLayoutsGlobal.size());
// Settle allocate layouts first
// First we insert the global layouts
for (auto const& layout : descriptorSetLayoutsGlobal)
{
descriptorSetLayoutsPipeline.emplace_back(layout);
//vkDescriptorSetLayoutsPipeline.emplace_back(layout->GetVkHandle());
}
// Then the allocate layouts
vkDescriptorSetLayoutsAllocate.reserve(descriptorSetLayoutsAllocate.size());
for (auto const& layout : descriptorSetLayoutsAllocate)
{
@ -226,18 +235,13 @@ namespace SHADE
vkDescriptorSetLayoutsAllocate.emplace_back(layout->GetVkHandle());
}
// pipeline layouts contain global layouts first, then layouts for allocation
vkDescriptorSetLayoutsPipeline.reserve(descriptorSetLayoutsAllocate.size() + descriptorSetLayoutsGlobal.size());
// First we insert the global layouts
for (auto const& layout : descriptorSetLayoutsGlobal)
for (auto const& layout : descriptorSetLayoutsPipeline)
{
descriptorSetLayoutsPipeline.emplace_back(layout);
vkDescriptorSetLayoutsPipeline.emplace_back(layout->GetVkHandle());
}
// Then we append layouts for allocation at the back of the vector
std::copy(vkDescriptorSetLayoutsAllocate.begin(), vkDescriptorSetLayoutsAllocate.end(), std::back_inserter(vkDescriptorSetLayoutsPipeline));
//std::copy(vkDescriptorSetLayoutsAllocate.begin(), vkDescriptorSetLayoutsAllocate.end(), std::back_inserter(vkDescriptorSetLayoutsPipeline));
}
/***************************************************************************/
@ -294,6 +298,7 @@ namespace SHADE
, descriptorSetLayoutsGlobal{pipelineLayoutParams.globalDescSetLayouts } // do a copy, some other pipeline layout might need this
, descriptorSetLayoutsAllocate{}
, vkDescriptorSetLayoutsAllocate{}
, descriptorSetLayoutsPipeline{}
, vkDescriptorSetLayoutsPipeline{}
{
for (auto& mod : shaderModules)
@ -318,6 +323,7 @@ namespace SHADE
, descriptorSetLayoutsGlobal{}
, descriptorSetLayoutsAllocate{}
, vkDescriptorSetLayoutsAllocate{}
, descriptorSetLayoutsPipeline{}
, vkDescriptorSetLayoutsPipeline{}
{
@ -368,7 +374,8 @@ namespace SHADE
, descriptorSetLayoutsGlobal {std::move (rhs.descriptorSetLayoutsGlobal)}
, descriptorSetLayoutsAllocate {std::move (rhs.descriptorSetLayoutsAllocate)}
, vkDescriptorSetLayoutsAllocate{std::move (rhs.vkDescriptorSetLayoutsAllocate)}
, vkDescriptorSetLayoutsPipeline{std::move (rhs.vkDescriptorSetLayoutsAllocate)}
, descriptorSetLayoutsPipeline { std::move(rhs.descriptorSetLayoutsPipeline) }
, vkDescriptorSetLayoutsPipeline{ std::move(rhs.vkDescriptorSetLayoutsPipeline) }
{
rhs.vkPipelineLayout = VK_NULL_HANDLE;
}
@ -441,12 +448,12 @@ namespace SHADE
return {};
}
std::vector<Handle<SHVkDescriptorSetLayout>> SHVkPipelineLayout::GetDescriptorSetLayoutsPipeline(void) const noexcept
std::vector<Handle<SHVkDescriptorSetLayout>> const& SHVkPipelineLayout::GetDescriptorSetLayoutsPipeline(void) const noexcept
{
return descriptorSetLayoutsPipeline;
}
std::vector<Handle<SHVkDescriptorSetLayout>> SHVkPipelineLayout::GetDescriptorSetLayoutsAllocate(void) const noexcept
std::vector<Handle<SHVkDescriptorSetLayout>> const& SHVkPipelineLayout::GetDescriptorSetLayoutsAllocate(void) const noexcept
{
return descriptorSetLayoutsAllocate;
}
@ -464,7 +471,8 @@ namespace SHADE
descriptorSetLayoutsGlobal = std::move(rhs.descriptorSetLayoutsGlobal);
descriptorSetLayoutsAllocate = std::move(rhs.descriptorSetLayoutsAllocate);
vkDescriptorSetLayoutsAllocate = std::move(rhs.vkDescriptorSetLayoutsAllocate);
vkDescriptorSetLayoutsPipeline = std::move(rhs.vkDescriptorSetLayoutsAllocate);
descriptorSetLayoutsPipeline = std::move(rhs.descriptorSetLayoutsPipeline);
vkDescriptorSetLayoutsPipeline = std::move(rhs.vkDescriptorSetLayoutsPipeline);
rhs.vkPipelineLayout = VK_NULL_HANDLE;

View File

@ -78,8 +78,8 @@ namespace SHADE
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;
std::vector<Handle<SHVkDescriptorSetLayout>> const& GetDescriptorSetLayoutsPipeline(void) const noexcept;
std::vector<Handle<SHVkDescriptorSetLayout>> const& GetDescriptorSetLayoutsAllocate(void) const noexcept;
};
}

View File

@ -10,6 +10,8 @@ namespace SHADE
DEPTH = 0x04,
STENCIL = 0x08,
DEPTH_STENCIL = 0x10,
INPUT = 0x20
INPUT = 0x20,
STORAGE = 0x40
};
}

View File

@ -9,6 +9,8 @@
#include "Graphics/Buffers/SHVkBuffer.h"
#include "Tools/SHLogger.h"
#include "SHAttachmentDescInitParams.h"
#include "SHRenderGraphStorage.h"
#include "Graphics/RenderGraph/SHRenderGraphNodeCompute.h"
namespace SHADE
{
@ -52,12 +54,12 @@ namespace SHADE
// If we set to
if (w == static_cast<uint32_t>(-1) && h == static_cast<uint32_t>(-1))
{
w = swapchainHdl->GetSwapchainImage(0)->GetWidth();
h = swapchainHdl->GetSwapchainImage(0)->GetHeight();
format = swapchainHdl->GetSurfaceFormatKHR().format;
w = renderGraphStorage->swapchain->GetSwapchainImage(0)->GetWidth();
h = renderGraphStorage->swapchain->GetSwapchainImage(0)->GetHeight();
format = renderGraphStorage->swapchain->GetSurfaceFormatKHR().format;
}
graphResources.try_emplace(resourceName, resourceManager->Create<SHRenderGraphResource>(logicalDeviceHdl, swapchainHdl, resourceName, typeFlags, format, w, h, levels, usageFlags, createFlags));
renderGraphStorage->graphResources->try_emplace(resourceName, resourceManager->Create<SHRenderGraphResource>(renderGraphStorage, resourceName, typeFlags, format, w, h, levels, usageFlags, createFlags));
}
/***************************************************************************/
@ -77,36 +79,38 @@ namespace SHADE
for (uint32_t i = 0; auto& node : nodes)
{
// key is handle ID, value is pair (first is initial layout, second is final layout).
std::unordered_map<uint32_t, vk::ImageLayout> resourceAttLayouts;
// key is handle ID, value is final layout.
std::unordered_map<uint32_t, vk::ImageLayout> resourceAttFinalLayouts;
if (node->subpasses.empty())
{
SHLOG_ERROR("Node does not contain a subpass. Cannot configure attachment descriptions as a result. ");
return;
}
// attempt to get all final layouts for all resources
for (auto& subpass : node->subpasses)
{
for (auto& color : subpass->colorReferences)
{
// If final renderpass and attachment is a COLOR_PRESENT resource, make resource transition to present after last subpass
if (i == nodes.size() - 1 && (node->attResources[color.attachment]->resourceTypeFlags & static_cast<uint32_t>(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)))
resourceAttLayouts[color.attachment] = vk::ImageLayout::ePresentSrcKHR;
resourceAttFinalLayouts[color.attachment] = vk::ImageLayout::ePresentSrcKHR;
else
resourceAttLayouts[color.attachment] = color.layout;
resourceAttFinalLayouts[color.attachment] = color.layout;
}
for (auto& depth : subpass->depthReferences)
resourceAttLayouts[depth.attachment] = depth.layout;
resourceAttFinalLayouts[depth.attachment] = depth.layout;
for (auto& input : subpass->inputReferences)
resourceAttLayouts[input.attachment] = input.layout;
resourceAttFinalLayouts[input.attachment] = input.layout;
}
for (uint32_t j = 0; j < node->attachmentDescriptions.size(); ++j)
{
auto& att = node->attachmentDescriptions[j];
att.initialLayout = vk::ImageLayout::eUndefined;
att.finalLayout = resourceAttLayouts[j];
att.finalLayout = resourceAttFinalLayouts[j];
}
++i;
}
@ -292,6 +296,9 @@ namespace SHADE
dep.dstAccessMask = dstAccess;
dep.srcStageMask = srcStage;
// initialize input descriptors
node->subpasses[i]->CreateInputDescriptors();
}
}
}
@ -343,10 +350,18 @@ namespace SHADE
*/
/***************************************************************************/
void SHRenderGraph::Init(Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain) noexcept
void SHRenderGraph::Init(Handle<SHVkLogicalDevice> logicalDevice, Handle<SHVkSwapchain> swapchain) noexcept
{
logicalDeviceHdl = logicalDevice;
swapchainHdl = swapchain;
resourceManager = std::make_shared<SHResourceHub>();
renderGraphStorage = resourceManager->Create<SHRenderGraphStorage>();
renderGraphStorage->graphResources = resourceManager->Create<std::unordered_map<std::string, Handle<SHRenderGraphResource>>>();
renderGraphStorage->logicalDevice = logicalDevice;
renderGraphStorage->swapchain = swapchain;
renderGraphStorage->resourceManager = resourceManager;
renderGraphStorage->descriptorPool = logicalDevice->CreateDescriptorPools();
}
/***************************************************************************/
@ -361,21 +376,16 @@ namespace SHADE
*/
/***************************************************************************/
SHRenderGraph::SHRenderGraph(void) noexcept
: logicalDeviceHdl{ }
, swapchainHdl{ }
: renderGraphStorage{}
, nodes{}
, graphResources{}
, resourceManager{nullptr}
{
resourceManager = std::make_shared<SHResourceHub>();
}
SHRenderGraph::SHRenderGraph(SHRenderGraph&& rhs) noexcept
: logicalDeviceHdl{ rhs.logicalDeviceHdl }
, swapchainHdl{ rhs.swapchainHdl }
: renderGraphStorage{ rhs.renderGraphStorage }
, nodeIndexing{ std::move(rhs.nodeIndexing) }
, nodes{ std::move(rhs.nodes) }
, graphResources{ std::move(rhs.graphResources) }
, resourceManager{ std::move(rhs.resourceManager) }
{
@ -386,11 +396,9 @@ namespace SHADE
if (&rhs == this)
return *this;
logicalDeviceHdl = rhs.logicalDeviceHdl;
swapchainHdl = rhs.swapchainHdl;
renderGraphStorage = rhs.renderGraphStorage;
nodeIndexing = std::move(rhs.nodeIndexing);
nodes = std::move(rhs.nodes);
graphResources = std::move(rhs.graphResources);
resourceManager = std::move(rhs.resourceManager);
return *this;
@ -426,12 +434,12 @@ namespace SHADE
for (auto const& instruction : resourceInstruction)
{
// If the resource that the new node is requesting for exists, allow the graph to reference it
if (graphResources.contains(instruction.resourceName))
if (renderGraphStorage->graphResources->contains(instruction.resourceName))
{
descInitParams.push_back(
{
.resourceHdl = graphResources.at(instruction.resourceName),
.dontClearOnLoad = false,
.resourceHdl = renderGraphStorage->graphResources->at(instruction.resourceName),
.dontClearOnLoad = instruction.dontClearOnLoad,
}
);
}
@ -456,7 +464,7 @@ namespace SHADE
}
}
nodes.emplace_back(resourceManager->Create<SHRenderGraphNode>(resourceManager, logicalDeviceHdl, swapchainHdl, std::move(descInitParams), std::move(predecessors), &graphResources));
nodes.emplace_back(resourceManager->Create<SHRenderGraphNode>(renderGraphStorage, std::move(descInitParams), std::move(predecessors)));
nodeIndexing.emplace(nodeName, static_cast<uint32_t>(nodes.size()) - 1u);
return nodes.at(nodeIndexing[nodeName]);
}
@ -476,12 +484,31 @@ namespace SHADE
/***************************************************************************/
void SHRenderGraph::Generate(void) noexcept
{
CheckForNodeComputes();
ConfigureAttachmentDescriptions();
ConfigureSubpasses();
ConfigureRenderpasses();
ConfigureFramebuffers();
}
/***************************************************************************/
/*!
\brief
This function goes through all renderpasses and checks for existence of
node computes. If they exist, adds dummy subpasses to transition resources
into general.
*/
/***************************************************************************/
void SHRenderGraph::CheckForNodeComputes(void) noexcept
{
for (auto& node : nodes)
{
node->AddDummySubpassIfNeeded();
}
}
// TODO: The graph scope buffers were meant to bind vertex buffers and index buffers for meshes. Find a
// better way to manage these
void SHRenderGraph::Execute(uint32_t frameIndex, Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHVkDescriptorPool> descPool) noexcept
@ -501,7 +528,7 @@ namespace SHADE
void SHRenderGraph::HandleResize(uint32_t newWidth, uint32_t newHeight) noexcept
{
// resize resources
for (auto& [name, resource]: graphResources)
for (auto& [name, resource] : *renderGraphStorage->graphResources)
resource->HandleResize(newWidth, newHeight);
for (auto& node : nodes)
@ -521,9 +548,9 @@ namespace SHADE
Handle<SHRenderGraphResource> SHRenderGraph::GetRenderGraphResource(std::string const& resourceName) const noexcept
{
if (graphResources.contains(resourceName))
if (renderGraphStorage->graphResources->contains(resourceName))
{
return graphResources.at(resourceName);
return renderGraphStorage->graphResources->at(resourceName);
}
return {};
}

View File

@ -30,7 +30,8 @@ namespace SHADE
class SHVkCommandBuffer;
class SHRenderGraphNode;
class SHGraphicsGlobalData;
class SHVkDescriptorPool;
class SHRenderGraphStorage;
class SH_API SHRenderGraph
{
@ -56,10 +57,8 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/
Handle<SHVkLogicalDevice> logicalDeviceHdl;
//! swapchain used for querying image count
Handle<SHVkSwapchain> swapchainHdl;
Handle<SHRenderGraphStorage> renderGraphStorage;
//! For indexing render graph node container
std::map<std::string, uint32_t> nodeIndexing;
@ -67,9 +66,6 @@ namespace SHADE
//! Render graph nodes
std::vector<Handle<SHRenderGraphNode>> nodes;
//! Resources that exist for the entire render graph
std::unordered_map<std::string, Handle<SHRenderGraphResource>> graphResources;
//! Resource library for graph handles
std::shared_ptr<SHResourceHub> resourceManager;
@ -85,11 +81,12 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
void Init (Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain) noexcept;
void Init (Handle<SHVkLogicalDevice> logicalDevice, Handle<SHVkSwapchain> swapchain) noexcept;
void AddResource(std::string resourceName, std::initializer_list<SH_ATT_DESC_TYPE_FLAGS> typeFlags, 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::ImageUsageFlagBits usageFlags = {}, vk::ImageCreateFlagBits createFlags = {});
Handle<SHRenderGraphNode> AddNode (std::string nodeName, std::initializer_list<ResourceInstruction> resourceInstruction, std::initializer_list<std::string> predecessorNodes) noexcept;
void Generate (void) noexcept;
void CheckForNodeComputes (void) noexcept;
void Execute (uint32_t frameIndex, Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHVkDescriptorPool> descPool) noexcept;
void FinaliseBatch (uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
void HandleResize (uint32_t newWidth, uint32_t newHeight) noexcept;

View File

@ -6,6 +6,9 @@
#include "Graphics/Framebuffer/SHVkFramebuffer.h"
#include "SHRenderGraphResource.h"
#include "SHSubpass.h"
#include "SHRenderGraphStorage.h"
#include "Graphics/RenderGraph/SHRenderGraphNodeCompute.h"
#include "Graphics/SHVkUtil.h"
namespace SHADE
{
@ -21,7 +24,7 @@ namespace SHADE
/***************************************************************************/
void SHRenderGraphNode::CreateRenderpass(void) noexcept
{
renderpass = logicalDeviceHdl->CreateRenderpass(attachmentDescriptions, spDescs, spDeps);
renderpass = graphStorage->logicalDevice->CreateRenderpass(attachmentDescriptions, spDescs, spDeps);
}
/***************************************************************************/
@ -53,7 +56,7 @@ namespace SHADE
}
framebuffers[i] = logicalDeviceHdl->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight);
framebuffers[i] = graphStorage->logicalDevice->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight);
}
}
@ -79,9 +82,18 @@ namespace SHADE
fbHeight = attResources[j]->height;
}
framebuffers[i]->HandleResize(renderpass, imageViews, fbWidth, fbHeight);
}
for (auto& subpass : subpasses)
{
subpass->HandleResize();
}
for (auto& nodeCompute : nodeComputes)
{
nodeCompute->HandleResize();
}
}
/***************************************************************************/
@ -104,8 +116,8 @@ namespace SHADE
*/
/***************************************************************************/
SHRenderGraphNode::SHRenderGraphNode(std::shared_ptr<SHResourceHub> rm, Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, std::vector<SHAttachmentDescInitParams> attDescInitParams, std::vector<Handle<SHRenderGraphNode>> predecessors, std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* resources) noexcept
: logicalDeviceHdl{ logicalDevice }
SHRenderGraphNode::SHRenderGraphNode(Handle<SHRenderGraphStorage> renderGraphStorage, std::vector<SHAttachmentDescInitParams> attDescInitParams, std::vector<Handle<SHRenderGraphNode>> predecessors) noexcept
: graphStorage{ renderGraphStorage}
, renderpass{}
, framebuffers{}
, prereqNodes{ std::move(predecessors) }
@ -115,11 +127,10 @@ namespace SHADE
, subpasses{}
, executed{ false }
, configured{ false }
, resourceManager{ rm }
, ptrToResources{ resources }
, nodeComputes{}
{
// pipeline library initialization
pipelineLibrary.Init(logicalDeviceHdl);
pipelineLibrary.Init(graphStorage->logicalDevice);
// Store all the handles to resources
attResources.reserve (attDescInitParams.size());
@ -155,15 +166,14 @@ namespace SHADE
if (!containsSwapchainImage)
framebuffers.resize(1);
else
framebuffers.resize(swapchain->GetNumImages());
framebuffers.resize(graphStorage->swapchain->GetNumImages());
// At this point, we could configure framebuffers if we had the renderpass object but we don't so their creation has to be
// deferred to when renderpasses are also created.
}
SHRenderGraphNode::SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept
: resourceManager{ std::move (rhs.resourceManager) }
, logicalDeviceHdl{ rhs.logicalDeviceHdl }
: graphStorage{ rhs.graphStorage}
, renderpass{ rhs.renderpass }
, framebuffers{ std::move(rhs.framebuffers) }
, prereqNodes{ std::move(rhs.prereqNodes) }
@ -174,11 +184,11 @@ namespace SHADE
, subpassIndexing{ std::move(rhs.subpassIndexing) }
, configured{ rhs.configured }
, executed{ rhs.executed }
, ptrToResources{ rhs.ptrToResources }
, pipelineLibrary{ std::move(rhs.pipelineLibrary) }
, batcher{ std::move(rhs.batcher) }
, spDescs{ std::move(rhs.spDescs) }
, spDeps{ std::move(rhs.spDeps) }
, nodeComputes{ std::move(rhs.nodeComputes) }
{
rhs.renderpass = {};
@ -189,8 +199,7 @@ namespace SHADE
if (&rhs == this)
return *this;
resourceManager = std::move(rhs.resourceManager);
logicalDeviceHdl = rhs.logicalDeviceHdl;
graphStorage = rhs.graphStorage;
renderpass = rhs.renderpass;
framebuffers = std::move(rhs.framebuffers);
prereqNodes = std::move(rhs.prereqNodes);
@ -199,11 +208,11 @@ namespace SHADE
subpasses = std::move(rhs.subpasses);
resourceAttachmentMapping = std::move(rhs.resourceAttachmentMapping);
subpassIndexing = std::move(rhs.subpassIndexing);
ptrToResources = std::move(rhs.ptrToResources);
pipelineLibrary = std::move(rhs.pipelineLibrary);
batcher = std::move(rhs.batcher);
spDescs = std::move(rhs.spDescs);
spDeps = std::move(rhs.spDeps);
nodeComputes = std::move(rhs.nodeComputes);
rhs.renderpass = {};
@ -235,10 +244,10 @@ namespace SHADE
}
// Add subpass to container and create mapping for it
subpasses.emplace_back(resourceManager->Create<SHSubpass>(GetHandle(), subpasses.size(), &resourceAttachmentMapping, ptrToResources));
subpasses.emplace_back(graphStorage->resourceManager->Create<SHSubpass>(graphStorage, GetHandle(), static_cast<uint32_t>(subpasses.size()), &resourceAttachmentMapping));
subpassIndexing.try_emplace(subpassName, static_cast<uint32_t>(subpasses.size()) - 1u);
Handle<SHSubpass> subpass = subpasses.back();
subpass->Init(*resourceManager);
subpass->Init(*graphStorage->resourceManager);
// Register the SuperBatch
batcher.RegisterSuperBatch(subpass->GetSuperBatch());
@ -246,21 +255,84 @@ namespace SHADE
return subpass;
}
Handle<SHRenderGraphNodeCompute> SHRenderGraphNode::AddNodeCompute(Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, float numWorkGroupScale/* = 1.0f*/) noexcept
{
// Look for the required resources in the graph
std::vector<Handle<SHRenderGraphResource>> nodeComputeResources{};
nodeComputeResources.reserve(resources.size());
for (auto& resourceName : resources)
{
auto resource = graphStorage->graphResources->at(resourceName);
nodeComputeResources.push_back(resource);
}
// Create the subpass compute with the resources
auto nodeCompute = graphStorage->resourceManager->Create<SHRenderGraphNodeCompute>(graphStorage, computeShaderModule, std::move(nodeComputeResources));
nodeComputes.push_back(nodeCompute);
return nodeCompute;
}
/***************************************************************************/
/*!
\brief
This function checks all node computes and adds a subpass to transition
all needed resources to general.
*/
/***************************************************************************/
void SHRenderGraphNode::AddDummySubpassIfNeeded(void) noexcept
{
if (!nodeComputes.empty())
{
// we save the resource names involved
std::unordered_set<std::string> resourcesInvolved;
for (auto& compute : nodeComputes)
{
for (auto& resource : compute->resources)
{
resourcesInvolved.emplace(resource->GetName());
}
}
// insert them all for a subpass to transition them. This subpass is the last subpass
auto dummySubpass = AddSubpass("dummy");
for (auto& resource : resourcesInvolved)
{
dummySubpass->AddGeneralInput(resource);
if (SHVkUtil::IsDepthStencilAttachment(graphStorage->graphResources->at(resource)->GetResourceFormat()))
dummySubpass->AddGeneralDepthOutput(resource);
else
dummySubpass->AddGeneralColorOutput(resource);
}
}
}
void SHRenderGraphNode::Execute(Handle<SHVkCommandBuffer>& commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept
{
frameIndex = (framebuffers.size() > 1) ? frameIndex : 0;
commandBuffer->BeginRenderpass(renderpass, framebuffers[frameIndex]);
uint32_t framebufferIndex = (framebuffers.size() > 1) ? frameIndex : 0;
commandBuffer->BeginRenderpass(renderpass, framebuffers[framebufferIndex]);
for (uint32_t i = 0; i < subpasses.size(); ++i)
{
subpasses[i]->Execute(commandBuffer, descPool, frameIndex);
// Go to next subpass if not last subpass
if (i != subpasses.size() - 1)
if (i != static_cast<uint32_t>(subpasses.size()) - 1u)
commandBuffer->NextSubpass();
}
commandBuffer->EndRenderpass();
// Execute all subpass computes
for (auto& sbCompute : nodeComputes)
{
sbCompute->Execute(commandBuffer, frameIndex);
}
}
Handle<SHVkPipeline> SHRenderGraphNode::GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> subpass) noexcept
@ -273,10 +345,10 @@ namespace SHADE
}
Handle<SHVkPipeline> pipeline = pipelineLibrary.GetDrawPipline(vsFsPair);
Handle<SHVkPipeline> pipeline = pipelineLibrary.GetGraphicsPipeline(vsFsPair);
if (!pipeline)
{
pipeline = pipelineLibrary.CreateDrawPipeline
pipeline = pipelineLibrary.CreateGraphicsPipelines
(
vsFsPair,
renderpass,
@ -289,7 +361,7 @@ namespace SHADE
void SHRenderGraphNode::FinaliseBatch(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{
batcher.FinaliseBatches(logicalDeviceHdl, descPool, frameIndex);
batcher.FinaliseBatches(graphStorage->logicalDevice, descPool, frameIndex);
}
/***************************************************************************/

View File

@ -19,6 +19,9 @@ namespace SHADE
class SHVkLogicalDevice;
class SHVkRenderpass;
class SHVkDescriptorPool;
class SHGraphicsGlobalData;
class SHRenderGraphStorage;
class SHRenderGraphNodeCompute;
class SH_API SHRenderGraphNode : public ISelfHandle<SHRenderGraphNode>
{
@ -26,10 +29,9 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/
std::shared_ptr<SHResourceHub> resourceManager;
//! For Vulkan object creation
Handle<SHVkLogicalDevice> logicalDeviceHdl;
//Handle<SHVkLogicalDevice> logicalDeviceHdl;
Handle<SHRenderGraphStorage> graphStorage;
//! Each node will have a renderpass and each renderpass will have its own subpasses.
//! These subpasses will execute sequentially.
@ -63,12 +65,13 @@ namespace SHADE
//! For indexing subpasses
std::map<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;
//! Sometimes we want the subpass to do something to the images instead
//! of drawing objects on the image (i.e. compute).
std::vector<Handle<SHRenderGraphNodeCompute>> nodeComputes;
//! Whether or not the node has finished execution
bool executed;
@ -77,6 +80,7 @@ namespace SHADE
SHBatcher batcher;
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
@ -88,7 +92,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
/* CTORS AND DTORS */
/*-----------------------------------------------------------------------*/
SHRenderGraphNode(std::shared_ptr<SHResourceHub> rm, Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, std::vector<SHAttachmentDescInitParams> attDescInitParams, std::vector<Handle<SHRenderGraphNode>> predecessors, std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* resources) noexcept;
SHRenderGraphNode(Handle<SHRenderGraphStorage> renderGraphStorage, std::vector<SHAttachmentDescInitParams> attDescInitParams, std::vector<Handle<SHRenderGraphNode>> predecessors) noexcept;
SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept;
SHRenderGraphNode& operator= (SHRenderGraphNode&& rhs) noexcept;
@ -96,6 +100,9 @@ namespace SHADE
/* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
Handle<SHSubpass> AddSubpass(std::string subpassName) noexcept;
Handle<SHRenderGraphNodeCompute> AddNodeCompute(Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, float numWorkGroupScale = 1.0f) noexcept;
void AddDummySubpassIfNeeded (void) 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;

View File

@ -0,0 +1,109 @@
#include "SHpch.h"
#include "SHRenderGraphNodeCompute.h"
#include "Graphics/Pipeline/SHVkPipeline.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "Graphics/Descriptors/SHVkDescriptorPool.h"
#include "Graphics/Descriptors/SHVkDescriptorSetLayout.h"
#include "Graphics/Devices/SHVkLogicalDevice.h"
#include "Graphics/Pipeline/SHVkPipelineLayout.h"
#include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h"
#include "SHRenderGraphStorage.h"
#include "SHRenderGraphResource.h"
#include "Graphics/Commands/SHVkCommandBuffer.h"
namespace SHADE
{
SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(Handle<SHRenderGraphStorage> graphStorage, Handle<SHVkShaderModule> computeShaderModule, std::vector<Handle<SHRenderGraphResource>>&& subpassComputeResources, float inNumWorkGroupScale/* = 1.0f*/) noexcept
: computePipeline{}
, pipelineLayout{}
, resources{}
, groupSizeX{0}
, groupSizeY{0}
, numWorkGroupScale {std::clamp(inNumWorkGroupScale, 0.0f, 1.0f)}
{
SHPipelineLayoutParams pipelineLayoutParams
{
.shaderModules = {computeShaderModule},
.globalDescSetLayouts = SHGraphicsGlobalData::GetDescSetLayouts()
};
// Create pipeline layout from parameters
pipelineLayout = graphStorage->logicalDevice->CreatePipelineLayout (pipelineLayoutParams);
// Create the compute pipeline
computePipeline = graphStorage->logicalDevice->CreateComputePipeline(pipelineLayout);
// and construct it
computePipeline->ConstructPipeline();
// save the resources
resources = std::move (subpassComputeResources);
//Get the descriptor set layouts required to allocate. We only want the ones for allocate because
//global descriptors are already bound in the main system.
auto const& layouts = computePipeline->GetPipelineLayout()->GetDescriptorSetLayoutsAllocate();
//Variable counts for the descriptor sets (all should be 1).
std::vector<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)
for (uint32_t i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
{
descSetGroups[i] = graphStorage->descriptorPool->Allocate(layouts, variableCounts);
}
HandleResize();
}
void SHRenderGraphNodeCompute::Execute(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
{
// bind the compute pipeline
cmdBuffer->BindPipeline(computePipeline);
// bind descriptor sets
cmdBuffer->BindDescriptorSet(descSetGroups[frameIndex], SH_PIPELINE_TYPE::COMPUTE, SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, {});
// dispatch compute
cmdBuffer->ComputeDispatch(groupSizeX, groupSizeY, 1);
// TODO: barrier
}
void SHRenderGraphNodeCompute::HandleResize(void) noexcept
{
// Get the layout for the render graph resource. We can index it this way because the container returned is a container of layouts that includes the global ones
auto pipelineDescSetLayouts = computePipeline->GetPipelineLayout()->GetDescriptorSetLayoutsPipeline()[SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE];
// everything below here needs resizing
for (uint32_t frameIndex = 0; frameIndex < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++frameIndex)
{
uint32_t i = 0;
// loop through bindings and write descriptor sets
for (auto& binding : pipelineDescSetLayouts->GetBindings())
{
uint32_t imageIndex = (resources[i]->resourceTypeFlags & static_cast<uint32_t>(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)) ? frameIndex : 0;
SHVkDescriptorSetGroup::viewSamplerLayout vsl = std::make_tuple(resources[i]->GetImageView(imageIndex), Handle<SHVkSampler>{}, vk::ImageLayout::eGeneral);
descSetGroups[frameIndex]->ModifyWriteDescImage(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint, { &vsl, 1 });
descSetGroups[frameIndex]->UpdateDescriptorSetImages(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint);
++i;
}
}
// Get the group size from the max width and height
uint32_t maxWidth = 0, maxHeight = 0;
for (auto& resource : resources)
{
maxWidth = std::max(resource->GetWidth(), maxWidth);
maxHeight = std::max(resource->GetHeight(), maxHeight);
}
groupSizeX = maxWidth / workGroupSizeX;
groupSizeY = maxHeight / workGroupSizeY;
}
}

View File

@ -0,0 +1,57 @@
#pragma once
#include "Resource/SHHandle.h"
#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
#include <initializer_list>
#include <string>
#include <unordered_set>
namespace SHADE
{
class SHVkPipeline;
class SHVkDescriptorSetGroup;
class SHVkDescriptorPool;
class SHVkLogicalDevice;
class SHVkPipelineLayout;
class SHRenderGraphStorage;
class SHRenderGraphResource;
class SHVkShaderModule;
class SHVkCommandBuffer;
class SHRenderGraphNodeCompute
{
private:
static constexpr uint32_t workGroupSizeX = 16;
static constexpr uint32_t workGroupSizeY = 16;
//! To run the dispatch command
Handle<SHVkPipeline> computePipeline;
//! Pipeline layout for the pipeline creation
Handle<SHVkPipelineLayout> pipelineLayout;
//! Descriptor set group to hold the images for reading (STORAGE_IMAGE)
std::array<Handle<SHVkDescriptorSetGroup>, SHGraphicsConstants::NUM_FRAME_BUFFERS> descSetGroups;
//! vector of resources needed by the subpass compute
std::vector<Handle<SHRenderGraphResource>> resources;
//! X dimension work group size. Should scale with resource size.
uint32_t groupSizeX;
//! Y dimension work group size
uint32_t groupSizeY;
float numWorkGroupScale;
public:
SHRenderGraphNodeCompute(Handle<SHRenderGraphStorage> graphStorage, Handle<SHVkShaderModule> computeShaderModule, std::vector<Handle<SHRenderGraphResource>>&& subpassComputeResources, float inNumWorkGroupScale = 1.0f) noexcept;
void Execute (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
void HandleResize (void) noexcept;
friend class SHRenderGraph;
friend class SHRenderGraphNode;
};
}

View File

@ -5,6 +5,7 @@
#include "Graphics/Images/SHVkImageView.h"
#include "Graphics/Buffers/SHVkBuffer.h"
#include "Graphics/SHVkUtil.h"
#include "SHRenderGraphStorage.h"
namespace SHADE
{
@ -45,9 +46,8 @@ namespace SHADE
*/
/***************************************************************************/
SHRenderGraphResource::SHRenderGraphResource(Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, std::string const& name, std::initializer_list<SH_ATT_DESC_TYPE_FLAGS> typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept
: logicalDevice {logicalDevice}
, swapchain{ swapchain }
SHRenderGraphResource::SHRenderGraphResource(Handle<SHRenderGraphStorage> renderGraphStorage, std::string const& name, std::initializer_list<SH_ATT_DESC_TYPE_FLAGS> typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept
: graphStorage{renderGraphStorage}
, resourceTypeFlags{ }
, resourceFormat{ format }
, images{}
@ -66,7 +66,7 @@ namespace SHADE
SHImageViewDetails viewDetails
{
.viewType = vk::ImageViewType::e2D,
.format = swapchain->GetSurfaceFormatKHR().format,
.format = graphStorage->swapchain->GetSurfaceFormatKHR().format,
.imageAspectFlags = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.mipLevelCount = 1,
@ -75,13 +75,13 @@ namespace SHADE
};
// We want an image handle for every swapchain image
images.resize(swapchain->GetNumImages());
imageViews.resize(swapchain->GetNumImages());
images.resize(graphStorage->swapchain->GetNumImages());
imageViews.resize(graphStorage->swapchain->GetNumImages());
for (uint32_t i = 0; i < swapchain->GetNumImages(); ++i)
for (uint32_t i = 0; i < graphStorage->swapchain->GetNumImages(); ++i)
{
images[i] = swapchain->GetSwapchainImage(i);
imageViews[i] = images[i]->CreateImageView(logicalDevice, images[i], viewDetails);
images[i] = graphStorage->swapchain->GetSwapchainImage(i);
imageViews[i] = images[i]->CreateImageView(graphStorage->logicalDevice, images[i], viewDetails);
}
}
else // if swapchain image resource
@ -117,6 +117,9 @@ namespace SHADE
usage |= vk::ImageUsageFlagBits::eInputAttachment;
usage |= vk::ImageUsageFlagBits::eSampled;
break;
case SH_ATT_DESC_TYPE_FLAGS::STORAGE:
usage |= vk::ImageUsageFlagBits::eStorage;
break;
case SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT:
{
SHLOG_ERROR ("COLOR_PRESENT cannot be with other resource type flags. ");
@ -126,7 +129,7 @@ namespace SHADE
}
// The resource is not a swapchain image, just use the first slot of the vector
images.push_back(logicalDevice->CreateImage(width, height, mipLevels, resourceFormat, usage, createFlags));
images.push_back(graphStorage->logicalDevice->CreateImage(width, height, mipLevels, resourceFormat, usage, createFlags));
// prepare image view details
SHImageViewDetails viewDetails
@ -141,7 +144,7 @@ namespace SHADE
};
// just 1 image view created
imageViews.push_back(images[0]->CreateImageView(logicalDevice, images[0], viewDetails));
imageViews.push_back(images[0]->CreateImageView(graphStorage->logicalDevice, images[0], viewDetails));
}
}
@ -166,7 +169,7 @@ namespace SHADE
, height{ rhs.height }
, mipLevels{ rhs.mipLevels }
, imageAspectFlags{ rhs.imageAspectFlags }
, swapchain {rhs.swapchain}
, graphStorage{rhs.graphStorage}
{
}
@ -198,7 +201,7 @@ namespace SHADE
height = rhs.height;
mipLevels = rhs.mipLevels;
imageAspectFlags = rhs.imageAspectFlags;
swapchain = rhs.swapchain;
graphStorage = rhs.graphStorage;
return *this;
}
@ -247,7 +250,7 @@ namespace SHADE
SHImageViewDetails viewDetails
{
.viewType = vk::ImageViewType::e2D,
.format = swapchain->GetSurfaceFormatKHR().format,
.format = graphStorage->swapchain->GetSurfaceFormatKHR().format,
.imageAspectFlags = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.mipLevelCount = 1,
@ -255,9 +258,9 @@ namespace SHADE
.layerCount = 1,
};
for (uint32_t i = 0; i < swapchain->GetNumImages(); ++i)
for (uint32_t i = 0; i < graphStorage->swapchain->GetNumImages(); ++i)
{
images[i] = swapchain->GetSwapchainImage(i);
images[i] = graphStorage->swapchain->GetSwapchainImage(i);
imageViews[i]->ViewNewImage(images[i], viewDetails);
}
}
@ -308,6 +311,7 @@ namespace SHADE
return resourceFormat;
}
uint32_t SHRenderGraphResource::GetWidth(void) const noexcept
{
return width;
@ -323,4 +327,19 @@ namespace SHADE
return imageViews [index];
}
Handle<SHVkImage> SHRenderGraphResource::GetImage(uint32_t index /*= NON_SWAPCHAIN_RESOURCE_INDEX*/) const noexcept
{
return images[index];
}
uint8_t SHRenderGraphResource::GetMipLevels(void) const noexcept
{
return mipLevels;
}
std::string SHRenderGraphResource::GetName(void) const noexcept
{
return resourceName;
}
}

View File

@ -15,6 +15,7 @@ namespace SHADE
class SHVkSwapchain;
class SHVkCommandBuffer;
class SHVkBuffer;
class SHRenderGraphStorage;
static constexpr uint32_t NON_SWAPCHAIN_RESOURCE_INDEX = 0;
@ -24,11 +25,8 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/
// for creation/recreation
Handle<SHVkLogicalDevice> logicalDevice;
// for creation/recreation
Handle<SHVkSwapchain> swapchain;
//! Storage from the render graph
Handle<SHRenderGraphStorage> graphStorage;
//! Name of the resource
std::string resourceName;
@ -69,7 +67,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
/* CTORS AND DTORS */
/*-----------------------------------------------------------------------*/
SHRenderGraphResource(Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, std::string const& name, std::initializer_list<SH_ATT_DESC_TYPE_FLAGS> typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept;
SHRenderGraphResource(Handle<SHRenderGraphStorage> renderGraphStorage, std::string const& name, std::initializer_list<SH_ATT_DESC_TYPE_FLAGS> typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept;
SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept;
SHRenderGraphResource& operator=(SHRenderGraphResource&& rhs) noexcept;
~SHRenderGraphResource(void) noexcept;
@ -88,8 +86,13 @@ namespace SHADE
uint32_t GetWidth (void) const noexcept;
uint32_t GetHeight (void) const noexcept;
Handle<SHVkImageView> GetImageView (uint32_t index = NON_SWAPCHAIN_RESOURCE_INDEX) const noexcept;
Handle<SHVkImage> GetImage (uint32_t index = NON_SWAPCHAIN_RESOURCE_INDEX) const noexcept;
uint8_t GetMipLevels (void) const noexcept;
std::string GetName (void) const noexcept;
friend class SHRenderGraphNode;
friend class SHRenderGraph;
friend class SHSubpass;
friend class SHRenderGraphNodeCompute;
};
}

View File

@ -0,0 +1,43 @@
#pragma once
#include "Resource/SHHandle.h"
#include <memory>
namespace SHADE
{
class SHVkLogicalDevice;
class SHVkSwapchain;
class SHGraphicsGlobalData;
class SHVkDescriptorPool;
class SHRenderGraphResource;
class SHRenderGraphStorage
{
//! Logical device for creation of vulkan objects
Handle<SHVkLogicalDevice> logicalDevice;
//! swapchain handle
Handle<SHVkSwapchain> swapchain;
//! Resource manager for creation of objects
std::shared_ptr<SHResourceHub> resourceManager;
//! Descriptor pool for the descriptor sets to be created in the subpasses
Handle<SHVkDescriptorPool> descriptorPool;
//! For accessing resources anywhere in the graph
Handle<std::unordered_map<std::string, Handle<SHRenderGraphResource>>> graphResources;
//SHRenderGraphStorage(void) noexcept;
//SHRenderGraphStorage(SHRenderGraphStorage&& rhs) noexcept;
//SHRenderGraphStorage& operator=(SHRenderGraphStorage&& rhs) noexcept;
friend class SHRenderGraph;
friend class SHRenderGraphNode;
friend class SHSubpass;
friend class SHRenderGraphResource;
friend class SHRenderGraphNodeCompute;
};
}

View File

@ -4,6 +4,13 @@
#include "Graphics/Devices/SHVkLogicalDevice.h"
#include "SHRenderGraphNode.h"
#include "SHRenderGraphResource.h"
#include "Graphics/Shaders/SHVkShaderModule.h"
#include "SHRenderGraphNode.h"
#include "SHRenderGraphStorage.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "Graphics/Swapchain/SHVkSwapchain.h"
#include "Graphics/Images/SHVkSampler.h"
#include "SHRenderGraphResource.h"
namespace SHADE
{
@ -23,15 +30,16 @@ namespace SHADE
*/
/***************************************************************************/
SHSubpass::SHSubpass(Handle<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
SHSubpass::SHSubpass(Handle<SHRenderGraphStorage> renderGraphStorage, Handle<SHRenderGraphNode> const& parent, uint32_t index, std::unordered_map<uint64_t, uint32_t> const* mapping) noexcept
: resourceAttachmentMapping{ mapping }
, ptrToResources{ resources }
, parentNode{ parent }
, subpassIndex{ index }
, superBatch{}
, colorReferences{}
, depthReferences{}
, inputReferences{}
, graphStorage{ renderGraphStorage }
, inputImageDescriptors {SHGraphicsConstants::NUM_FRAME_BUFFERS}
{
}
@ -54,9 +62,14 @@ namespace SHADE
, depthReferences{ std::move(rhs.depthReferences) }
, inputReferences{ std::move(rhs.inputReferences) }
, resourceAttachmentMapping{ rhs.resourceAttachmentMapping }
, ptrToResources{ rhs.ptrToResources }
, descriptorSetLayout{ rhs.descriptorSetLayout }
, exteriorDrawCalls{ std::move(rhs.exteriorDrawCalls) }
, graphStorage{ rhs.graphStorage }
, inputNames{ std::move(rhs.inputNames) }
, inputImageDescriptors{ std::move(rhs.inputImageDescriptors) }
, inputDescriptorLayout{ rhs.inputDescriptorLayout }
, inputSamplers{ rhs.inputSamplers }
{
}
@ -84,9 +97,13 @@ namespace SHADE
depthReferences = std::move(rhs.depthReferences);
inputReferences = std::move(rhs.inputReferences);
resourceAttachmentMapping = rhs.resourceAttachmentMapping;
ptrToResources = rhs.ptrToResources;
descriptorSetLayout = rhs.descriptorSetLayout;
exteriorDrawCalls = std::move(rhs.exteriorDrawCalls);
graphStorage = rhs.graphStorage;
inputNames = std::move(rhs.inputNames);
inputImageDescriptors = std::move(rhs.inputImageDescriptors);
inputDescriptorLayout = rhs.inputDescriptorLayout;
inputSamplers = rhs.inputSamplers;
return *this;
}
@ -105,7 +122,12 @@ namespace SHADE
/***************************************************************************/
void SHSubpass::AddColorOutput(std::string resourceToReference) noexcept
{
colorReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eColorAttachmentOptimal });
colorReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eColorAttachmentOptimal });
}
void SHSubpass::AddGeneralColorOutput(std::string resourceToReference) noexcept
{
colorReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eGeneral });
}
/***************************************************************************/
@ -142,7 +164,13 @@ namespace SHADE
//Invalid
return;
}
depthReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), imageLayout });
depthReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), imageLayout });
}
void SHSubpass::AddGeneralDepthOutput(std::string resourceToReference) noexcept
{
depthReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eGeneral });
}
/***************************************************************************/
@ -159,7 +187,14 @@ namespace SHADE
/***************************************************************************/
void SHSubpass::AddInput(std::string resourceToReference) noexcept
{
inputReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eShaderReadOnlyOptimal });
inputReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eShaderReadOnlyOptimal });
inputNames.push_back(resourceToReference);
}
void SHSubpass::AddGeneralInput(std::string resourceToReference) noexcept
{
inputReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eGeneral });
}
void SHSubpass::Execute(Handle<SHVkCommandBuffer>& commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept
@ -175,6 +210,12 @@ namespace SHADE
{
drawCall(commandBuffer);
}
}
void SHSubpass::HandleResize(void) noexcept
{
UpdateWriteDescriptors();
}
void SHSubpass::AddExteriorDrawCalls(std::function<void(Handle<SHVkCommandBuffer>&)> const& newDrawCall) noexcept
@ -188,6 +229,152 @@ namespace SHADE
}
void SHSubpass::CreateInputDescriptors(void) noexcept
{
if (inputNames.empty())
return;
std::vector<SHVkDescriptorSetLayout::Binding> bindings{};
for (auto& input : inputReferences)
{
SHVkDescriptorSetLayout::Binding newBinding
{
.Type = (input.layout == vk::ImageLayout::eShaderReadOnlyOptimal) ? vk::DescriptorType::eInputAttachment : vk::DescriptorType::eStorageImage,
.Stage = vk::ShaderStageFlagBits::eFragment,
.BindPoint = static_cast<uint32_t>(bindings.size()),
.DescriptorCount = 1,
.flags = {},
};
bindings.push_back(newBinding);
}
// We build a new descriptor set layout to store our images
inputDescriptorLayout = graphStorage->logicalDevice->CreateDescriptorSetLayout(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, bindings);
// we store a sampler if its an input attachment. if it is storage image, no need sampler, store an empty handle.
for (uint32_t i = 0; i < bindings.size(); ++i)
{
if (bindings[i].Type == vk::DescriptorType::eInputAttachment)
{
auto newSampler = graphStorage->logicalDevice->CreateSampler(SHVkSamplerParams
{
.minFilter = vk::Filter::eLinear,
.magFilter = vk::Filter::eLinear,
.addressMode = vk::SamplerAddressMode::eRepeat,
.mipmapMode = vk::SamplerMipmapMode::eLinear,
.minLod = -1000,
.maxLod = 1000
}
);
inputSamplers.push_back(newSampler);
}
else
{
inputSamplers.push_back({});
}
}
//// maybe do this in handle resize?
//UpdateWriteDescriptors();
}
void SHSubpass::UpdateWriteDescriptors(void) noexcept
{
if (inputNames.empty())
return;
auto const& bindings = inputDescriptorLayout->GetBindings();
std::vector<uint32_t> variableCounts{ static_cast<uint32_t>(bindings.size()) };
std::fill (variableCounts.begin(), variableCounts.end(), 0u);
// For every frame's descriptor set
for (auto& group : inputImageDescriptors)
{
if (group)
group.Free();
group = graphStorage->descriptorPool->Allocate({ inputDescriptorLayout }, variableCounts);
uint32_t i = 0;
for (auto& binding : bindings)
{
// get the resource
auto resource = graphStorage->graphResources->at(inputNames[binding.BindPoint]);
// If resource is swapchain image, get the correct image, if not just get 0.
uint32_t viewIndex = (resource->resourceTypeFlags & static_cast<uint32_t>(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)) ? i : 0;
// layout is GENERAL if image is meant to be used as storage image, if not use SHADER_READ_ONLY_OPTINAL
vk::ImageLayout descriptorLayout = (binding.Type == vk::DescriptorType::eStorageImage) ? vk::ImageLayout::eGeneral : vk::ImageLayout::eShaderReadOnlyOptimal;
// Update descriptor sets
auto args = std::make_tuple(resource->GetImageView(viewIndex), inputSamplers[i], descriptorLayout);
group->ModifyWriteDescImage(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint, std::span{&args, 1});
group->UpdateDescriptorSetImages(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint);
}
++i;
}
}
//void SHSubpass::InitComputeBarriers(void) noexcept
//{
// std::unordered_set <uint64_t> handleBarriers{};
// // we will have swapchainNumImages vectors of vector of barriers
// subpassComputeBarriers.resize(graphStorage->swapchain->GetNumImages());
// for (auto sbCompute : subpassComputes)
// {
// // for every resource the subpass compute is using
// for (auto resource : sbCompute->resources)
// {
// // Get the resource handle
// uint64_t resourceRaw = resource.GetId().Raw;
// // if the barrier is not registered
// if (!handleBarriers.contains(resourceRaw))
// {
// // If the resource is a swapchain image
// bool isSwapchainImage = (resource->resourceTypeFlags & static_cast<uint32_t>(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT));
// for (uint32_t i = 0; i < graphStorage->swapchain->GetNumImages(); ++i)
// {
// // if swapchain image, we want the index of the swapchain image, if not take base image
// uint32_t imageIndex = isSwapchainImage ? i : 0;
// // Prepare image barrier
// vk::ImageMemoryBarrier imageBarrier
// {
// .oldLayout = colorReferences[resourceAttachmentMapping->at(resource.GetId().Raw)].layout,
// .newLayout = vk::ImageLayout::eGeneral,
// .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
// .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
// .image = resource->GetImage(imageIndex)->GetVkImage(),
// .subresourceRange =
// {
// .aspectMask = resource->imageAspectFlags,
// .levelCount = resource->GetMipLevels(),
// .baseArrayLayer = 0,
// .layerCount = 1
// }
// };
// // push the barrier
// subpassComputeBarriers[i].push_back(imageBarrier);
// }
// // Image transition registered
// handleBarriers.emplace(resourceRaw);
// }
// }
// }
//}
/***************************************************************************/
/*!

View File

@ -14,7 +14,11 @@ namespace SHADE
class SHRenderGraphResource;
class SHVkCommandBuffer;
class SHVkDescriptorSetLayout;
class SHVkDescriptorSetGroup;
class SHVkDescriptorPool;
class SHRenderGraphStorage;
class SHVkShaderModule;
class SHVkSampler;
class SH_API SHSubpass : public ISelfHandle<SHSubpass>
{
@ -22,6 +26,8 @@ namespace SHADE
/*---------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */
/*---------------------------------------------------------------------*/
Handle<SHRenderGraphStorage> graphStorage;
//! The index of the subpass in the render graph
uint32_t subpassIndex;
@ -43,11 +49,26 @@ namespace SHADE
//! Input attachments
std::vector<vk::AttachmentReference> inputReferences;
//! This is mainly for when we want to retrieve resources using names.
std::vector<std::string> inputNames;
//! 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;
//! Descriptor set group to hold the images for input
std::vector<Handle<SHVkDescriptorSetGroup>> inputImageDescriptors;
//! Descriptor set layout for allocating descriptor set for inputs
Handle<SHVkDescriptorSetLayout> inputDescriptorLayout;
std::vector<Handle<SHVkSampler>> inputSamplers;
////! subpass compute image barriers. We do this because every frame has a different
////! swapchain image. If the resource we want to transition is not a swapchain image,
////! we duplicate the barrier anyway, not much memory wasted. ;)
//std::vector<std::vector<vk::ImageMemoryBarrier>> subpassComputeBarriers{};
//! Sometimes there exists entities that we want to render onto a render target
//! but don't want it to come from the batching system. An example would be ImGUI.
@ -62,7 +83,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
/* CTORS AND DTORS */
/*-----------------------------------------------------------------------*/
SHSubpass(Handle<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(Handle<SHRenderGraphStorage> renderGraphStorage, Handle<SHRenderGraphNode> const& parent, uint32_t index, std::unordered_map<uint64_t, uint32_t> const* mapping) noexcept;
SHSubpass(SHSubpass&& rhs) noexcept;
SHSubpass& operator=(SHSubpass&& rhs) noexcept;
@ -71,15 +92,23 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
// Preparation functions
void AddColorOutput(std::string resourceToReference) noexcept;
void AddGeneralColorOutput(std::string resourceToReference) noexcept;
void AddDepthOutput(std::string resourceToReference, SH_ATT_DESC_TYPE_FLAGS attachmentDescriptionType = SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL) noexcept;
void AddGeneralDepthOutput(std::string resourceToReference) noexcept;
void AddInput(std::string resourceToReference) noexcept;
void AddGeneralInput (std::string resourceToReference) noexcept;
void AddExteriorDrawCalls(std::function<void(Handle<SHVkCommandBuffer>&)> const& newDrawCall) 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 HandleResize (void) noexcept;
void Init(SHResourceHub& resourceManager) noexcept;
//void InitComputeBarriers (void) noexcept;
void CreateInputDescriptors (void) noexcept;
void UpdateWriteDescriptors (void) noexcept;
/*-----------------------------------------------------------------------*/
/* GETTERS AND SETTERS */
/*-----------------------------------------------------------------------*/
@ -91,5 +120,6 @@ namespace SHADE
friend class SHRenderGraphNode;
friend class SHRenderGraph;
friend class SHSubpass;
};
}

View File

@ -1,23 +0,0 @@
#include "SHpch.h"
#include "SHSubpassCompute.h"
#include "Graphics/Pipeline/SHVkPipeline.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "Graphics/Descriptors/SHVkDescriptorPool.h"
namespace SHADE
{
SHSubpassCompute::SHSubpassCompute(Handle<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

@ -1,25 +0,0 @@
#pragma once
#include <Resource/SHHandle.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

@ -55,6 +55,21 @@ namespace SHADE
return 0;
}
vk::PipelineBindPoint SHVkUtil::GetPipelineBindPointFromType(SH_PIPELINE_TYPE pipelineType) noexcept
{
switch (pipelineType)
{
case SH_PIPELINE_TYPE::GRAPHICS:
return vk::PipelineBindPoint::eGraphics;
case SH_PIPELINE_TYPE::COMPUTE:
return vk::PipelineBindPoint::eCompute;
case SH_PIPELINE_TYPE::RAY_TRACING:
return vk::PipelineBindPoint::eRayTracingKHR;
default:
return vk::PipelineBindPoint::eGraphics;
}
}
void SHVkUtil::EnsureBufferAndCopyData(Handle<SHVkLogicalDevice> device, Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHVkBuffer>& bufferHandle, void* src, uint32_t size, vk::BufferUsageFlagBits usage)
{
if (bufferHandle)

View File

@ -4,6 +4,7 @@
#include "SHVulkanIncludes.h"
#include "Resource/SHHandle.h"
#include "Graphics/Pipeline/SHPipelineType.h"
namespace SHADE
{
@ -24,6 +25,7 @@ namespace SHADE
static bool IsDepthStencilAttachment (vk::Format format) noexcept;
static bool IsBlendCompatible (vk::Format format) noexcept;
static uint32_t GetBytesPerPixelFromFormat (vk::Format format) noexcept;
static vk::PipelineBindPoint GetPipelineBindPointFromType (SH_PIPELINE_TYPE pipelineType) noexcept;
/***********************************************************************************/
/*!

View File

@ -177,6 +177,9 @@ namespace SHADE
return vk::DescriptorType::eStorageBufferDynamic;
case SpvReflectDescriptorType::SPV_REFLECT_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
return vk::DescriptorType::eInputAttachment;
case SpvReflectDescriptorType::SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE:
return vk::DescriptorType::eStorageImage;
break;
default:
return vk::DescriptorType::eCombinedImageSampler;
break;

View File

@ -0,0 +1,167 @@
//#version 450
//
//layout(local_size_x = 16, local_size_y = 16) in;
//layout(set = 4, binding = 0, rgba8) uniform image2D targetImage;
//
//
//void main()
//{
// ivec2 imageSize = imageSize (targetImage);
//
// if (gl_GlobalInvocationID.x >= imageSize.x && gl_GlobalInvocationID.y >= imageSize.y)
// return;
//
// // load the image
// vec4 color = imageLoad (targetImage, ivec2 (gl_GlobalInvocationID));
//
// // get the average
// float average = 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b;
//
// // store result into result image
// imageStore(targetImage, ivec2(gl_GlobalInvocationID), vec4(average, average, average, 1.0f));
//
//}
//
//
//
//
/* Start Header *****************************************************************/
/*! \file (e.g. kirsch.comp)
\author William Zheng, william.zheng, 60001906. Brandon Mak, brandon.hao 390003920.
\par william.zheng\@digipen.edu. brandon.hao\@digipen.edu.
\date Sept 20, 2022
\brief Copyright (C) 20xx DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent of DigiPen Institute of Technology is prohibited. */
/* End Header *******************************************************************/
#version 450
#define MASK_WIDTH 3
#define HALF_M_WIDTH MASK_WIDTH / 2
#define SHM_WIDTH 18
#define NUM_MASKS 8
layout(local_size_x = 16, local_size_y = 16) in;
layout(set = 4, binding = 0, rgba8) uniform image2D inputImage;
layout(set = 4, binding = 1, rgba8) uniform image2D resultImage;
const float kirsch[8][3][3] = {
{
{5, 5, 5},
{-3, 0, -3}, /*rotation 1 */
{-3, -3, -3}
},
{
{5, 5, -3},
{5, 0, -3}, /*rotation 2 */
{-3, -3, -3}
},
{
{5, -3, -3},
{5, 0, -3}, /*rotation 3 */
{5, -3, -3}
},
{
{-3, -3, -3},
{5, 0, -3}, /*rotation 4 */
{5, 5, -3}
},
{
{-3, -3, -3},
{-3, 0, -3}, /*rotation 5 */
{5, 5, 5}
},
{
{-3, -3, -3},
{-3, 0, 5}, /*rotation 6 */
{-3, 5, 5}
},
{
{-3, -3, 5},
{-3, 0, 5}, /*rotation 7 */
{-3, -3, 5}
},
{
{-3, 5, 5},
{-3, 0, 5}, /*rotation 8 */
{-3, -3, -3}
}
};
vec3 GetImageValues(ivec2 uv, ivec2 inputImageSize)
{
if (uv.x >= 0 && uv.y >= 0 && uv.x < inputImageSize.x && uv.y < inputImageSize.y)
{
return imageLoad(inputImage, uv).rgb;
}
else
return vec3(0.0f);
}
//two extra row/col
shared vec3 sData[16 + 2][16 + 2];
void main()
{
// convenient variables
ivec3 globalThread = ivec3(gl_GlobalInvocationID);
ivec3 localThread = ivec3(gl_LocalInvocationID);
ivec2 inputImageSize = imageSize(inputImage);
// load shared memory
ivec2 start = ivec2(gl_WorkGroupID) * ivec2(gl_WorkGroupSize) - ivec2(HALF_M_WIDTH);
for (int i = localThread.x; i < SHM_WIDTH; i += int(gl_WorkGroupSize.x))
{
for (int j = localThread.y; j < SHM_WIDTH; j += int(gl_WorkGroupSize.y))
{
// get from source image (either real values or 0)
vec3 sourceValue = GetImageValues(start + ivec2(i, j), inputImageSize);
sData[i][j] = sourceValue;
}
}
// wait for shared memory to finish loading
barrier();
// max (between all 8 masks)
vec3 maxSum = vec3(0.0f);
// loop through all masks
for (int i = 0; i < NUM_MASKS; ++i)
{
vec3 sum = vec3(0.0f);
// start of shared memory
ivec2 shmStart = ivec2(localThread + HALF_M_WIDTH);
for (int j = -1; j < HALF_M_WIDTH + 1; ++j)
{
for (int k = -1; k < HALF_M_WIDTH + 1; ++k)
{
// Perform convolution using shared_memory
sum += sData[shmStart.x + j][shmStart.y + k] * kirsch[i][j + 1][k + 1];
}
}
// Get highest sum
maxSum = max(sum, maxSum);
}
// average the max sum
maxSum = min(max(maxSum / 8, 0), 1.0f);
// store result into result image
imageStore(resultImage, ivec2(gl_GlobalInvocationID.xy), vec4(maxSum, 1.0f));
}

Binary file not shown.