diff --git a/SHADE_Engine/src/Events/SHEventDefines.h b/SHADE_Engine/src/Events/SHEventDefines.h index a7447be0..e03dfd82 100644 --- a/SHADE_Engine/src/Events/SHEventDefines.h +++ b/SHADE_Engine/src/Events/SHEventDefines.h @@ -30,4 +30,5 @@ constexpr SHEventIdentifier SH_BUTTON_RELEASE_EVENT { 21 }; constexpr SHEventIdentifier SH_BUTTON_HOVER_ENTER_EVENT { 22 }; constexpr SHEventIdentifier SH_BUTTON_HOVER_EXIT_EVENT { 23 }; constexpr SHEventIdentifier SH_ASSET_COMPILE_EVENT { 24 }; +constexpr SHEventIdentifier SH_LIGHT_DELETE_EVENT { 25 }; diff --git a/SHADE_Engine/src/Graphics/Events/SHGraphicsEvents.h b/SHADE_Engine/src/Graphics/Events/SHGraphicsEvents.h index 51cd7aa2..e8f00c8a 100644 --- a/SHADE_Engine/src/Graphics/Events/SHGraphicsEvents.h +++ b/SHADE_Engine/src/Graphics/Events/SHGraphicsEvents.h @@ -6,13 +6,16 @@ namespace SHADE { - struct SHLightEnableShadowEvent + struct SHLightShadowEvent { //! We need to get the light component and initialize the relevant variables. EntityID lightEntity; //! Generate a renderer for the light component - bool generateRenderer; + bool firstEnable; + + //! True when light is set enable shadow + bool enableShadow; }; struct SHWindowResizeEvent @@ -23,4 +26,10 @@ namespace SHADE // New height when window resizes uint32_t resizeHeight; }; + + struct SHDeleteLightEvent + { + //! Entity of the light we are deleting + EntityID lightEntity; + }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index 69b4503c..22f0423d 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -537,12 +537,21 @@ namespace SHADE ReceiverPtr lightEnableShadowReceivePtr = std::dynamic_pointer_cast(lightEnableShadowReceiver); SHEventManager::SubscribeTo(SH_GRAPHICS_LIGHT_ENABLE_SHADOW_EVENT, lightEnableShadowReceivePtr); + std::shared_ptr> lightDeleteEvent + { + std::make_shared>(this, &SHGraphicsSystem::ReceiveLightDeleteEvent) + }; + ReceiverPtr lightDeleteReceivePtr = std::dynamic_pointer_cast(lightDeleteEvent); + SHEventManager::SubscribeTo(SH_ASSET_COMPILE_EVENT, lightDeleteReceivePtr); + + std::shared_ptr> compileAssetReceiever { std::make_shared>(this, &SHGraphicsSystem::ReceiveCompileAssetEvent) }; ReceiverPtr compileAssetReceivePtr = std::dynamic_pointer_cast(compileAssetReceiever); SHEventManager::SubscribeTo(SH_ASSET_COMPILE_EVENT, compileAssetReceivePtr); + } void SHGraphicsSystem::InitGenericDataAndTexturesDescSet(void) noexcept @@ -846,10 +855,7 @@ namespace SHADE SHEventHandle SHGraphicsSystem::ReceiveLightEnableShadowEvent(SHEventPtr eventPtr) noexcept { - // we need to wait for the device to finish using the graph first - device->WaitIdle(); - - auto const& EVENT_DATA = reinterpret_cast*>(eventPtr.get())->data; + auto const& EVENT_DATA = reinterpret_cast*>(eventPtr.get())->data; auto* lightComp = SHComponentManager::GetComponent(EVENT_DATA->lightEntity); std::string depthResourceName = "ShadowMap_Depth " + std::to_string(EVENT_DATA->lightEntity); std::string shadowMapResourceName = "ShadowMap " + std::to_string(EVENT_DATA->lightEntity); @@ -857,71 +863,112 @@ namespace SHADE Handle gBufferWriteSubpass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data())->GetSubpass(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_WRITE_SUBPASS); Handle gBufferWriteVfxSubpass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data())->GetSubpass(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_WRITE_VFX_SUBPASS); - if (EVENT_DATA->generateRenderer) + if (EVENT_DATA->enableShadow) { - // Create new renderer for the light component and give it to the light component - Handle newRenderer = resourceManager.Create(device, swapchain->GetNumImages(), descPool, SHRenderer::PROJECTION_TYPE::ORTHOGRAPHIC); - lightComp->SetRenderer (newRenderer); + // When the light first enables shadow rendering, we need to prepare the relevant objects to render shadows; namely renderpasses and subpasses, pipelines and descriptor sets + if (EVENT_DATA->firstEnable) + { + // we need to wait for the device to finish using the graph first + device->WaitIdle(); - // assign shadow map index to light component - lightComp->SetShadowMapIndex (lightingSubSystem->GetNumShadowMaps()); + // Create new renderer for the light component and give it to the light component + Handle newRenderer = resourceManager.Create(device, swapchain->GetNumImages(), descPool, SHRenderer::PROJECTION_TYPE::ORTHOGRAPHIC); + lightComp->SetRenderer(newRenderer); + + // assign shadow map index to light component + lightComp->SetShadowMapIndex(lightingSubSystem->GetNumShadowMaps()); + + + // Add the shadow map resource to the graph + renderGraph->AddResource(depthResourceName, { SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH }, false, SHLightingSubSystem::SHADOW_MAP_WIDTH, SHLightingSubSystem::SHADOW_MAP_HEIGHT, vk::Format::eD32Sfloat); + renderGraph->AddResource(shadowMapResourceName, { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, false, SHLightingSubSystem::SHADOW_MAP_WIDTH, SHLightingSubSystem::SHADOW_MAP_HEIGHT, vk::Format::eR32G32B32A32Sfloat); + renderGraph->AddResource(shadowMapBlurredResourceName, { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, false, SHLightingSubSystem::SHADOW_MAP_WIDTH, SHLightingSubSystem::SHADOW_MAP_HEIGHT, vk::Format::eR32G32B32A32Sfloat); + + + + // link resource to node. This means linking the resource and regenerating the node's renderpass and framebuffer. + auto shadowMapNode = renderGraph->AddNodeAfter(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data() + shadowMapResourceName, { depthResourceName.c_str(), shadowMapResourceName.c_str(), shadowMapBlurredResourceName.c_str() }, SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data()); + + // Add a subpass to render to that shadow map + auto shadowMapDrawSubpass = shadowMapNode->RuntimeAddSubpass(shadowMapResourceName + " Subpass", shadowMapViewport, lightComp->GetRenderer()); + shadowMapDrawSubpass->AddColorOutput(shadowMapResourceName); + shadowMapDrawSubpass->AddDepthOutput(depthResourceName, SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH); + + // add compute pass to blur shadow ma + shadowMapNode->AddNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data() + shadowMapResourceName, shadowMapBlurCS, { shadowMapResourceName.c_str(), shadowMapBlurredResourceName.c_str() }); + + // regenerate the node + shadowMapNode->RuntimeStandaloneRegenerate(); + + // Create pipeline from new renderpass and subpass if it's not created yet + if (!shadowMapPipeline) + { + SHPipelineLibrary tempLibrary{}; + Handle rgNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data()); + + SHRasterizationState rasterState{}; + rasterState.cull_mode = vk::CullModeFlagBits::eBack; + + tempLibrary.Init(device); + tempLibrary.CreateGraphicsPipelines + ( + { shadowMapVS, shadowMapFS }, shadowMapNode->GetRenderpass(), shadowMapDrawSubpass, + SHGraphicsPredefinedData::SystemType::BATCHING, + SHGraphicsPredefinedData::GetShadowMapViState(), rasterState + ); + shadowMapPipeline = tempLibrary.GetGraphicsPipeline({ shadowMapVS, shadowMapFS, shadowMapDrawSubpass }); + } + shadowMapDrawSubpass->AddCompanionSubpass(gBufferWriteSubpass, shadowMapPipeline); // set companion subpass and pipeline + shadowMapDrawSubpass->AddCompanionSubpass(gBufferWriteVfxSubpass, shadowMapPipeline); // set companion subpass and pipeline + + // add the shadow map and the blurred version to the lighting system + uint32_t const NEW_SHADOW_MAP_INDEX = lightingSubSystem->AddShadowMap(renderGraph->GetRenderGraphResource(shadowMapBlurredResourceName), EVENT_DATA->lightEntity); + + // Get deferred composite node compute and modify descriptor set + auto nodeCompute = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data())->GetNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data()); + nodeCompute->ModifyWriteDescImageComputeResource(SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA, lightingSubSystem->GetViewSamplerLayout(NEW_SHADOW_MAP_INDEX), NEW_SHADOW_MAP_INDEX); + } + else + { + // get the shadow map node + renderGraph->GetNode (SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data() + shadowMapResourceName)->SetDynamicActive(true); + } + } + else + { + // get the shadow map node + renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data() + shadowMapResourceName)->SetDynamicActive(false); } + return eventPtr->handle; + } - // Add the shadow map resource to the graph - renderGraph->AddResource(depthResourceName, {SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH}, false, SHLightingSubSystem::SHADOW_MAP_WIDTH, SHLightingSubSystem::SHADOW_MAP_HEIGHT, vk::Format::eD32Sfloat); - renderGraph->AddResource(shadowMapResourceName, { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, false, SHLightingSubSystem::SHADOW_MAP_WIDTH, SHLightingSubSystem::SHADOW_MAP_HEIGHT, vk::Format::eR32G32B32A32Sfloat); - renderGraph->AddResource(shadowMapBlurredResourceName, { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, false, SHLightingSubSystem::SHADOW_MAP_WIDTH, SHLightingSubSystem::SHADOW_MAP_HEIGHT, vk::Format::eR32G32B32A32Sfloat); + SHEventHandle SHGraphicsSystem::ReceiveLightDeleteEvent(SHEventPtr eventPtr) noexcept + { + // we need to wait for the device to finish using the graph first + device->WaitIdle(); - - - // link resource to node. This means linking the resource and regenerating the node's renderpass and framebuffer. - auto shadowMapNode = renderGraph->AddNodeAfter(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data() + shadowMapResourceName, {depthResourceName.c_str(), shadowMapResourceName.c_str(), shadowMapBlurredResourceName.c_str()}, SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data()); - - // Add a subpass to render to that shadow map - auto shadowMapDrawSubpass = shadowMapNode->RuntimeAddSubpass(shadowMapResourceName + " Subpass", shadowMapViewport, lightComp->GetRenderer()); - shadowMapDrawSubpass->AddColorOutput(shadowMapResourceName); - shadowMapDrawSubpass->AddDepthOutput(depthResourceName, SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH); - - // add dummy subpass to transition the shadow map images for compute shader usage - //auto dummySubpass = shadowMapNode->RuntimeAddSubpass(shadowMapResourceName + "Dummy", {}, {}); - //dummySubpass->AddGeneralColorOutput(shadowMapResourceName); - //dummySubpass->AddGeneralColorOutput(shadowMapBlurredResourceName); - - // add compute pass to blur shadow ma - shadowMapNode->AddNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data() + shadowMapResourceName, shadowMapBlurCS, { shadowMapResourceName.c_str(), shadowMapBlurredResourceName.c_str() }); - //shadowMapNode->AddNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data() + shadowMapResourceName, shadowMapBlurCS, { shadowMapBlurredResourceName.c_str(), shadowMapResourceName.c_str() }); - //shadowMapNode->AddNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data() + shadowMapResourceName, shadowMapBlurCS, { shadowMapResourceName.c_str(), shadowMapBlurredResourceName.c_str() }); - - // regenerate the node - shadowMapNode->RuntimeStandaloneRegenerate(); - - // Create pipeline from new renderpass and subpass if it's not created yet - if (!shadowMapPipeline) - { - SHPipelineLibrary tempLibrary{}; - Handle rgNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data()); - - SHRasterizationState rasterState{}; - rasterState.cull_mode = vk::CullModeFlagBits::eBack; - - tempLibrary.Init(device); - tempLibrary.CreateGraphicsPipelines - ( - { shadowMapVS, shadowMapFS }, shadowMapNode->GetRenderpass(), shadowMapDrawSubpass, - SHGraphicsPredefinedData::SystemType::BATCHING, - SHGraphicsPredefinedData::GetShadowMapViState(), rasterState - ); - shadowMapPipeline = tempLibrary.GetGraphicsPipeline({ shadowMapVS, shadowMapFS, shadowMapDrawSubpass }); - } - shadowMapDrawSubpass->AddCompanionSubpass(gBufferWriteSubpass, shadowMapPipeline); // set companion subpass and pipeline - shadowMapDrawSubpass->AddCompanionSubpass(gBufferWriteVfxSubpass, shadowMapPipeline); // set companion subpass and pipeline + auto const& EVENT_DATA = reinterpret_cast*>(eventPtr.get())->data; + auto* lightComp = SHComponentManager::GetComponent(EVENT_DATA->lightEntity); - // add the shadow map and the blurred version to the lighting system - uint32_t const NEW_SHADOW_MAP_INDEX = lightingSubSystem->AddShadowMap(renderGraph->GetRenderGraphResource(shadowMapBlurredResourceName), EVENT_DATA->lightEntity); + if (lightComp && lightComp->GetShadowMapIndex()) + { + std::string depthResourceName = "ShadowMap_Depth " + std::to_string(EVENT_DATA->lightEntity); + std::string shadowMapResourceName = "ShadowMap " + std::to_string(EVENT_DATA->lightEntity); + std::string shadowMapBlurredResourceName = "ShadowMap Blurred" + std::to_string(EVENT_DATA->lightEntity); + + // Remove render graph node + renderGraph->RemoveNode(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data() + shadowMapResourceName); + + // Remove render graph resource + renderGraph->RemoveResource(depthResourceName); + renderGraph->RemoveResource(shadowMapResourceName); + renderGraph->RemoveResource(shadowMapBlurredResourceName); + + // Register light component shadow map index into light system as recyclable + lightingSubSystem->RemoveShadowMap (EVENT_DATA->lightEntity); + } - auto nodeCompute = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data())->GetNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data()); - nodeCompute->ModifyWriteDescImageComputeResource(SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA, lightingSubSystem->GetViewSamplerLayout(NEW_SHADOW_MAP_INDEX), NEW_SHADOW_MAP_INDEX); return eventPtr->handle; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h index 33227f8f..68752a6e 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h @@ -182,6 +182,7 @@ namespace SHADE /* Light functions */ /*-----------------------------------------------------------------------*/ SHEventHandle ReceiveLightEnableShadowEvent (SHEventPtr eventPtr) noexcept; + SHEventHandle ReceiveLightDeleteEvent (SHEventPtr eventPtr) noexcept; /*-----------------------------------------------------------------------*/ /* Asset Events */ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp index 61552614..5e95c6ad 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp @@ -113,15 +113,21 @@ namespace SHADE lightData.castShadows = flag; // If the flag is true - if (flag && lightData.shadowMapIndex == SHLightData::INVALID_SHADOW_MAP_INDEX) + if (flag) { // Create new event and broadcast it - SHLightEnableShadowEvent newEvent; + SHLightShadowEvent newEvent; newEvent.lightEntity = GetEID(); - newEvent.generateRenderer = static_cast(!renderer); - SHEventManager::BroadcastEvent(newEvent, SH_GRAPHICS_LIGHT_ENABLE_SHADOW_EVENT); + // If shadow map index is invalid, that means light is enabling shadow for the first time. + newEvent.firstEnable = (lightData.shadowMapIndex == SHLightData::INVALID_SHADOW_MAP_INDEX); + + // pass the flag to the event + newEvent.enableShadow = flag; + + SHEventManager::BroadcastEvent(newEvent, SH_GRAPHICS_LIGHT_ENABLE_SHADOW_EVENT); } + } void SHLightComponent::SetRenderer(Handle newRenderer) noexcept @@ -195,6 +201,11 @@ namespace SHADE return lightData.castShadows; } + uint32_t SHLightComponent::GetShadowMapIndex(void) const noexcept + { + return lightData.shadowMapIndex; + } + } RTTR_REGISTRATION diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h index a90d23b0..a24b5ede 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h @@ -70,6 +70,8 @@ namespace SHADE float GetStrength (void) const noexcept; Handle GetRenderer (void) const noexcept; bool GetEnableShadow (void) const noexcept; + uint32_t GetShadowMapIndex (void) const noexcept; + RTTR_ENABLE() }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp index f89582fc..27685d69 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp @@ -599,39 +599,15 @@ namespace SHADE { //Bind descriptor set(We bind at an offset because the buffer holds NUM_FRAME_BUFFERS sets of data). cmdBuffer->BindDescriptorSet(lightingDataDescSet, SH_PIPELINE_TYPE::COMPUTE, setIndex, { dynamicOffsets[frameIndex] }); - } uint32_t SHLightingSubSystem::AddShadowMap(Handle newShadowMapBlurred, EntityID lightEntity) noexcept { - // Add to container of shadow maps - shadowMapIndexing.emplace(lightEntity, static_cast (shadowMaps.size())); - shadowMaps.emplace_back(newShadowMapBlurred); + uint32_t usedIndex = 0; // Just use the image view stored in the resource Handle const NEW_IMAGE_VIEW = newShadowMapBlurred->GetImageView(); - // Prepare to write to descriptor - shadowMapImageSamplers.emplace_back(NEW_IMAGE_VIEW, shadowMapSampler, vk::ImageLayout::eShaderReadOnlyOptimal); - - // Update descriptor set - //static constexpr uint32_t SHADOW_MAP_DESC_SET_INDEX = 0; - //uint32_t const SHADOW_MAP_DESC_ARRAY_INDEX = static_cast(shadowMapImageSamplers.size()) - 1u; - //shadowMapDescriptorSet->ModifyWriteDescImage - //( - // SHADOW_MAP_DESC_SET_INDEX, - // SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA, - // shadowMapImageSamplers[SHADOW_MAP_DESC_ARRAY_INDEX], - // SHADOW_MAP_DESC_ARRAY_INDEX - //); - - //// TODO: Definitely can be optimized by writing a function that modifies a specific descriptor in the array - //shadowMapDescriptorSet->UpdateDescriptorSetImages - //( - // SHADOW_MAP_DESC_SET_INDEX, - // SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA - //); - // add to barriers shadowMapMemoryBarriers.push_back (vk::ImageMemoryBarrier { @@ -652,8 +628,68 @@ namespace SHADE } }); + if (recyclableIndices.empty()) + { + shadowMaps.emplace_back(newShadowMapBlurred); + + // Prepare to write to descriptor + shadowMapImageSamplers.emplace_back(NEW_IMAGE_VIEW, shadowMapSampler, vk::ImageLayout::eShaderReadOnlyOptimal); + + // Add to container of shadow maps + shadowMapIndexing.emplace(lightEntity, static_cast (shadowMaps.size())); + + usedIndex = static_cast(shadowMapImageSamplers.size()) - 1u; + } + else + { + uint32_t usedIndex = recyclableIndices.top(); + recyclableIndices.pop(); + + // Recycle the slot in the vector of shadow maps + shadowMaps[usedIndex] = newShadowMapBlurred; + + // register indexing for shadow maps + shadowMapIndexing.emplace(lightEntity, usedIndex); + + // Recycle the slot in the vector of image view, samplers and layout + shadowMapImageSamplers[usedIndex] = std::make_tuple(NEW_IMAGE_VIEW, shadowMapSampler, vk::ImageLayout::eShaderReadOnlyOptimal); + } + + // return new index of shadow map - return static_cast(shadowMapImageSamplers.size()) - 1u; + return usedIndex; + } + + void SHLightingSubSystem::RemoveShadowMap(EntityID lightEntity) noexcept + { + auto* lightComp = SHComponentManager::GetComponent(lightEntity); + + if (lightComp && shadowMapIndexing.contains(lightEntity)) + { + uint32_t shadowMapIndex = shadowMapIndexing[lightEntity]; + + // Recycle the shadow map index used by the component + RecycleShadowMapIndex(lightComp); + + // Not removed from container, can recycle + shadowMaps[shadowMapIndex] = {}; + + // Not removed from container, can recycle + shadowMapImageSamplers[shadowMapIndex] = {}; + + // Remove from barriers + shadowMapMemoryBarriers.erase(shadowMapMemoryBarriers.begin() + shadowMapIndex); + + // remove from map for indexing + shadowMapIndexing.erase(lightEntity); + } + } + + void SHLightingSubSystem::RecycleShadowMapIndex(SHLightComponent* lightComp) noexcept + { + // if index is recyclable, recycle it + if (lightComp && lightComp->GetShadowMapIndex() != SHLightData::INVALID_SHADOW_MAP_INDEX) + recyclableIndices.push (lightComp->GetShadowMapIndex()); } void SHLightingSubSystem::PrepareShadowMapsForRead(Handle cmdBuffer) noexcept @@ -662,28 +698,6 @@ namespace SHADE cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader, {}, {}, {}, shadowMapMemoryBarriers); } - //void SHLightingSubSystem::HandleResize(Handle compute) noexcept - //{ - // uint32_t const NUM_SHADOW_MAPS = static_cast(shadowMaps.size()); - // for (uint32_t i = 0; i < NUM_SHADOW_MAPS; ++i) - // { - // // Just use the image view stored in the resource - // Handle const NEW_IMAGE_VIEW = shadowMaps[i]->GetImageView(); - - // // set new image view - // std::get>(shadowMapImageSamplers[i]) = NEW_IMAGE_VIEW; - - // // Set image for barrier - // shadowMapMemoryBarriers[i].image = shadowMaps[i]->GetImage()->GetVkImage(); - // } - - // if (NUM_SHADOW_MAPS > 0) - // { - // // modify descriptors in render graph node compute - // compute->ModifyWriteDescImageComputeResource (SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA, shadowMapImageSamplers); - // } - //} - Handle SHLightingSubSystem::GetLightDataDescriptorSet(void) const noexcept { return lightingDataDescSet; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h index 3613f762..652b8226 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h @@ -9,6 +9,7 @@ #include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" #include "Graphics/RenderGraph/SHRenderGraphResource.h" #include "ECS_Base/SHECSMacros.h" +#include namespace SHADE @@ -183,10 +184,6 @@ namespace SHADE //! Shadow maps for every light that casts a shadow Order here doesn't matter. We just want to store it std::vector> shadowMaps; - //! Descriptor sets required to be given to the compute shader for shadow calculation. This will be a descriptor array. - //! It will also be preallocated. - //Handle shadowMapDescriptorSet; - //! Combined image samplers for the texture descriptors std::vector, Handle, vk::ImageLayout>> shadowMapImageSamplers; @@ -194,6 +191,9 @@ namespace SHADE //! to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) std::vector shadowMapMemoryBarriers; + //! recycled indices after deleting lights with shadows + std::stack recyclableIndices; + //! Resource hub from Graphics System SHResourceHub* resourceHub; @@ -212,12 +212,14 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ - void Init (Handle device, Handle descPool, SHResourceHub* rh, Handle inShadowMapSampler) noexcept; - void Run (SHMatrix const& viewMat, uint32_t frameIndex) noexcept; - void Exit (void) noexcept; - void BindDescSet (Handle cmdBuffer, uint32_t setIndex, uint32_t frameIndex) noexcept; - uint32_t AddShadowMap (Handle newShadowMapBlurred, EntityID lightEntity) noexcept; - void PrepareShadowMapsForRead (Handle cmdBuffer) noexcept; + void Init (Handle device, Handle descPool, SHResourceHub* rh, Handle inShadowMapSampler) noexcept; + void Run (SHMatrix const& viewMat, uint32_t frameIndex) noexcept; + void Exit (void) noexcept; + void BindDescSet (Handle cmdBuffer, uint32_t setIndex, uint32_t frameIndex) noexcept; + uint32_t AddShadowMap (Handle newShadowMapBlurred, EntityID lightEntity) noexcept; + void RemoveShadowMap (EntityID lightEntity) noexcept; + void RecycleShadowMapIndex (SHLightComponent* lightComp) noexcept; + void PrepareShadowMapsForRead (Handle cmdBuffer) noexcept; //void HandleResize (Handle compute) noexcept; //void RemoveShadowMap (uint32_t index) noexcept; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp index 04d4af0b..34206e5b 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp @@ -81,7 +81,8 @@ namespace SHADE renderGraphStorage->logicalDevice->WaitIdle(); - uint64_t handleID = renderGraphStorage->graphResources->at (resourceName).GetId().Raw; + auto resourceHdl = renderGraphStorage->graphResources->at(resourceName); + uint64_t handleID = resourceHdl.GetId().Raw; // Record nodes that will be affected std::vector affectedNodes{}; @@ -89,7 +90,7 @@ namespace SHADE // Detach resource from all nodes if applicable for (uint32_t i = 0; i < nodes.size(); ++i) { - if (nodes[i]->DetachResource(resourceName, handleID)) + if (nodes[i] && nodes[i]->DetachResource(resourceName, handleID)) affectedNodes.emplace_back(i); } @@ -109,6 +110,8 @@ namespace SHADE renderGraphStorage->graphResources->at(resourceName).Free(); renderGraphStorage->graphResources->erase (resourceName); + + resourceHdl.Free (); /* * IMPORTANT NOTES * @@ -121,6 +124,21 @@ namespace SHADE */ } + void SHRenderGraph::RemoveNode(std::string nodeName) noexcept + { + if (nodeIndexing.contains(nodeName)) + { + // wait for device to stop + renderGraphStorage->logicalDevice->WaitIdle(); + + // Get handle to node since it exists + auto nodeHdl = nodes[nodeIndexing[nodeName]]; + + nodeHdl.Free(); + nodeIndexing.erase(nodeName); + } + } + void SHRenderGraph::LinkNonOwningResource(Handle resourceOrigin, std::string resourceName) noexcept { // resource to link diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h index 0ae30015..42d829b0 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h @@ -112,6 +112,7 @@ namespace SHADE ); void RemoveResource (std::string resourceName) noexcept; + void RemoveNode (std::string nodeName) noexcept; void LinkNonOwningResource ( diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp index 2f316c79..53363a63 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp @@ -405,6 +405,22 @@ namespace SHADE return *this; } + SHRenderGraphNode::~SHRenderGraphNode(void) noexcept + { + if (renderpass) + renderpass.Free(); + + for (auto& framebuffer : framebuffers) + framebuffer.Free(); + + for (auto& subpass : subpasses) + subpass.Free(); + + // Too tired to test, its nearing end of milestone 3.... + //for (auto& nc : nodeComputes) + // nc.Free(); + } + /***************************************************************************/ /*! diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h index 2877fdee..971a84ae 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h @@ -111,6 +111,7 @@ namespace SHADE SHRenderGraphNode(std::string nodeName, Handle renderGraphStorage, std::vector attDescInitParams, std::vector> predecessors, bool inIsDynamic = false) noexcept; SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept; SHRenderGraphNode& operator= (SHRenderGraphNode&& rhs) noexcept; + ~SHRenderGraphNode (void) noexcept; /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ @@ -132,12 +133,12 @@ namespace SHADE /*-----------------------------------------------------------------------*/ void SetDynamicActive(bool active) noexcept; - Handle GetRenderpass(void) const noexcept; - Handle GetSubpass(std::string_view subpassName) const noexcept; - Handle GetResource (uint32_t resourceIndex) const noexcept; + Handle GetRenderpass(void) const noexcept; + Handle GetSubpass(std::string_view subpassName) const noexcept; + Handle GetResource (uint32_t resourceIndex) const noexcept; std::vector> const& GetResources (void) const noexcept; - Handle GetNodeCompute (std::string nodeComputeName) const noexcept; - bool GetDynamicActive (void) const noexcept; + Handle GetNodeCompute (std::string nodeComputeName) const noexcept; + bool GetDynamicActive (void) const noexcept; friend class SHRenderGraph; }; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp index db78c5aa..ca13155d 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp @@ -80,6 +80,14 @@ namespace SHADE , companionSubpasses {std::move (rhs.companionSubpasses)} , dummyPipelineLayout{rhs.dummyPipelineLayout} { + superBatch = std::move(rhs.superBatch); + rhs.superBatch = {}; + + inputDescriptorLayout = std::move(rhs.inputDescriptorLayout); + rhs.inputDescriptorLayout = {}; + + dummyPipelineLayout = std::move(rhs.dummyPipelineLayout); + rhs.dummyPipelineLayout = {}; } @@ -101,7 +109,6 @@ namespace SHADE subpassIndex = std::move(rhs.subpassIndex); parentNode = std::move(rhs.parentNode); - superBatch = std::move(rhs.superBatch); colorReferences = std::move(rhs.colorReferences); depthReferences = std::move(rhs.depthReferences); inputReferences = std::move(rhs.inputReferences); @@ -118,10 +125,36 @@ namespace SHADE companionSubpasses = rhs.companionSubpasses; dummyPipelineLayout = rhs.dummyPipelineLayout; + superBatch = std::move(rhs.superBatch); + rhs.superBatch = {}; + + inputDescriptorLayout = std::move(rhs.inputDescriptorLayout); + rhs.inputDescriptorLayout = {}; + + dummyPipelineLayout = std::move(rhs.dummyPipelineLayout); + rhs.dummyPipelineLayout = {}; return *this; } + SHSubpass::~SHSubpass(void) noexcept + { + graphStorage->logicalDevice->WaitIdle(); + + for (auto& set : inputImageDescriptorSets) + set.Free(); + + if (inputDescriptorLayout) + inputDescriptorLayout.Free(); + + if (dummyPipelineLayout) + dummyPipelineLayout.Free(); + + // not working + //if (superBatch) + // superBatch.Free(); + } + /***************************************************************************/ /*! diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h index 640ccb2d..7f843773 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h @@ -130,6 +130,7 @@ namespace SHADE SHSubpass(const std::string& name, Handle inViewport, Handle inRenderer, Handle renderGraphStorage, Handle const& parent, uint32_t index, std::unordered_map const* mapping) noexcept; SHSubpass(SHSubpass&& rhs) noexcept; SHSubpass& operator=(SHSubpass&& rhs) noexcept; + ~SHSubpass(void) noexcept; /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */