diff --git a/SHADE_Engine/src/Camera/SHCameraSystem.cpp b/SHADE_Engine/src/Camera/SHCameraSystem.cpp index 9c97131a..c9822b82 100644 --- a/SHADE_Engine/src/Camera/SHCameraSystem.cpp +++ b/SHADE_Engine/src/Camera/SHCameraSystem.cpp @@ -62,6 +62,7 @@ namespace SHADE system->editorCamera.position -= UP * dt * camera.movementSpeed; system->editorCamera.dirtyView = true; } + system->UpdateCameraComponent(system->editorCamera); } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h index 67cbc001..a0457b65 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h @@ -63,6 +63,14 @@ namespace SHADE */ /***************************************************************************/ static constexpr uint32_t PER_INSTANCE = 3; + /***************************************************************************/ + /*! + \brief + DescriptorSet Index for render graph resources. + */ + /***************************************************************************/ + static constexpr uint32_t RENDERGRAPH_RESOURCE = 4; + }; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index 06762db8..386cef54 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -115,6 +115,23 @@ namespace SHADE graphicsCmdPool = device->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS, SH_CMD_POOL_RESET::POOL_BASED, true); transferCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY); graphicsTexCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY); + + + // TODO: This is VERY temporarily here until a more solid resource management system is implemented + shaderSourceLibrary.Init("../../TempShaderFolder/"); + + shaderSourceLibrary.LoadShader(0, "TestCubeVs.glsl", SH_SHADER_TYPE::VERTEX, true); + shaderSourceLibrary.LoadShader(1, "TestCubeFs.glsl", SH_SHADER_TYPE::FRAGMENT, true); + + shaderSourceLibrary.LoadShader(2, "GreyscaleCs.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("GreyscaleCs.glsl"); + cubeVS->Reflect(); + cubeFS->Reflect(); + greyscale->Reflect(); } void SHGraphicsSystem::InitSceneRenderGraph(void) noexcept @@ -166,6 +183,13 @@ namespace SHADE gBufferWriteSubpass->AddColorOutput("Entity ID"); gBufferWriteSubpass->AddDepthOutput("Depth Buffer", SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL); + auto greyscale = shaderModuleLibrary.GetShaderModule("GreyscaleCs.glsl"); + + auto greyscaleSubpass = node->AddSubpass("Greyscale Subpass"); + greyscaleSubpass->AddGeneralInput("Scene"); + greyscaleSubpass->AddSubpassCompute(greyscale); + + // We do this to just transition our scene layout to shader read auto sceneLayoutTransitionSubpass = node->AddSubpass("Scene Layout Transition"); sceneLayoutTransitionSubpass->AddInput("Scene"); @@ -177,20 +201,11 @@ namespace SHADE worldRenderer = worldViewport->AddRenderer(resourceManager, swapchain->GetNumImages(), renderContextCmdPools, descPool, SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS], worldRenderGraph); worldRenderer->SetCamera(worldCamera); - - // 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 diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.cpp b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.cpp index c03fd2a7..973218d1 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.cpp +++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.cpp @@ -171,6 +171,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; + } } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h b/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h index 241292d4..efd3fb0f 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h @@ -12,4 +12,5 @@ namespace SHADE DEPTH_STENCIL = 0x10, INPUT = 0x20 }; + } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp index 1db410c0..df588c05 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp @@ -10,6 +10,7 @@ #include "Tools/SHLogger.h" #include "SHAttachmentDescInitParams.h" #include "SHRenderGraphStorage.h" +#include "Graphics/RenderGraph/SHSubpassCompute.h" namespace SHADE { @@ -78,36 +79,48 @@ namespace SHADE for (uint32_t i = 0; auto& node : nodes) { - // key is handle ID, value is pair (first is initial layout, second is final layout). - std::unordered_map resourceAttLayouts; + // key is handle ID, value is final layout. + std::unordered_map resourceAttFinalLayouts; if (node->subpasses.empty()) { SHLOG_ERROR("Node does not contain a subpass. Cannot configure attachment descriptions as a result. "); return; } + // attempt to get all final layouts for all resources for (auto& subpass : node->subpasses) { for (auto& color : subpass->colorReferences) { + // If final renderpass and attachment is a COLOR_PRESENT resource, make resource transition to present after last subpass if (i == nodes.size() - 1 && (node->attResources[color.attachment]->resourceTypeFlags & static_cast(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT))) - resourceAttLayouts[color.attachment] = vk::ImageLayout::ePresentSrcKHR; + resourceAttFinalLayouts[color.attachment] = vk::ImageLayout::ePresentSrcKHR; else - resourceAttLayouts[color.attachment] = color.layout; + resourceAttFinalLayouts[color.attachment] = color.layout; } for (auto& depth : subpass->depthReferences) - resourceAttLayouts[depth.attachment] = depth.layout; + resourceAttFinalLayouts[depth.attachment] = depth.layout; for (auto& input : subpass->inputReferences) - resourceAttLayouts[input.attachment] = input.layout; + resourceAttFinalLayouts[input.attachment] = input.layout; + + // Go through all subpass computes and initialize final layouts to GENERAL when a resource is detected to be used in it + //for (auto sbCompute : subpass->subpassComputes) + //{ + // auto const& indices = sbCompute->attachmentDescriptionIndices; + // for (auto& index : indices) + // { + // resourceAttFinalLayouts[index] = vk::ImageLayout::eGeneral; + // } + //} } 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; } @@ -175,7 +188,7 @@ namespace SHADE // Now we want to loop through all attachments in all subpasses in the node and query // the resources being used. For each resource we want to query the type and record it // in bit fields (1 bit for each subpass). - uint32_t colorRead = 0, colorWrite = 0, depthRead = 0, depthWrite = 0, inputDependencies = 0; + uint32_t colorRead = 0, colorWrite = 0, depthRead = 0, depthWrite = 0, inputDependencies = 0, descriptorDependencies = 0; uint32_t i = 0; @@ -214,6 +227,9 @@ namespace SHADE if (subpass->inputReferences.size()) inputDependencies |= (1 << i); + if (!subpass->subpassComputes.empty()) + descriptorDependencies |= (1 << i); + // Input attachments can be any type, so we need to check what type it is for (auto& inputAtt : subpass->inputReferences) { @@ -279,6 +295,12 @@ namespace SHADE dstAccess |= vk::AccessFlagBits::eInputAttachmentRead; } + if (descriptorDependencies & (1 << i)) + { + dstStage |= vk::PipelineStageFlagBits::eComputeShader; + dstAccess |= vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eShaderRead; + } + //// If subpass of first renderpass, stage flag should be bottom of pipe //if (&node == &nodes.front() && i == 0) // srcStage = vk::PipelineStageFlagBits::eBottomOfPipe; @@ -293,6 +315,9 @@ namespace SHADE dep.dstAccessMask = dstAccess; dep.srcStageMask = srcStage; + + // initialize the barriers + //node->subpasses[i]->InitComputeBarriers(); } } } @@ -353,6 +378,8 @@ namespace SHADE renderGraphStorage->resourceManager = resourceManager; renderGraphStorage->descriptorPool = logicalDevice->CreateDescriptorPools(); + + renderGraphStorage->ptrToResources = &graphResources; } /***************************************************************************/ @@ -459,7 +486,7 @@ namespace SHADE } } - nodes.emplace_back(resourceManager->Create(renderGraphStorage, std::move(descInitParams), std::move(predecessors), &graphResources)); + nodes.emplace_back(resourceManager->Create(renderGraphStorage, std::move(descInitParams), std::move(predecessors))); nodeIndexing.emplace(nodeName, static_cast(nodes.size()) - 1u); return nodes.at(nodeIndexing[nodeName]); } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h index 9dbfa6d3..529476cf 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h @@ -57,10 +57,6 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ /*-----------------------------------------------------------------------*/ - //Handle logicalDeviceHdl; - - //! swapchain used for querying image count - //Handle swapchainHdl; Handle renderGraphStorage; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp index 48855806..0d88a93a 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp @@ -83,6 +83,11 @@ namespace SHADE framebuffers[i]->HandleResize(renderpass, imageViews, fbWidth, fbHeight); } + + for (auto& subpass : subpasses) + { + subpass->HandleResize(); + } } /***************************************************************************/ @@ -105,7 +110,7 @@ namespace SHADE */ /***************************************************************************/ - SHRenderGraphNode::SHRenderGraphNode(Handle renderGraphStorage, std::vector attDescInitParams, std::vector> predecessors, std::unordered_map> const* resources) noexcept + SHRenderGraphNode::SHRenderGraphNode(Handle renderGraphStorage, std::vector attDescInitParams, std::vector> predecessors) noexcept : graphStorage{ renderGraphStorage} , renderpass{} , framebuffers{} @@ -116,7 +121,6 @@ namespace SHADE , subpasses{} , executed{ false } , configured{ false } - , ptrToResources{ resources } { // pipeline library initialization pipelineLibrary.Init(graphStorage->logicalDevice); @@ -173,7 +177,6 @@ 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) } @@ -197,7 +200,6 @@ 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); @@ -233,7 +235,7 @@ namespace SHADE } // Add subpass to container and create mapping for it - subpasses.emplace_back(graphStorage->resourceManager->Create(graphStorage, GetHandle(), subpasses.size(), &resourceAttachmentMapping, ptrToResources)); + subpasses.emplace_back(graphStorage->resourceManager->Create(graphStorage, GetHandle(), subpasses.size(), &resourceAttachmentMapping)); subpassIndexing.try_emplace(subpassName, static_cast(subpasses.size()) - 1u); Handle subpass = subpasses.back(); subpass->Init(*graphStorage->resourceManager); diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h index 04638c37..7c3622ad 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h @@ -64,9 +64,6 @@ namespace SHADE //! For indexing subpasses std::map subpassIndexing; - //! Pointer to resources in the render graph (for getting handle IDs) - std::unordered_map> const* ptrToResources; - //! Every renderpass will require a pipeline library that will contain pipelines compatible with this renderpass SHPipelineLibrary pipelineLibrary; @@ -89,7 +86,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* CTORS AND DTORS */ /*-----------------------------------------------------------------------*/ - SHRenderGraphNode(Handle renderGraphStorage, std::vector attDescInitParams, std::vector> predecessors, std::unordered_map> const* resources) noexcept; + SHRenderGraphNode(Handle renderGraphStorage, std::vector attDescInitParams, std::vector> predecessors) noexcept; SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept; SHRenderGraphNode& operator= (SHRenderGraphNode&& rhs) noexcept; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp index d3f20665..651ba88b 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp @@ -308,6 +308,7 @@ namespace SHADE return resourceFormat; } + uint32_t SHRenderGraphResource::GetWidth(void) const noexcept { return width; @@ -323,4 +324,14 @@ namespace SHADE return imageViews [index]; } + Handle SHRenderGraphResource::GetImage(uint32_t index /*= NON_SWAPCHAIN_RESOURCE_INDEX*/) const noexcept + { + return images[index]; + } + + uint8_t SHRenderGraphResource::GetMipLevels(void) const noexcept + { + return mipLevels; + } + } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h index 4bdecc49..55f25864 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h @@ -82,12 +82,15 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ /*-----------------------------------------------------------------------*/ - vk::Format GetResourceFormat (void) const noexcept; - uint32_t GetWidth (void) const noexcept; - uint32_t GetHeight (void) const noexcept; - Handle GetImageView (uint32_t index = NON_SWAPCHAIN_RESOURCE_INDEX) const noexcept; + vk::Format GetResourceFormat (void) const noexcept; + uint32_t GetWidth (void) const noexcept; + uint32_t GetHeight (void) const noexcept; + Handle GetImageView (uint32_t index = NON_SWAPCHAIN_RESOURCE_INDEX) const noexcept; + Handle GetImage (uint32_t index = NON_SWAPCHAIN_RESOURCE_INDEX) const noexcept; + uint8_t GetMipLevels (void) const noexcept; friend class SHRenderGraphNode; friend class SHRenderGraph; + friend class SHSubpass; }; } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphStorage.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphStorage.h index 9fcc4528..cb274697 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphStorage.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphStorage.h @@ -24,6 +24,9 @@ namespace SHADE //! Descriptor pool for the descriptor sets to be created in the subpasses Handle descriptorPool; + //! For accessing resources anyone in the graph + std::unordered_map> const* ptrToResources; + friend class SHRenderGraph; friend class SHRenderGraphNode; friend class SHSubpass; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp index 3daafb8f..e6472c52 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp @@ -8,6 +8,10 @@ #include "SHRenderGraphNode.h" #include "SHRenderGraphStorage.h" #include "Graphics/RenderGraph/SHSubpassCompute.h" +#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" +#include "Graphics/Swapchain/SHVkSwapchain.h" +#include "Graphics/Images/SHVkSampler.h" +#include "SHRenderGraphResource.h" namespace SHADE { @@ -27,9 +31,8 @@ namespace SHADE */ /***************************************************************************/ - SHSubpass::SHSubpass(Handle renderGraphStorage, Handle const& parent, uint32_t index, std::unordered_map const* mapping, std::unordered_map> const* resources) noexcept + SHSubpass::SHSubpass(Handle renderGraphStorage, Handle const& parent, uint32_t index, std::unordered_map const* mapping) noexcept : resourceAttachmentMapping{ mapping } - , ptrToResources{ resources } , parentNode{ parent } , subpassIndex{ index } , superBatch{} @@ -37,6 +40,8 @@ namespace SHADE , depthReferences{} , inputReferences{} , graphStorage{ renderGraphStorage } + , subpassComputes{} + , inputImageDescriptors {SHGraphicsConstants::NUM_FRAME_BUFFERS} { } @@ -59,10 +64,10 @@ 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{ std::move(rhs.graphStorage) } + , subpassComputes{std::move (rhs.subpassComputes)} { } @@ -90,10 +95,10 @@ 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 = std::move(rhs.graphStorage); + subpassComputes = std::move(rhs.subpassComputes); return *this; } @@ -112,7 +117,7 @@ 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->ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eColorAttachmentOptimal }); } /***************************************************************************/ @@ -149,7 +154,7 @@ namespace SHADE //Invalid return; } - depthReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), imageLayout }); + depthReferences.push_back({ resourceAttachmentMapping->at(graphStorage->ptrToResources->at(resourceToReference).GetId().Raw), imageLayout }); } /***************************************************************************/ @@ -166,7 +171,15 @@ 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->ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eShaderReadOnlyOptimal }); + + inputNames.push_back(resourceToReference); + } + + void SHSubpass::AddGeneralInput(std::string resourceToReference) noexcept + { + inputReferences.push_back({ resourceAttachmentMapping->at(graphStorage->ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eGeneral }); + } void SHSubpass::Execute(Handle& commandBuffer, Handle descPool, uint32_t frameIndex) noexcept @@ -182,6 +195,17 @@ namespace SHADE { drawCall(commandBuffer); } + + // if there are subpass computes, transition all to GENERAL layout first + for (auto& sbCompute : subpassComputes) + { + + } + } + + void SHSubpass::HandleResize(void) noexcept + { + UpdateWriteDescriptors(); } void SHSubpass::AddExteriorDrawCalls(std::function&)> const& newDrawCall) noexcept @@ -189,9 +213,27 @@ namespace SHADE exteriorDrawCalls.push_back(newDrawCall); } - Handle SHSubpass::ActivateSubpassCompute(Handle computeShaderModule, std::initializer_list resources) noexcept + Handle SHSubpass::AddSubpassCompute(Handle computeShaderModule/*, std::initializer_list resources*/) noexcept { - subpassCompute = graphStorage->resourceManager->Create(graphStorage, computeShaderModule, resources); + //// for the subpass compute to store indices to the resources, see member comments + //std::unordered_set attDescIndices{}; + //attDescIndices.reserve (resources.size()); + + //// Look for the required resources in the graph + //std::vector> subpassComputeResources{}; + //subpassComputeResources.reserve(resources.size()); + + //for (auto& resourceName : resources) + //{ + // auto resource = graphStorage->ptrToResources->at(resourceName); + // subpassComputeResources.push_back(resource); + // attDescIndices.emplace(resourceAttachmentMapping->at (resource.GetId().Raw)); + //} + + // Create the subpass compute with the resources + auto subpassCompute = graphStorage->resourceManager->Create(graphStorage, computeShaderModule/*, std::move(subpassComputeResources), std::move (attDescIndices)*/); + subpassComputes.push_back(subpassCompute); + return subpassCompute; } @@ -201,6 +243,145 @@ namespace SHADE } + void SHSubpass::CreateInputDescriptors(void) noexcept + { + //std::vector bindings{}; + + //for (auto& input : inputReferences) + //{ + // SHVkDescriptorSetLayout::Binding newBinding + // { + // .Type = (input.layout == vk::ImageLayout::eShaderReadOnlyOptimal) ? vk::DescriptorType::eInputAttachment : vk::DescriptorType::eStorageImage, + // .Stage = vk::ShaderStageFlagBits::eFragment | vk::ShaderStageFlagBits::eCompute, + // .BindPoint = static_cast(bindings.size()), + // .DescriptorCount = 1, + // .flags = {}, + // }; + + // bindings.push_back(newBinding); + //} + + //// We build a new descriptor set layout to store our images + //inputDescriptorLayout = graphStorage->logicalDevice->CreateDescriptorSetLayout(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, bindings); + + //// we store a sampler if its an input attachment. if it is storage image, no need sampler, store an empty handle. + //for (uint32_t i = 0; i < bindings.size(); ++i) + //{ + // if (bindings[i].Type == vk::DescriptorType::eInputAttachment) + // { + // auto newSampler = graphStorage->logicalDevice->CreateSampler(SHVkSamplerParams + // { + // .minFilter = vk::Filter::eLinear, + // .magFilter = vk::Filter::eLinear, + // .addressMode = vk::SamplerAddressMode::eRepeat, + // .mipmapMode = vk::SamplerMipmapMode::eLinear, + // .minLod = -1000, + // .maxLod = 1000 + // } + // ); + + // inputSamplers.push_back(newSampler); + // } + // else + // { + // inputSamplers.push_back({}); + // } + //} + + //// maybe do this in handle resize? + //UpdateWriteDescriptors(); + } + + void SHSubpass::UpdateWriteDescriptors(void) noexcept + { + //auto const& bindings = inputDescriptorLayout->GetBindings(); + + //std::vector variableCounts{ static_cast(bindings.size()), 0 }; + + //uint32_t i = 0; + + //// For every frame's descriptor set + //for (auto& group : inputImageDescriptors) + //{ + // if (group) + // group.Free(); + + // group = graphStorage->descriptorPool->Allocate({ inputDescriptorLayout }, variableCounts); + + // for (auto& binding : bindings) + // { + // // get the resource + // auto resource = graphStorage->ptrToResources->at(inputNames[binding.BindPoint]); + + // // If resource is swapchain image, get the correct image, if not just get 0. + // uint32_t viewIndex = (resource->resourceTypeFlags & static_cast(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)) ? i : 0; + + // // layout is GENERAL if image is meant to be used as storage image, if not use SHADER_READ_ONLY_OPTINAL + // vk::ImageLayout descriptorLayout = (binding.Type == vk::DescriptorType::eStorageImage) ? vk::ImageLayout::eGeneral : vk::ImageLayout::eShaderReadOnlyOptimal; + + // // Update descriptor sets + // auto args = std::make_tuple(resource->GetImageView(viewIndex), inputSamplers[i], descriptorLayout); + // group->ModifyWriteDescImage(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint, std::span{&args, 1}); + // group->UpdateDescriptorSetImages(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint); + // } + + // ++i; + //} + } + + //void SHSubpass::InitComputeBarriers(void) noexcept + //{ + // std::unordered_set handleBarriers{}; + + // // we will have swapchainNumImages vectors of vector of barriers + // subpassComputeBarriers.resize(graphStorage->swapchain->GetNumImages()); + + // for (auto sbCompute : subpassComputes) + // { + // // for every resource the subpass compute is using + // for (auto resource : sbCompute->resources) + // { + // // Get the resource handle + // uint64_t resourceRaw = resource.GetId().Raw; + + // // if the barrier is not registered + // if (!handleBarriers.contains(resourceRaw)) + // { + // // If the resource is a swapchain image + // bool isSwapchainImage = (resource->resourceTypeFlags & static_cast(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)); + // for (uint32_t i = 0; i < graphStorage->swapchain->GetNumImages(); ++i) + // { + // // if swapchain image, we want the index of the swapchain image, if not take base image + // uint32_t imageIndex = isSwapchainImage ? i : 0; + + // // Prepare image barrier + // vk::ImageMemoryBarrier imageBarrier + // { + // .oldLayout = colorReferences[resourceAttachmentMapping->at(resource.GetId().Raw)].layout, + // .newLayout = vk::ImageLayout::eGeneral, + // .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + // .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + // .image = resource->GetImage(imageIndex)->GetVkImage(), + // .subresourceRange = + // { + // .aspectMask = resource->imageAspectFlags, + // .levelCount = resource->GetMipLevels(), + // .baseArrayLayer = 0, + // .layerCount = 1 + // } + // }; + + // // push the barrier + // subpassComputeBarriers[i].push_back(imageBarrier); + // } + + // // Image transition registered + // handleBarriers.emplace(resourceRaw); + // } + // } + // } + //} + /***************************************************************************/ /*! diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h index 71496b92..48874a06 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h @@ -14,10 +14,12 @@ namespace SHADE class SHRenderGraphResource; class SHVkCommandBuffer; class SHVkDescriptorSetLayout; + class SHVkDescriptorSetGroup; class SHVkDescriptorPool; class SHRenderGraphStorage; class SHSubpassCompute; class SHVkShaderModule; + class SHVkSampler; class SH_API SHSubpass : public ISelfHandle { @@ -25,38 +27,52 @@ namespace SHADE /*---------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ /*---------------------------------------------------------------------*/ - Handle graphStorage; + Handle graphStorage; //! The index of the subpass in the render graph - uint32_t subpassIndex; + uint32_t subpassIndex; //! The parent renderpass that this subpass belongs to - Handle parentNode; + Handle parentNode; //! - Handle superBatch; + Handle superBatch; //! Descriptor set layout to hold attachments - Handle descriptorSetLayout; + Handle descriptorSetLayout; //! Color attachments - std::vector colorReferences; + std::vector colorReferences; //! Depth attachments - std::vector depthReferences; + std::vector depthReferences; //! Input attachments - std::vector inputReferences; + std::vector inputReferences; + + //! This is mainly for when we want to retrieve resources using names. + std::vector inputNames; //! For getting attachment reference indices using handles std::unordered_map const* resourceAttachmentMapping; - //! Pointer to resources in the render graph (for getting handle IDs) - std::unordered_map> const* ptrToResources; + //! Descriptor set group to hold the images for input + std::vector> inputImageDescriptors; + + //! Descriptor set layout for allocating descriptor set for inputs + Handle inputDescriptorLayout; + + std::vector> inputSamplers; //! Sometimes we want the subpass to do something to the images instead //! of drawing objects on the image (i.e. compute). - Handle subpassCompute; + std::vector> subpassComputes; + + ////! subpass compute image barriers. We do this because every frame has a different + ////! swapchain image. If the resource we want to transition is not a swapchain image, + ////! we duplicate the barrier anyway, not much memory wasted. ;) + //std::vector> subpassComputeBarriers{}; + //! Sometimes there exists entities that we want to render onto a render target //! but don't want it to come from the batching system. An example would be ImGUI. @@ -71,7 +87,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* CTORS AND DTORS */ /*-----------------------------------------------------------------------*/ - SHSubpass(Handle renderGraphStorage, Handle const& parent, uint32_t index, std::unordered_map const* mapping, std::unordered_map> const* ptrToResources) noexcept; + SHSubpass(Handle renderGraphStorage, Handle const& parent, uint32_t index, std::unordered_map const* mapping) noexcept; SHSubpass(SHSubpass&& rhs) noexcept; SHSubpass& operator=(SHSubpass&& rhs) noexcept; @@ -82,14 +98,20 @@ namespace SHADE void AddColorOutput(std::string resourceToReference) noexcept; void AddDepthOutput(std::string resourceToReference, SH_ATT_DESC_TYPE_FLAGS attachmentDescriptionType = SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL) noexcept; void AddInput(std::string resourceToReference) noexcept; + void AddGeneralInput (std::string resourceToReference) noexcept; + void AddExteriorDrawCalls(std::function&)> const& newDrawCall) noexcept; // Runtime functions void Execute(Handle& commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; - void AddExteriorDrawCalls(std::function&)> const& newDrawCall) noexcept; + void HandleResize (void) noexcept; - Handle ActivateSubpassCompute(Handle computeShaderModule, std::initializer_list resources) noexcept; + Handle AddSubpassCompute(Handle computeShaderModule/*, std::initializer_list resources*/) noexcept; void Init(ResourceManager& resourceManager) noexcept; + + //void InitComputeBarriers (void) noexcept; + void CreateInputDescriptors (void) noexcept; + void UpdateWriteDescriptors (void) noexcept; /*-----------------------------------------------------------------------*/ /* GETTERS AND SETTERS */ @@ -102,5 +124,6 @@ namespace SHADE friend class SHRenderGraphNode; friend class SHRenderGraph; + friend class SHSubpass; }; } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.cpp index f30fa85f..79242c7d 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.cpp @@ -11,25 +11,43 @@ namespace SHADE { - SHSubpassCompute::SHSubpassCompute(Handle graphStorage, Handle computeShaderModule, std::initializer_list resources) noexcept + SHSubpassCompute::SHSubpassCompute(Handle graphStorage, Handle computeShaderModule/*, std::vector>&& subpassComputeResources, std::unordered_set&& attDescIndices*/) noexcept : pipeline{} { SHPipelineLayoutParams pipelineLayoutParams { + .shaderModules = {computeShaderModule}, .globalDescSetLayouts = SHGraphicsGlobalData::GetDescSetLayouts() }; - //pipeline = logicalDevice->CreateComputePipeline() + // Create descriptor set from + pipelineLayout = graphStorage->logicalDevice->CreatePipelineLayout (pipelineLayoutParams); - // 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(); + // Create the compute pipeline + pipeline = graphStorage->logicalDevice->CreateComputePipeline(pipelineLayout); + + pipeline->ConstructPipeline(); + + // 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 = pipeline->GetPipelineLayout()->GetDescriptorSetLayoutsAllocate(); // Variable counts for the descriptor sets (all should be 1). - std::vector variableCounts{ static_cast(layouts.size()) }; - std::fill(variableCounts.begin(), variableCounts.end(), 0); + //std::vector variableCounts{ static_cast(layouts.size()) }; + //std::fill(variableCounts.begin(), variableCounts.end(), 0); - // Allocate descriptor sets to hold the images for reading (STORAGE_IMAGE) - descSetGroup = graphStorage->descriptorPool->Allocate(layouts, variableCounts); + //// Allocate descriptor sets to hold the images for reading (STORAGE_IMAGE) + //descSetGroup = graphStorage->descriptorPool->Allocate(layouts, variableCounts); + + //// save the resources + //resources = std::move (subpassComputeResources); + + //// we save this because when we configure the graph, we want to make sure final layouts + //// of attachment descriptions are set to GENERAL. See ConfigureAttachmentDescriptions in SHRenderGraph.cpp. + //attachmentDescriptionIndices = std::move (attDescIndices); + + //descSetGroup->ModifyWriteDescImage (SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, ) } + //SHSubpass } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.h b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.h index 8dfc361e..aae2a9b9 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.h @@ -3,6 +3,7 @@ #include "Resource/Handle.h" #include #include +#include namespace SHADE { @@ -12,26 +13,37 @@ namespace SHADE class SHVkLogicalDevice; class SHVkPipelineLayout; class SHRenderGraphStorage; + class SHRenderGraphResource; class SHVkShaderModule; class SHSubpassCompute { private: //! To run the dispatch command - Handle pipeline; + Handle pipeline; - //! Pipeline layout for the pipline creation - Handle pipelineLayout; + //! Pipeline layout for the pipeline creation + Handle pipelineLayout; - //! Descriptor set group to hold the images for reading (STORAGE_IMAGE) - Handle descSetGroup; + ////! Descriptor set group to hold the images for reading (STORAGE_IMAGE) + //Handle descSetGroup; - //! Required resources to be used in the descriptors - std::vector resourcesRequired; + ////! Required resources to be used in the descriptors + //std::vector resourcesRequired; + + ////! vector of resources needed by the subpass compute + //std::vector> resources; + + ////! we save this because when we configure the graph, we want to make sure final layouts + ////! of attachment descriptions are set to GENERAL. See ConfigureAttachmentDescriptions in SHRenderGraph.cpp. + //std::unordered_set attachmentDescriptionIndices{}; public: - SHSubpassCompute(Handle graphStorage, Handle computeShaderModule, std::initializer_list resources) noexcept; + SHSubpassCompute(Handle graphStorage, Handle computeShaderModule/*, std::vector>&& subpassComputeResources, std::unordered_set&& attDescIndices*/) noexcept; + //void ExecuteSubpass (void) noexcept; + friend class SHRenderGraph; + friend class SHSubpass; }; } diff --git a/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp b/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp index 41327988..e635f763 100644 --- a/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp +++ b/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp @@ -177,6 +177,9 @@ namespace SHADE return vk::DescriptorType::eStorageBufferDynamic; case SpvReflectDescriptorType::SPV_REFLECT_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: return vk::DescriptorType::eInputAttachment; + case SpvReflectDescriptorType::SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE: + return vk::DescriptorType::eStorageImage; + break; default: return vk::DescriptorType::eCombinedImageSampler; break; diff --git a/TempShaderFolder/GreyscaleCs.glsl b/TempShaderFolder/GreyscaleCs.glsl new file mode 100644 index 00000000..3167a57c --- /dev/null +++ b/TempShaderFolder/GreyscaleCs.glsl @@ -0,0 +1,38 @@ +/* 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 + +layout(local_size_x = 16, local_size_y = 16) in; +layout(set = 4, binding = 0, rgba8) uniform image2D targetImage; + + +void main() +{ + // 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)); + +} + + + + diff --git a/TempShaderFolder/GreyscaleCs.spv b/TempShaderFolder/GreyscaleCs.spv new file mode 100644 index 00000000..5b36e003 Binary files /dev/null and b/TempShaderFolder/GreyscaleCs.spv differ