diff --git a/Assets/Scenes/Scene2.shade b/Assets/Scenes/Scene2.shade index 2f38a933..de902c55 100644 --- a/Assets/Scenes/Scene2.shade +++ b/Assets/Scenes/Scene2.shade @@ -7,6 +7,7 @@ Translate: {x: 0, y: 0.304069757, z: 1.73034382} Rotate: {x: 0, y: 0, z: 0} Scale: {x: 1, y: 1, z: 1} + IsActive: true Camera Component: Position: {x: 0, y: 0.304069757, z: 1.73034382} Pitch: 0 @@ -17,6 +18,7 @@ Near: 0.00999999978 Far: 10000 Perspective: true + IsActive: true Scripts: ~ - EID: 1 Name: Raccoon @@ -24,12 +26,14 @@ NumberOfChildren: 1 Components: Transform Component: - Translate: {x: 0, y: 0, z: 0} - Rotate: {x: 0, y: 0, z: 0} + Translate: {x: -1.86388135, y: 0.0544953719, z: 0} + Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} + IsActive: true Renderable Component: Mesh: 149697411 Material: 126974645 + IsActive: true Scripts: ~ - EID: 3 Name: Bag @@ -40,9 +44,11 @@ Translate: {x: 0.006237939, y: -0.000393368304, z: 0} Rotate: {x: -0, y: 2.79945588, z: 0} Scale: {x: 1.0000881, y: 1, z: 1.0000881} + IsActive: true Renderable Component: Mesh: 144838771 Material: 123745521 + IsActive: true Scripts: ~ - EID: 2 Name: DirectionalLight @@ -50,12 +56,13 @@ NumberOfChildren: 0 Components: Light Component: - Position: {x: 0, y: 0, z: 0} + Position: {x: 3, y: 4.5, z: 7} Type: Directional - Direction: {x: 0, y: 0, z: 1} + Direction: {x: -0.298000008, y: 0.522498012, z: 0.798600018} Color: {x: 1, y: 1, z: 1, w: 1} Layer: 4294967295 Strength: 0 + IsActive: true Scripts: ~ - EID: 4 Name: AmbientLight @@ -69,4 +76,20 @@ Color: {x: 1, y: 1, z: 1, w: 1} Layer: 4294967295 Strength: 0.600000024 + IsActive: true + Scripts: ~ +- EID: 5 + Name: Floor + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 0, y: 0.0810000002, z: 0} + Rotate: {x: -1.57079637, y: 0, z: 0} + Scale: {x: 50, y: 50, z: 50} + IsActive: true + Renderable Component: + Mesh: 141771688 + Material: 124370424 + IsActive: true Scripts: ~ \ No newline at end of file diff --git a/Assets/Shaders/DeferredComposite_CS.glsl b/Assets/Shaders/DeferredComposite_CS.glsl index 0a8085b1..d28eaec0 100644 --- a/Assets/Shaders/DeferredComposite_CS.glsl +++ b/Assets/Shaders/DeferredComposite_CS.glsl @@ -6,6 +6,8 @@ struct DirectionalLightStruct uint isActive; uint cullingMask; vec4 diffuseColor; + mat4 pvMatrix; + uint shadowData; }; struct AmbientLightStruct @@ -22,7 +24,10 @@ layout(set = 3, binding = 1, rgba32f) uniform image2D normals; layout(set = 3, binding = 2, rgba8) uniform image2D albedo; layout(set = 3, binding = 3, r32ui) uniform uimage2D lightLayerData; layout(set = 3, binding = 4, r8) uniform image2D ssaoBlurredImage; -layout(set = 3, binding = 5, rgba8) uniform image2D targetImage; +layout(set = 3, binding = 5, rgba8) uniform image2D positionWorldSpace; +layout(set = 3, binding = 6, rgba8) uniform image2D targetImage; + +layout (set = 4, binding = 0) uniform sampler2D shadowMaps[]; // for textures (global) layout(set = 1, binding = 0) uniform LightCounts { @@ -43,6 +48,25 @@ layout(std430, set = 1, binding = 4) buffer AmbientLightData AmbientLightStruct aLightData[]; } AmbLightData; +float CalcShadowValue (sampler2D shadowMap, vec4 worldSpaceFragPos, mat4 lightPV) +{ + vec4 fragPosLightPOV = lightPV * worldSpaceFragPos; + vec3 converted = (fragPosLightPOV.xyz / fragPosLightPOV.w) * vec3(0.5f) + vec3(0.5f); + + float sampledDepth = texture(shadowMap, converted.xy).r; + + if (converted.x < 0.0f || converted.x > 1.0f || converted.y < 0.0f || converted.y > 1.0f) + return 1.0f; + + if (fragPosLightPOV.z > sampledDepth && fragPosLightPOV.w > 0.0f) + { + return 0.0f; + } + else + return 1.0f; + // return step (fragPosLightPOV.z, ); +} + void main() { // convenient variables @@ -52,6 +76,9 @@ void main() vec3 pixelDiffuse = imageLoad (albedo, globalThread).rgb; // Get position of fragment in world space + vec4 positionWorld = vec4 (imageLoad (positionWorldSpace, globalThread).rgb, 1.0f); + + // Get position of fragment in view spacee vec3 positionView = imageLoad (positions, globalThread).rgb; // normal of fragment @@ -62,6 +89,18 @@ void main() vec3 fragColor = vec3 (0.0f); + vec4 shadowMapColor = vec4 (1.0f); + + for (int i = 0; i < lightCounts.ambientLights; ++i) + { + if ((lightLayer & AmbLightData.aLightData[i].cullingMask) != 0) + { + // Just do some add + //fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (0.5f); + fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (AmbLightData.aLightData[i].strength); + } + } + for (int i = 0; i < lightCounts.directionalLights; ++i) { if ((lightLayer & DirLightData.dLightData[i].cullingMask) != 0) @@ -74,16 +113,13 @@ void main() // Calculate the fragment color fragColor += DirLightData.dLightData[i].diffuseColor.rgb * diffuseStrength.rrr * pixelDiffuse; - } - } - for (int i = 0; i < lightCounts.ambientLights; ++i) - { - if ((lightLayer & AmbLightData.aLightData[i].cullingMask) != 0) - { - // Just do some add - //fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (0.5f); - fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (AmbLightData.aLightData[i].strength); + // If the shadow map is enabled (test the bit) + if ((DirLightData.dLightData[i].shadowData & uint(1)) == 1) + { + // calculate shadow map here + fragColor *= CalcShadowValue (shadowMaps[0], positionWorld, DirLightData.dLightData[i].pvMatrix).xxx; + } } } @@ -92,6 +128,12 @@ void main() // store result into result image imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(fragColor.rgb, 1.0f)); - //imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(ssaoVal.rrr, 1.0f)); + + // vec2 normTexCoords = vec2 (gl_GlobalInvocationID.xy) / vec2 (1024.0f); + // vec4 shadowMapVal = texture(shadowMaps[0], normTexCoords); + // if (normTexCoords.x > 1.0f || normTexCoords.y > 1.0f) + // shadowMapVal = vec4(0.0f); + + // imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), shadowMapVal.xxxx); } \ No newline at end of file diff --git a/Assets/Shaders/DeferredComposite_CS.shshaderb b/Assets/Shaders/DeferredComposite_CS.shshaderb index cabce080..ceca4e13 100644 Binary files a/Assets/Shaders/DeferredComposite_CS.shshaderb and b/Assets/Shaders/DeferredComposite_CS.shshaderb differ diff --git a/Assets/Shaders/ShadowMap_VS.glsl b/Assets/Shaders/ShadowMap_VS.glsl new file mode 100644 index 00000000..e078679e --- /dev/null +++ b/Assets/Shaders/ShadowMap_VS.glsl @@ -0,0 +1,22 @@ +#version 450 +#extension GL_KHR_vulkan_glsl : enable + +//#include "ShaderDescriptorDefinitions.glsl" + + +layout(location = 0) in vec3 aVertexPos; +layout(location = 4) in mat4 worldTransform; + +layout(set = 1, binding = 0) uniform CameraData +{ + vec4 position; + mat4 vpMat; + mat4 viewMat; + mat4 projMat; +} cameraData; + +void main() +{ + // clip space for rendering + gl_Position = cameraData.vpMat * worldTransform * vec4 (aVertexPos, 1.0f); +} \ No newline at end of file diff --git a/Assets/Shaders/ShadowMap_VS.shshaderb b/Assets/Shaders/ShadowMap_VS.shshaderb new file mode 100644 index 00000000..3a8734c9 Binary files /dev/null and b/Assets/Shaders/ShadowMap_VS.shshaderb differ diff --git a/Assets/Shaders/ShadowMap_VS.shshaderb.shmeta b/Assets/Shaders/ShadowMap_VS.shshaderb.shmeta new file mode 100644 index 00000000..837cec19 --- /dev/null +++ b/Assets/Shaders/ShadowMap_VS.shshaderb.shmeta @@ -0,0 +1,3 @@ +Name: ShadowMap_VS +ID: 44646107 +Type: 2 diff --git a/Assets/Shaders/TestCube_FS.glsl b/Assets/Shaders/TestCube_FS.glsl index b6a1eab6..cb7bfefd 100644 --- a/Assets/Shaders/TestCube_FS.glsl +++ b/Assets/Shaders/TestCube_FS.glsl @@ -16,11 +16,12 @@ layout(location = 0) in struct vec4 vertPos; // location 0 vec2 uv; // location = 1 vec4 normal; // location = 2 + vec4 worldPos; // location = 3 } In; // material stuff -layout(location = 3) flat in struct +layout(location = 4) flat in struct { int materialIndex; uint eid; @@ -38,12 +39,14 @@ layout(location = 1) out uint outEntityID; layout(location = 2) out uint lightLayerIndices; layout(location = 3) out vec4 normals; layout(location = 4) out vec4 albedo; +layout(location = 5) out vec4 worldSpacePosition; void main() { position = In.vertPos; normals = In.normal; albedo = texture(textures[nonuniformEXT(MatProp.data[In2.materialIndex].textureIndex)], In.uv) * MatProp.data[In2.materialIndex].color; + worldSpacePosition = In.worldPos; outEntityID = In2.eid; lightLayerIndices = In2.lightLayerIndex; diff --git a/Assets/Shaders/TestCube_FS.shshaderb b/Assets/Shaders/TestCube_FS.shshaderb index abd90cf7..2974523d 100644 Binary files a/Assets/Shaders/TestCube_FS.shshaderb and b/Assets/Shaders/TestCube_FS.shshaderb differ diff --git a/Assets/Shaders/TestCube_VS.glsl b/Assets/Shaders/TestCube_VS.glsl index 554ce379..041c552f 100644 --- a/Assets/Shaders/TestCube_VS.glsl +++ b/Assets/Shaders/TestCube_VS.glsl @@ -17,11 +17,12 @@ layout(location = 0) out struct vec4 vertPos; // location 0 vec2 uv; // location = 1 vec4 normal; // location = 2 + vec4 worldPos; // location = 3 } Out; // material stuff -layout(location = 3) out struct +layout(location = 4) out struct { int materialIndex; uint eid; @@ -49,6 +50,8 @@ void main() // gBuffer position will be in view space Out.vertPos = modelViewMat * vec4(aVertexPos, 1.0f); + Out.worldPos = worldTransform * vec4 (aVertexPos, 1.0f); + // uvs for texturing in fragment shader Out.uv = aUV; diff --git a/Assets/Shaders/TestCube_VS.shshaderb b/Assets/Shaders/TestCube_VS.shshaderb index a1138f75..0467a41d 100644 Binary files a/Assets/Shaders/TestCube_VS.shshaderb and b/Assets/Shaders/TestCube_VS.shshaderb differ diff --git a/SHADE_Engine/src/Camera/SHCameraSystem.cpp b/SHADE_Engine/src/Camera/SHCameraSystem.cpp index 8ef7ff64..6feece48 100644 --- a/SHADE_Engine/src/Camera/SHCameraSystem.cpp +++ b/SHADE_Engine/src/Camera/SHCameraSystem.cpp @@ -270,8 +270,12 @@ namespace SHADE camera.viewMatrix(1, 3) = -UP.Dot(camera.position + camera.offset); camera.viewMatrix(2, 3) = -view.Dot(camera.position + camera.offset); - - + //SHVec3 target{ 0.0f,0.0f,-1.0f }; + //target = SHVec3::RotateX(target, SHMath::DegreesToRadians(camera.pitch)); + //target = SHVec3::RotateY(target, SHMath::DegreesToRadians(camera.yaw)); + //target += camera.position; + + //camera.viewMatrix = SHMatrix::Transpose(SHMatrix::LookAtLH(camera.position, target, SHVec3(0.0f, -1.0f, 0.0f))); camera.dirtyView = false; } @@ -309,7 +313,9 @@ namespace SHADE camera.orthoProjMatrix(2, 3) = -n / (f-n); camera.orthoProjMatrix(3, 3) = 1.0f; - //camera.orthoProjMatrix = SHMatrix::OrthographicRH(camera.GetWidth(), camera.GetHeight(), camera.GetNear(), camera.GetFar()); + //camera.perspProjMatrix = SHMatrix::OrthographicLH(9.0f, 9.0f, 0.1f, 20.0f); + camera.orthoProjMatrix = SHMatrix::OrthographicRH(camera.GetWidth(), camera.GetHeight(), camera.GetNear(), camera.GetFar()); + //camera.perspProjMatrix = SHMatrix::OrthographicLH(5.0f, 5.0f, 0.1f, 20.0f); //camera.projMatrix.Transpose(); camera.dirtyProj = false; diff --git a/SHADE_Engine/src/Editor/SHEditor.cpp b/SHADE_Engine/src/Editor/SHEditor.cpp index 2b8ddbb5..14b37263 100644 --- a/SHADE_Engine/src/Editor/SHEditor.cpp +++ b/SHADE_Engine/src/Editor/SHEditor.cpp @@ -489,7 +489,7 @@ namespace SHADE //auto const& renderers = gfxSystem->GetDefaultViewport()->GetRenderers(); auto renderGraph = gfxSystem->GetRenderGraph(); - auto renderPass = renderGraph->GetNode("ImGui Node")->GetRenderpass(); + auto renderPass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::IMGUI_PASS.data())->GetRenderpass(); if(ImGui_ImplVulkan_Init(&initInfo, renderPass->GetVkRenderpass()) == false) { @@ -508,7 +508,7 @@ namespace SHADE ImGui_ImplVulkan_DestroyFontUploadObjects(); - renderGraph->GetNode("ImGui Node")->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle cmd, Handle renderer, uint32_t frameIndex) + renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::IMGUI_PASS.data())->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle cmd, Handle renderer, uint32_t frameIndex) { cmd->BeginLabeledSegment("ImGui Draw"); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd->GetVkCommandBuffer()); diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp index e77234ca..8143ec0e 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp @@ -175,6 +175,27 @@ namespace SHADE writeInfo.descImageInfos[i].sampler = sampler ? sampler->GetVkSampler() : nullptr; writeInfo.descImageInfos[i].imageLayout = layout; } + + // Rest is not used, so it doesn't matter what's in them, we just want to pacify Vulkan + for (uint32_t i = imageViewsAndSamplers.size(); i < writeInfo.descImageInfos.size(); ++i) + { + writeInfo.descImageInfos[i].sampler = std::get>(imageViewsAndSamplers.back())->GetVkSampler(); + } + } + + void SHVkDescriptorSetGroup::ModifyWriteDescImage(uint32_t set, uint32_t binding, std::tuple, Handle, vk::ImageLayout> const& imageViewAndSampler, uint32_t descIndex) noexcept + { + // Find the target writeDescSet + BindingAndSetHash writeHash = binding; + writeHash |= static_cast(set) << 32; + auto& writeInfo = updater.writeInfos[updater.writeHashMap.at(writeHash)]; + + // write sampler and image view + auto& [view, sampler, layout] = imageViewAndSampler; + writeInfo.descImageInfos[descIndex].imageView = view->GetImageView(); + writeInfo.descImageInfos[descIndex].sampler = sampler ? sampler->GetVkSampler() : nullptr; + writeInfo.descImageInfos[descIndex].imageLayout = layout; + } void SHVkDescriptorSetGroup::ModifyWriteDescBuffer(uint32_t set, uint32_t binding, std::span> const& buffers, uint32_t offset, uint32_t range) noexcept @@ -200,6 +221,28 @@ namespace SHADE } + void SHVkDescriptorSetGroup::UpdateDescriptorSetImage(uint32_t set, uint32_t binding, uint32_t descArrayIndex) noexcept + { + vk::WriteDescriptorSet writeDescSet{}; + + // Get binding + set hash + BindingAndSetHash bsHash = SHVkUtil::GenBindingSetHash(set, binding); + + // to index a write for a binding + uint32_t writeInfoIndex = updater.writeHashMap[bsHash]; + + // Initialize info for write + writeDescSet.descriptorType = layoutsUsed[set]->GetBindings()[binding].Type; + writeDescSet.dstArrayElement = descArrayIndex; + writeDescSet.dstSet = descSets[set]; + writeDescSet.dstBinding = binding; + + writeDescSet.pImageInfo = updater.writeInfos[writeInfoIndex].descImageInfos.data() + descArrayIndex; + writeDescSet.descriptorCount = 1u; + + device->UpdateDescriptorSet(writeDescSet); + } + void SHVkDescriptorSetGroup::UpdateDescriptorSetImages(uint32_t set, uint32_t binding) noexcept { vk::WriteDescriptorSet writeDescSet{}; diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h index a228bc66..5b65174a 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h @@ -63,10 +63,12 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Public member functions */ /*-----------------------------------------------------------------------------*/ + void UpdateDescriptorSetImage (uint32_t set, uint32_t binding, uint32_t descArrayIndex) noexcept; void UpdateDescriptorSetImages(uint32_t set, uint32_t binding) noexcept; void UpdateDescriptorSetBuffer(uint32_t set, uint32_t binding) noexcept; void ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span, Handle, vk::ImageLayout>> const& imageViewsAndSamplers) noexcept; + void ModifyWriteDescImage(uint32_t set, uint32_t binding, std::tuple, Handle, vk::ImageLayout> const& imageViewAndSampler, uint32_t descIndex) noexcept; void ModifyWriteDescBuffer (uint32_t set, uint32_t binding, std::span> const& buffers, uint32_t offset, uint32_t range) noexcept; diff --git a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp index 6a6e385f..5653bbe7 100644 --- a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp +++ b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp @@ -183,33 +183,43 @@ namespace SHADE /*if (!extensionsSupported) SHUtil::ReportWarning("Some of the required extensions cannot be found on the physical device. ");*/ - vk::PhysicalDeviceFeatures features{}; // ADD MORE FEATURES HERE IF NEEDED + vk::PhysicalDeviceDescriptorIndexingFeatures descIndexingFeature + { + .shaderSampledImageArrayNonUniformIndexing = VK_TRUE, + .descriptorBindingPartiallyBound = VK_TRUE, + .descriptorBindingVariableDescriptorCount = VK_TRUE, + .runtimeDescriptorArray = VK_TRUE, + }; + + vk::PhysicalDeviceRobustness2FeaturesEXT robustFeatures + { + .nullDescriptor = VK_TRUE, + }; + + robustFeatures.pNext = &descIndexingFeature; + + vk::PhysicalDeviceFeatures2 features{}; // ADD MORE FEATURES HERE IF NEEDED // point and lines fill mode - features.fillModeNonSolid = VK_TRUE; - features.samplerAnisotropy = VK_TRUE; - features.multiDrawIndirect = VK_TRUE; - features.independentBlend = VK_TRUE; + features.features.fillModeNonSolid = VK_TRUE; + features.features.samplerAnisotropy = VK_TRUE; + features.features.multiDrawIndirect = VK_TRUE; + features.features.independentBlend = VK_TRUE; + features.features.wideLines = VK_TRUE; - // for wide lines - features.wideLines = true; - - vk::PhysicalDeviceDescriptorIndexingFeatures descIndexingFeature{}; - descIndexingFeature.descriptorBindingVariableDescriptorCount = true; - descIndexingFeature.shaderSampledImageArrayNonUniformIndexing = true; - descIndexingFeature.runtimeDescriptorArray = true; + features.pNext = &robustFeatures; // Prepare to create the device vk::DeviceCreateInfo deviceCreateInfo { - .pNext = &descIndexingFeature, + .pNext = &features, .queueCreateInfoCount = static_cast(queueCreateInfos.size()), .pQueueCreateInfos = queueCreateInfos.data(), .enabledLayerCount = 0, // deprecated and ignored .ppEnabledLayerNames = nullptr, // deprecated and ignored .enabledExtensionCount = !extensionsSupported ? 0 : static_cast(requiredExtensions.size()), .ppEnabledExtensionNames = !extensionsSupported ? nullptr : requiredExtensions.data(), - .pEnabledFeatures = &features + //.pEnabledFeatures = &features }; // Actually create the device diff --git a/SHADE_Engine/src/Graphics/Events/SHGraphicsEvents.h b/SHADE_Engine/src/Graphics/Events/SHGraphicsEvents.h index ab120a1f..06c480ef 100644 --- a/SHADE_Engine/src/Graphics/Events/SHGraphicsEvents.h +++ b/SHADE_Engine/src/Graphics/Events/SHGraphicsEvents.h @@ -10,5 +10,8 @@ namespace SHADE { //! We need to get the light component and initialize the relevant variables. EntityID lightEntity; + + //! Generate a renderer for the light component + bool generateRenderer; }; } diff --git a/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp b/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp index 7443b6e2..255fa5e4 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp +++ b/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp @@ -33,6 +33,7 @@ namespace SHADE .maxAnisotropy = 1.0f, .minLod = params.minLod, .maxLod = params.maxLod, + .borderColor = vk::BorderColor::eFloatOpaqueWhite }; // Create the sampler diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp index 7e4069f6..fd2ccd3b 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp @@ -551,7 +551,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* SHBatch - Usage Functions */ /*---------------------------------------------------------------------------------*/ - void SHBatch::Draw(Handle cmdBuffer, uint32_t frameIndex) + void SHBatch::Draw(Handle cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline/* = true*/) { if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) { @@ -566,7 +566,10 @@ namespace SHADE // Bind all required objects before drawing static std::array dynamicOffset{ 0 }; cmdBuffer->BeginLabeledSegment("SHBatch for Pipeline #" + std::to_string(pipeline.GetId().Data.Index)); - cmdBuffer->BindPipeline(pipeline); + + if (bindBatchPipeline) + cmdBuffer->BindPipeline(pipeline); + cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRANSFORM, transformDataBuffer[frameIndex], 0); cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::INTEGER_DATA, instancedIntegerBuffer[frameIndex], 0); if (matPropsDescSet[frameIndex]) diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h index d4ce068e..6d1f775f 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h @@ -87,7 +87,7 @@ namespace SHADE void UpdateTransformBuffer(uint32_t frameIndex); void UpdateInstancedIntegerBuffer(uint32_t frameIndex); void Build(Handle device, Handle descPool, uint32_t frameIndex) ; - void Draw(Handle cmdBuffer, uint32_t frameIndex); + void Draw(Handle cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline = true); /*-----------------------------------------------------------------------------*/ /* Getter Functions */ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp index 58993026..8006d0be 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp @@ -107,12 +107,12 @@ namespace SHADE } } - void SHSuperBatch::Draw(Handle cmdBuffer, uint32_t frameIndex) noexcept + void SHSuperBatch::Draw(Handle cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline /*= true*/) noexcept { // Build all batches for (auto& batch : batches) { - batch.Draw(cmdBuffer, frameIndex); + batch.Draw(cmdBuffer, frameIndex, bindBatchPipeline); } } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h index 75bd1829..4d831b9c 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h @@ -57,7 +57,7 @@ namespace SHADE void Clear() noexcept; void UpdateBuffers(uint32_t frameIndex, Handle descPool); void Build(Handle device, Handle descPool, uint32_t frameIndex) noexcept; - void Draw(Handle cmdBuffer, uint32_t frameIndex) noexcept; + void Draw(Handle cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline = true) noexcept; /*-----------------------------------------------------------------------------*/ /* Getter Functions */ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp index ffe29b36..d5f744fb 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp @@ -13,6 +13,8 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ std::vector> SHGraphicsPredefinedData::predefinedLayouts; SHVertexInputState SHGraphicsPredefinedData::defaultVertexInputState; + SHVertexInputState SHGraphicsPredefinedData::shadowMapVertexInputState; + std::vector SHGraphicsPredefinedData::perSystemData; //SHGraphicsPredefinedData::PerSystem SHGraphicsPredefinedData::batchingSystemData; @@ -150,12 +152,26 @@ namespace SHADE Handle fontDataDescSetLayout = logicalDevice->CreateDescriptorSetLayout({ fontBitmapBinding, fontMatrixBinding }); SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSetLayout, fontDataDescSetLayout->GetVkHandle(), "[Descriptor Set Layout] Font Data"); + // descriptor binding for storing shadow maps + SHVkDescriptorSetLayout::Binding shadowMapBinding + { + .Type = vk::DescriptorType::eCombinedImageSampler, + .Stage = vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment | vk::ShaderStageFlagBits::eCompute, + .BindPoint = SHGraphicsConstants::DescriptorSetBindings::IMAGE_AND_SAMPLERS_DATA, + .DescriptorCount = 200, // we can have up to 200 textures for now + .flags = vk::DescriptorBindingFlagBits::eVariableDescriptorCount, + }; + + // For global data (generic data and textures) + Handle shadowMapDescLayout = logicalDevice->CreateDescriptorSetLayout({ shadowMapBinding }); + SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSetLayout, shadowMapDescLayout->GetVkHandle(), "[Descriptor Set Layout] Shadow Maps"); predefinedLayouts.push_back(staticGlobalLayout); predefinedLayouts.push_back(lightDataDescSetLayout); predefinedLayouts.push_back(cameraDataGlobalLayout); predefinedLayouts.push_back(materialDataPerInstanceLayout); predefinedLayouts.push_back(fontDataDescSetLayout); + predefinedLayouts.push_back(shadowMapDescLayout); perSystemData[SHUtilities::ConvertEnum(SystemType::BATCHING)].descSetLayouts = GetPredefinedDescSetLayouts ( @@ -179,7 +195,7 @@ namespace SHADE ); } - void SHGraphicsPredefinedData::InitDefaultVertexInputState(void) noexcept + void SHGraphicsPredefinedData::InitPredefinedVertexInputState(void) noexcept { defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D) }); // positions at binding 0 defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_2D) }); // UVs at binding 1 @@ -187,13 +203,16 @@ namespace SHADE defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D) }); // Tangents at binding 3 defaultVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::MAT_4D) }); // Transform at binding 4 - 7 (4 slots) defaultVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::UINT32_2D) }); // Instanced integer data at index 8 + + shadowMapVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D)}); + shadowMapVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::MAT_4D) }, 4, 4); // Transform at binding 4 - 7 (4 slots) } void SHGraphicsPredefinedData::Init(Handle logicalDevice) noexcept { perSystemData.resize(SHUtilities::ConvertEnum(SystemType::NUM_TYPES)); InitDescSetLayouts(logicalDevice); - InitDefaultVertexInputState(); + InitPredefinedVertexInputState(); InitDescMappings(); InitDummyPipelineLayouts (logicalDevice); } @@ -217,6 +236,11 @@ namespace SHADE } + SHVertexInputState const& SHGraphicsPredefinedData::GetShadowMapViState(void) noexcept + { + return shadowMapVertexInputState; + } + SHGraphicsPredefinedData::PerSystem const& SHGraphicsPredefinedData::GetSystemData(SystemType systemType) noexcept { return perSystemData[static_cast(systemType)]; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h index 11bfc469..9331ed01 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h @@ -28,6 +28,7 @@ namespace SHADE CAMERA = 0x04, MATERIALS = 0x08, FONT = 0x10, + SHADOW = 0x20, }; enum class SystemType @@ -57,6 +58,9 @@ namespace SHADE //! Default vertex input state (used by everything). static SHVertexInputState defaultVertexInputState; + //! vertex input state for shadow mapping + static SHVertexInputState shadowMapVertexInputState; + //! Predefined data for each type of system static std::vector perSystemData; @@ -72,7 +76,7 @@ namespace SHADE static void InitDescMappings (void) noexcept; static void InitDummyPipelineLayouts (Handle logicalDevice) noexcept; static void InitDescSetLayouts (Handle logicalDevice) noexcept; - static void InitDefaultVertexInputState (void) noexcept; + static void InitPredefinedVertexInputState (void) noexcept; public: /*-----------------------------------------------------------------------*/ @@ -90,6 +94,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ static std::vector> GetPredefinedDescSetLayouts (SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes types) noexcept; static SHVertexInputState const& GetDefaultViState (void) noexcept; + static SHVertexInputState const& GetShadowMapViState (void) noexcept; static PerSystem const& GetSystemData (SystemType systemType) noexcept; static SHDescriptorMappings::MapType const& GetMappings (SystemType systemType) noexcept; //static PerSystem const& GetBatchingSystemData(void) noexcept; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHPredefinedDescriptorTypes.h b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHPredefinedDescriptorTypes.h index 931101f4..fc7f6a1b 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHPredefinedDescriptorTypes.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHPredefinedDescriptorTypes.h @@ -13,7 +13,7 @@ namespace SHADE CAMERA, MATERIALS, FONT, - RENDER_GRAPH_RESOURCE, RENDER_GRAPH_NODE_COMPUTE_RESOURCE, + RENDER_GRAPH_RESOURCE, }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp index 5a694516..e8868eba 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp @@ -101,7 +101,7 @@ namespace SHADE // Register function for subpass //auto const& RENDERERS = gfxSystem->GetDefaultViewport()->GetRenderers(); auto renderGraph = gfxSystem->GetRenderGraph(); - auto subPass = renderGraph->GetNode("Debug Draw")->GetSubpass("Debug Draw"); + auto subPass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW.data())->GetSubpass("Debug Draw"); subPass->AddExteriorDrawCalls([this](Handle cmdBuffer, Handle renderer, uint32_t frameIndex) { // Set line width first @@ -129,7 +129,7 @@ namespace SHADE } cmdBuffer->EndLabeledSegment(); }); - auto subPassWithDepth = renderGraph->GetNode("Debug Draw with Depth")->GetSubpass("Debug Draw with Depth"); + auto subPassWithDepth = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW_DEPTH_PASS.data())->GetSubpass("Debug Draw with Depth"); subPassWithDepth->AddExteriorDrawCalls([this](Handle cmdBuffer, Handle renderer, uint32_t frameIndex) { // Set line width first diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h index c889a321..b3945689 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h @@ -31,68 +31,91 @@ namespace SHADE static constexpr uint32_t EDITOR = 0; }; - //struct DescriptorSetIndex - //{ - // /***************************************************************************/ - // /*! - // \brief - // DescriptorSet Index for static global values like generic data, and - // texture samplers - // */ - // /***************************************************************************/ - // static constexpr uint32_t STATIC_GLOBALS = 0; - // /***************************************************************************/ - // /*! - // \brief - // DescriptorSet Index for dynamic global values like lights. - // */ - // /***************************************************************************/ - // static constexpr uint32_t DYNAMIC_GLOBALS = 1; - // /***************************************************************************/ - // /*! - // \brief - // DescriptorSet Index for high frequency changing global values like - // camera matrices. - // */ - // /***************************************************************************/ - // static constexpr uint32_t HIGH_FREQUENCY_GLOBALS = 2; - // /***************************************************************************/ - // /*! - // \brief - // DescriptorSet Index for per-instance/material changing values. - // */ - // /***************************************************************************/ - // static constexpr uint32_t PER_INSTANCE = 3; - // /***************************************************************************/ - // /*! - // \brief - // DescriptorSet Index for render graph resources. Unlike the sets from - // 1 to 3 and 6, this set index does not have hard coded bindings and is - // NOT part of the layouts included in the global data. - // */ - // /***************************************************************************/ - // static constexpr uint32_t RENDERGRAPH_RESOURCE = 4; - // /***************************************************************************/ - // /*! - // \brief - // DescriptorSet Index for render graph node compute resources. For data - // that we wish to pass to compute shaders in the render graph, this is - // the set to use. Unlike the sets from 1 to 3 and 6, this set index does not have - // hard coded bindings and is NOT part of the layouts included in the global - // data. - // */ - // /***************************************************************************/ - // static constexpr uint32_t RENDERGRAPH_NODE_COMPUTE_RESOURCE = 5; + struct RenderGraphEntityNames + { + /***************************************************************************/ + /*! + + \brief + Name of G-Buffer render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view GBUFFER_PASS = "G-Buffer"; - // /***************************************************************************/ - // /*! - // \brief - // To store font data. - // - // */ - // /***************************************************************************/ - // static constexpr uint32_t FONT_DATA = 4; - //}; + /***************************************************************************/ + /*! + + \brief + Name of shadow map render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view SHADOW_MAP_PASS = "Shadow Map Pass"; + + /***************************************************************************/ + /*! + + \brief + Name of deferred composite render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view DEFERRED_COMPOSITE_PASS = "Deferred Comp Pass"; + + /***************************************************************************/ + /*! + + \brief + Name of Debug Draw with Depth render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view DEBUG_DRAW_DEPTH_PASS = "Debug Draw with Depth Pass"; + + /***************************************************************************/ + /*! + + \brief + Name of Debug Draw render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view DEBUG_DRAW = "Debug Draw Pass"; + + /***************************************************************************/ + /*! + + \brief + Name of screen space pass render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view SCREEN_SPACE_PASS = "Screen Space Pass"; + + /***************************************************************************/ + /*! + + \brief + Name of ImGui pass render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view IMGUI_PASS = "ImGui Pass"; + + /***************************************************************************/ + /*! + + \brief + Name of deferred composite compute. + + */ + /***************************************************************************/ + static constexpr std::string_view DEFERRED_COMPOSITE_COMPUTE = "Deferred Composite"; + + + + }; struct DescriptorSetBindings { @@ -158,6 +181,16 @@ namespace SHADE /***************************************************************************/ static constexpr uint32_t FONT_MATRIX_DATA = 1; + /***************************************************************************/ + /*! + \brief + Descriptor set binding for shadow map images. + + */ + /***************************************************************************/ + static constexpr uint32_t SHADOW_MAP_IMAGE_SAMPLER_DATA = 0; + + }; struct VertexBufferBindings diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index f3bcc8f7..c4990153 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -44,6 +44,9 @@ of DigiPen Institute of Technology is prohibited. #include "Graphics/MiddleEnd/TextRendering/SHFreetypeInstance.h" #include "Graphics/MiddleEnd/TextRendering/SHTextRenderingSubSystem.h" #include "Graphics/MiddleEnd/GlobalData/SHGlobalDescriptorSets.h" +#include "Events/SHEvent.h" +#include "Graphics/MiddleEnd/Lights/SHLightComponent.h" +#include "Input/SHInputManager.h" namespace SHADE { @@ -124,6 +127,13 @@ namespace SHADE SHFreetypeInstance::Init(); + SHAssetManager::CompileAsset("../../Assets/Shaders/DeferredComposite_CS.glsl", false); + SHAssetManager::CompileAsset("../../Assets/Shaders/SSAO_CS.glsl", false); + SHAssetManager::CompileAsset("../../Assets/Shaders/SSAOBlur_CS.glsl", false); + SHAssetManager::CompileAsset("../../Assets/Shaders/PureCopy_CS.glsl", false); + SHAssetManager::CompileAsset("../../Assets/Shaders/TestCube_VS.glsl", false); + SHAssetManager::CompileAsset("../../Assets/Shaders/TestCube_FS.glsl", false); + // Load Built In Shaders static constexpr AssetID VS_DEFAULT = 39210065; defaultVertShader = SHResourceManager::LoadOrGet(VS_DEFAULT); static constexpr AssetID FS_DEFAULT = 46377769; defaultFragShader = SHResourceManager::LoadOrGet(FS_DEFAULT); @@ -137,6 +147,8 @@ namespace SHADE static constexpr AssetID TEXT_FS = 38024754; textFS = SHResourceManager::LoadOrGet(TEXT_FS); static constexpr AssetID RENDER_SC_VS = 48082949; renderToSwapchainVS = SHResourceManager::LoadOrGet(RENDER_SC_VS); static constexpr AssetID RENDER_SC_FS = 36869006; renderToSwapchainFS = SHResourceManager::LoadOrGet(RENDER_SC_FS); + static constexpr AssetID SHADOW_MAP_VS = 44646107; shadowMapVS = SHResourceManager::LoadOrGet(SHADOW_MAP_VS); + } void SHGraphicsSystem::InitRenderGraph(void) noexcept @@ -169,6 +181,8 @@ namespace SHADE // Create Default Viewport worldViewport = AddViewport(vk::Viewport(0.0f, 0.0f, static_cast(window->GetWindowSize().first), static_cast(window->GetWindowSize().second), 0.0f, 1.0f)); + shadowMapViewport = AddViewport(vk::Viewport(0.0f, 0.0f, static_cast(SHLightingSubSystem::SHADOW_MAP_WIDTH), static_cast(SHLightingSubSystem::SHADOW_MAP_HEIGHT), 0.0f, 1.0f)); + std::vector> renderContextCmdPools{ swapchain->GetNumImages() }; for (uint32_t i = 0; i < renderContextCmdPools.size(); ++i) { @@ -183,22 +197,24 @@ namespace SHADE /*-----------------------------------------------------------------------*/ // Initialize world render graph renderGraph->Init("World Render Graph", device, swapchain, &resourceManager, renderContextCmdPools); - renderGraph->AddResource("Position", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); - renderGraph->AddResource("Normals", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); + renderGraph->AddResource("Position", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); + renderGraph->AddResource("Position World Space", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); + renderGraph->AddResource("Normals", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); //worldRenderGraph->AddResource("Tangents", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); - renderGraph->AddResource("Albedo", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second); - renderGraph->AddResource("Depth Buffer", { SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL }, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint); - renderGraph->AddResource("Entity ID", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); - renderGraph->AddResource("Light Layer Indices", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); - renderGraph->AddResource("Scene", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE, SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED }, windowDims.first, windowDims.second); - renderGraph->AddResource("SSAO", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR8Unorm); - renderGraph->AddResource("SSAO Blur", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR8Unorm); - renderGraph->AddResource("Present", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT }, windowDims.first, windowDims.second); + renderGraph->AddResource("Albedo", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second); + renderGraph->AddResource("Depth Buffer", { SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL }, true, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint); + renderGraph->AddResource("Entity ID", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED }, true, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); + renderGraph->AddResource("Light Layer Indices", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); + renderGraph->AddResource("Scene", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE, SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED }, true, windowDims.first, windowDims.second); + renderGraph->AddResource("SSAO", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR8Unorm); + renderGraph->AddResource("SSAO Blur", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR8Unorm); + renderGraph->AddResource("Present", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT }, true, windowDims.first, windowDims.second); /*-----------------------------------------------------------------------*/ /* MAIN NODE */ /*-----------------------------------------------------------------------*/ - auto gBufferNode = renderGraph->AddNode("G-Buffer", + auto gBufferNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(), + //auto gBufferNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data() { "Position", "Entity ID", @@ -207,7 +223,8 @@ namespace SHADE "Albedo", "Depth Buffer", "SSAO", - "SSAO Blur" + "SSAO Blur", + "Position World Space" }, {}); // no predecessors @@ -220,6 +237,7 @@ namespace SHADE gBufferSubpass->AddColorOutput("Light Layer Indices"); gBufferSubpass->AddColorOutput("Normals"); gBufferSubpass->AddColorOutput("Albedo"); + gBufferSubpass->AddColorOutput("Position World Space"); gBufferSubpass->AddDepthOutput("Depth Buffer", SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL); @@ -254,53 +272,52 @@ namespace SHADE // Add another pass to blur SSAO Handle ssaoBlurPass = gBufferNode->AddNodeCompute("SSAO Blur Step", ssaoBlurShader, { "SSAO", "SSAO Blur" }); - /*-----------------------------------------------------------------------*/ - /* SHADOW MAP PASS */ - /*-----------------------------------------------------------------------*/ - // Shadow map pass will have no resources bound at first. Lighting system will add resources to the node. - // It will initially also not have any subpasses since they will be added for each light that casts shadows. - //auto shadowMapPass = renderGraph->AddNode("Shadow Map Pass", {}, {}); - - /*-----------------------------------------------------------------------*/ /* DEFERRED COMPOSITE NODE */ /*-----------------------------------------------------------------------*/ // This pass will facilitate both lighting and shadows in 1 single pass. - auto deferredCompositeNode = renderGraph->AddNode("Deferred Comp Pass", + auto deferredCompositeNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data(), { "Position", "Light Layer Indices", "Normals", "Albedo", "Scene", - "SSAO Blur" + "SSAO Blur", + "Position World Space" }, - {"G-Buffer"}); + { SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS .data()}); + /*-----------------------------------------------------------------------*/ /* DEFERRED COMPOSITE SUBPASS INIT */ /*-----------------------------------------------------------------------*/ - deferredCompositeNode->AddNodeCompute("Deferred Composite", deferredCompositeShader, { "Position", "Normals", "Albedo", "Light Layer Indices", "SSAO Blur", "Scene" }); + auto deferredCompositeCompute = deferredCompositeNode->AddNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data(), deferredCompositeShader, {"Position", "Normals", "Albedo", "Light Layer Indices", "SSAO Blur", "Position World Space", "Scene"}, {}, SHLightingSubSystem::MAX_SHADOWS); + deferredCompositeCompute->AddPreComputeFunction([=](Handle cmdBuffer, uint32_t frameIndex) + { + lightingSubSystem->PrepareShadowMapsForRead(cmdBuffer); + }); + /*-----------------------------------------------------------------------*/ /* DEBUG DRAW PASS INIT */ /*-----------------------------------------------------------------------*/ // Set up Debug Draw Passes // - Depth Tested - auto debugDrawNodeDepth = renderGraph->AddNode("Debug Draw with Depth", { "Scene", "Depth Buffer" }, {"G-Buffer", "Deferred Comp Pass"}); + auto debugDrawNodeDepth = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW_DEPTH_PASS.data(), {"Scene", "Depth Buffer"}, {SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data()}); auto debugDrawDepthSubpass = debugDrawNodeDepth->AddSubpass("Debug Draw with Depth", worldViewport, worldRenderer); debugDrawDepthSubpass->AddColorOutput("Scene"); debugDrawDepthSubpass->AddDepthOutput("Depth Buffer"); // - No Depth Test - auto debugDrawNode = renderGraph->AddNode("Debug Draw", { "Scene" }, { "Debug Draw with Depth" }); + auto debugDrawNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW.data(), {"Scene"}, {SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW_DEPTH_PASS.data()}); auto debugDrawSubpass = debugDrawNode->AddSubpass("Debug Draw", worldViewport, worldRenderer); debugDrawSubpass->AddColorOutput("Scene"); /*-----------------------------------------------------------------------*/ /* SCREEN SPACE PASS */ /*-----------------------------------------------------------------------*/ - auto screenSpaceNode = renderGraph->AddNode("Screen Space Pass", { "Scene", "Entity ID" }, {"Deferred Comp Pass", "G-Buffer", "Debug Draw" }); + auto screenSpaceNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS.data(), {"Scene", "Entity ID"}, {SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW.data()}); auto uiSubpass = screenSpaceNode->AddSubpass("UI", worldViewport, screenRenderer); uiSubpass->AddColorOutput("Scene"); uiSubpass->AddColorOutput("Entity ID"); @@ -315,16 +332,16 @@ namespace SHADE #ifdef SHEDITOR { // Dummy Node to transition scene render graph resource - auto dummyNode = renderGraph->AddNode("Dummy Pass", { "Scene" }, { "Screen Space Pass" }); + auto dummyNode = renderGraph->AddNode("Dummy Pass", { "Scene" }, { SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS .data()}); auto dummySubpass = dummyNode->AddSubpass("Dummy Subpass", {}, {}); dummySubpass->AddInput("Scene"); - auto imGuiNode = renderGraph->AddNode("ImGui Node", { "Present" }, {}); + auto imGuiNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::IMGUI_PASS.data(), {"Present"}, {}); auto imGuiSubpass = imGuiNode->AddSubpass("ImGui Draw", {}, {}); imGuiSubpass->AddColorOutput("Present"); } #else - renderGraph->AddRenderToSwapchainNode("Scene", "Present", { "Screen Space Pass" }, { renderToSwapchainVS, renderToSwapchainFS }); + renderGraph->AddRenderToSwapchainNode("Scene", "Present", { SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS .data()}, {renderToSwapchainVS, renderToSwapchainFS}); #endif @@ -393,12 +410,16 @@ namespace SHADE postOffscreenRenderSubSystem->Init(device, renderGraph->GetRenderGraphResource("Scene"), descPool); lightingSubSystem = resourceManager.Create(); - lightingSubSystem->Init(device, descPool); + lightingSubSystem->Init(device, descPool, &resourceManager, samplerCache.GetSampler (device, SHVkSamplerParams + { + .addressMode = vk::SamplerAddressMode::eClampToBorder, + }) + ); textRenderingSubSystem = resourceManager.Create(); // initialize the text renderer - auto uiNode = renderGraph->GetNode("Screen Space Pass"); + auto uiNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS.data()); textRenderingSubSystem->Init(device, uiNode->GetRenderpass(), uiNode->GetSubpass("UI"), descPool, textVS, textFS); SHGlobalDescriptorSets::SetLightingSubSystem(lightingSubSystem); @@ -426,7 +447,7 @@ namespace SHADE defaultMaterial = AddMaterial ( defaultVertShader, defaultFragShader, - renderGraph->GetNode("G-Buffer")->GetSubpass("G-Buffer Write") + renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data())->GetSubpass("G-Buffer Write") ); defaultMaterial->SetProperty("data.textureIndex", defaultTexture->TextureArrayIndex); } @@ -451,6 +472,7 @@ namespace SHADE InitMiddleEnd(); InitSubsystems(); InitBuiltInResources(); + InitEvents(); } void SHGraphicsSystem::Exit(void) @@ -546,6 +568,15 @@ namespace SHADE #endif } + if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::B)) + { + auto& lightComps = SHComponentManager::GetDense(); + for (auto& comp : lightComps) + { + comp.SetEnableShadow(true); + } + } + renderGraph->Begin(frameIndex); auto cmdBuffer = renderGraph->GetCommandBuffer(frameIndex); @@ -726,16 +757,61 @@ namespace SHADE renderers.erase(iter); } - SHEventHandle SHGraphicsSystem::ReceiveLightEnableShadowEvent(SHEventPtr event) noexcept + 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* lightComp = SHComponentManager::GetComponent(EVENT_DATA->lightEntity); + std::string resourceName = "ShadowMap " + std::to_string(EVENT_DATA->lightEntity); + Handle companionSubpass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data())->GetSubpass("G-Buffer Write"); + + if (EVENT_DATA->generateRenderer) + { + // 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(resourceName, {SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT}, false, SHLightingSubSystem::SHADOW_MAP_WIDTH, SHLightingSubSystem::SHADOW_MAP_HEIGHT, vk::Format::eD32Sfloat); // 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() + resourceName, {resourceName.c_str()}, SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data()); // Add a subpass to render to that shadow map + auto newSubpass = shadowMapNode->RuntimeAddSubpass(resourceName + " Subpass", shadowMapViewport, lightComp->GetRenderer()); + newSubpass->AddDepthOutput(resourceName, SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH); + + // 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, {} }, shadowMapNode->GetRenderpass(), newSubpass, SHGraphicsPredefinedData::GetShadowMapViState(), rasterState); + shadowMapPipeline = tempLibrary.GetGraphicsPipeline({ shadowMapVS, {} }); + } + newSubpass->SetCompanionSubpass(companionSubpass, shadowMapPipeline); // set companion subpass and pipeline - //renderGraph->GetNode (); - return event->handle; + // add the shadow map to the lighting system + uint32_t const NEW_SHADOW_MAP_INDEX = lightingSubSystem->AddShadowMap(renderGraph->GetRenderGraphResource(resourceName), 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; } Handle SHGraphicsSystem::AddMaterial(Handle vertShader, Handle fragShader, Handle subpass) @@ -1047,6 +1123,7 @@ namespace SHADE mousePickSubSystem->HandleResize(); postOffscreenRenderSubSystem->HandleResize(); + //lightingSubSystem->HandleResize(renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data())->GetNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data())); worldViewport->SetWidth(static_cast(resizeWidth)); worldViewport->SetHeight(static_cast(resizeHeight)); @@ -1079,7 +1156,7 @@ namespace SHADE Handle SHGraphicsSystem::GetPrimaryRenderpass() const noexcept { - return renderGraph->GetNode(G_BUFFER_RENDER_GRAPH_NODE_NAME.data()); + return renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data()); } Handle SHGraphicsSystem::GetDebugDrawPipeline(DebugDrawPipelineType type) const noexcept diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h index 707862f9..c736599f 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h @@ -178,7 +178,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* Light functions */ /*-----------------------------------------------------------------------*/ - SHEventHandle ReceiveLightEnableShadowEvent (SHEventPtr event) noexcept; + SHEventHandle ReceiveLightEnableShadowEvent (SHEventPtr eventPtr) noexcept; /*-----------------------------------------------------------------------------*/ /* Material Functions */ @@ -406,10 +406,6 @@ namespace SHADE SHWindow* GetWindow() noexcept { return window; } private: - /*-----------------------------------------------------------------------------*/ - /* Constants */ - /*-----------------------------------------------------------------------------*/ - static constexpr std::string_view G_BUFFER_RENDER_GRAPH_NODE_NAME = "G-Buffer"; /*-----------------------------------------------------------------------------*/ /* Data Members */ @@ -446,6 +442,7 @@ namespace SHADE #endif Handle worldViewport; // Whole screen + Handle shadowMapViewport; std::vector> viewports; // Additional viewports // Renderers @@ -469,6 +466,7 @@ namespace SHADE Handle textFS; Handle renderToSwapchainVS; Handle renderToSwapchainFS; + Handle shadowMapVS; // Fonts Handle testFont; @@ -483,6 +481,7 @@ namespace SHADE Handle debugDrawWireMeshDepthPipeline; Handle debugDrawFilledPipeline; Handle debugDrawFilledDepthPipeline; + Handle shadowMapPipeline; // initialized only when a shadow map is needed // Built-In Textures Handle defaultTexture; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp index f1d4dc7f..731489fb 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp @@ -122,4 +122,9 @@ namespace SHADE return cameraDirector; } + SHShaderCameraData SHRenderer::GetCPUCameraData(void) const noexcept + { + return cpuCameraData; + } + } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h index baf76187..867851ee 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h @@ -18,9 +18,9 @@ of DigiPen Institute of Technology is prohibited. // Project Includes #include "SHCamera.h" #include "Resource/SHHandle.h" -#include "Graphics/RenderGraph/SHRenderGraph.h" #include "Math/SHMath.h" #include +#include "Graphics/Pipeline/SHPipelineType.h" namespace SHADE { @@ -93,6 +93,7 @@ namespace SHADE /* Setters and Getters */ /*-----------------------------------------------------------------------------*/ Handle GetCameraDirector (void) const noexcept; + SHShaderCameraData GetCPUCameraData (void) const noexcept; private: /*-----------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp index 362b0e8f..6943ec09 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp @@ -2,6 +2,7 @@ #include "SHLightComponent.h" #include "Graphics/Events/SHGraphicsEvents.h" #include "Events/SHEventManager.hpp" +#include "Graphics/MiddleEnd/Interface/SHRenderer.h" namespace SHADE { @@ -14,6 +15,7 @@ namespace SHADE //indexInBuffer = std::numeric_limits::max(); isActive = true; //Unbind(); + renderer = {}; } @@ -116,11 +118,22 @@ namespace SHADE // Create new event and broadcast it SHLightEnableShadowEvent newEvent; newEvent.lightEntity = GetEID(); + newEvent.generateRenderer = static_cast(!renderer); SHEventManager::BroadcastEvent(newEvent, SH_GRAPHICS_LIGHT_ENABLE_SHADOW_EVENT); } } + void SHLightComponent::SetRenderer(Handle newRenderer) noexcept + { + renderer = newRenderer; + } + + void SHLightComponent::SetShadowMapIndex(uint32_t index) noexcept + { + lightData.shadowMapIndex = index; + } + SHLightData const& SHLightComponent::GetLightData(void) const noexcept { return lightData; @@ -172,6 +185,11 @@ namespace SHADE return lightData.strength; } + Handle SHLightComponent::GetRenderer(void) const noexcept + { + return renderer; + } + } RTTR_REGISTRATION diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h index 1d636595..4974f3f5 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h @@ -3,9 +3,11 @@ #include #include "ECS_Base/Components/SHComponent.h" #include "SHLightData.h" +#include "Resource/SHHandle.h" namespace SHADE { + class SHRenderer; class SH_API SHLightComponent final : public SHComponent { @@ -14,6 +16,9 @@ namespace SHADE //! GPU depends on the type of the light. SHLightData lightData; + //! Renderer to calculate light world to projection matrix + Handle renderer; + //! Since the lighting system is gonna be self contained and light weight, we store this //! so that we only write this to the CPU buffer when this light component change, we don't //! rewrite everything. However we still write to the GPU buffer when everything changes. @@ -49,6 +54,8 @@ namespace SHADE //void SetBound (uint32_t inIndexInBuffer) noexcept; void SetStrength (float value) noexcept; // serialized void SetEnableShadow (bool flag) noexcept; + void SetRenderer (Handle newRenderer) noexcept; + void SetShadowMapIndex (uint32_t index) noexcept; SHLightData const& GetLightData (void) const noexcept; @@ -61,6 +68,7 @@ namespace SHADE //bool GetBound (void) const noexcept; //uint32_t GetIndexInBuffer (void) const noexcept; float GetStrength (void) const noexcept; + Handle GetRenderer (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 ddacf3a7..9acdfed0 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp @@ -10,6 +10,13 @@ #include "SHLightComponent.h" #include "Math/Vector/SHVec4.h" #include "Math/SHMatrix.h" +#include "Graphics/Images/SHVkImageView.h" +#include "Graphics/MiddleEnd/Textures/SHVkSamplerCache.h" +#include "Graphics/Images/SHVkSampler.h" +#include "Graphics/Events/SHGraphicsEvents.h" +#include "Graphics/MiddleEnd/Interface/SHRenderer.h" +#include "Math/Transform/SHTransformComponent.h" +#include "Graphics/RenderGraph/SHRenderGraphNodeCompute.h" namespace SHADE { @@ -50,6 +57,19 @@ namespace SHADE //lightPtr->direction = lightData.direction; lightPtr->diffuseColor = lightData.color; lightPtr->active = lightComp->isActive; + + // write view projection matrix if renderer is available + auto lightRenderer = lightComp->GetRenderer(); + if (lightRenderer) + { + lightPtr->pvMatrix = lightRenderer->GetCPUCameraData().viewProjectionMatrix; + + // Boolean to cast shadows in first 8 bits (1 byte) + lightPtr->shadowData = lightData.castShadows; + + // Next 24 bits for shadow map index + lightPtr->shadowData |= (lightData.shadowMapIndex << 8); + } break; } case SH_LIGHT_TYPE::POINT: @@ -365,6 +385,32 @@ namespace SHADE } } + void SHLightingSubSystem::UpdateShadowMapDesc(void) noexcept + { + + } + + SHMatrix SHLightingSubSystem::GetViewMatrix(SHLightComponent* lightComp) noexcept + { + switch (lightComp->GetLightData().type) + { + case SH_LIGHT_TYPE::DIRECTIONAL: + return SHMatrix::Transpose(SHMatrix::LookAtLH(lightComp->GetLightData().position, SHVec3::Normalise (lightComp->GetLightData().direction), SHVec3(0.0f, -1.0f, 0.0f))); + //return SHMatrix::Transpose(SHMatrix::LookAtLH(/*lightComp->GetLightData().position*/SHVec3(1.27862f, 4.78952f, 4.12811f), SHVec3(-0.280564f, -0.66262f, -0.69422f), SHVec3(0.0f, -1.0f, 0.0f))); + case SH_LIGHT_TYPE::POINT: + return {}; + case SH_LIGHT_TYPE::SPOT: + return {}; + case SH_LIGHT_TYPE::AMBIENT: + return {}; + case SH_LIGHT_TYPE::NUM_TYPES: + return {}; + default: + return {}; + + } + } + /***************************************************************************/ /*! @@ -375,13 +421,15 @@ namespace SHADE */ /***************************************************************************/ - void SHLightingSubSystem::Init(Handle device, Handle descPool) noexcept + void SHLightingSubSystem::Init(Handle device, Handle descPool, SHResourceHub* rh, Handle inShadowMapSampler) noexcept { SHComponentManager::CreateComponentSparseSet(); logicalDevice = device; + resourceHub = rh; uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ConvertEnum(SH_LIGHT_TYPE::NUM_TYPES); +#pragma region LIGHTING std::vector variableSizes{ NUM_LIGHT_TYPES }; std::fill (variableSizes.begin(), variableSizes.end(), 1); @@ -418,7 +466,22 @@ namespace SHADE dynamicOffsets[i].resize(NUM_LIGHT_TYPES + 1); // +1 for the count } +#pragma endregion + +#pragma region SHADOWS + //std::vector shadowDescVariableSizes{ MAX_SHADOWS }; + //shadowMapDescriptorSet = descPool->Allocate({SHGraphicsPredefinedData::GetPredefinedDescSetLayouts(SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes::SHADOW)}, shadowDescVariableSizes); + +//#ifdef _DEBUG +// const auto& SHADOW_MAP_DESC_SETS = shadowMapDescriptorSet->GetVkHandle(); +// for (int i = 0; i < static_cast(SHADOW_MAP_DESC_SETS.size()); ++i) +// SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSet, SHADOW_MAP_DESC_SETS[i], "[Descriptor Set] Shadow Map Data Frame #" + std::to_string(i)); +//#endif + + shadowMapSampler = inShadowMapSampler; + shadowMaps.clear(); //numLightComponents = 0; +#pragma endregion } /***************************************************************************/ @@ -452,6 +515,12 @@ namespace SHADE for (auto& light : lightComps) { + if (auto renderer = light.GetRenderer()) + { + //SHMatrix orthoMatrix = SHMatrix::OrthographicRH() + renderer->UpdateDataManual(frameIndex, GetViewMatrix(&light), SHMatrix::OrthographicLH(10.0f, 10.0f, 1.0f, 50.0f)); + } + auto enumValue = SHUtilities::ConvertEnum(light.GetLightData().type); // First we want to make sure the light is already bound to the system. if it @@ -503,7 +572,6 @@ namespace SHADE // so we do it anyway. #NoteToSelf: if at any point it affects performance, do a check before computing. ComputeDynamicOffsets(); - } /***************************************************************************/ @@ -526,9 +594,101 @@ namespace SHADE } + uint32_t SHLightingSubSystem::AddShadowMap(Handle newShadowMap, EntityID lightEntity) noexcept + { + // Add to container of shadow maps + shadowMapIndexing.emplace(lightEntity, static_cast (shadowMaps.size())); + shadowMaps.emplace_back(newShadowMap); + + // Just use the image view stored in the resource + Handle const NEW_IMAGE_VIEW = newShadowMap->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 + { + .srcAccessMask = vk::AccessFlagBits::eDepthStencilAttachmentWrite, + .dstAccessMask = vk::AccessFlagBits::eShaderRead, + .oldLayout = vk::ImageLayout::eDepthAttachmentOptimal, + .newLayout = vk::ImageLayout::eShaderReadOnlyOptimal, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = newShadowMap->GetImage()->GetVkImage(), + .subresourceRange = vk::ImageSubresourceRange + { + .aspectMask = vk::ImageAspectFlagBits::eDepth, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + } + }); + + // return new index of shadow map + return static_cast(shadowMapImageSamplers.size()) - 1u; + } + + void SHLightingSubSystem::PrepareShadowMapsForRead(Handle cmdBuffer) noexcept + { + // Issue barrier to transition shadow maps for reading in compute shader + cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eEarlyFragmentTests | vk::PipelineStageFlagBits::eLateFragmentTests, 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; } + std::tuple, Handle, vk::ImageLayout> const& SHLightingSubSystem::GetViewSamplerLayout(uint32_t index) const noexcept + { + return shadowMapImageSamplers[index]; + } + + uint32_t SHLightingSubSystem::GetNumShadowMaps(void) const noexcept + { + return static_cast(shadowMaps.size()); + } + } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h index fa103136..7794a2fb 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h @@ -3,9 +3,13 @@ #include "Resource/SHHandle.h" #include "Math/Vector/SHVec3.h" #include "Math/Vector/SHVec4.h" +#include "Math/SHMatrix.h" #include "SHLightData.h" #include #include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" +#include "Graphics/RenderGraph/SHRenderGraphResource.h" +#include "ECS_Base/SHECSMacros.h" + namespace SHADE { @@ -16,6 +20,10 @@ namespace SHADE class SHVkBuffer; class SHLightComponent; class SHVkCommandBuffer; + class SHSamplerCache; + class SHVkImageView; + class SHVkSampler; + class SHRenderGraphNodeCompute; // Represents how the data will be interpreted in GPU. we want to copy to a container of these before passing to GPU. struct SHDirectionalLightData @@ -34,6 +42,12 @@ namespace SHADE //! Diffuse color emitted by the light alignas (16) SHVec4 diffuseColor; + //! Matrix for world to projection from light's perspective + SHMatrix pvMatrix; + + //! Represents boolean for casting shadows in first byte and shadow map index in the other 3. + uint32_t shadowData; + }; // Represents how the data will be interpreted in GPU. we want to copy to a container of these before passing to GPU. @@ -52,24 +66,27 @@ namespace SHADE //! when a fragment is being evaluated, the shader will use the fragment's //! layer value to AND with the light's. If result is 1, do lighting calculations. uint32_t cullingMask; - - }; class SH_API SHLightingSubSystem { public: using DynamicOffsetArray = std::array, static_cast(SHGraphicsConstants::NUM_FRAME_BUFFERS)>; - + static constexpr uint32_t MAX_SHADOWS = 200; + static constexpr uint32_t SHADOW_MAP_WIDTH = 1024; + static constexpr uint32_t SHADOW_MAP_HEIGHT = 1024; private: class PerTypeData { + public: + + private: /*-----------------------------------------------------------------------*/ /* STATIC MEMBER VARIABLES */ /*-----------------------------------------------------------------------*/ - static constexpr uint32_t STARTING_NUM_LIGHTS = 50; + static constexpr uint32_t STARTING_NUM_LIGHTS = 50; /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ @@ -123,51 +140,90 @@ namespace SHADE }; private: + /*-----------------------------------------------------------------------*/ + /* STATIC MEMBER VARIABLES */ + /*-----------------------------------------------------------------------*/ + //! logical device used for creation - Handle logicalDevice; + Handle logicalDevice; //! The descriptor set that will hold the lighting data. Each binding will hold a buffer, NUM_FRAMES times the size required. - Handle lightingDataDescSet; - - //! Each type will have some data associated with it for processing - std::array(SH_LIGHT_TYPE::NUM_TYPES)> perTypeData; - - //! Container to store dynamic offsets for binding descriptor sets - DynamicOffsetArray dynamicOffsets; - - //! holds the data that represents how many lights are in the scene - std::array(SH_LIGHT_TYPE::NUM_TYPES)> lightCountsData; - - //! GPU buffer to hold lightCountData - Handle lightCountsBuffer; - - //! For padding in the buffer - uint32_t lightCountsAlignedSize; + Handle lightingDataDescSet; + + //! Each type will have some data associated with it for processing + std::array(SH_LIGHT_TYPE::NUM_TYPES)> perTypeData; + + //! Container to store dynamic offsets for binding descriptor sets + DynamicOffsetArray dynamicOffsets; + + //! holds the data that represents how many lights are in the scene + std::array(SH_LIGHT_TYPE::NUM_TYPES)> lightCountsData; + + //! GPU buffer to hold lightCountData + Handle lightCountsBuffer; + + //! For padding in the buffer + uint32_t lightCountsAlignedSize; //! Number of SHLightComponents recorded. If at the beginning of the run function the size returned by the dense //! set is less than the size recorded, rewrite all light components into the its respective buffers. If its more, //! don't do anything. //uint32_t numLightComponents; + //! Handle to sampler that all shadow map descriptors will use + Handle shadowMapSampler; + + //! For indexing shadow maps + std::unordered_map shadowMapIndexing; + + //! 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; + + //! Barriers required to transition the resources from whatever layout they are in (probably from VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) + //! to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) + std::vector shadowMapMemoryBarriers; + + //! Resource hub from Graphics System + SHResourceHub* resourceHub; + + /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ void UpdateDescSet (uint32_t binding) noexcept; void ComputeDynamicOffsets (void) noexcept; void ResetNumLights (void) noexcept; + void UpdateShadowMapDesc (void) noexcept; + SHMatrix GetViewMatrix (SHLightComponent* lightComp) noexcept; public: /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ - void Init (Handle device, Handle descPool) noexcept; - void Run (SHMatrix const& viewMat, uint32_t frameIndex) noexcept; - void Exit (void) 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 newShadowMap, EntityID lightEntity) noexcept; + void PrepareShadowMapsForRead (Handle cmdBuffer) noexcept; + //void HandleResize (Handle compute) noexcept; + //void RemoveShadowMap (uint32_t index) noexcept; - void BindDescSet (Handle cmdBuffer, uint32_t setIndex, uint32_t frameIndex) noexcept; + /*-----------------------------------------------------------------------*/ + /* SETTERS AND GETTERS */ + /*-----------------------------------------------------------------------*/ Handle GetLightDataDescriptorSet (void) const noexcept; + std::tuple, Handle, vk::ImageLayout> const& GetViewSamplerLayout (uint32_t index) const noexcept; + uint32_t GetNumShadowMaps (void) const noexcept; }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp index baf09a2d..74795034 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp @@ -1,18 +1,23 @@ #include "SHpch.h" #include "SHPipelineLibrary.h" #include "Graphics/Devices/SHVkLogicalDevice.h" -#include "Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h" #include "Graphics/RenderGraph/SHSubpass.h" #include "Graphics/SHVkUtil.h" namespace SHADE { - Handle SHPipelineLibrary::CreateGraphicsPipelines(std::pair, Handle> const& vsFsPair, Handle renderpass, Handle subpass) noexcept + Handle SHPipelineLibrary::CreateGraphicsPipelines(std::pair, Handle> const& vsFsPair, Handle renderpass, Handle subpass, SHVertexInputState const& viState/* = SHGraphicsPredefinedData::GetDefaultViState()*/, SHRasterizationState const& rasterState) noexcept { + std::vector> modules{}; + if (vsFsPair.first) + modules.push_back(vsFsPair.first); + if (vsFsPair.second) + modules.push_back(vsFsPair.second); + SHPipelineLayoutParams params { - .shaderModules = {vsFsPair.first, vsFsPair.second}, + .shaderModules = std::move(modules), .predefinedDescSetLayouts = SHGraphicsPredefinedData::GetSystemData(SHGraphicsPredefinedData::SystemType::BATCHING).descSetLayouts }; @@ -21,7 +26,7 @@ namespace SHADE // Create the pipeline and configure the default vertex input state auto newPipeline = logicalDevice->CreateGraphicsPipeline(pipelineLayout, nullptr, renderpass, subpass); - newPipeline->GetPipelineState().SetVertexInputState(SHGraphicsPredefinedData::GetDefaultViState()); + newPipeline->GetPipelineState().SetVertexInputState(viState); SHColorBlendState colorBlendState{}; colorBlendState.logic_op_enable = VK_FALSE; @@ -30,6 +35,7 @@ namespace SHADE auto const& subpassColorReferences = subpass->GetColorAttachmentReferences(); colorBlendState.attachments.reserve(subpassColorReferences.size()); + for (auto& att : subpassColorReferences) { colorBlendState.attachments.push_back(vk::PipelineColorBlendAttachmentState @@ -47,6 +53,8 @@ namespace SHADE } newPipeline->GetPipelineState().SetColorBlenState(colorBlendState); + + newPipeline->GetPipelineState().SetRasterizationState(rasterState); // Actually construct the pipeline newPipeline->ConstructPipeline(); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h index 5085f21f..ca46c71a 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h @@ -3,6 +3,7 @@ #include #include "Graphics/Shaders/SHVkShaderModule.h" #include "Graphics/Pipeline/SHVkPipeline.h" +#include "Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h" namespace SHADE { @@ -32,7 +33,9 @@ namespace SHADE Handle CreateGraphicsPipelines ( std::pair, Handle> const& vsFsPair, Handle renderpass, - Handle subpass + Handle subpass, + SHVertexInputState const& viState = SHGraphicsPredefinedData::GetDefaultViState(), + SHRasterizationState const& rasterState = SHRasterizationState{} ) noexcept; Handle GetGraphicsPipeline (std::pair, Handle> const& vsFsPair) noexcept; bool CheckGraphicsPipelineExistence (std::pair, Handle> const& vsFsPair) noexcept; diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.cpp b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.cpp index c7ada11f..30d81d89 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.cpp +++ b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.cpp @@ -195,7 +195,7 @@ namespace SHADE return *this; } - void SHVertexInputState::AddBinding(bool instanced, bool calcOffset, std::initializer_list inAttribs) noexcept + void SHVertexInputState::AddBinding(bool instanced, bool calcOffset, std::initializer_list inAttribs, uint32_t fixedBinding /*= static_cast(-1)*/, uint32_t fixedAttributeLocation/* = static_cast(-1)*/) noexcept { // add a binding and get ref to it bindings.emplace_back(); @@ -210,7 +210,7 @@ namespace SHADE // Offset is 0 at first (for first element) uint32_t offset = 0; - binding.binding = static_cast(bindings.size() - 1); + binding.binding = (fixedBinding != static_cast(-1)) ? fixedBinding : static_cast(bindings.size() - 1); // for every attribute passed in for (auto const& attrib : inAttribs) @@ -226,10 +226,11 @@ namespace SHADE auto& vertexAttrib = attributes.back(); // The binding for that attribute description is index of the new binding created earlier in this function - vertexAttrib.binding = static_cast(bindings.size() - 1); + vertexAttrib.binding = (fixedBinding != static_cast(-1)) ? fixedBinding : static_cast(bindings.size() - 1); - // Attribute location. New index is simply + 1 of the previous. Starts from 0 obviously - vertexAttrib.location = static_cast(attributes.size () - 1); + //Attribute location. New index is simply + 1 of the previous. Starts from 0 obviously + vertexAttrib.location = (fixedAttributeLocation != static_cast(-1)) ? fixedAttributeLocation + i : static_cast(attributes.size () - 1); + //vertexAttrib.location = static_cast(attributes.size() - 1); // Get the vkFormat associated with the SHAttribFormat vertexAttrib.format = format; diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.h b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.h index 4c8d679a..73eb1ef5 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.h +++ b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.h @@ -34,7 +34,7 @@ namespace SHADE SHVertexInputState& operator= (SHVertexInputState const& rhs) noexcept; SHVertexInputState& operator= (SHVertexInputState&& rhs) noexcept; - void AddBinding(bool instanced, bool calcOffset, std::initializer_list inAttribs) noexcept; + void AddBinding(bool instanced, bool calcOffset, std::initializer_list inAttribs, uint32_t fixedBinding = static_cast(-1), uint32_t fixedAttributeLocation = static_cast(-1)) noexcept; friend class SHVkPipelineState; friend class SHVkPipeline; diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp index c2d83052..6a6ef879 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp +++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp @@ -19,69 +19,71 @@ namespace SHADE for (auto& shaderModule : shaderModules) { - // References for convenience - auto const& reflectedData = shaderModule->GetReflectedData(); - auto const& pcInfo = reflectedData.GetPushConstantInfo(); - - // If a push constant block exists for the shader module - if (pcInfo.memberCount != 0) + if (shaderModule) { - bool exists = false; + // References for convenience + auto const& reflectedData = shaderModule->GetReflectedData(); + auto const& pcInfo = reflectedData.GetPushConstantInfo(); - // Check if push constant block already exists - for (uint32_t i = 0; i < pcInfos.size(); ++i) + // If a push constant block exists for the shader module + if (pcInfo.memberCount != 0) { - // If there is a block with the same name, member count and size - if (std::strcmp(pcInfos[i]->name, pcInfo.name) == 0 && pcInfos[i]->memberCount == pcInfo.memberCount && pcInfos[i]->size == pcInfo.size) + bool exists = false; + + // Check if push constant block already exists + for (uint32_t i = 0; i < pcInfos.size(); ++i) { - // We just take the existing pc range we built earlier, and allow it to be accessed in potentially other shader stages - vkPcRanges[i].stageFlags |= shaderModule->GetShaderStageFlagBits(); + // If there is a block with the same name, member count and size + if (std::strcmp(pcInfos[i]->name, pcInfo.name) == 0 && pcInfos[i]->memberCount == pcInfo.memberCount && pcInfos[i]->size == pcInfo.size) + { + // We just take the existing pc range we built earlier, and allow it to be accessed in potentially other shader stages + vkPcRanges[i].stageFlags |= shaderModule->GetShaderStageFlagBits(); - // Set flag and stop checking - exists = true; - break; - } - } - - // If the block doesn't exist yet - if (!exists) - { - // Loop through all member variables of the new push constant block - for (uint32_t i = 0; i < pcInfo.memberCount; ++i) - { - std::string variableName; - variableName.reserve(50); - variableName += pcInfo.name; - variableName += "."; - variableName += pcInfo.members[i].name; - - // Add the variable's offset info to the interface - pushConstantInterface.AddOffset(std::move(variableName), startOffset + pcInfo.members[i].offset); + // Set flag and stop checking + exists = true; + break; + } } - // New push constant range - vk::PushConstantRange newRange; + // If the block doesn't exist yet + if (!exists) + { + // Loop through all member variables of the new push constant block + for (uint32_t i = 0; i < pcInfo.memberCount; ++i) + { + std::string variableName; + variableName.reserve(50); + variableName += pcInfo.name; + variableName += "."; + variableName += pcInfo.members[i].name; - // set offset and size - newRange.offset = startOffset; - newRange.size = pcInfo.size; + // Add the variable's offset info to the interface + pushConstantInterface.AddOffset(std::move(variableName), startOffset + pcInfo.members[i].offset); + } - // Stage flags will be whatever shader stage of the shader that contains the push constant block - newRange.stageFlags = shaderModule->GetShaderStageFlagBits(); + // New push constant range + vk::PushConstantRange newRange; - // Add to the list foe checking later - pcInfos.push_back(&pcInfo); + // set offset and size + newRange.offset = startOffset; + newRange.size = pcInfo.size; - // For pipeline layout to consume - vkPcRanges.push_back(newRange); + // Stage flags will be whatever shader stage of the shader that contains the push constant block + newRange.stageFlags = shaderModule->GetShaderStageFlagBits(); - // Next push constant block will start next to the previous push constant block - startOffset += pcInfo.size; + // Add to the list foe checking later + pcInfos.push_back(&pcInfo); + + // For pipeline layout to consume + vkPcRanges.push_back(newRange); + + // Next push constant block will start next to the previous push constant block + startOffset += pcInfo.size; + } + + stageFlags |= shaderModule->GetShaderStageFlagBits(); } - - stageFlags |= shaderModule->GetShaderStageFlagBits(); } - } // After all the sizes of the push constant blocks have been added, record the size in the interface @@ -132,6 +134,9 @@ namespace SHADE //! Now we take descriptor set info from all shaders and prepare some bindings for the descriptor set for (auto& shaderModule : shaderModules) { + if (!shaderModule) + continue; + auto const& descBindingInfo = shaderModule->GetReflectedData().GetDescriptorBindingInfo(); auto const& reflectedSets = descBindingInfo.GetReflectedSets(); @@ -200,10 +205,12 @@ namespace SHADE newBinding.DescriptorCount = SHVkDescriptorSetLayout::Binding::VARIABLE_DESCRIPTOR_UPPER_BOUND; // Set the flags for variable bindings - newBinding.flags = vk::DescriptorBindingFlagBits::eVariableDescriptorCount; + newBinding.flags = vk::DescriptorBindingFlagBits::eVariableDescriptorCount | vk::DescriptorBindingFlagBits::ePartiallyBound; } else + { SHLOG_ERROR("Variable size binding is detected, but the binding is not the last binding of the set and is therefore invalid. "); + } } setsWithBindings[CURRENT_SET].emplace_back(newBinding); @@ -326,11 +333,10 @@ namespace SHADE { for (auto& mod : shaderModules) { - mod->AddCallback([this]() - { - RecreateIfNeeded(); - } - ); + if (mod) + { + mod->AddCallback([this]() { RecreateIfNeeded(); }); + } } RecreateIfNeeded (); diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp index 74371a64..74ea951a 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp @@ -54,7 +54,7 @@ namespace SHADE */ /***************************************************************************/ - void SHRenderGraph::AddResource(std::string resourceName, std::initializer_list typeFlags, uint32_t w /*= static_cast(-1)*/, uint32_t h /*= static_cast(-1)*/, vk::Format format/* = vk::Format::eB8G8R8A8Unorm*/, uint8_t levels /*= 1*/, vk::ImageUsageFlagBits usageFlags/* = {}*/, vk::ImageCreateFlagBits createFlags /*= {}*/) + void SHRenderGraph::AddResource(std::string resourceName, std::initializer_list typeFlags, bool resizeWithWindow, uint32_t w /*= static_cast(-1)*/, uint32_t h /*= static_cast(-1)*/, vk::Format format/* = vk::Format::eB8G8R8A8Unorm*/, uint8_t levels /*= 1*/, vk::ImageUsageFlagBits usageFlags/* = {}*/, vk::ImageCreateFlagBits createFlags /*= {}*/) { // If we set to if (w == static_cast(-1) && h == static_cast(-1)) @@ -64,7 +64,7 @@ namespace SHADE format = renderGraphStorage->swapchain->GetSurfaceFormatKHR().format; } - auto resource = renderGraphStorage->resourceHub->Create(renderGraphStorage, resourceName, typeFlags, format, w, h, levels, usageFlags, createFlags); + auto resource = renderGraphStorage->resourceHub->Create(renderGraphStorage, resourceName, typeFlags, format, w, h, levels, usageFlags, createFlags, resizeWithWindow); renderGraphStorage->graphResources->try_emplace(resourceName, resource); } @@ -106,6 +106,9 @@ namespace SHADE for (auto& affectedNode : affectedNodes) nodes[affectedNode]->CreateFramebuffer(); + + renderGraphStorage->graphResources->at(resourceName).Free(); + renderGraphStorage->graphResources->erase (resourceName); /* * IMPORTANT NOTES * @@ -166,68 +169,7 @@ namespace SHADE for (uint32_t i = 0; auto& node : nodes) { - // 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; - } - - // We first want to take all resources track their layout as undefined at the start of the node/renderpass - auto const resources = node->GetResources(); - for (auto& resource : resources) - { - resource->GetInfoTracker()->TrackLayout(node, {}, vk::ImageLayout::eUndefined); - } - - // 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_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT))) - resourceAttFinalLayouts[color.attachment] = vk::ImageLayout::ePresentSrcKHR; - else - resourceAttFinalLayouts[color.attachment] = color.layout; - - node->attResources[color.attachment]->infoTracker->TrackLayout(node, subpass, color.layout); - } - - for (auto& depth : subpass->depthReferences) - { - resourceAttFinalLayouts[depth.attachment] = depth.layout; - node->attResources[depth.attachment]->infoTracker->TrackLayout(node, subpass, depth.layout); - } - - for (auto& input : subpass->inputReferences) - { - resourceAttFinalLayouts[input.attachment] = input.layout; - node->attResources[input.attachment]->infoTracker->TrackLayout(node, subpass, input.layout); - } - } - - for (uint32_t j = 0; j < node->attachmentDescriptions.size(); ++j) - { - auto& att = node->attachmentDescriptions[j]; - auto& resource = node->attResources[j]; - - // If resource is from another render graph, use the final layout it had when it was last used in that graph. This is initialized in LinkNonOwningResource. - // We also want to load the attachment, not "don't care". - if (resource->resourceTypeFlags & SHUtilities::ConvertEnum(SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED) && - renderGraphStorage->nonOwningResourceInitialLayouts.contains(resource.GetId().Raw)) - { - att.initialLayout = renderGraphStorage->nonOwningResourceInitialLayouts.at (resource.GetId().Raw); - att.loadOp = vk::AttachmentLoadOp::eLoad; - att.stencilLoadOp = vk::AttachmentLoadOp::eLoad; - } - else - att.initialLayout = vk::ImageLayout::eUndefined; - - att.finalLayout = resourceAttFinalLayouts[j]; - resource->GetInfoTracker()->TrackLayout(node, {}, att.finalLayout); - } + node->StandaloneConfigureAttDesc(i == nodes.size() - 1); ++i; } @@ -333,6 +275,17 @@ namespace SHADE } } + void SHRenderGraph::ReindexNodes(void) noexcept + { + nodeIndexing.clear(); + uint32_t i = 0; + for (auto& node : nodes) + { + nodeIndexing.emplace (node->name, i); + ++i; + } + } + /***************************************************************************/ /*! @@ -473,6 +426,65 @@ namespace SHADE return node; } + /***************************************************************************/ + /*! + + \brief + This function is purely used for dynamic nodes (if such a thing were to + exist in our architecture). In other words, don't use this function unless + the new node is fully standalone and does not rely or is a prereq of + other nodes. + + \param nodeName + Name of new node + + \param resourceInstruction + Resources for the node + + \param nodeToAddAfter + The node to add the new node after. + + \return + + */ + /***************************************************************************/ + Handle SHRenderGraph::AddNodeAfter(std::string nodeName, std::initializer_list resourceInstruction, std::string nodeToAddAfter) noexcept + { + if (nodeIndexing.contains(nodeName)) + { + SHLOG_ERROR("Node already exists, cannot add node. "); + return {}; + } + + std::vector descInitParams; + for (auto const& instruction : resourceInstruction) + { + // If the resource that the new node is requesting for exists, allow the graph to reference it + if (renderGraphStorage->graphResources->contains(instruction.resourceName)) + { + descInitParams.push_back( + { + .resourceHdl = renderGraphStorage->graphResources->at(instruction.resourceName), + .dontClearOnLoad = instruction.dontClearOnLoad, + } + ); + } + else + { + SHLOG_ERROR("Resource doesn't exist in graph yet. Cannot create new node."); + return{}; + } + } + + // get target node + auto targetNode = nodes.begin() + nodeIndexing.at(nodeToAddAfter); + + auto node = nodes.insert(targetNode, renderGraphStorage->resourceHub->Create(nodeName, renderGraphStorage, std::move(descInitParams), std::vector>())); + ReindexNodes (); + return *node; + + } + void SHRenderGraph::AddRenderToSwapchainNode(std::string toSwapchainResource, std::string swapchainResource, std::initializer_list predecessorNodes, std::pair, Handle> shaderModules) noexcept { for (auto& node : predecessorNodes) @@ -532,10 +544,6 @@ namespace SHADE ConfigureSubSystems(); } - void SHRenderGraph::Regenerate(void) noexcept - { - - } /***************************************************************************/ /*! @@ -572,10 +580,13 @@ namespace SHADE for (auto& node : nodes) { - // bind static global data - SHGlobalDescriptorSets::BindStaticGlobalData(cmdBuffer, SH_PIPELINE_TYPE::GRAPHICS, descMappings.at(SHPredefinedDescriptorTypes::STATIC_DATA)); + if (node->renderpass) + { + // bind static global data + SHGlobalDescriptorSets::BindStaticGlobalData(cmdBuffer, SH_PIPELINE_TYPE::GRAPHICS, descMappings.at(SHPredefinedDescriptorTypes::STATIC_DATA)); - node->Execute(cmdBuffer, descPool, frameIndex); + node->Execute(cmdBuffer, descPool, frameIndex); + } } cmdBuffer->EndLabeledSegment(); @@ -605,8 +616,11 @@ namespace SHADE // resize resources for (auto& [name, resource] : *renderGraphStorage->graphResources) { - if (!renderGraphStorage->nonOwningResourceInitialLayouts.contains (resource.GetId().Raw)) - resource->HandleResize(newWidth, newHeight); + if (resource->resizeWithWindow) + { + if (!renderGraphStorage->nonOwningResourceInitialLayouts.contains (resource.GetId().Raw)) + resource->HandleResize(newWidth, newHeight); + } } for (auto& node : nodes) diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h index c7fe221b..5abcd6b6 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h @@ -55,6 +55,7 @@ namespace SHADE void ConfigureRenderpasses (void) noexcept; void ConfigureSubSystems (void) noexcept; void ConfigureFramebuffers (void) noexcept; + void ReindexNodes (void) noexcept; /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ @@ -101,6 +102,7 @@ namespace SHADE ( std::string resourceName, std::initializer_list typeFlags, + bool resizeWithWindow = true, uint32_t w = static_cast(-1), uint32_t h = static_cast(-1), vk::Format format = vk::Format::eB8G8R8A8Unorm, @@ -123,6 +125,12 @@ namespace SHADE std::initializer_list resourceInstruction, std::initializer_list predecessorNodes ) noexcept; + Handle AddNodeAfter + ( + std::string nodeName, + std::initializer_list resourceInstruction, + std::string nodeToAddAfter + ) noexcept; void AddRenderToSwapchainNode ( @@ -134,7 +142,6 @@ namespace SHADE ) noexcept; void Generate (void) noexcept; - void Regenerate (void) noexcept; void CheckForNodeComputes (void) noexcept; void Execute (uint32_t frameIndex, Handle descPool) noexcept; void Begin (uint32_t frameIndex) noexcept; @@ -165,7 +172,14 @@ namespace SHADE * that manage the resources instead and can facilitate such linking of resources. Either that, or we allow only 1 render graph, * but different matrices (SHRenderer) can be used in different nodes. * - There are also way too many hash maps created for ease of access. This definitely can be cut down. - * - + * - In hindsight there should have been a distinction between static and dynamic nodes. Static nodes are the ones that are accounted + * for in the generation of the render graph. Dynamic nodes begin with nothing at first, but allows for linking of resources and subpasses + * while the render graph is executing. The resources here should also be dynamic, which means it should never be used in anywhere else other + * than in the node that is using it. This would mean its initial layouts are always specified as undefined and final layouts specified as + * whatever the last subpass that is using that resource specifies in the node. Dynamic nodes are meant to render to resources that would later + * be used externally, as descriptors for example (the descriptors can be used in a render graph node compute for example). Dynamic nodes run as + * if they are the only nodes in the graph, because their resources are not used in other nodes and are thus not predecessors or successors of any + * other node. * */ diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp index 3c412645..ff540ce1 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp @@ -32,8 +32,11 @@ namespace SHADE renderpass.Free(); } - renderpass = graphStorage->logicalDevice->CreateRenderpass(attachmentDescriptions, spDescs, spDeps); - SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eRenderPass, renderpass->GetVkRenderpass(), "[RenderPass] " + name); + if (!spDescs.empty()) + { + renderpass = graphStorage->logicalDevice->CreateRenderpass(attachmentDescriptions, spDescs, spDeps); + SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eRenderPass, renderpass->GetVkRenderpass(), "[RenderPass] " + name); + } } /***************************************************************************/ @@ -46,91 +49,105 @@ namespace SHADE /***************************************************************************/ void SHRenderGraphNode::CreateFramebuffer(void) noexcept { - if (!framebuffers.empty()) + if (renderpass) { - for (auto fbo : framebuffers) + if (!framebuffers.empty()) { - if (fbo) - fbo.Free(); - } - } - - for (uint32_t i = 0; i < framebuffers.size(); ++i) - { - std::vector> imageViews(attResources.size()); - uint32_t fbWidth = std::numeric_limits::max(); - uint32_t fbHeight = std::numeric_limits::max(); - - for (uint32_t j = 0; j < attResources.size(); ++j) - { - uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0; - imageViews[j] = attResources[j]->imageViews[imageViewIndex]; - - // We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's - if (fbWidth > attResources[j]->width) - fbWidth = attResources[j]->width; - if (fbHeight > attResources[j]->height) - fbHeight = attResources[j]->height; + for (auto fbo : framebuffers) + { + if (fbo) + fbo.Free(); + } } + for (uint32_t i = 0; i < framebuffers.size(); ++i) + { + std::vector> imageViews(attResources.size()); + uint32_t fbWidth = std::numeric_limits::max(); + uint32_t fbHeight = std::numeric_limits::max(); - framebuffers[i] = graphStorage->logicalDevice->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight); - SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eFramebuffer, framebuffers[i]->GetVkFramebuffer(), "[Framebuffer] " + name + std::to_string(i)); + for (uint32_t j = 0; j < attResources.size(); ++j) + { + uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0; + imageViews[j] = attResources[j]->imageViews[imageViewIndex]; + + // We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's + if (fbWidth > attResources[j]->width) + fbWidth = attResources[j]->width; + if (fbHeight > attResources[j]->height) + fbHeight = attResources[j]->height; + } + + + framebuffers[i] = graphStorage->logicalDevice->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight); + SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eFramebuffer, framebuffers[i]->GetVkFramebuffer(), "[Framebuffer] " + name + std::to_string(i)); + } } } void SHRenderGraphNode::HandleResize(void) noexcept { - renderpass->HandleResize(); - - for (uint32_t i = 0; i < framebuffers.size(); ++i) + if (renderpass) { - std::vector> imageViews(attResources.size()); - uint32_t fbWidth = std::numeric_limits::max(); - uint32_t fbHeight = std::numeric_limits::max(); + renderpass->HandleResize(); - for (uint32_t j = 0; j < attResources.size(); ++j) + for (uint32_t i = 0; i < framebuffers.size(); ++i) { - uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0; - imageViews[j] = attResources[j]->imageViews[imageViewIndex]; + std::vector> imageViews(attResources.size()); + uint32_t fbWidth = std::numeric_limits::max(); + uint32_t fbHeight = std::numeric_limits::max(); - // We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's - if (fbWidth > attResources[j]->width) - fbWidth = attResources[j]->width; - if (fbHeight > attResources[j]->height) - fbHeight = attResources[j]->height; + for (uint32_t j = 0; j < attResources.size(); ++j) + { + uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0; + imageViews[j] = attResources[j]->imageViews[imageViewIndex]; + + // We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's + if (fbWidth > attResources[j]->width) + fbWidth = attResources[j]->width; + if (fbHeight > attResources[j]->height) + fbHeight = attResources[j]->height; + } + + framebuffers[i]->HandleResize(renderpass, imageViews, fbWidth, fbHeight); } - framebuffers[i]->HandleResize(renderpass, imageViews, fbWidth, fbHeight); - } + for (auto& subpass : subpasses) + { + subpass->HandleResize(); + } - for (auto& subpass : subpasses) - { - subpass->HandleResize(); - } - - for (auto& nodeCompute : nodeComputes) - { - nodeCompute->HandleResize(); + for (auto& nodeCompute : nodeComputes) + { + nodeCompute->HandleResize(); + } } } void SHRenderGraphNode::ConfigureSubpasses(void) noexcept { + if (subpasses.empty()) + return; + + uint32_t numValidSubpasses = std::count_if(subpasses.begin(), subpasses.end(), [](Handle subpass) {return !subpass->HasNoAttachments();}); + // Create subpass description and dependencies based on number of subpasses - spDescs.resize(subpasses.size()); - spDeps.resize(subpasses.size()); + spDescs.resize(numValidSubpasses); + spDeps.resize(numValidSubpasses); // 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 i = 0; // For all subpasses (see above description about bit field for this). - for (auto& subpass : subpasses) + for (uint32_t i = 0; auto& subpass : subpasses) { + // skip if subpass is not valid + if (subpass->HasNoAttachments()) + continue; + // Configure subpass description auto& desc = spDescs[i]; desc.pColorAttachments = subpass->colorReferences.data(); @@ -186,8 +203,11 @@ namespace SHADE // Loop through all subpasses again but this time we use the bit field to initialize // the dependencies. - for (i = 0; i < subpasses.size(); ++i) + for (uint32_t i = 0; auto & subpass : subpasses) { + if (subpass->HasNoAttachments()) + continue; + vk::PipelineStageFlags srcStage; vk::PipelineStageFlags dstStage; vk::AccessFlags srcAccess; @@ -245,6 +265,8 @@ namespace SHADE // initialize input descriptors subpasses[i]->CreateInputDescriptors(); + + ++i; } } @@ -343,6 +365,7 @@ namespace SHADE , spDeps{ std::move(rhs.spDeps) } , nodeComputes{ std::move(rhs.nodeComputes) } , name { std::move(rhs.name) } + , ISelfHandle{std::move(rhs)} { rhs.renderpass = {}; @@ -419,7 +442,7 @@ namespace SHADE return subpass; } - Handle SHRenderGraphNode::AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings, float numWorkGroupScale/* = 1.0f*/) noexcept + Handle SHRenderGraphNode::AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings, uint32_t variableDescCount/* = 0*/, float numWorkGroupScale/* = 1.0f*/) noexcept { // Look for the required resources in the graph std::vector> nodeComputeResources{}; @@ -435,7 +458,7 @@ namespace SHADE std::vector> temp (nodeComputeResources); // Create the subpass compute with the resources - auto nodeCompute = graphStorage->resourceHub->Create(std::move(nodeName), graphStorage, computeShaderModule, std::move(nodeComputeResources), std::move (dynamicBufferBindings), nodeComputes.empty()); + auto nodeCompute = graphStorage->resourceHub->Create(std::move(nodeName), graphStorage, computeShaderModule, std::move(nodeComputeResources), std::move (dynamicBufferBindings), nodeComputes.empty(), variableDescCount); nodeComputes.push_back(nodeCompute); for (auto& resource : temp) @@ -483,6 +506,68 @@ namespace SHADE } } + void SHRenderGraphNode::StandaloneConfigureAttDesc(bool isLastNode) noexcept + { + // key is handle ID, value is final layout. + std::unordered_map resourceAttFinalLayouts; + if (!subpasses.empty()) + { + // We first want to take all resources track their layout as undefined at the start of the node/renderpass + for (auto& resource : attResources) + { + resource->GetInfoTracker()->TrackLayout(GetHandle(), {}, vk::ImageLayout::eUndefined); + } + + // attempt to get all final layouts for all resources + for (auto& subpass : 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 (isLastNode && (attResources[color.attachment]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT))) + resourceAttFinalLayouts[color.attachment] = vk::ImageLayout::ePresentSrcKHR; + else + resourceAttFinalLayouts[color.attachment] = color.layout; + + attResources[color.attachment]->infoTracker->TrackLayout(GetHandle(), subpass, color.layout); + } + + for (auto& depth : subpass->depthReferences) + { + resourceAttFinalLayouts[depth.attachment] = depth.layout; + attResources[depth.attachment]->infoTracker->TrackLayout(GetHandle(), subpass, depth.layout); + } + + for (auto& input : subpass->inputReferences) + { + resourceAttFinalLayouts[input.attachment] = input.layout; + attResources[input.attachment]->infoTracker->TrackLayout(GetHandle(), subpass, input.layout); + } + } + + for (uint32_t j = 0; j < attachmentDescriptions.size(); ++j) + { + auto& att = attachmentDescriptions[j]; + auto& resource = attResources[j]; + + // If resource is from another render graph, use the final layout it had when it was last used in that graph. This is initialized in LinkNonOwningResource. + // We also want to load the attachment, not "don't care". + if (resource->resourceTypeFlags & SHUtilities::ConvertEnum(SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED) && + graphStorage->nonOwningResourceInitialLayouts.contains(resource.GetId().Raw)) + { + att.initialLayout = graphStorage->nonOwningResourceInitialLayouts.at(resource.GetId().Raw); + att.loadOp = vk::AttachmentLoadOp::eLoad; + att.stencilLoadOp = vk::AttachmentLoadOp::eLoad; + } + else + att.initialLayout = vk::ImageLayout::eUndefined; + + att.finalLayout = resourceAttFinalLayouts[j]; + resource->GetInfoTracker()->TrackLayout(GetHandle(), {}, att.finalLayout); + } + } + } + /***************************************************************************/ /*! @@ -509,14 +594,14 @@ namespace SHADE // remove attachment reference attachmentDescriptions.erase (attachmentDescriptions.begin() + index); + // erase from mapping as well + resourceAttachmentMapping->erase(resourceHandleID); + // Remove footprint of attachment from all subpasses as well for (auto it = subpasses.begin(); it != subpasses.end(); ++it) { - // attempt to detach resource from subpass - (*it)->DetachResource(resourceName, index); - - // If the subpass ends up having no attachments after, erase it from the node - if ((*it)->HasNoAttachments()) + // If the subpass uses the resource, just remove the subpass since the subpass will be invalid + if ((*it)->UsesResource(index)) { // erase from indexing subpassIndexing.erase((*it)->GetName()); @@ -530,6 +615,24 @@ namespace SHADE for (uint32_t i = 0; i < subpasses.size(); ++i) subpasses[i]->SetIndex(i); + // remove node computes using the resource + for (auto it = nodeComputes.begin(); it != nodeComputes.end(); ++it) + { + if ((*it)->UsesResource(resourceHandleID)) + { + it = nodeComputes.erase(it); + } + } + + // recompute the barriers for the other computes + for (auto it = nodeComputes.begin(); it != nodeComputes.end(); ++it) + { + if (it == nodeComputes.begin()) + (*it)->SetFollowingEndRenderpass(true); + + (*it)->InitializeBarriers(); + } + return true; } return false; @@ -537,37 +640,40 @@ namespace SHADE void SHRenderGraphNode::Execute(Handle commandBuffer, Handle descPool, uint32_t frameIndex) noexcept { - uint32_t framebufferIndex = (framebuffers.size() > 1) ? frameIndex : 0; - commandBuffer->BeginRenderpass(renderpass, framebuffers[framebufferIndex]); - - for (uint32_t i = 0; i < subpasses.size(); ++i) + if (renderpass) { - subpasses[i]->Execute(commandBuffer, descPool, frameIndex); + uint32_t framebufferIndex = (framebuffers.size() > 1) ? frameIndex : 0; + commandBuffer->BeginRenderpass(renderpass, framebuffers[framebufferIndex]); - // Go to next subpass if not last subpass - if (i != static_cast(subpasses.size()) - 1u) - commandBuffer->NextSubpass(); + 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 != static_cast(subpasses.size()) - 1u && !subpasses[i]->HasNoAttachments()) + commandBuffer->NextSubpass(); + } + + commandBuffer->EndRenderpass(); + + auto const& descMappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::RENDER_GRAPH_NODE_COMPUTE); + + // We bind these 2 descriptor sets here because they apply to all node computes + if (!nodeComputes.empty()) + { + commandBuffer->ForceSetPipelineLayout(SHGraphicsPredefinedData::GetSystemData(SHGraphicsPredefinedData::SystemType::RENDER_GRAPH_NODE_COMPUTE).dummyPipelineLayout, SH_PIPELINE_TYPE::COMPUTE); + + // bind static global data + SHGlobalDescriptorSets::BindStaticGlobalData(commandBuffer, SH_PIPELINE_TYPE::COMPUTE, descMappings.at(SHPredefinedDescriptorTypes::STATIC_DATA)); + + // bind lighting data + SHGlobalDescriptorSets::BindLightingData(commandBuffer, SH_PIPELINE_TYPE::COMPUTE, descMappings.at(SHPredefinedDescriptorTypes::LIGHTS), frameIndex); + } + + // Execute all subpass computes + for (auto& sbCompute : nodeComputes) + sbCompute->Execute(commandBuffer, frameIndex); } - - commandBuffer->EndRenderpass(); - - auto const& descMappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::RENDER_GRAPH_NODE_COMPUTE); - - // We bind these 2 descriptor sets here because they apply to all node computes - if (!nodeComputes.empty()) - { - commandBuffer->ForceSetPipelineLayout(SHGraphicsPredefinedData::GetSystemData(SHGraphicsPredefinedData::SystemType::RENDER_GRAPH_NODE_COMPUTE).dummyPipelineLayout, SH_PIPELINE_TYPE::COMPUTE); - - // bind static global data - SHGlobalDescriptorSets::BindStaticGlobalData(commandBuffer, SH_PIPELINE_TYPE::COMPUTE, descMappings.at(SHPredefinedDescriptorTypes::STATIC_DATA)); - - // bind lighting data - SHGlobalDescriptorSets::BindLightingData(commandBuffer, SH_PIPELINE_TYPE::COMPUTE, descMappings.at(SHPredefinedDescriptorTypes::LIGHTS), frameIndex); - } - - // Execute all subpass computes - for (auto& sbCompute : nodeComputes) - sbCompute->Execute(commandBuffer, frameIndex); } Handle SHRenderGraphNode::GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept @@ -599,6 +705,77 @@ namespace SHADE batcher.FinaliseBatches(graphStorage->logicalDevice, descPool, frameIndex); } + /***************************************************************************/ + /*! + + \brief + This function simply appends to the container of VkAttachmentDescription + and attResources. It will assume the resource is used standalone in the + node and will not account for its usage in other nodes. As such its + initialLayout will always be UNDEFINED and its finalLayout will be + whatever is calculated if the node is regenerated using + StandaloneRegnerate. This function also does not affect the render graph + while its running since the 2 containers above have already been copied + to the GPU. + + \param resourceName + The name of the resource for getting the resource. + + */ + /***************************************************************************/ + void SHRenderGraphNode::RuntimeLinkResource(std::string resourceName) noexcept + { + // Get new resource + Handle newResource = graphStorage->graphResources->at(resourceName); + + // append new resource to container + attResources.push_back(newResource); + + attachmentDescriptions.push_back(vk::AttachmentDescription + { + .format = newResource->GetResourceFormat(), + .samples = vk::SampleCountFlagBits::e1, + .loadOp = vk::AttachmentLoadOp::eClear, + .storeOp = vk::AttachmentStoreOp::eStore, + .stencilLoadOp = vk::AttachmentLoadOp::eClear, + .stencilStoreOp = vk::AttachmentStoreOp::eStore, + }); + + resourceAttachmentMapping->try_emplace(newResource.GetId().Raw, attachmentDescriptions.size() - 1); + } + + Handle SHRenderGraphNode::RuntimeAddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept + { + return AddSubpass(std::move (subpassName), viewport, renderer); + } + + /***************************************************************************/ + /*! + + \brief + USE WITH CAUTION because the function does not reevaluate resource + layouts in attachment descriptions. All resources here will start at + UNDEFINED and end at whatever the last subpass using the attachment + specifies. It will also not support render graph node computes given its + complexity if it has to be accounted for. + + IN SHORT, IT GENERATES A RENDERPASS AS IF ITS THE ONLY NODE + IN THE RENDER GRAPH. SEE NOTES IN SHRenderGraph.h + + This function is mainly meant for nodes that are dynamic (in hindsight, + there really should have been a distinction between static and dynamic + nodes). + + */ + /***************************************************************************/ + void SHRenderGraphNode::RuntimeStandaloneRegenerate(void) noexcept + { + StandaloneConfigureAttDesc(false); + ConfigureSubpasses(); + CreateRenderpass(); + CreateFramebuffer(); + } + /***************************************************************************/ /*! @@ -633,4 +810,15 @@ namespace SHADE return attResources; } + Handle SHRenderGraphNode::GetNodeCompute(std::string nodeComputeName) const noexcept + { + for (auto nc : nodeComputes) + { + if (nc->name == nodeComputeName) + return nc; + } + + return {}; + } + } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h index a581d21c..b070b8fa 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h @@ -93,6 +93,9 @@ namespace SHADE void CreateFramebuffer(void) noexcept; void HandleResize (void) noexcept; void ConfigureSubpasses (void) noexcept; + bool DetachResource(std::string const& resourceName, uint64_t resourceHandleID) noexcept; + void AddDummySubpassIfNeeded(void) noexcept; + void StandaloneConfigureAttDesc (bool isLastNode) noexcept; public: /*-----------------------------------------------------------------------*/ @@ -105,15 +108,17 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ - Handle AddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept; - Handle AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings = {}, float numWorkGroupScale = 1.0f) noexcept; - void AddDummySubpassIfNeeded (void) noexcept; - bool DetachResource (std::string const& resourceName, uint64_t resourceHandleID) noexcept; + Handle AddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept; + Handle AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings = {}, uint32_t variableDescCount = 0, float numWorkGroupScale = 1.0f) noexcept; + + void Execute(Handle commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; + Handle GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept; + void FinaliseBatch(uint32_t frameIndex, Handle descPool); - // TODO: RemoveSubpass() - void Execute(Handle commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; - Handle GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept; - void FinaliseBatch(uint32_t frameIndex, Handle descPool); + // Runtime functions that don't affect the renderpass + void RuntimeLinkResource(std::string resourceName) noexcept; + Handle RuntimeAddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept; + void RuntimeStandaloneRegenerate (void) noexcept; /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ @@ -122,6 +127,7 @@ namespace SHADE 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; friend class SHRenderGraph; }; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp index cfc8443c..ef1b6b03 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp @@ -14,7 +14,56 @@ namespace SHADE { - SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(std::string nodeName, Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, std::unordered_set&& dynamicBufferBindings, bool followingEndRP, float inNumWorkGroupScale/* = 1.0f*/) noexcept + + bool SHRenderGraphNodeCompute::UsesResource(uint64_t resourceHandleID) const noexcept + { + for (auto& resource : resources) + { + if (resource.GetId().Raw == resourceHandleID) + return true; + } + return false; + } + + void SHRenderGraphNodeCompute::InitializeBarriers(void) noexcept + { + for (uint32_t i = 0; auto & barriers : memoryBarriers) + { + barriers.clear(); + + for (auto& resource : resources) + { + vk::AccessFlags srcAccessMask = (followingEndRenderpass) ? vk::AccessFlagBits::eInputAttachmentRead : (vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite); + barriers.push_back(vk::ImageMemoryBarrier + { + .srcAccessMask = srcAccessMask, + .dstAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite, + .oldLayout = vk::ImageLayout::eGeneral, + .newLayout = vk::ImageLayout::eGeneral, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = resource->GetImage((resource->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0)->GetVkImage(), + .subresourceRange = vk::ImageSubresourceRange + { + .aspectMask = resource->imageAspectFlags, + .baseMipLevel = 0, + .levelCount = resource->mipLevels, + .baseArrayLayer = 0, + .layerCount = 1, + } + }); + } + ++i; + } + } + + void SHRenderGraphNodeCompute::SetFollowingEndRenderpass(uint32_t flag) noexcept + { + followingEndRenderpass = flag; + } + + + SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(std::string nodeName, Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, std::unordered_set&& dynamicBufferBindings, bool followingEndRP, uint32_t variableDescCount, float inNumWorkGroupScale/* = 1.0f*/) noexcept : computePipeline{} , pipelineLayout{} , resources{} @@ -68,10 +117,12 @@ namespace SHADE // check if all layouts are there if (layouts.size() == descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE) + 1) { + Handle computeResourceLayout = {}; + computeResourceLayout = layouts[descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE)]; + // create compute resources computeResource = graphStorage->resourceHub->Create(); - auto computeResourceLayout = layouts[descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE)]; - computeResource->descSet = graphStorage->descriptorPool->Allocate({ computeResourceLayout }, { 1 }); + computeResource->descSet = graphStorage->descriptorPool->Allocate({ computeResourceLayout }, {variableDescCount}); #ifdef _DEBUG for (auto set : computeResource->descSet->GetVkHandle()) SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eDescriptorSet, set, "[Descriptor Set] " + name + " Resources"); @@ -91,6 +142,11 @@ namespace SHADE void SHRenderGraphNodeCompute::Execute(Handle cmdBuffer, uint32_t frameIndex) noexcept { + for (auto& fn : preComputeFunctions) + { + fn (cmdBuffer, frameIndex); + } + // bind the compute pipeline cmdBuffer->BindPipeline(computePipeline); @@ -157,35 +213,7 @@ namespace SHADE groupSizeX = maxWidth / workGroupSizeX; groupSizeY = maxHeight / workGroupSizeY; - for (uint32_t i = 0; auto& barriers : memoryBarriers) - { - barriers.clear(); - - for (auto& resource : resources) - { - vk::AccessFlags srcAccessMask = (followingEndRenderpass) ? vk::AccessFlagBits::eInputAttachmentRead : (vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite); - barriers.push_back(vk::ImageMemoryBarrier - { - .srcAccessMask = srcAccessMask, - .dstAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite, - .oldLayout = vk::ImageLayout::eGeneral, - .newLayout = vk::ImageLayout::eGeneral, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = resource->GetImage((resource->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0)->GetVkImage(), - .subresourceRange = vk::ImageSubresourceRange - { - .aspectMask = resource->imageAspectFlags, - .baseMipLevel = 0, - .levelCount = resource->mipLevels, - .baseArrayLayer = 0, - .layerCount = 1, - } - }); - } - - ++i; - } + InitializeBarriers(); } void SHRenderGraphNodeCompute::SetDynamicOffsets(std::span perFrameSizes) noexcept @@ -219,4 +247,17 @@ namespace SHADE } + void SHRenderGraphNodeCompute::ModifyWriteDescImageComputeResource(uint32_t binding, SHVkDescriptorSetGroup::viewSamplerLayout const& viewSamplerLayout, uint32_t descArrayIndex) noexcept + { + static constexpr uint32_t COMPUTE_RESOURCE_SET_INDEX = 0; + computeResource->descSet->ModifyWriteDescImage(COMPUTE_RESOURCE_SET_INDEX, binding, viewSamplerLayout, descArrayIndex); + computeResource->descSet->UpdateDescriptorSetImage(COMPUTE_RESOURCE_SET_INDEX, binding, descArrayIndex); + + } + + void SHRenderGraphNodeCompute::AddPreComputeFunction(PreComputeFunction const& fn) noexcept + { + preComputeFunctions.push_back(fn); + } + } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h index dc3ca886..83bc5d33 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h @@ -25,6 +25,10 @@ namespace SHADE class SHRenderGraphNodeCompute { + public: + using PreComputeFunction = std::function, uint32_t)>; + + private: // Binding of set SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_NODE_COMPUTE_RESOURCE struct ComputeResource @@ -73,8 +77,23 @@ namespace SHADE //! Name of this node std::string name; + std::vector preComputeFunctions; + + + private: + /*-----------------------------------------------------------------------*/ + /* PRIVATE MEMBER FUNCTIONS */ + /*-----------------------------------------------------------------------*/ + bool UsesResource (uint64_t resourceHandleID) const noexcept; + void InitializeBarriers (void) noexcept; + + /*-----------------------------------------------------------------------*/ + /* PRIVATE SETTERS AND GETTERS */ + /*-----------------------------------------------------------------------*/ + void SetFollowingEndRenderpass (uint32_t flag) noexcept; + public: - SHRenderGraphNodeCompute(std::string nodeName, Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, std::unordered_set&& dynamicBufferBindings, bool followingEndRP, float inNumWorkGroupScale = 1.0f) noexcept; + SHRenderGraphNodeCompute(std::string nodeName, Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, std::unordered_set&& dynamicBufferBindings, bool followingEndRP, uint32_t variableDescCount, float inNumWorkGroupScale = 1.0f) noexcept; void Execute (Handle cmdBuffer, uint32_t frameIndex) noexcept; void HandleResize (void) noexcept; @@ -84,7 +103,9 @@ namespace SHADE void ModifyWriteDescBufferComputeResource (uint32_t binding, std::span> const& buffers, uint32_t offset, uint32_t range) noexcept; void ModifyWriteDescImageComputeResource(uint32_t binding, std::span const& viewSamplerLayouts) noexcept; + void ModifyWriteDescImageComputeResource(uint32_t binding, SHVkDescriptorSetGroup::viewSamplerLayout const& viewSamplerLayout, uint32_t descArrayIndex) noexcept; + void AddPreComputeFunction (PreComputeFunction const& fn) noexcept; friend class SHRenderGraph; friend class SHRenderGraphNode; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp index 5a34fa04..d0a88e86 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp @@ -78,7 +78,7 @@ namespace SHADE */ /***************************************************************************/ - SHRenderGraphResource::SHRenderGraphResource(Handle renderGraphStorage, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept + SHRenderGraphResource::SHRenderGraphResource(Handle renderGraphStorage, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags, bool inResizeWithWindow) noexcept : graphStorage{renderGraphStorage} , resourceTypeFlags{ } , resourceFormat{ format } @@ -88,6 +88,7 @@ namespace SHADE , height{ h } , mipLevels{ levels } , resourceName{ name } + , resizeWithWindow { inResizeWithWindow } { // If the resource type is an arbitrary image and not swapchain image if (typeFlags.size() == 1 && *typeFlags.begin() == SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT) @@ -210,6 +211,7 @@ namespace SHADE , imageAspectFlags{ rhs.imageAspectFlags } , graphStorage{rhs.graphStorage} , infoTracker {std::move (rhs.infoTracker)} + , resizeWithWindow{rhs.resizeWithWindow} { } @@ -242,7 +244,8 @@ namespace SHADE mipLevels = rhs.mipLevels; imageAspectFlags = rhs.imageAspectFlags; graphStorage = rhs.graphStorage; - infoTracker = std::move(infoTracker); + infoTracker = std::move(rhs.infoTracker); + resizeWithWindow = rhs.resizeWithWindow; return *this; } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h index 7ac2b824..b9fe219e 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h @@ -96,11 +96,14 @@ namespace SHADE //! For tracking resource states in stages of the render graphs Handle infoTracker; + //! Whether or not to resize (recreate vulkan image) when window resizes + bool resizeWithWindow; + public: /*-----------------------------------------------------------------------*/ /* CTORS AND DTORS */ /*-----------------------------------------------------------------------*/ - SHRenderGraphResource(Handle renderGraphStorage, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept; + SHRenderGraphResource(Handle renderGraphStorage, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags, bool inResizeWithWindow) noexcept; SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept; SHRenderGraphResource& operator=(SHRenderGraphResource&& rhs) noexcept; ~SHRenderGraphResource(void) noexcept; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp index 3d2b1699..5205b44d 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp @@ -77,6 +77,7 @@ namespace SHADE , name { rhs.name } , viewport {rhs.viewport} , renderer {rhs.renderer} + , companionSubpass {rhs.companionSubpass} { } @@ -113,6 +114,7 @@ namespace SHADE name = std::move(rhs.name); renderer = rhs.renderer; viewport = rhs.viewport; + companionSubpass = rhs.companionSubpass; return *this; @@ -162,7 +164,7 @@ namespace SHADE switch (attachmentDescriptionType) { case SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH: - imageLayout = vk::ImageLayout::eDepthAttachmentOptimal; + imageLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal; break; case SH_RENDER_GRAPH_RESOURCE_FLAGS::STENCIL: imageLayout = vk::ImageLayout::eStencilAttachmentOptimal; @@ -211,25 +213,38 @@ namespace SHADE { commandBuffer->BeginLabeledSegment(name); - // Ensure correct transforms are provided - superBatch->UpdateBuffers(frameIndex, descPool); - - if (viewport) + if (!HasNoAttachments()) { - // set viewport and scissor - uint32_t w = static_cast(viewport->GetWidth()); - uint32_t h = static_cast(viewport->GetHeight()); - commandBuffer->SetViewportScissor(static_cast(w), static_cast(h), w, h); + // Ensure correct transforms are provided + superBatch->UpdateBuffers(frameIndex, descPool); + + if (viewport) + { + // set viewport and scissor + uint32_t w = static_cast(viewport->GetWidth()); + uint32_t h = static_cast(viewport->GetHeight()); + commandBuffer->SetViewportScissor(static_cast(w), static_cast(h), w, h); + } + + auto const& descMappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::BATCHING); + + if (renderer) + renderer->BindDescriptorSet(commandBuffer, SH_PIPELINE_TYPE::GRAPHICS, descMappings.at(SHPredefinedDescriptorTypes::CAMERA), frameIndex); + + // If companion subpass is not a valid handle, render super batch normally + if (!companionSubpass.companion) + { + // Draw all the batches + superBatch->Draw(commandBuffer, frameIndex); + } + else + { + // if not bind pipeline for companion and and execute draw command + commandBuffer->BindPipeline(companionSubpass.pipeline); + companionSubpass.companion->superBatch->Draw(commandBuffer, frameIndex, false); + } } - auto const& descMappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::BATCHING); - - if (renderer) - renderer->BindDescriptorSet(commandBuffer, SH_PIPELINE_TYPE::GRAPHICS, descMappings.at(SHPredefinedDescriptorTypes::CAMERA), frameIndex); - - // Draw all the batches - superBatch->Draw(commandBuffer, frameIndex); - // Draw all the exterior draw calls for (auto& drawCall : exteriorDrawCalls) { @@ -265,43 +280,27 @@ namespace SHADE */ /***************************************************************************/ - void SHSubpass::DetachResource(std::string const& resourceName, uint32_t attachmentIndex) noexcept + bool SHSubpass::UsesResource(uint32_t attachmentIndex) noexcept { for (uint32_t i = 0; i < colorReferences.size(); ++i) { if (colorReferences[i].attachment == attachmentIndex) - { - colorReferences.erase (colorReferences.begin() + i); - break; - } + return true; } for (uint32_t i = 0; i < depthReferences.size(); ++i) { if (depthReferences[i].attachment == attachmentIndex) - { - depthReferences.erase(depthReferences.begin() + i); - break; - } + return true; } for (uint32_t i = 0; i < inputReferences.size(); ++i) { if (inputReferences[i].attachment == attachmentIndex) - { - inputReferences.erase(inputReferences.begin() + i); - break; - } + return true; } - for (uint32_t i = 0; i < inputNames.size(); ++i) - { - if (inputNames[i] == resourceName) - { - inputNames.erase(inputNames.begin() + i); - break; - } - } + return false; } bool SHSubpass::HasNoAttachments(void) const noexcept @@ -458,6 +457,12 @@ namespace SHADE subpassIndex = index; } + void SHSubpass::SetCompanionSubpass(Handle companion, Handle pipeline) noexcept + { + companionSubpass.companion = companion; + companionSubpass.pipeline = pipeline; + } + /***************************************************************************/ /*! diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h index 6c582aa6..f84d4dee 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h @@ -21,12 +21,23 @@ namespace SHADE class SHVkSampler; class SHRenderer; class SHViewport; + class SHVkPipeline; class SH_API SHSubpass : public ISelfHandle { public: using ExteriorDrawCallFunction = std::function, Handle, uint32_t)>; + // Allows for subpasses to run using a companions data + struct CompanionSubpass + { + // subpass whose data will be borrowed to draw + Handle companion; + + // Pipeline that will be used for all the draw calls from all batches of the companion subpass + Handle pipeline; + }; + private: /*---------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ @@ -94,6 +105,15 @@ namespace SHADE // For identifying subpasses std::string name; + //! Optional component to a companion subpass. If the subpass handle of this object + //! is valid, the subpass will be drawn using this companion's data. + CompanionSubpass companionSubpass; + + private: + /*-----------------------------------------------------------------------*/ + /* PRIVATE MEMBER FUNCTIONS */ + /*-----------------------------------------------------------------------*/ + bool UsesResource(uint32_t attachmentIndex) noexcept; public: /*-----------------------------------------------------------------------*/ @@ -119,7 +139,6 @@ namespace SHADE void Execute(Handle commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; void HandleResize (void) noexcept; void BindInputDescriptorSets (Handle cmdBuffer, uint32_t setIndex, uint32_t frameIndex) const noexcept; - void DetachResource (std::string const& resourceName, uint32_t attachmentIndex) noexcept; bool HasNoAttachments (void) const noexcept; void Init(SHResourceHub& resourceManager) noexcept; @@ -128,19 +147,24 @@ namespace SHADE void CreateInputDescriptors (void) noexcept; void UpdateWriteDescriptors (void) noexcept; - /*-----------------------------------------------------------------------*/ - /* GETTERS AND SETTERS */ - /*-----------------------------------------------------------------------*/ private: + /*-----------------------------------------------------------------------*/ + /* PRIVATE GETTERS AND SETTERS */ + /*-----------------------------------------------------------------------*/ void SetIndex (uint32_t index) noexcept; public: - Handle const& GetParentNode(void) const noexcept; - SHSubPassIndex GetIndex() const noexcept; - Handle GetSuperBatch(void) const noexcept; + /*-----------------------------------------------------------------------*/ + /* PUBLIC SETTERS AND GETTERS */ + /*-----------------------------------------------------------------------*/ + void SetCompanionSubpass (Handle companion, Handle pipeline) noexcept; + + Handle const& GetParentNode(void) const noexcept; + SHSubPassIndex GetIndex() const noexcept; + Handle GetSuperBatch(void) const noexcept; std::vector const& GetColorAttachmentReferences (void) const noexcept; - vk::Format GetFormatFromAttachmentReference (uint32_t attachmentReference) const noexcept; - const std::string& GetName() const; + vk::Format GetFormatFromAttachmentReference (uint32_t attachmentReference) const noexcept; + const std::string& GetName() const; friend class SHRenderGraphNode; friend class SHRenderGraph;