Implemented Shadow maps (still needs improvement) #314

Merged
Xenosas1337 merged 22 commits from SP3-1-Rendering into main 2023-01-16 15:40:30 +08:00
49 changed files with 1389 additions and 502 deletions

View File

@ -7,6 +7,7 @@
Translate: {x: 0, y: 0.304069757, z: 1.73034382} Translate: {x: 0, y: 0.304069757, z: 1.73034382}
Rotate: {x: 0, y: 0, z: 0} Rotate: {x: 0, y: 0, z: 0}
Scale: {x: 1, y: 1, z: 1} Scale: {x: 1, y: 1, z: 1}
IsActive: true
Camera Component: Camera Component:
Position: {x: 0, y: 0.304069757, z: 1.73034382} Position: {x: 0, y: 0.304069757, z: 1.73034382}
Pitch: 0 Pitch: 0
@ -17,6 +18,7 @@
Near: 0.00999999978 Near: 0.00999999978
Far: 10000 Far: 10000
Perspective: true Perspective: true
IsActive: true
Scripts: ~ Scripts: ~
- EID: 1 - EID: 1
Name: Raccoon Name: Raccoon
@ -24,12 +26,14 @@
NumberOfChildren: 1 NumberOfChildren: 1
Components: Components:
Transform Component: Transform Component:
Translate: {x: 0, y: 0, z: 0} Translate: {x: -1.86388135, y: 0.0544953719, z: 0}
Rotate: {x: 0, y: 0, z: 0} Rotate: {x: -0, y: 0, z: -0}
Scale: {x: 1, y: 1, z: 1} Scale: {x: 1, y: 1, z: 1}
IsActive: true
Renderable Component: Renderable Component:
Mesh: 149697411 Mesh: 149697411
Material: 126974645 Material: 126974645
IsActive: true
Scripts: ~ Scripts: ~
- EID: 3 - EID: 3
Name: Bag Name: Bag
@ -40,9 +44,11 @@
Translate: {x: 0.006237939, y: -0.000393368304, z: 0} Translate: {x: 0.006237939, y: -0.000393368304, z: 0}
Rotate: {x: -0, y: 2.79945588, z: 0} Rotate: {x: -0, y: 2.79945588, z: 0}
Scale: {x: 1.0000881, y: 1, z: 1.0000881} Scale: {x: 1.0000881, y: 1, z: 1.0000881}
IsActive: true
Renderable Component: Renderable Component:
Mesh: 144838771 Mesh: 144838771
Material: 123745521 Material: 123745521
IsActive: true
Scripts: ~ Scripts: ~
- EID: 2 - EID: 2
Name: DirectionalLight Name: DirectionalLight
@ -50,12 +56,13 @@
NumberOfChildren: 0 NumberOfChildren: 0
Components: Components:
Light Component: Light Component:
Position: {x: 0, y: 0, z: 0} Position: {x: 3, y: 4.5, z: 7}
Type: Directional 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} Color: {x: 1, y: 1, z: 1, w: 1}
Layer: 4294967295 Layer: 4294967295
Strength: 0 Strength: 0
IsActive: true
Scripts: ~ Scripts: ~
- EID: 4 - EID: 4
Name: AmbientLight Name: AmbientLight
@ -69,4 +76,20 @@
Color: {x: 1, y: 1, z: 1, w: 1} Color: {x: 1, y: 1, z: 1, w: 1}
Layer: 4294967295 Layer: 4294967295
Strength: 0.600000024 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: ~ Scripts: ~

View File

@ -6,6 +6,8 @@ struct DirectionalLightStruct
uint isActive; uint isActive;
uint cullingMask; uint cullingMask;
vec4 diffuseColor; vec4 diffuseColor;
mat4 pvMatrix;
uint shadowData;
}; };
struct AmbientLightStruct 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 = 2, rgba8) uniform image2D albedo;
layout(set = 3, binding = 3, r32ui) uniform uimage2D lightLayerData; layout(set = 3, binding = 3, r32ui) uniform uimage2D lightLayerData;
layout(set = 3, binding = 4, r8) uniform image2D ssaoBlurredImage; 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 layout(set = 1, binding = 0) uniform LightCounts
{ {
@ -43,6 +48,25 @@ layout(std430, set = 1, binding = 4) buffer AmbientLightData
AmbientLightStruct aLightData[]; AmbientLightStruct aLightData[];
} AmbLightData; } 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() void main()
{ {
// convenient variables // convenient variables
@ -52,6 +76,9 @@ void main()
vec3 pixelDiffuse = imageLoad (albedo, globalThread).rgb; vec3 pixelDiffuse = imageLoad (albedo, globalThread).rgb;
// Get position of fragment in world space // 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; vec3 positionView = imageLoad (positions, globalThread).rgb;
// normal of fragment // normal of fragment
@ -62,6 +89,18 @@ void main()
vec3 fragColor = vec3 (0.0f); 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) for (int i = 0; i < lightCounts.directionalLights; ++i)
{ {
if ((lightLayer & DirLightData.dLightData[i].cullingMask) != 0) if ((lightLayer & DirLightData.dLightData[i].cullingMask) != 0)
@ -74,16 +113,13 @@ void main()
// Calculate the fragment color // Calculate the fragment color
fragColor += DirLightData.dLightData[i].diffuseColor.rgb * diffuseStrength.rrr * pixelDiffuse; fragColor += DirLightData.dLightData[i].diffuseColor.rgb * diffuseStrength.rrr * pixelDiffuse;
}
}
for (int i = 0; i < lightCounts.ambientLights; ++i) // If the shadow map is enabled (test the bit)
{ if ((DirLightData.dLightData[i].shadowData & uint(1)) == 1)
if ((lightLayer & AmbLightData.aLightData[i].cullingMask) != 0) {
{ // calculate shadow map here
// Just do some add fragColor *= CalcShadowValue (shadowMaps[0], positionWorld, DirLightData.dLightData[i].pvMatrix).xxx;
//fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (0.5f); }
fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (AmbLightData.aLightData[i].strength);
} }
} }
@ -92,6 +128,12 @@ void main()
// store result into result image // store result into result image
imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(fragColor.rgb, 1.0f)); 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);
} }

View File

@ -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);
}

Binary file not shown.

View File

@ -0,0 +1,3 @@
Name: ShadowMap_VS
ID: 44646107
Type: 2

View File

@ -16,11 +16,12 @@ layout(location = 0) in struct
vec4 vertPos; // location 0 vec4 vertPos; // location 0
vec2 uv; // location = 1 vec2 uv; // location = 1
vec4 normal; // location = 2 vec4 normal; // location = 2
vec4 worldPos; // location = 3
} In; } In;
// material stuff // material stuff
layout(location = 3) flat in struct layout(location = 4) flat in struct
{ {
int materialIndex; int materialIndex;
uint eid; uint eid;
@ -38,12 +39,14 @@ layout(location = 1) out uint outEntityID;
layout(location = 2) out uint lightLayerIndices; layout(location = 2) out uint lightLayerIndices;
layout(location = 3) out vec4 normals; layout(location = 3) out vec4 normals;
layout(location = 4) out vec4 albedo; layout(location = 4) out vec4 albedo;
layout(location = 5) out vec4 worldSpacePosition;
void main() void main()
{ {
position = In.vertPos; position = In.vertPos;
normals = In.normal; normals = In.normal;
albedo = texture(textures[nonuniformEXT(MatProp.data[In2.materialIndex].textureIndex)], In.uv) * MatProp.data[In2.materialIndex].color; albedo = texture(textures[nonuniformEXT(MatProp.data[In2.materialIndex].textureIndex)], In.uv) * MatProp.data[In2.materialIndex].color;
worldSpacePosition = In.worldPos;
outEntityID = In2.eid; outEntityID = In2.eid;
lightLayerIndices = In2.lightLayerIndex; lightLayerIndices = In2.lightLayerIndex;

Binary file not shown.

View File

@ -17,11 +17,12 @@ layout(location = 0) out struct
vec4 vertPos; // location 0 vec4 vertPos; // location 0
vec2 uv; // location = 1 vec2 uv; // location = 1
vec4 normal; // location = 2 vec4 normal; // location = 2
vec4 worldPos; // location = 3
} Out; } Out;
// material stuff // material stuff
layout(location = 3) out struct layout(location = 4) out struct
{ {
int materialIndex; int materialIndex;
uint eid; uint eid;
@ -49,6 +50,8 @@ void main()
// gBuffer position will be in view space // gBuffer position will be in view space
Out.vertPos = modelViewMat * vec4(aVertexPos, 1.0f); Out.vertPos = modelViewMat * vec4(aVertexPos, 1.0f);
Out.worldPos = worldTransform * vec4 (aVertexPos, 1.0f);
// uvs for texturing in fragment shader // uvs for texturing in fragment shader
Out.uv = aUV; Out.uv = aUV;

Binary file not shown.

View File

@ -270,8 +270,12 @@ namespace SHADE
camera.viewMatrix(1, 3) = -UP.Dot(camera.position + camera.offset); camera.viewMatrix(1, 3) = -UP.Dot(camera.position + camera.offset);
camera.viewMatrix(2, 3) = -view.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; camera.dirtyView = false;
} }
@ -309,7 +313,9 @@ namespace SHADE
camera.orthoProjMatrix(2, 3) = -n / (f-n); camera.orthoProjMatrix(2, 3) = -n / (f-n);
camera.orthoProjMatrix(3, 3) = 1.0f; 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.projMatrix.Transpose();
camera.dirtyProj = false; camera.dirtyProj = false;

View File

@ -489,7 +489,7 @@ namespace SHADE
//auto const& renderers = gfxSystem->GetDefaultViewport()->GetRenderers(); //auto const& renderers = gfxSystem->GetDefaultViewport()->GetRenderers();
auto renderGraph = gfxSystem->GetRenderGraph(); 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) if(ImGui_ImplVulkan_Init(&initInfo, renderPass->GetVkRenderpass()) == false)
{ {
@ -508,7 +508,7 @@ namespace SHADE
ImGui_ImplVulkan_DestroyFontUploadObjects(); ImGui_ImplVulkan_DestroyFontUploadObjects();
renderGraph->GetNode("ImGui Node")->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle<SHVkCommandBuffer> cmd, Handle<SHRenderer> renderer, uint32_t frameIndex) renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::IMGUI_PASS.data())->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle<SHVkCommandBuffer> cmd, Handle<SHRenderer> renderer, uint32_t frameIndex)
{ {
cmd->BeginLabeledSegment("ImGui Draw"); cmd->BeginLabeledSegment("ImGui Draw");
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd->GetVkCommandBuffer()); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd->GetVkCommandBuffer());

View File

@ -175,6 +175,27 @@ namespace SHADE
writeInfo.descImageInfos[i].sampler = sampler ? sampler->GetVkSampler() : nullptr; writeInfo.descImageInfos[i].sampler = sampler ? sampler->GetVkSampler() : nullptr;
writeInfo.descImageInfos[i].imageLayout = layout; 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<Handle<SHVkSampler>>(imageViewsAndSamplers.back())->GetVkSampler();
}
}
void SHVkDescriptorSetGroup::ModifyWriteDescImage(uint32_t set, uint32_t binding, std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, vk::ImageLayout> const& imageViewAndSampler, uint32_t descIndex) noexcept
{
// Find the target writeDescSet
BindingAndSetHash writeHash = binding;
writeHash |= static_cast<uint64_t>(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<Handle<SHVkBuffer>> const& buffers, uint32_t offset, uint32_t range) noexcept void SHVkDescriptorSetGroup::ModifyWriteDescBuffer(uint32_t set, uint32_t binding, std::span<Handle<SHVkBuffer>> 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 void SHVkDescriptorSetGroup::UpdateDescriptorSetImages(uint32_t set, uint32_t binding) noexcept
{ {
vk::WriteDescriptorSet writeDescSet{}; vk::WriteDescriptorSet writeDescSet{};

View File

@ -63,10 +63,12 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Public member functions */ /* 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 UpdateDescriptorSetImages(uint32_t set, uint32_t binding) noexcept;
void UpdateDescriptorSetBuffer(uint32_t set, uint32_t binding) noexcept; void UpdateDescriptorSetBuffer(uint32_t set, uint32_t binding) noexcept;
void ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span<std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, vk::ImageLayout>> const& imageViewsAndSamplers) noexcept; void ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span<std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, vk::ImageLayout>> const& imageViewsAndSamplers) noexcept;
void ModifyWriteDescImage(uint32_t set, uint32_t binding, std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, vk::ImageLayout> const& imageViewAndSampler, uint32_t descIndex) noexcept;
void ModifyWriteDescBuffer (uint32_t set, uint32_t binding, std::span<Handle<SHVkBuffer>> const& buffers, uint32_t offset, uint32_t range) noexcept; void ModifyWriteDescBuffer (uint32_t set, uint32_t binding, std::span<Handle<SHVkBuffer>> const& buffers, uint32_t offset, uint32_t range) noexcept;

View File

@ -183,33 +183,43 @@ namespace SHADE
/*if (!extensionsSupported) /*if (!extensionsSupported)
SHUtil::ReportWarning("Some of the required extensions cannot be found on the physical device. ");*/ 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 // point and lines fill mode
features.fillModeNonSolid = VK_TRUE; features.features.fillModeNonSolid = VK_TRUE;
features.samplerAnisotropy = VK_TRUE; features.features.samplerAnisotropy = VK_TRUE;
features.multiDrawIndirect = VK_TRUE; features.features.multiDrawIndirect = VK_TRUE;
features.independentBlend = VK_TRUE; features.features.independentBlend = VK_TRUE;
features.features.wideLines = VK_TRUE;
// for wide lines features.pNext = &robustFeatures;
features.wideLines = true;
vk::PhysicalDeviceDescriptorIndexingFeatures descIndexingFeature{};
descIndexingFeature.descriptorBindingVariableDescriptorCount = true;
descIndexingFeature.shaderSampledImageArrayNonUniformIndexing = true;
descIndexingFeature.runtimeDescriptorArray = true;
// Prepare to create the device // Prepare to create the device
vk::DeviceCreateInfo deviceCreateInfo vk::DeviceCreateInfo deviceCreateInfo
{ {
.pNext = &descIndexingFeature, .pNext = &features,
.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size()), .queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size()),
.pQueueCreateInfos = queueCreateInfos.data(), .pQueueCreateInfos = queueCreateInfos.data(),
.enabledLayerCount = 0, // deprecated and ignored .enabledLayerCount = 0, // deprecated and ignored
.ppEnabledLayerNames = nullptr, // deprecated and ignored .ppEnabledLayerNames = nullptr, // deprecated and ignored
.enabledExtensionCount = !extensionsSupported ? 0 : static_cast<uint32_t>(requiredExtensions.size()), .enabledExtensionCount = !extensionsSupported ? 0 : static_cast<uint32_t>(requiredExtensions.size()),
.ppEnabledExtensionNames = !extensionsSupported ? nullptr : requiredExtensions.data(), .ppEnabledExtensionNames = !extensionsSupported ? nullptr : requiredExtensions.data(),
.pEnabledFeatures = &features //.pEnabledFeatures = &features
}; };
// Actually create the device // Actually create the device

View File

@ -10,5 +10,8 @@ namespace SHADE
{ {
//! We need to get the light component and initialize the relevant variables. //! We need to get the light component and initialize the relevant variables.
EntityID lightEntity; EntityID lightEntity;
//! Generate a renderer for the light component
bool generateRenderer;
}; };
} }

View File

@ -33,6 +33,7 @@ namespace SHADE
.maxAnisotropy = 1.0f, .maxAnisotropy = 1.0f,
.minLod = params.minLod, .minLod = params.minLod,
.maxLod = params.maxLod, .maxLod = params.maxLod,
.borderColor = vk::BorderColor::eFloatOpaqueWhite
}; };
// Create the sampler // Create the sampler

View File

@ -551,7 +551,7 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* SHBatch - Usage Functions */ /* SHBatch - Usage Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void SHBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) void SHBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline/* = true*/)
{ {
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{ {
@ -566,7 +566,10 @@ namespace SHADE
// Bind all required objects before drawing // Bind all required objects before drawing
static std::array<uint32_t, 1> dynamicOffset{ 0 }; static std::array<uint32_t, 1> dynamicOffset{ 0 };
cmdBuffer->BeginLabeledSegment("SHBatch for Pipeline #" + std::to_string(pipeline.GetId().Data.Index)); 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::TRANSFORM, transformDataBuffer[frameIndex], 0);
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::INTEGER_DATA, instancedIntegerBuffer[frameIndex], 0); cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::INTEGER_DATA, instancedIntegerBuffer[frameIndex], 0);
if (matPropsDescSet[frameIndex]) if (matPropsDescSet[frameIndex])

View File

@ -87,7 +87,7 @@ namespace SHADE
void UpdateTransformBuffer(uint32_t frameIndex); void UpdateTransformBuffer(uint32_t frameIndex);
void UpdateInstancedIntegerBuffer(uint32_t frameIndex); void UpdateInstancedIntegerBuffer(uint32_t frameIndex);
void Build(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) ; void Build(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) ;
void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex); void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline = true);
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Getter Functions */ /* Getter Functions */

View File

@ -107,12 +107,12 @@ namespace SHADE
} }
} }
void SHSuperBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept void SHSuperBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline /*= true*/) noexcept
{ {
// Build all batches // Build all batches
for (auto& batch : batches) for (auto& batch : batches)
{ {
batch.Draw(cmdBuffer, frameIndex); batch.Draw(cmdBuffer, frameIndex, bindBatchPipeline);
} }
} }

View File

@ -57,7 +57,7 @@ namespace SHADE
void Clear() noexcept; void Clear() noexcept;
void UpdateBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool); void UpdateBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
void Build(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept; void Build(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept;
void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept; void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline = true) noexcept;
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Getter Functions */ /* Getter Functions */

View File

@ -13,6 +13,8 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
std::vector<Handle<SHVkDescriptorSetLayout>> SHGraphicsPredefinedData::predefinedLayouts; std::vector<Handle<SHVkDescriptorSetLayout>> SHGraphicsPredefinedData::predefinedLayouts;
SHVertexInputState SHGraphicsPredefinedData::defaultVertexInputState; SHVertexInputState SHGraphicsPredefinedData::defaultVertexInputState;
SHVertexInputState SHGraphicsPredefinedData::shadowMapVertexInputState;
std::vector<SHGraphicsPredefinedData::PerSystem> SHGraphicsPredefinedData::perSystemData; std::vector<SHGraphicsPredefinedData::PerSystem> SHGraphicsPredefinedData::perSystemData;
//SHGraphicsPredefinedData::PerSystem SHGraphicsPredefinedData::batchingSystemData; //SHGraphicsPredefinedData::PerSystem SHGraphicsPredefinedData::batchingSystemData;
@ -150,12 +152,26 @@ namespace SHADE
Handle<SHVkDescriptorSetLayout> fontDataDescSetLayout = logicalDevice->CreateDescriptorSetLayout({ fontBitmapBinding, fontMatrixBinding }); Handle<SHVkDescriptorSetLayout> fontDataDescSetLayout = logicalDevice->CreateDescriptorSetLayout({ fontBitmapBinding, fontMatrixBinding });
SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSetLayout, fontDataDescSetLayout->GetVkHandle(), "[Descriptor Set Layout] Font Data"); 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<SHVkDescriptorSetLayout> 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(staticGlobalLayout);
predefinedLayouts.push_back(lightDataDescSetLayout); predefinedLayouts.push_back(lightDataDescSetLayout);
predefinedLayouts.push_back(cameraDataGlobalLayout); predefinedLayouts.push_back(cameraDataGlobalLayout);
predefinedLayouts.push_back(materialDataPerInstanceLayout); predefinedLayouts.push_back(materialDataPerInstanceLayout);
predefinedLayouts.push_back(fontDataDescSetLayout); predefinedLayouts.push_back(fontDataDescSetLayout);
predefinedLayouts.push_back(shadowMapDescLayout);
perSystemData[SHUtilities::ConvertEnum(SystemType::BATCHING)].descSetLayouts = GetPredefinedDescSetLayouts 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_3D) }); // positions at binding 0
defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_2D) }); // UVs at binding 1 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(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::MAT_4D) }); // Transform at binding 4 - 7 (4 slots)
defaultVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::UINT32_2D) }); // Instanced integer data at index 8 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<SHVkLogicalDevice> logicalDevice) noexcept void SHGraphicsPredefinedData::Init(Handle<SHVkLogicalDevice> logicalDevice) noexcept
{ {
perSystemData.resize(SHUtilities::ConvertEnum(SystemType::NUM_TYPES)); perSystemData.resize(SHUtilities::ConvertEnum(SystemType::NUM_TYPES));
InitDescSetLayouts(logicalDevice); InitDescSetLayouts(logicalDevice);
InitDefaultVertexInputState(); InitPredefinedVertexInputState();
InitDescMappings(); InitDescMappings();
InitDummyPipelineLayouts (logicalDevice); InitDummyPipelineLayouts (logicalDevice);
} }
@ -217,6 +236,11 @@ namespace SHADE
} }
SHVertexInputState const& SHGraphicsPredefinedData::GetShadowMapViState(void) noexcept
{
return shadowMapVertexInputState;
}
SHGraphicsPredefinedData::PerSystem const& SHGraphicsPredefinedData::GetSystemData(SystemType systemType) noexcept SHGraphicsPredefinedData::PerSystem const& SHGraphicsPredefinedData::GetSystemData(SystemType systemType) noexcept
{ {
return perSystemData[static_cast<uint32_t>(systemType)]; return perSystemData[static_cast<uint32_t>(systemType)];

View File

@ -28,6 +28,7 @@ namespace SHADE
CAMERA = 0x04, CAMERA = 0x04,
MATERIALS = 0x08, MATERIALS = 0x08,
FONT = 0x10, FONT = 0x10,
SHADOW = 0x20,
}; };
enum class SystemType enum class SystemType
@ -57,6 +58,9 @@ namespace SHADE
//! Default vertex input state (used by everything). //! Default vertex input state (used by everything).
static SHVertexInputState defaultVertexInputState; static SHVertexInputState defaultVertexInputState;
//! vertex input state for shadow mapping
static SHVertexInputState shadowMapVertexInputState;
//! Predefined data for each type of system //! Predefined data for each type of system
static std::vector<PerSystem> perSystemData; static std::vector<PerSystem> perSystemData;
@ -72,7 +76,7 @@ namespace SHADE
static void InitDescMappings (void) noexcept; static void InitDescMappings (void) noexcept;
static void InitDummyPipelineLayouts (Handle<SHVkLogicalDevice> logicalDevice) noexcept; static void InitDummyPipelineLayouts (Handle<SHVkLogicalDevice> logicalDevice) noexcept;
static void InitDescSetLayouts (Handle<SHVkLogicalDevice> logicalDevice) noexcept; static void InitDescSetLayouts (Handle<SHVkLogicalDevice> logicalDevice) noexcept;
static void InitDefaultVertexInputState (void) noexcept; static void InitPredefinedVertexInputState (void) noexcept;
public: public:
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@ -90,6 +94,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
static std::vector<Handle<SHVkDescriptorSetLayout>> GetPredefinedDescSetLayouts (SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes types) noexcept; static std::vector<Handle<SHVkDescriptorSetLayout>> GetPredefinedDescSetLayouts (SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes types) noexcept;
static SHVertexInputState const& GetDefaultViState (void) noexcept; static SHVertexInputState const& GetDefaultViState (void) noexcept;
static SHVertexInputState const& GetShadowMapViState (void) noexcept;
static PerSystem const& GetSystemData (SystemType systemType) noexcept; static PerSystem const& GetSystemData (SystemType systemType) noexcept;
static SHDescriptorMappings::MapType const& GetMappings (SystemType systemType) noexcept; static SHDescriptorMappings::MapType const& GetMappings (SystemType systemType) noexcept;
//static PerSystem const& GetBatchingSystemData(void) noexcept; //static PerSystem const& GetBatchingSystemData(void) noexcept;

View File

@ -13,7 +13,7 @@ namespace SHADE
CAMERA, CAMERA,
MATERIALS, MATERIALS,
FONT, FONT,
RENDER_GRAPH_RESOURCE,
RENDER_GRAPH_NODE_COMPUTE_RESOURCE, RENDER_GRAPH_NODE_COMPUTE_RESOURCE,
RENDER_GRAPH_RESOURCE,
}; };
} }

View File

@ -101,7 +101,7 @@ namespace SHADE
// Register function for subpass // Register function for subpass
//auto const& RENDERERS = gfxSystem->GetDefaultViewport()->GetRenderers(); //auto const& RENDERERS = gfxSystem->GetDefaultViewport()->GetRenderers();
auto renderGraph = gfxSystem->GetRenderGraph(); 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<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex) subPass->AddExteriorDrawCalls([this](Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex)
{ {
// Set line width first // Set line width first
@ -129,7 +129,7 @@ namespace SHADE
} }
cmdBuffer->EndLabeledSegment(); 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<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex) subPassWithDepth->AddExteriorDrawCalls([this](Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex)
{ {
// Set line width first // Set line width first

View File

@ -31,68 +31,91 @@ namespace SHADE
static constexpr uint32_t EDITOR = 0; static constexpr uint32_t EDITOR = 0;
}; };
//struct DescriptorSetIndex struct RenderGraphEntityNames
//{ {
// /***************************************************************************/ /***************************************************************************/
// /*! /*!
// \brief
// DescriptorSet Index for static global values like generic data, and \brief
// texture samplers Name of G-Buffer render graph node.
// */
// /***************************************************************************/ */
// static constexpr uint32_t STATIC_GLOBALS = 0; /***************************************************************************/
// /***************************************************************************/ static constexpr std::string_view GBUFFER_PASS = "G-Buffer";
// /*!
// \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;
// /***************************************************************************/ /***************************************************************************/
// /*! /*!
// \brief
// To store font data. \brief
// Name of shadow map render graph node.
// */
// /***************************************************************************/ */
// static constexpr uint32_t FONT_DATA = 4; /***************************************************************************/
//}; 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 struct DescriptorSetBindings
{ {
@ -158,6 +181,16 @@ namespace SHADE
/***************************************************************************/ /***************************************************************************/
static constexpr uint32_t FONT_MATRIX_DATA = 1; 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 struct VertexBufferBindings

View File

@ -44,6 +44,9 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/MiddleEnd/TextRendering/SHFreetypeInstance.h" #include "Graphics/MiddleEnd/TextRendering/SHFreetypeInstance.h"
#include "Graphics/MiddleEnd/TextRendering/SHTextRenderingSubSystem.h" #include "Graphics/MiddleEnd/TextRendering/SHTextRenderingSubSystem.h"
#include "Graphics/MiddleEnd/GlobalData/SHGlobalDescriptorSets.h" #include "Graphics/MiddleEnd/GlobalData/SHGlobalDescriptorSets.h"
#include "Events/SHEvent.h"
#include "Graphics/MiddleEnd/Lights/SHLightComponent.h"
#include "Input/SHInputManager.h"
namespace SHADE namespace SHADE
{ {
@ -124,6 +127,13 @@ namespace SHADE
SHFreetypeInstance::Init(); 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 // Load Built In Shaders
static constexpr AssetID VS_DEFAULT = 39210065; defaultVertShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(VS_DEFAULT); static constexpr AssetID VS_DEFAULT = 39210065; defaultVertShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(VS_DEFAULT);
static constexpr AssetID FS_DEFAULT = 46377769; defaultFragShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(FS_DEFAULT); static constexpr AssetID FS_DEFAULT = 46377769; defaultFragShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(FS_DEFAULT);
@ -137,6 +147,8 @@ namespace SHADE
static constexpr AssetID TEXT_FS = 38024754; textFS = SHResourceManager::LoadOrGet<SHVkShaderModule>(TEXT_FS); static constexpr AssetID TEXT_FS = 38024754; textFS = SHResourceManager::LoadOrGet<SHVkShaderModule>(TEXT_FS);
static constexpr AssetID RENDER_SC_VS = 48082949; renderToSwapchainVS = SHResourceManager::LoadOrGet<SHVkShaderModule>(RENDER_SC_VS); static constexpr AssetID RENDER_SC_VS = 48082949; renderToSwapchainVS = SHResourceManager::LoadOrGet<SHVkShaderModule>(RENDER_SC_VS);
static constexpr AssetID RENDER_SC_FS = 36869006; renderToSwapchainFS = SHResourceManager::LoadOrGet<SHVkShaderModule>(RENDER_SC_FS); static constexpr AssetID RENDER_SC_FS = 36869006; renderToSwapchainFS = SHResourceManager::LoadOrGet<SHVkShaderModule>(RENDER_SC_FS);
static constexpr AssetID SHADOW_MAP_VS = 44646107; shadowMapVS = SHResourceManager::LoadOrGet<SHVkShaderModule>(SHADOW_MAP_VS);
} }
void SHGraphicsSystem::InitRenderGraph(void) noexcept void SHGraphicsSystem::InitRenderGraph(void) noexcept
@ -169,6 +181,8 @@ namespace SHADE
// Create Default Viewport // Create Default Viewport
worldViewport = AddViewport(vk::Viewport(0.0f, 0.0f, static_cast<float>(window->GetWindowSize().first), static_cast<float>(window->GetWindowSize().second), 0.0f, 1.0f)); worldViewport = AddViewport(vk::Viewport(0.0f, 0.0f, static_cast<float>(window->GetWindowSize().first), static_cast<float>(window->GetWindowSize().second), 0.0f, 1.0f));
shadowMapViewport = AddViewport(vk::Viewport(0.0f, 0.0f, static_cast<float>(SHLightingSubSystem::SHADOW_MAP_WIDTH), static_cast<float>(SHLightingSubSystem::SHADOW_MAP_HEIGHT), 0.0f, 1.0f));
std::vector<Handle<SHVkCommandPool>> renderContextCmdPools{ swapchain->GetNumImages() }; std::vector<Handle<SHVkCommandPool>> renderContextCmdPools{ swapchain->GetNumImages() };
for (uint32_t i = 0; i < renderContextCmdPools.size(); ++i) for (uint32_t i = 0; i < renderContextCmdPools.size(); ++i)
{ {
@ -183,22 +197,24 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
// Initialize world render graph // Initialize world render graph
renderGraph->Init("World Render Graph", device, swapchain, &resourceManager, renderContextCmdPools); 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("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("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 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); //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("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 }, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint); 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 }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); 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 }, 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 }, windowDims.first, windowDims.second); 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 }, windowDims.first, windowDims.second, vk::Format::eR8Unorm); 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 }, 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 }, windowDims.first, windowDims.second); renderGraph->AddResource("Present", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT }, true, windowDims.first, windowDims.second);
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* MAIN NODE */ /* 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", "Position",
"Entity ID", "Entity ID",
@ -207,7 +223,8 @@ namespace SHADE
"Albedo", "Albedo",
"Depth Buffer", "Depth Buffer",
"SSAO", "SSAO",
"SSAO Blur" "SSAO Blur",
"Position World Space"
}, },
{}); // no predecessors {}); // no predecessors
@ -220,6 +237,7 @@ namespace SHADE
gBufferSubpass->AddColorOutput("Light Layer Indices"); gBufferSubpass->AddColorOutput("Light Layer Indices");
gBufferSubpass->AddColorOutput("Normals"); gBufferSubpass->AddColorOutput("Normals");
gBufferSubpass->AddColorOutput("Albedo"); gBufferSubpass->AddColorOutput("Albedo");
gBufferSubpass->AddColorOutput("Position World Space");
gBufferSubpass->AddDepthOutput("Depth Buffer", SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL); gBufferSubpass->AddDepthOutput("Depth Buffer", SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL);
@ -254,53 +272,52 @@ namespace SHADE
// Add another pass to blur SSAO // Add another pass to blur SSAO
Handle<SHRenderGraphNodeCompute> ssaoBlurPass = gBufferNode->AddNodeCompute("SSAO Blur Step", ssaoBlurShader, { "SSAO", "SSAO Blur" }); Handle<SHRenderGraphNodeCompute> 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 */ /* DEFERRED COMPOSITE NODE */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
// This pass will facilitate both lighting and shadows in 1 single pass. // 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", "Position",
"Light Layer Indices", "Light Layer Indices",
"Normals", "Normals",
"Albedo", "Albedo",
"Scene", "Scene",
"SSAO Blur" "SSAO Blur",
"Position World Space"
}, },
{"G-Buffer"}); { SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS .data()});
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* DEFERRED COMPOSITE SUBPASS INIT */ /* 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<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex)
{
lightingSubSystem->PrepareShadowMapsForRead(cmdBuffer);
});
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* DEBUG DRAW PASS INIT */ /* DEBUG DRAW PASS INIT */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
// Set up Debug Draw Passes // Set up Debug Draw Passes
// - Depth Tested // - 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); auto debugDrawDepthSubpass = debugDrawNodeDepth->AddSubpass("Debug Draw with Depth", worldViewport, worldRenderer);
debugDrawDepthSubpass->AddColorOutput("Scene"); debugDrawDepthSubpass->AddColorOutput("Scene");
debugDrawDepthSubpass->AddDepthOutput("Depth Buffer"); debugDrawDepthSubpass->AddDepthOutput("Depth Buffer");
// - No Depth Test // - 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); auto debugDrawSubpass = debugDrawNode->AddSubpass("Debug Draw", worldViewport, worldRenderer);
debugDrawSubpass->AddColorOutput("Scene"); debugDrawSubpass->AddColorOutput("Scene");
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* SCREEN SPACE PASS */ /* 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); auto uiSubpass = screenSpaceNode->AddSubpass("UI", worldViewport, screenRenderer);
uiSubpass->AddColorOutput("Scene"); uiSubpass->AddColorOutput("Scene");
uiSubpass->AddColorOutput("Entity ID"); uiSubpass->AddColorOutput("Entity ID");
@ -315,16 +332,16 @@ namespace SHADE
#ifdef SHEDITOR #ifdef SHEDITOR
{ {
// Dummy Node to transition scene render graph resource // 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", {}, {}); auto dummySubpass = dummyNode->AddSubpass("Dummy Subpass", {}, {});
dummySubpass->AddInput("Scene"); 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", {}, {}); auto imGuiSubpass = imGuiNode->AddSubpass("ImGui Draw", {}, {});
imGuiSubpass->AddColorOutput("Present"); imGuiSubpass->AddColorOutput("Present");
} }
#else #else
renderGraph->AddRenderToSwapchainNode("Scene", "Present", { "Screen Space Pass" }, { renderToSwapchainVS, renderToSwapchainFS }); renderGraph->AddRenderToSwapchainNode("Scene", "Present", { SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS .data()}, {renderToSwapchainVS, renderToSwapchainFS});
#endif #endif
@ -393,12 +410,16 @@ namespace SHADE
postOffscreenRenderSubSystem->Init(device, renderGraph->GetRenderGraphResource("Scene"), descPool); postOffscreenRenderSubSystem->Init(device, renderGraph->GetRenderGraphResource("Scene"), descPool);
lightingSubSystem = resourceManager.Create<SHLightingSubSystem>(); lightingSubSystem = resourceManager.Create<SHLightingSubSystem>();
lightingSubSystem->Init(device, descPool); lightingSubSystem->Init(device, descPool, &resourceManager, samplerCache.GetSampler (device, SHVkSamplerParams
{
.addressMode = vk::SamplerAddressMode::eClampToBorder,
})
);
textRenderingSubSystem = resourceManager.Create<SHTextRenderingSubSystem>(); textRenderingSubSystem = resourceManager.Create<SHTextRenderingSubSystem>();
// initialize the text renderer // 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); textRenderingSubSystem->Init(device, uiNode->GetRenderpass(), uiNode->GetSubpass("UI"), descPool, textVS, textFS);
SHGlobalDescriptorSets::SetLightingSubSystem(lightingSubSystem); SHGlobalDescriptorSets::SetLightingSubSystem(lightingSubSystem);
@ -426,7 +447,7 @@ namespace SHADE
defaultMaterial = AddMaterial defaultMaterial = AddMaterial
( (
defaultVertShader, defaultFragShader, 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); defaultMaterial->SetProperty("data.textureIndex", defaultTexture->TextureArrayIndex);
} }
@ -451,6 +472,7 @@ namespace SHADE
InitMiddleEnd(); InitMiddleEnd();
InitSubsystems(); InitSubsystems();
InitBuiltInResources(); InitBuiltInResources();
InitEvents();
} }
void SHGraphicsSystem::Exit(void) void SHGraphicsSystem::Exit(void)
@ -546,6 +568,15 @@ namespace SHADE
#endif #endif
} }
if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::B))
{
auto& lightComps = SHComponentManager::GetDense<SHLightComponent>();
for (auto& comp : lightComps)
{
comp.SetEnableShadow(true);
}
}
renderGraph->Begin(frameIndex); renderGraph->Begin(frameIndex);
auto cmdBuffer = renderGraph->GetCommandBuffer(frameIndex); auto cmdBuffer = renderGraph->GetCommandBuffer(frameIndex);
@ -726,16 +757,61 @@ namespace SHADE
renderers.erase(iter); 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<const SHEventSpec<SHLightEnableShadowEvent>*>(eventPtr.get())->data;
auto* lightComp = SHComponentManager::GetComponent<SHLightComponent>(EVENT_DATA->lightEntity);
std::string resourceName = "ShadowMap " + std::to_string(EVENT_DATA->lightEntity);
Handle<SHSubpass> 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<SHRenderer> newRenderer = resourceManager.Create<SHRenderer>(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 // 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. // 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 // 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<SHRenderGraphNode> 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 (); // add the shadow map to the lighting system
return event->handle; 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<SHMaterial> SHGraphicsSystem::AddMaterial(Handle<SHVkShaderModule> vertShader, Handle<SHVkShaderModule> fragShader, Handle<SHSubpass> subpass) Handle<SHMaterial> SHGraphicsSystem::AddMaterial(Handle<SHVkShaderModule> vertShader, Handle<SHVkShaderModule> fragShader, Handle<SHSubpass> subpass)
@ -1047,6 +1123,7 @@ namespace SHADE
mousePickSubSystem->HandleResize(); mousePickSubSystem->HandleResize();
postOffscreenRenderSubSystem->HandleResize(); postOffscreenRenderSubSystem->HandleResize();
//lightingSubSystem->HandleResize(renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data())->GetNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data()));
worldViewport->SetWidth(static_cast<float>(resizeWidth)); worldViewport->SetWidth(static_cast<float>(resizeWidth));
worldViewport->SetHeight(static_cast<float>(resizeHeight)); worldViewport->SetHeight(static_cast<float>(resizeHeight));
@ -1079,7 +1156,7 @@ namespace SHADE
Handle<SHRenderGraphNode> SHGraphicsSystem::GetPrimaryRenderpass() const noexcept Handle<SHRenderGraphNode> SHGraphicsSystem::GetPrimaryRenderpass() const noexcept
{ {
return renderGraph->GetNode(G_BUFFER_RENDER_GRAPH_NODE_NAME.data()); return renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data());
} }
Handle<SHVkPipeline> SHGraphicsSystem::GetDebugDrawPipeline(DebugDrawPipelineType type) const noexcept Handle<SHVkPipeline> SHGraphicsSystem::GetDebugDrawPipeline(DebugDrawPipelineType type) const noexcept

View File

@ -178,7 +178,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Light functions */ /* Light functions */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
SHEventHandle ReceiveLightEnableShadowEvent (SHEventPtr event) noexcept; SHEventHandle ReceiveLightEnableShadowEvent (SHEventPtr eventPtr) noexcept;
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Material Functions */ /* Material Functions */
@ -406,10 +406,6 @@ namespace SHADE
SHWindow* GetWindow() noexcept { return window; } SHWindow* GetWindow() noexcept { return window; }
private: private:
/*-----------------------------------------------------------------------------*/
/* Constants */
/*-----------------------------------------------------------------------------*/
static constexpr std::string_view G_BUFFER_RENDER_GRAPH_NODE_NAME = "G-Buffer";
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Data Members */ /* Data Members */
@ -446,6 +442,7 @@ namespace SHADE
#endif #endif
Handle<SHViewport> worldViewport; // Whole screen Handle<SHViewport> worldViewport; // Whole screen
Handle<SHViewport> shadowMapViewport;
std::vector<Handle<SHViewport>> viewports; // Additional viewports std::vector<Handle<SHViewport>> viewports; // Additional viewports
// Renderers // Renderers
@ -469,6 +466,7 @@ namespace SHADE
Handle<SHVkShaderModule> textFS; Handle<SHVkShaderModule> textFS;
Handle<SHVkShaderModule> renderToSwapchainVS; Handle<SHVkShaderModule> renderToSwapchainVS;
Handle<SHVkShaderModule> renderToSwapchainFS; Handle<SHVkShaderModule> renderToSwapchainFS;
Handle<SHVkShaderModule> shadowMapVS;
// Fonts // Fonts
Handle<SHFont> testFont; Handle<SHFont> testFont;
@ -483,6 +481,7 @@ namespace SHADE
Handle<SHVkPipeline> debugDrawWireMeshDepthPipeline; Handle<SHVkPipeline> debugDrawWireMeshDepthPipeline;
Handle<SHVkPipeline> debugDrawFilledPipeline; Handle<SHVkPipeline> debugDrawFilledPipeline;
Handle<SHVkPipeline> debugDrawFilledDepthPipeline; Handle<SHVkPipeline> debugDrawFilledDepthPipeline;
Handle<SHVkPipeline> shadowMapPipeline; // initialized only when a shadow map is needed
// Built-In Textures // Built-In Textures
Handle<SHTexture> defaultTexture; Handle<SHTexture> defaultTexture;

View File

@ -122,4 +122,9 @@ namespace SHADE
return cameraDirector; return cameraDirector;
} }
SHShaderCameraData SHRenderer::GetCPUCameraData(void) const noexcept
{
return cpuCameraData;
}
} }

View File

@ -18,9 +18,9 @@ of DigiPen Institute of Technology is prohibited.
// Project Includes // Project Includes
#include "SHCamera.h" #include "SHCamera.h"
#include "Resource/SHHandle.h" #include "Resource/SHHandle.h"
#include "Graphics/RenderGraph/SHRenderGraph.h"
#include "Math/SHMath.h" #include "Math/SHMath.h"
#include <vector> #include <vector>
#include "Graphics/Pipeline/SHPipelineType.h"
namespace SHADE namespace SHADE
{ {
@ -93,6 +93,7 @@ namespace SHADE
/* Setters and Getters */ /* Setters and Getters */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
Handle<SHCameraDirector> GetCameraDirector (void) const noexcept; Handle<SHCameraDirector> GetCameraDirector (void) const noexcept;
SHShaderCameraData GetCPUCameraData (void) const noexcept;
private: private:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/

View File

@ -2,6 +2,7 @@
#include "SHLightComponent.h" #include "SHLightComponent.h"
#include "Graphics/Events/SHGraphicsEvents.h" #include "Graphics/Events/SHGraphicsEvents.h"
#include "Events/SHEventManager.hpp" #include "Events/SHEventManager.hpp"
#include "Graphics/MiddleEnd/Interface/SHRenderer.h"
namespace SHADE namespace SHADE
{ {
@ -14,6 +15,7 @@ namespace SHADE
//indexInBuffer = std::numeric_limits<uint32_t>::max(); //indexInBuffer = std::numeric_limits<uint32_t>::max();
isActive = true; isActive = true;
//Unbind(); //Unbind();
renderer = {};
} }
@ -116,11 +118,22 @@ namespace SHADE
// Create new event and broadcast it // Create new event and broadcast it
SHLightEnableShadowEvent newEvent; SHLightEnableShadowEvent newEvent;
newEvent.lightEntity = GetEID(); newEvent.lightEntity = GetEID();
newEvent.generateRenderer = static_cast<bool>(!renderer);
SHEventManager::BroadcastEvent<SHLightEnableShadowEvent>(newEvent, SH_GRAPHICS_LIGHT_ENABLE_SHADOW_EVENT); SHEventManager::BroadcastEvent<SHLightEnableShadowEvent>(newEvent, SH_GRAPHICS_LIGHT_ENABLE_SHADOW_EVENT);
} }
} }
void SHLightComponent::SetRenderer(Handle<SHRenderer> newRenderer) noexcept
{
renderer = newRenderer;
}
void SHLightComponent::SetShadowMapIndex(uint32_t index) noexcept
{
lightData.shadowMapIndex = index;
}
SHLightData const& SHLightComponent::GetLightData(void) const noexcept SHLightData const& SHLightComponent::GetLightData(void) const noexcept
{ {
return lightData; return lightData;
@ -172,6 +185,11 @@ namespace SHADE
return lightData.strength; return lightData.strength;
} }
Handle<SHRenderer> SHLightComponent::GetRenderer(void) const noexcept
{
return renderer;
}
} }
RTTR_REGISTRATION RTTR_REGISTRATION

View File

@ -3,9 +3,11 @@
#include <rttr/registration> #include <rttr/registration>
#include "ECS_Base/Components/SHComponent.h" #include "ECS_Base/Components/SHComponent.h"
#include "SHLightData.h" #include "SHLightData.h"
#include "Resource/SHHandle.h"
namespace SHADE namespace SHADE
{ {
class SHRenderer;
class SH_API SHLightComponent final : public SHComponent class SH_API SHLightComponent final : public SHComponent
{ {
@ -14,6 +16,9 @@ namespace SHADE
//! GPU depends on the type of the light. //! GPU depends on the type of the light.
SHLightData lightData; SHLightData lightData;
//! Renderer to calculate light world to projection matrix
Handle<SHRenderer> renderer;
//! Since the lighting system is gonna be self contained and light weight, we store this //! 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 //! 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. //! 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 SetBound (uint32_t inIndexInBuffer) noexcept;
void SetStrength (float value) noexcept; // serialized void SetStrength (float value) noexcept; // serialized
void SetEnableShadow (bool flag) noexcept; void SetEnableShadow (bool flag) noexcept;
void SetRenderer (Handle<SHRenderer> newRenderer) noexcept;
void SetShadowMapIndex (uint32_t index) noexcept;
SHLightData const& GetLightData (void) const noexcept; SHLightData const& GetLightData (void) const noexcept;
@ -61,6 +68,7 @@ namespace SHADE
//bool GetBound (void) const noexcept; //bool GetBound (void) const noexcept;
//uint32_t GetIndexInBuffer (void) const noexcept; //uint32_t GetIndexInBuffer (void) const noexcept;
float GetStrength (void) const noexcept; float GetStrength (void) const noexcept;
Handle<SHRenderer> GetRenderer (void) const noexcept;
RTTR_ENABLE() RTTR_ENABLE()
}; };
} }

View File

@ -10,6 +10,13 @@
#include "SHLightComponent.h" #include "SHLightComponent.h"
#include "Math/Vector/SHVec4.h" #include "Math/Vector/SHVec4.h"
#include "Math/SHMatrix.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 namespace SHADE
{ {
@ -50,6 +57,19 @@ namespace SHADE
//lightPtr->direction = lightData.direction; //lightPtr->direction = lightData.direction;
lightPtr->diffuseColor = lightData.color; lightPtr->diffuseColor = lightData.color;
lightPtr->active = lightComp->isActive; 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; break;
} }
case SH_LIGHT_TYPE::POINT: 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<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool) noexcept void SHLightingSubSystem::Init(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, SHResourceHub* rh, Handle<SHVkSampler> inShadowMapSampler) noexcept
{ {
SHComponentManager::CreateComponentSparseSet<SHLightComponent>(); SHComponentManager::CreateComponentSparseSet<SHLightComponent>();
logicalDevice = device; logicalDevice = device;
resourceHub = rh;
uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ConvertEnum(SH_LIGHT_TYPE::NUM_TYPES); uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ConvertEnum(SH_LIGHT_TYPE::NUM_TYPES);
#pragma region LIGHTING
std::vector<uint32_t> variableSizes{ NUM_LIGHT_TYPES }; std::vector<uint32_t> variableSizes{ NUM_LIGHT_TYPES };
std::fill (variableSizes.begin(), variableSizes.end(), 1); std::fill (variableSizes.begin(), variableSizes.end(), 1);
@ -418,7 +466,22 @@ namespace SHADE
dynamicOffsets[i].resize(NUM_LIGHT_TYPES + 1); // +1 for the count dynamicOffsets[i].resize(NUM_LIGHT_TYPES + 1); // +1 for the count
} }
#pragma endregion
#pragma region SHADOWS
//std::vector<uint32_t> 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<int>(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; //numLightComponents = 0;
#pragma endregion
} }
/***************************************************************************/ /***************************************************************************/
@ -452,6 +515,12 @@ namespace SHADE
for (auto& light : lightComps) 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); auto enumValue = SHUtilities::ConvertEnum(light.GetLightData().type);
// First we want to make sure the light is already bound to the system. if it // 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. // so we do it anyway. #NoteToSelf: if at any point it affects performance, do a check before computing.
ComputeDynamicOffsets(); ComputeDynamicOffsets();
} }
/***************************************************************************/ /***************************************************************************/
@ -526,9 +594,101 @@ namespace SHADE
} }
uint32_t SHLightingSubSystem::AddShadowMap(Handle<SHRenderGraphResource> newShadowMap, EntityID lightEntity) noexcept
{
// Add to container of shadow maps
shadowMapIndexing.emplace(lightEntity, static_cast<uint32_t> (shadowMaps.size()));
shadowMaps.emplace_back(newShadowMap);
// Just use the image view stored in the resource
Handle<SHVkImageView> 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<uint32_t>(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<uint32_t>(shadowMapImageSamplers.size()) - 1u;
}
void SHLightingSubSystem::PrepareShadowMapsForRead(Handle<SHVkCommandBuffer> 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<SHRenderGraphNodeCompute> compute) noexcept
//{
// uint32_t const NUM_SHADOW_MAPS = static_cast<uint32_t>(shadowMaps.size());
// for (uint32_t i = 0; i < NUM_SHADOW_MAPS; ++i)
// {
// // Just use the image view stored in the resource
// Handle<SHVkImageView> const NEW_IMAGE_VIEW = shadowMaps[i]->GetImageView();
// // set new image view
// std::get<Handle<SHVkImageView>>(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<SHVkDescriptorSetGroup> SHLightingSubSystem::GetLightDataDescriptorSet(void) const noexcept Handle<SHVkDescriptorSetGroup> SHLightingSubSystem::GetLightDataDescriptorSet(void) const noexcept
{ {
return lightingDataDescSet; return lightingDataDescSet;
} }
std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, vk::ImageLayout> const& SHLightingSubSystem::GetViewSamplerLayout(uint32_t index) const noexcept
{
return shadowMapImageSamplers[index];
}
uint32_t SHLightingSubSystem::GetNumShadowMaps(void) const noexcept
{
return static_cast<uint32_t>(shadowMaps.size());
}
} }

View File

@ -3,9 +3,13 @@
#include "Resource/SHHandle.h" #include "Resource/SHHandle.h"
#include "Math/Vector/SHVec3.h" #include "Math/Vector/SHVec3.h"
#include "Math/Vector/SHVec4.h" #include "Math/Vector/SHVec4.h"
#include "Math/SHMatrix.h"
#include "SHLightData.h" #include "SHLightData.h"
#include <array> #include <array>
#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" #include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
#include "Graphics/RenderGraph/SHRenderGraphResource.h"
#include "ECS_Base/SHECSMacros.h"
namespace SHADE namespace SHADE
{ {
@ -16,6 +20,10 @@ namespace SHADE
class SHVkBuffer; class SHVkBuffer;
class SHLightComponent; class SHLightComponent;
class SHVkCommandBuffer; 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. // Represents how the data will be interpreted in GPU. we want to copy to a container of these before passing to GPU.
struct SHDirectionalLightData struct SHDirectionalLightData
@ -34,6 +42,12 @@ namespace SHADE
//! Diffuse color emitted by the light //! Diffuse color emitted by the light
alignas (16) SHVec4 diffuseColor; 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. // 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 //! 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. //! layer value to AND with the light's. If result is 1, do lighting calculations.
uint32_t cullingMask; uint32_t cullingMask;
}; };
class SH_API SHLightingSubSystem class SH_API SHLightingSubSystem
{ {
public: public:
using DynamicOffsetArray = std::array<std::vector<uint32_t>, static_cast<uint32_t>(SHGraphicsConstants::NUM_FRAME_BUFFERS)>; using DynamicOffsetArray = std::array<std::vector<uint32_t>, static_cast<uint32_t>(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: private:
class PerTypeData class PerTypeData
{ {
public:
private: private:
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* STATIC MEMBER VARIABLES */ /* STATIC MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
static constexpr uint32_t STARTING_NUM_LIGHTS = 50; static constexpr uint32_t STARTING_NUM_LIGHTS = 50;
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */ /* PRIVATE MEMBER VARIABLES */
@ -123,51 +140,90 @@ namespace SHADE
}; };
private: private:
/*-----------------------------------------------------------------------*/
/* STATIC MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/
//! logical device used for creation //! logical device used for creation
Handle<SHVkLogicalDevice> logicalDevice; Handle<SHVkLogicalDevice> logicalDevice;
//! The descriptor set that will hold the lighting data. Each binding will hold a buffer, NUM_FRAMES times the size required. //! The descriptor set that will hold the lighting data. Each binding will hold a buffer, NUM_FRAMES times the size required.
Handle<SHVkDescriptorSetGroup> lightingDataDescSet; Handle<SHVkDescriptorSetGroup> lightingDataDescSet;
//! Each type will have some data associated with it for processing //! Each type will have some data associated with it for processing
std::array<PerTypeData, static_cast<uint32_t>(SH_LIGHT_TYPE::NUM_TYPES)> perTypeData; std::array<PerTypeData, static_cast<uint32_t>(SH_LIGHT_TYPE::NUM_TYPES)> perTypeData;
//! Container to store dynamic offsets for binding descriptor sets //! Container to store dynamic offsets for binding descriptor sets
DynamicOffsetArray dynamicOffsets; DynamicOffsetArray dynamicOffsets;
//! holds the data that represents how many lights are in the scene //! holds the data that represents how many lights are in the scene
std::array<uint32_t, static_cast<uint32_t>(SH_LIGHT_TYPE::NUM_TYPES)> lightCountsData; std::array<uint32_t, static_cast<uint32_t>(SH_LIGHT_TYPE::NUM_TYPES)> lightCountsData;
//! GPU buffer to hold lightCountData //! GPU buffer to hold lightCountData
Handle<SHVkBuffer> lightCountsBuffer; Handle<SHVkBuffer> lightCountsBuffer;
//! For padding in the buffer //! For padding in the buffer
uint32_t lightCountsAlignedSize; uint32_t lightCountsAlignedSize;
//! Number of SHLightComponents recorded. If at the beginning of the run function the size returned by the dense //! 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, //! set is less than the size recorded, rewrite all light components into the its respective buffers. If its more,
//! don't do anything. //! don't do anything.
//uint32_t numLightComponents; //uint32_t numLightComponents;
//! Handle to sampler that all shadow map descriptors will use
Handle<SHVkSampler> shadowMapSampler;
//! For indexing shadow maps
std::unordered_map<EntityID, uint32_t> shadowMapIndexing;
//! Shadow maps for every light that casts a shadow Order here doesn't matter. We just want to store it
std::vector<Handle<SHRenderGraphResource>> 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<SHVkDescriptorSetGroup> shadowMapDescriptorSet;
//! Combined image samplers for the texture descriptors
std::vector<std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, 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<vk::ImageMemoryBarrier> shadowMapMemoryBarriers;
//! Resource hub from Graphics System
SHResourceHub* resourceHub;
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER FUNCTIONS */ /* PRIVATE MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
void UpdateDescSet (uint32_t binding) noexcept; void UpdateDescSet (uint32_t binding) noexcept;
void ComputeDynamicOffsets (void) noexcept; void ComputeDynamicOffsets (void) noexcept;
void ResetNumLights (void) noexcept; void ResetNumLights (void) noexcept;
void UpdateShadowMapDesc (void) noexcept;
SHMatrix GetViewMatrix (SHLightComponent* lightComp) noexcept;
public: public:
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */ /* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
void Init (Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool) noexcept; void Init (Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, SHResourceHub* rh, Handle<SHVkSampler> inShadowMapSampler) noexcept;
void Run (SHMatrix const& viewMat, uint32_t frameIndex) noexcept; void Run (SHMatrix const& viewMat, uint32_t frameIndex) noexcept;
void Exit (void) noexcept; void Exit (void) noexcept;
void BindDescSet (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t setIndex, uint32_t frameIndex) noexcept;
uint32_t AddShadowMap (Handle<SHRenderGraphResource> newShadowMap, EntityID lightEntity) noexcept;
void PrepareShadowMapsForRead (Handle<SHVkCommandBuffer> cmdBuffer) noexcept;
//void HandleResize (Handle<SHRenderGraphNodeCompute> compute) noexcept;
//void RemoveShadowMap (uint32_t index) noexcept;
void BindDescSet (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t setIndex, uint32_t frameIndex) noexcept; /*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/
Handle<SHVkDescriptorSetGroup> GetLightDataDescriptorSet (void) const noexcept; Handle<SHVkDescriptorSetGroup> GetLightDataDescriptorSet (void) const noexcept;
std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, vk::ImageLayout> const& GetViewSamplerLayout (uint32_t index) const noexcept;
uint32_t GetNumShadowMaps (void) const noexcept;
}; };
} }

View File

@ -1,18 +1,23 @@
#include "SHpch.h" #include "SHpch.h"
#include "SHPipelineLibrary.h" #include "SHPipelineLibrary.h"
#include "Graphics/Devices/SHVkLogicalDevice.h" #include "Graphics/Devices/SHVkLogicalDevice.h"
#include "Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h"
#include "Graphics/RenderGraph/SHSubpass.h" #include "Graphics/RenderGraph/SHSubpass.h"
#include "Graphics/SHVkUtil.h" #include "Graphics/SHVkUtil.h"
namespace SHADE namespace SHADE
{ {
Handle<SHVkPipeline> SHPipelineLibrary::CreateGraphicsPipelines(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHVkRenderpass> renderpass, Handle<SHSubpass> subpass) noexcept Handle<SHVkPipeline> SHPipelineLibrary::CreateGraphicsPipelines(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHVkRenderpass> renderpass, Handle<SHSubpass> subpass, SHVertexInputState const& viState/* = SHGraphicsPredefinedData::GetDefaultViState()*/, SHRasterizationState const& rasterState) noexcept
{ {
std::vector<Handle<SHVkShaderModule>> modules{};
if (vsFsPair.first)
modules.push_back(vsFsPair.first);
if (vsFsPair.second)
modules.push_back(vsFsPair.second);
SHPipelineLayoutParams params SHPipelineLayoutParams params
{ {
.shaderModules = {vsFsPair.first, vsFsPair.second}, .shaderModules = std::move(modules),
.predefinedDescSetLayouts = SHGraphicsPredefinedData::GetSystemData(SHGraphicsPredefinedData::SystemType::BATCHING).descSetLayouts .predefinedDescSetLayouts = SHGraphicsPredefinedData::GetSystemData(SHGraphicsPredefinedData::SystemType::BATCHING).descSetLayouts
}; };
@ -21,7 +26,7 @@ namespace SHADE
// Create the pipeline and configure the default vertex input state // Create the pipeline and configure the default vertex input state
auto newPipeline = logicalDevice->CreateGraphicsPipeline(pipelineLayout, nullptr, renderpass, subpass); auto newPipeline = logicalDevice->CreateGraphicsPipeline(pipelineLayout, nullptr, renderpass, subpass);
newPipeline->GetPipelineState().SetVertexInputState(SHGraphicsPredefinedData::GetDefaultViState()); newPipeline->GetPipelineState().SetVertexInputState(viState);
SHColorBlendState colorBlendState{}; SHColorBlendState colorBlendState{};
colorBlendState.logic_op_enable = VK_FALSE; colorBlendState.logic_op_enable = VK_FALSE;
@ -30,6 +35,7 @@ namespace SHADE
auto const& subpassColorReferences = subpass->GetColorAttachmentReferences(); auto const& subpassColorReferences = subpass->GetColorAttachmentReferences();
colorBlendState.attachments.reserve(subpassColorReferences.size()); colorBlendState.attachments.reserve(subpassColorReferences.size());
for (auto& att : subpassColorReferences) for (auto& att : subpassColorReferences)
{ {
colorBlendState.attachments.push_back(vk::PipelineColorBlendAttachmentState colorBlendState.attachments.push_back(vk::PipelineColorBlendAttachmentState
@ -47,6 +53,8 @@ namespace SHADE
} }
newPipeline->GetPipelineState().SetColorBlenState(colorBlendState); newPipeline->GetPipelineState().SetColorBlenState(colorBlendState);
newPipeline->GetPipelineState().SetRasterizationState(rasterState);
// Actually construct the pipeline // Actually construct the pipeline
newPipeline->ConstructPipeline(); newPipeline->ConstructPipeline();

View File

@ -3,6 +3,7 @@
#include <unordered_map> #include <unordered_map>
#include "Graphics/Shaders/SHVkShaderModule.h" #include "Graphics/Shaders/SHVkShaderModule.h"
#include "Graphics/Pipeline/SHVkPipeline.h" #include "Graphics/Pipeline/SHVkPipeline.h"
#include "Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h"
namespace SHADE namespace SHADE
{ {
@ -32,7 +33,9 @@ namespace SHADE
Handle<SHVkPipeline> CreateGraphicsPipelines ( Handle<SHVkPipeline> CreateGraphicsPipelines (
std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair,
Handle<SHVkRenderpass> renderpass, Handle<SHVkRenderpass> renderpass,
Handle<SHSubpass> subpass Handle<SHSubpass> subpass,
SHVertexInputState const& viState = SHGraphicsPredefinedData::GetDefaultViState(),
SHRasterizationState const& rasterState = SHRasterizationState{}
) noexcept; ) noexcept;
Handle<SHVkPipeline> GetGraphicsPipeline (std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept; Handle<SHVkPipeline> GetGraphicsPipeline (std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept;
bool CheckGraphicsPipelineExistence (std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept; bool CheckGraphicsPipelineExistence (std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept;

View File

@ -195,7 +195,7 @@ namespace SHADE
return *this; return *this;
} }
void SHVertexInputState::AddBinding(bool instanced, bool calcOffset, std::initializer_list<SHVertexAttribute> inAttribs) noexcept void SHVertexInputState::AddBinding(bool instanced, bool calcOffset, std::initializer_list<SHVertexAttribute> inAttribs, uint32_t fixedBinding /*= static_cast<uint32_t>(-1)*/, uint32_t fixedAttributeLocation/* = static_cast<uint32_t>(-1)*/) noexcept
{ {
// add a binding and get ref to it // add a binding and get ref to it
bindings.emplace_back(); bindings.emplace_back();
@ -210,7 +210,7 @@ namespace SHADE
// Offset is 0 at first (for first element) // Offset is 0 at first (for first element)
uint32_t offset = 0; uint32_t offset = 0;
binding.binding = static_cast<uint32_t>(bindings.size() - 1); binding.binding = (fixedBinding != static_cast<uint32_t>(-1)) ? fixedBinding : static_cast<uint32_t>(bindings.size() - 1);
// for every attribute passed in // for every attribute passed in
for (auto const& attrib : inAttribs) for (auto const& attrib : inAttribs)
@ -226,10 +226,11 @@ namespace SHADE
auto& vertexAttrib = attributes.back(); auto& vertexAttrib = attributes.back();
// The binding for that attribute description is index of the new binding created earlier in this function // The binding for that attribute description is index of the new binding created earlier in this function
vertexAttrib.binding = static_cast<uint32_t>(bindings.size() - 1); vertexAttrib.binding = (fixedBinding != static_cast<uint32_t>(-1)) ? fixedBinding : static_cast<uint32_t>(bindings.size() - 1);
// Attribute location. New index is simply + 1 of the previous. Starts from 0 obviously //Attribute location. New index is simply + 1 of the previous. Starts from 0 obviously
vertexAttrib.location = static_cast<uint32_t>(attributes.size () - 1); vertexAttrib.location = (fixedAttributeLocation != static_cast<uint32_t>(-1)) ? fixedAttributeLocation + i : static_cast<uint32_t>(attributes.size () - 1);
//vertexAttrib.location = static_cast<uint32_t>(attributes.size() - 1);
// Get the vkFormat associated with the SHAttribFormat // Get the vkFormat associated with the SHAttribFormat
vertexAttrib.format = format; vertexAttrib.format = format;

View File

@ -34,7 +34,7 @@ namespace SHADE
SHVertexInputState& operator= (SHVertexInputState const& rhs) noexcept; SHVertexInputState& operator= (SHVertexInputState const& rhs) noexcept;
SHVertexInputState& operator= (SHVertexInputState&& rhs) noexcept; SHVertexInputState& operator= (SHVertexInputState&& rhs) noexcept;
void AddBinding(bool instanced, bool calcOffset, std::initializer_list<SHVertexAttribute> inAttribs) noexcept; void AddBinding(bool instanced, bool calcOffset, std::initializer_list<SHVertexAttribute> inAttribs, uint32_t fixedBinding = static_cast<uint32_t>(-1), uint32_t fixedAttributeLocation = static_cast<uint32_t>(-1)) noexcept;
friend class SHVkPipelineState; friend class SHVkPipelineState;
friend class SHVkPipeline; friend class SHVkPipeline;

View File

@ -19,69 +19,71 @@ namespace SHADE
for (auto& shaderModule : shaderModules) for (auto& shaderModule : shaderModules)
{ {
// References for convenience if (shaderModule)
auto const& reflectedData = shaderModule->GetReflectedData();
auto const& pcInfo = reflectedData.GetPushConstantInfo();
// If a push constant block exists for the shader module
if (pcInfo.memberCount != 0)
{ {
bool exists = false; // References for convenience
auto const& reflectedData = shaderModule->GetReflectedData();
auto const& pcInfo = reflectedData.GetPushConstantInfo();
// Check if push constant block already exists // If a push constant block exists for the shader module
for (uint32_t i = 0; i < pcInfos.size(); ++i) if (pcInfo.memberCount != 0)
{ {
// If there is a block with the same name, member count and size bool exists = false;
if (std::strcmp(pcInfos[i]->name, pcInfo.name) == 0 && pcInfos[i]->memberCount == pcInfo.memberCount && pcInfos[i]->size == pcInfo.size)
// 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 // If there is a block with the same name, member count and size
vkPcRanges[i].stageFlags |= shaderModule->GetShaderStageFlagBits(); 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 // Set flag and stop checking
exists = true; exists = true;
break; 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);
} }
// New push constant range // If the block doesn't exist yet
vk::PushConstantRange newRange; 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 // Add the variable's offset info to the interface
newRange.offset = startOffset; pushConstantInterface.AddOffset(std::move(variableName), startOffset + pcInfo.members[i].offset);
newRange.size = pcInfo.size; }
// Stage flags will be whatever shader stage of the shader that contains the push constant block // New push constant range
newRange.stageFlags = shaderModule->GetShaderStageFlagBits(); vk::PushConstantRange newRange;
// Add to the list foe checking later // set offset and size
pcInfos.push_back(&pcInfo); newRange.offset = startOffset;
newRange.size = pcInfo.size;
// For pipeline layout to consume // Stage flags will be whatever shader stage of the shader that contains the push constant block
vkPcRanges.push_back(newRange); newRange.stageFlags = shaderModule->GetShaderStageFlagBits();
// Next push constant block will start next to the previous push constant block // Add to the list foe checking later
startOffset += pcInfo.size; 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 // 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 //! Now we take descriptor set info from all shaders and prepare some bindings for the descriptor set
for (auto& shaderModule : shaderModules) for (auto& shaderModule : shaderModules)
{ {
if (!shaderModule)
continue;
auto const& descBindingInfo = shaderModule->GetReflectedData().GetDescriptorBindingInfo(); auto const& descBindingInfo = shaderModule->GetReflectedData().GetDescriptorBindingInfo();
auto const& reflectedSets = descBindingInfo.GetReflectedSets(); auto const& reflectedSets = descBindingInfo.GetReflectedSets();
@ -200,10 +205,12 @@ namespace SHADE
newBinding.DescriptorCount = SHVkDescriptorSetLayout::Binding::VARIABLE_DESCRIPTOR_UPPER_BOUND; newBinding.DescriptorCount = SHVkDescriptorSetLayout::Binding::VARIABLE_DESCRIPTOR_UPPER_BOUND;
// Set the flags for variable bindings // Set the flags for variable bindings
newBinding.flags = vk::DescriptorBindingFlagBits::eVariableDescriptorCount; newBinding.flags = vk::DescriptorBindingFlagBits::eVariableDescriptorCount | vk::DescriptorBindingFlagBits::ePartiallyBound;
} }
else else
{
SHLOG_ERROR("Variable size binding is detected, but the binding is not the last binding of the set and is therefore invalid. "); 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); setsWithBindings[CURRENT_SET].emplace_back(newBinding);
@ -326,11 +333,10 @@ namespace SHADE
{ {
for (auto& mod : shaderModules) for (auto& mod : shaderModules)
{ {
mod->AddCallback([this]() if (mod)
{ {
RecreateIfNeeded(); mod->AddCallback([this]() { RecreateIfNeeded(); });
} }
);
} }
RecreateIfNeeded (); RecreateIfNeeded ();

View File

@ -54,7 +54,7 @@ namespace SHADE
*/ */
/***************************************************************************/ /***************************************************************************/
void SHRenderGraph::AddResource(std::string resourceName, std::initializer_list<SH_RENDER_GRAPH_RESOURCE_FLAGS> typeFlags, uint32_t w /*= static_cast<uint32_t>(-1)*/, uint32_t h /*= static_cast<uint32_t>(-1)*/, vk::Format format/* = vk::Format::eB8G8R8A8Unorm*/, uint8_t levels /*= 1*/, vk::ImageUsageFlagBits usageFlags/* = {}*/, vk::ImageCreateFlagBits createFlags /*= {}*/) void SHRenderGraph::AddResource(std::string resourceName, std::initializer_list<SH_RENDER_GRAPH_RESOURCE_FLAGS> typeFlags, bool resizeWithWindow, uint32_t w /*= static_cast<uint32_t>(-1)*/, uint32_t h /*= static_cast<uint32_t>(-1)*/, vk::Format format/* = vk::Format::eB8G8R8A8Unorm*/, uint8_t levels /*= 1*/, vk::ImageUsageFlagBits usageFlags/* = {}*/, vk::ImageCreateFlagBits createFlags /*= {}*/)
{ {
// If we set to // If we set to
if (w == static_cast<uint32_t>(-1) && h == static_cast<uint32_t>(-1)) if (w == static_cast<uint32_t>(-1) && h == static_cast<uint32_t>(-1))
@ -64,7 +64,7 @@ namespace SHADE
format = renderGraphStorage->swapchain->GetSurfaceFormatKHR().format; format = renderGraphStorage->swapchain->GetSurfaceFormatKHR().format;
} }
auto resource = renderGraphStorage->resourceHub->Create<SHRenderGraphResource>(renderGraphStorage, resourceName, typeFlags, format, w, h, levels, usageFlags, createFlags); auto resource = renderGraphStorage->resourceHub->Create<SHRenderGraphResource>(renderGraphStorage, resourceName, typeFlags, format, w, h, levels, usageFlags, createFlags, resizeWithWindow);
renderGraphStorage->graphResources->try_emplace(resourceName, resource); renderGraphStorage->graphResources->try_emplace(resourceName, resource);
} }
@ -106,6 +106,9 @@ namespace SHADE
for (auto& affectedNode : affectedNodes) for (auto& affectedNode : affectedNodes)
nodes[affectedNode]->CreateFramebuffer(); nodes[affectedNode]->CreateFramebuffer();
renderGraphStorage->graphResources->at(resourceName).Free();
renderGraphStorage->graphResources->erase (resourceName);
/* /*
* IMPORTANT NOTES * IMPORTANT NOTES
* *
@ -166,68 +169,7 @@ namespace SHADE
for (uint32_t i = 0; auto& node : nodes) for (uint32_t i = 0; auto& node : nodes)
{ {
// key is handle ID, value is final layout. node->StandaloneConfigureAttDesc(i == nodes.size() - 1);
std::unordered_map<uint32_t, vk::ImageLayout> resourceAttFinalLayouts;
if (node->subpasses.empty())
{
SHLOG_ERROR("Node does not contain a subpass. Cannot configure attachment descriptions as a result. ");
return;
}
// 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<uint32_t>(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);
}
++i; ++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; 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<SHRenderGraphNode> SHRenderGraph::AddNodeAfter(std::string nodeName, std::initializer_list<ResourceInstruction> resourceInstruction, std::string nodeToAddAfter) noexcept
{
if (nodeIndexing.contains(nodeName))
{
SHLOG_ERROR("Node already exists, cannot add node. ");
return {};
}
std::vector<SHAttachmentDescInitParams> 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<SHRenderGraphNode>(nodeName, renderGraphStorage, std::move(descInitParams), std::vector<Handle<SHRenderGraphNode>>()));
ReindexNodes ();
return *node;
}
void SHRenderGraph::AddRenderToSwapchainNode(std::string toSwapchainResource, std::string swapchainResource, std::initializer_list<std::string> predecessorNodes, std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> shaderModules) noexcept void SHRenderGraph::AddRenderToSwapchainNode(std::string toSwapchainResource, std::string swapchainResource, std::initializer_list<std::string> predecessorNodes, std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> shaderModules) noexcept
{ {
for (auto& node : predecessorNodes) for (auto& node : predecessorNodes)
@ -532,10 +544,6 @@ namespace SHADE
ConfigureSubSystems(); ConfigureSubSystems();
} }
void SHRenderGraph::Regenerate(void) noexcept
{
}
/***************************************************************************/ /***************************************************************************/
/*! /*!
@ -572,10 +580,13 @@ namespace SHADE
for (auto& node : nodes) for (auto& node : nodes)
{ {
// bind static global data if (node->renderpass)
SHGlobalDescriptorSets::BindStaticGlobalData(cmdBuffer, SH_PIPELINE_TYPE::GRAPHICS, descMappings.at(SHPredefinedDescriptorTypes::STATIC_DATA)); {
// 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(); cmdBuffer->EndLabeledSegment();
@ -605,8 +616,11 @@ namespace SHADE
// resize resources // resize resources
for (auto& [name, resource] : *renderGraphStorage->graphResources) for (auto& [name, resource] : *renderGraphStorage->graphResources)
{ {
if (!renderGraphStorage->nonOwningResourceInitialLayouts.contains (resource.GetId().Raw)) if (resource->resizeWithWindow)
resource->HandleResize(newWidth, newHeight); {
if (!renderGraphStorage->nonOwningResourceInitialLayouts.contains (resource.GetId().Raw))
resource->HandleResize(newWidth, newHeight);
}
} }
for (auto& node : nodes) for (auto& node : nodes)

View File

@ -55,6 +55,7 @@ namespace SHADE
void ConfigureRenderpasses (void) noexcept; void ConfigureRenderpasses (void) noexcept;
void ConfigureSubSystems (void) noexcept; void ConfigureSubSystems (void) noexcept;
void ConfigureFramebuffers (void) noexcept; void ConfigureFramebuffers (void) noexcept;
void ReindexNodes (void) noexcept;
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */ /* PRIVATE MEMBER VARIABLES */
@ -101,6 +102,7 @@ namespace SHADE
( (
std::string resourceName, std::string resourceName,
std::initializer_list<SH_RENDER_GRAPH_RESOURCE_FLAGS> typeFlags, std::initializer_list<SH_RENDER_GRAPH_RESOURCE_FLAGS> typeFlags,
bool resizeWithWindow = true,
uint32_t w = static_cast<uint32_t>(-1), uint32_t w = static_cast<uint32_t>(-1),
uint32_t h = static_cast<uint32_t>(-1), uint32_t h = static_cast<uint32_t>(-1),
vk::Format format = vk::Format::eB8G8R8A8Unorm, vk::Format format = vk::Format::eB8G8R8A8Unorm,
@ -123,6 +125,12 @@ namespace SHADE
std::initializer_list<ResourceInstruction> resourceInstruction, std::initializer_list<ResourceInstruction> resourceInstruction,
std::initializer_list<std::string> predecessorNodes std::initializer_list<std::string> predecessorNodes
) noexcept; ) noexcept;
Handle<SHRenderGraphNode> AddNodeAfter
(
std::string nodeName,
std::initializer_list<ResourceInstruction> resourceInstruction,
std::string nodeToAddAfter
) noexcept;
void AddRenderToSwapchainNode void AddRenderToSwapchainNode
( (
@ -134,7 +142,6 @@ namespace SHADE
) noexcept; ) noexcept;
void Generate (void) noexcept; void Generate (void) noexcept;
void Regenerate (void) noexcept;
void CheckForNodeComputes (void) noexcept; void CheckForNodeComputes (void) noexcept;
void Execute (uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool) noexcept; void Execute (uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool) noexcept;
void Begin (uint32_t frameIndex) 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, * 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. * 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. * - 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.
* *
*/ */

View File

@ -32,8 +32,11 @@ namespace SHADE
renderpass.Free(); renderpass.Free();
} }
renderpass = graphStorage->logicalDevice->CreateRenderpass(attachmentDescriptions, spDescs, spDeps); if (!spDescs.empty())
SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eRenderPass, renderpass->GetVkRenderpass(), "[RenderPass] " + name); {
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 void SHRenderGraphNode::CreateFramebuffer(void) noexcept
{ {
if (!framebuffers.empty()) if (renderpass)
{ {
for (auto fbo : framebuffers) if (!framebuffers.empty())
{ {
if (fbo) for (auto fbo : framebuffers)
fbo.Free(); {
} if (fbo)
} fbo.Free();
}
for (uint32_t i = 0; i < framebuffers.size(); ++i)
{
std::vector<Handle<SHVkImageView>> imageViews(attResources.size());
uint32_t fbWidth = std::numeric_limits<uint32_t>::max();
uint32_t fbHeight = std::numeric_limits<uint32_t>::max();
for (uint32_t j = 0; j < attResources.size(); ++j)
{
uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast<uint32_t>(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 (uint32_t i = 0; i < framebuffers.size(); ++i)
{
std::vector<Handle<SHVkImageView>> imageViews(attResources.size());
uint32_t fbWidth = std::numeric_limits<uint32_t>::max();
uint32_t fbHeight = std::numeric_limits<uint32_t>::max();
framebuffers[i] = graphStorage->logicalDevice->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight); for (uint32_t j = 0; j < attResources.size(); ++j)
SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eFramebuffer, framebuffers[i]->GetVkFramebuffer(), "[Framebuffer] " + name + std::to_string(i)); {
uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast<uint32_t>(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 void SHRenderGraphNode::HandleResize(void) noexcept
{ {
renderpass->HandleResize(); if (renderpass)
for (uint32_t i = 0; i < framebuffers.size(); ++i)
{ {
std::vector<Handle<SHVkImageView>> imageViews(attResources.size()); renderpass->HandleResize();
uint32_t fbWidth = std::numeric_limits<uint32_t>::max();
uint32_t fbHeight = std::numeric_limits<uint32_t>::max();
for (uint32_t j = 0; j < attResources.size(); ++j) for (uint32_t i = 0; i < framebuffers.size(); ++i)
{ {
uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast<uint32_t>(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0; std::vector<Handle<SHVkImageView>> imageViews(attResources.size());
imageViews[j] = attResources[j]->imageViews[imageViewIndex]; uint32_t fbWidth = std::numeric_limits<uint32_t>::max();
uint32_t fbHeight = std::numeric_limits<uint32_t>::max();
// We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's for (uint32_t j = 0; j < attResources.size(); ++j)
if (fbWidth > attResources[j]->width) {
fbWidth = attResources[j]->width; uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast<uint32_t>(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0;
if (fbHeight > attResources[j]->height) imageViews[j] = attResources[j]->imageViews[imageViewIndex];
fbHeight = attResources[j]->height;
// 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) for (auto& nodeCompute : nodeComputes)
{ {
subpass->HandleResize(); nodeCompute->HandleResize();
} }
for (auto& nodeCompute : nodeComputes)
{
nodeCompute->HandleResize();
} }
} }
void SHRenderGraphNode::ConfigureSubpasses(void) noexcept void SHRenderGraphNode::ConfigureSubpasses(void) noexcept
{ {
if (subpasses.empty())
return;
uint32_t numValidSubpasses = std::count_if(subpasses.begin(), subpasses.end(), [](Handle<SHSubpass> subpass) {return !subpass->HasNoAttachments();});
// Create subpass description and dependencies based on number of subpasses // Create subpass description and dependencies based on number of subpasses
spDescs.resize(subpasses.size()); spDescs.resize(numValidSubpasses);
spDeps.resize(subpasses.size()); spDeps.resize(numValidSubpasses);
// Now we want to loop through all attachments in all subpasses in the node and query // 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 // the resources being used. For each resource we want to query the type and record it
// in bit fields (1 bit for each subpass). // in bit fields (1 bit for each subpass).
uint32_t colorRead = 0, colorWrite = 0, depthRead = 0, depthWrite = 0, inputDependencies = 0; uint32_t colorRead = 0, colorWrite = 0, depthRead = 0, depthWrite = 0, inputDependencies = 0;
uint32_t i = 0;
// For all subpasses (see above description about bit field for this). // 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 // Configure subpass description
auto& desc = spDescs[i]; auto& desc = spDescs[i];
desc.pColorAttachments = subpass->colorReferences.data(); 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 // Loop through all subpasses again but this time we use the bit field to initialize
// the dependencies. // 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 srcStage;
vk::PipelineStageFlags dstStage; vk::PipelineStageFlags dstStage;
vk::AccessFlags srcAccess; vk::AccessFlags srcAccess;
@ -245,6 +265,8 @@ namespace SHADE
// initialize input descriptors // initialize input descriptors
subpasses[i]->CreateInputDescriptors(); subpasses[i]->CreateInputDescriptors();
++i;
} }
} }
@ -343,6 +365,7 @@ namespace SHADE
, spDeps{ std::move(rhs.spDeps) } , spDeps{ std::move(rhs.spDeps) }
, nodeComputes{ std::move(rhs.nodeComputes) } , nodeComputes{ std::move(rhs.nodeComputes) }
, name { std::move(rhs.name) } , name { std::move(rhs.name) }
, ISelfHandle<SHRenderGraphNode>{std::move(rhs)}
{ {
rhs.renderpass = {}; rhs.renderpass = {};
@ -419,7 +442,7 @@ namespace SHADE
return subpass; return subpass;
} }
Handle<SHRenderGraphNodeCompute> SHRenderGraphNode::AddNodeCompute(std::string nodeName, Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings, float numWorkGroupScale/* = 1.0f*/) noexcept Handle<SHRenderGraphNodeCompute> SHRenderGraphNode::AddNodeCompute(std::string nodeName, Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings, uint32_t variableDescCount/* = 0*/, float numWorkGroupScale/* = 1.0f*/) noexcept
{ {
// Look for the required resources in the graph // Look for the required resources in the graph
std::vector<Handle<SHRenderGraphResource>> nodeComputeResources{}; std::vector<Handle<SHRenderGraphResource>> nodeComputeResources{};
@ -435,7 +458,7 @@ namespace SHADE
std::vector<Handle<SHRenderGraphResource>> temp (nodeComputeResources); std::vector<Handle<SHRenderGraphResource>> temp (nodeComputeResources);
// Create the subpass compute with the resources // Create the subpass compute with the resources
auto nodeCompute = graphStorage->resourceHub->Create<SHRenderGraphNodeCompute>(std::move(nodeName), graphStorage, computeShaderModule, std::move(nodeComputeResources), std::move (dynamicBufferBindings), nodeComputes.empty()); auto nodeCompute = graphStorage->resourceHub->Create<SHRenderGraphNodeCompute>(std::move(nodeName), graphStorage, computeShaderModule, std::move(nodeComputeResources), std::move (dynamicBufferBindings), nodeComputes.empty(), variableDescCount);
nodeComputes.push_back(nodeCompute); nodeComputes.push_back(nodeCompute);
for (auto& resource : temp) 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<uint32_t, vk::ImageLayout> 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<uint32_t>(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 // remove attachment reference
attachmentDescriptions.erase (attachmentDescriptions.begin() + index); attachmentDescriptions.erase (attachmentDescriptions.begin() + index);
// erase from mapping as well
resourceAttachmentMapping->erase(resourceHandleID);
// Remove footprint of attachment from all subpasses as well // Remove footprint of attachment from all subpasses as well
for (auto it = subpasses.begin(); it != subpasses.end(); ++it) for (auto it = subpasses.begin(); it != subpasses.end(); ++it)
{ {
// attempt to detach resource from subpass // If the subpass uses the resource, just remove the subpass since the subpass will be invalid
(*it)->DetachResource(resourceName, index); if ((*it)->UsesResource(index))
// If the subpass ends up having no attachments after, erase it from the node
if ((*it)->HasNoAttachments())
{ {
// erase from indexing // erase from indexing
subpassIndexing.erase((*it)->GetName()); subpassIndexing.erase((*it)->GetName());
@ -530,6 +615,24 @@ namespace SHADE
for (uint32_t i = 0; i < subpasses.size(); ++i) for (uint32_t i = 0; i < subpasses.size(); ++i)
subpasses[i]->SetIndex(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 true;
} }
return false; return false;
@ -537,37 +640,40 @@ namespace SHADE
void SHRenderGraphNode::Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept void SHRenderGraphNode::Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept
{ {
uint32_t framebufferIndex = (framebuffers.size() > 1) ? frameIndex : 0; if (renderpass)
commandBuffer->BeginRenderpass(renderpass, framebuffers[framebufferIndex]);
for (uint32_t i = 0; i < subpasses.size(); ++i)
{ {
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 for (uint32_t i = 0; i < subpasses.size(); ++i)
if (i != static_cast<uint32_t>(subpasses.size()) - 1u) {
commandBuffer->NextSubpass(); subpasses[i]->Execute(commandBuffer, descPool, frameIndex);
// Go to next subpass if not last subpass
if (i != static_cast<uint32_t>(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<SHVkPipeline> SHRenderGraphNode::GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> subpass) noexcept Handle<SHVkPipeline> SHRenderGraphNode::GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> subpass) noexcept
@ -599,6 +705,77 @@ namespace SHADE
batcher.FinaliseBatches(graphStorage->logicalDevice, descPool, frameIndex); 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<SHRenderGraphResource> 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<SHSubpass> SHRenderGraphNode::RuntimeAddSubpass(std::string subpassName, Handle<SHViewport> viewport, Handle<SHRenderer> 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; return attResources;
} }
Handle<SHRenderGraphNodeCompute> SHRenderGraphNode::GetNodeCompute(std::string nodeComputeName) const noexcept
{
for (auto nc : nodeComputes)
{
if (nc->name == nodeComputeName)
return nc;
}
return {};
}
} }

View File

@ -93,6 +93,9 @@ namespace SHADE
void CreateFramebuffer(void) noexcept; void CreateFramebuffer(void) noexcept;
void HandleResize (void) noexcept; void HandleResize (void) noexcept;
void ConfigureSubpasses (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: public:
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@ -105,15 +108,17 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */ /* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
Handle<SHSubpass> AddSubpass(std::string subpassName, Handle<SHViewport> viewport, Handle<SHRenderer> renderer) noexcept; Handle<SHSubpass> AddSubpass(std::string subpassName, Handle<SHViewport> viewport, Handle<SHRenderer> renderer) noexcept;
Handle<SHRenderGraphNodeCompute> AddNodeCompute(std::string nodeName, Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings = {}, float numWorkGroupScale = 1.0f) noexcept; Handle<SHRenderGraphNodeCompute> AddNodeCompute(std::string nodeName, Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings = {}, uint32_t variableDescCount = 0, float numWorkGroupScale = 1.0f) noexcept;
void AddDummySubpassIfNeeded (void) noexcept;
bool DetachResource (std::string const& resourceName, uint64_t resourceHandleID) noexcept; void Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept;
Handle<SHVkPipeline> GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> subpass) noexcept;
void FinaliseBatch(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
// TODO: RemoveSubpass() // Runtime functions that don't affect the renderpass
void Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept; void RuntimeLinkResource(std::string resourceName) noexcept;
Handle<SHVkPipeline> GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> subpass) noexcept; Handle<SHSubpass> RuntimeAddSubpass(std::string subpassName, Handle<SHViewport> viewport, Handle<SHRenderer> renderer) noexcept;
void FinaliseBatch(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool); void RuntimeStandaloneRegenerate (void) noexcept;
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */ /* SETTERS AND GETTERS */
@ -122,6 +127,7 @@ namespace SHADE
Handle<SHSubpass> GetSubpass(std::string_view subpassName) const noexcept; Handle<SHSubpass> GetSubpass(std::string_view subpassName) const noexcept;
Handle<SHRenderGraphResource> GetResource (uint32_t resourceIndex) const noexcept; Handle<SHRenderGraphResource> GetResource (uint32_t resourceIndex) const noexcept;
std::vector<Handle<SHRenderGraphResource>> const& GetResources (void) const noexcept; std::vector<Handle<SHRenderGraphResource>> const& GetResources (void) const noexcept;
Handle<SHRenderGraphNodeCompute> GetNodeCompute (std::string nodeComputeName) const noexcept;
friend class SHRenderGraph; friend class SHRenderGraph;
}; };

View File

@ -14,7 +14,56 @@
namespace SHADE namespace SHADE
{ {
SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(std::string nodeName, Handle<SHRenderGraphStorage> graphStorage, Handle<SHVkShaderModule> computeShaderModule, std::vector<Handle<SHRenderGraphResource>>&& subpassComputeResources, std::unordered_set<BindingAndSetHash>&& 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<uint32_t>(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<SHRenderGraphStorage> graphStorage, Handle<SHVkShaderModule> computeShaderModule, std::vector<Handle<SHRenderGraphResource>>&& subpassComputeResources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings, bool followingEndRP, uint32_t variableDescCount, float inNumWorkGroupScale/* = 1.0f*/) noexcept
: computePipeline{} : computePipeline{}
, pipelineLayout{} , pipelineLayout{}
, resources{} , resources{}
@ -68,10 +117,12 @@ namespace SHADE
// check if all layouts are there // check if all layouts are there
if (layouts.size() == descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE) + 1) if (layouts.size() == descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE) + 1)
{ {
Handle<SHVkDescriptorSetLayout> computeResourceLayout = {};
computeResourceLayout = layouts[descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE)];
// create compute resources // create compute resources
computeResource = graphStorage->resourceHub->Create<ComputeResource>(); computeResource = graphStorage->resourceHub->Create<ComputeResource>();
auto computeResourceLayout = layouts[descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE)]; computeResource->descSet = graphStorage->descriptorPool->Allocate({ computeResourceLayout }, {variableDescCount});
computeResource->descSet = graphStorage->descriptorPool->Allocate({ computeResourceLayout }, { 1 });
#ifdef _DEBUG #ifdef _DEBUG
for (auto set : computeResource->descSet->GetVkHandle()) for (auto set : computeResource->descSet->GetVkHandle())
SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eDescriptorSet, set, "[Descriptor Set] " + name + " Resources"); SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eDescriptorSet, set, "[Descriptor Set] " + name + " Resources");
@ -91,6 +142,11 @@ namespace SHADE
void SHRenderGraphNodeCompute::Execute(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept void SHRenderGraphNodeCompute::Execute(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
{ {
for (auto& fn : preComputeFunctions)
{
fn (cmdBuffer, frameIndex);
}
// bind the compute pipeline // bind the compute pipeline
cmdBuffer->BindPipeline(computePipeline); cmdBuffer->BindPipeline(computePipeline);
@ -157,35 +213,7 @@ namespace SHADE
groupSizeX = maxWidth / workGroupSizeX; groupSizeX = maxWidth / workGroupSizeX;
groupSizeY = maxHeight / workGroupSizeY; groupSizeY = maxHeight / workGroupSizeY;
for (uint32_t i = 0; auto& barriers : memoryBarriers) InitializeBarriers();
{
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<uint32_t>(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::SetDynamicOffsets(std::span<uint32_t> perFrameSizes) noexcept void SHRenderGraphNodeCompute::SetDynamicOffsets(std::span<uint32_t> 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);
}
} }

View File

@ -25,6 +25,10 @@ namespace SHADE
class SHRenderGraphNodeCompute class SHRenderGraphNodeCompute
{ {
public:
using PreComputeFunction = std::function<void(Handle<SHVkCommandBuffer>, uint32_t)>;
private: private:
// Binding of set SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_NODE_COMPUTE_RESOURCE // Binding of set SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_NODE_COMPUTE_RESOURCE
struct ComputeResource struct ComputeResource
@ -73,8 +77,23 @@ namespace SHADE
//! Name of this node //! Name of this node
std::string name; std::string name;
std::vector<PreComputeFunction> 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: public:
SHRenderGraphNodeCompute(std::string nodeName, Handle<SHRenderGraphStorage> graphStorage, Handle<SHVkShaderModule> computeShaderModule, std::vector<Handle<SHRenderGraphResource>>&& subpassComputeResources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings, bool followingEndRP, float inNumWorkGroupScale = 1.0f) noexcept; SHRenderGraphNodeCompute(std::string nodeName, Handle<SHRenderGraphStorage> graphStorage, Handle<SHVkShaderModule> computeShaderModule, std::vector<Handle<SHRenderGraphResource>>&& subpassComputeResources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings, bool followingEndRP, uint32_t variableDescCount, float inNumWorkGroupScale = 1.0f) noexcept;
void Execute (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept; void Execute (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
void HandleResize (void) noexcept; void HandleResize (void) noexcept;
@ -84,7 +103,9 @@ namespace SHADE
void ModifyWriteDescBufferComputeResource (uint32_t binding, std::span<Handle<SHVkBuffer>> const& buffers, uint32_t offset, uint32_t range) noexcept; void ModifyWriteDescBufferComputeResource (uint32_t binding, std::span<Handle<SHVkBuffer>> const& buffers, uint32_t offset, uint32_t range) noexcept;
void ModifyWriteDescImageComputeResource(uint32_t binding, std::span<SHVkDescriptorSetGroup::viewSamplerLayout> const& viewSamplerLayouts) noexcept; void ModifyWriteDescImageComputeResource(uint32_t binding, std::span<SHVkDescriptorSetGroup::viewSamplerLayout> 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 SHRenderGraph;
friend class SHRenderGraphNode; friend class SHRenderGraphNode;

View File

@ -78,7 +78,7 @@ namespace SHADE
*/ */
/***************************************************************************/ /***************************************************************************/
SHRenderGraphResource::SHRenderGraphResource(Handle<SHRenderGraphStorage> renderGraphStorage, std::string const& name, std::initializer_list<SH_RENDER_GRAPH_RESOURCE_FLAGS> typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept SHRenderGraphResource::SHRenderGraphResource(Handle<SHRenderGraphStorage> renderGraphStorage, std::string const& name, std::initializer_list<SH_RENDER_GRAPH_RESOURCE_FLAGS> typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags, bool inResizeWithWindow) noexcept
: graphStorage{renderGraphStorage} : graphStorage{renderGraphStorage}
, resourceTypeFlags{ } , resourceTypeFlags{ }
, resourceFormat{ format } , resourceFormat{ format }
@ -88,6 +88,7 @@ namespace SHADE
, height{ h } , height{ h }
, mipLevels{ levels } , mipLevels{ levels }
, resourceName{ name } , resourceName{ name }
, resizeWithWindow { inResizeWithWindow }
{ {
// If the resource type is an arbitrary image and not swapchain image // 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) if (typeFlags.size() == 1 && *typeFlags.begin() == SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)
@ -210,6 +211,7 @@ namespace SHADE
, imageAspectFlags{ rhs.imageAspectFlags } , imageAspectFlags{ rhs.imageAspectFlags }
, graphStorage{rhs.graphStorage} , graphStorage{rhs.graphStorage}
, infoTracker {std::move (rhs.infoTracker)} , infoTracker {std::move (rhs.infoTracker)}
, resizeWithWindow{rhs.resizeWithWindow}
{ {
} }
@ -242,7 +244,8 @@ namespace SHADE
mipLevels = rhs.mipLevels; mipLevels = rhs.mipLevels;
imageAspectFlags = rhs.imageAspectFlags; imageAspectFlags = rhs.imageAspectFlags;
graphStorage = rhs.graphStorage; graphStorage = rhs.graphStorage;
infoTracker = std::move(infoTracker); infoTracker = std::move(rhs.infoTracker);
resizeWithWindow = rhs.resizeWithWindow;
return *this; return *this;
} }

View File

@ -96,11 +96,14 @@ namespace SHADE
//! For tracking resource states in stages of the render graphs //! For tracking resource states in stages of the render graphs
Handle<InfoTracker> infoTracker; Handle<InfoTracker> infoTracker;
//! Whether or not to resize (recreate vulkan image) when window resizes
bool resizeWithWindow;
public: public:
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* CTORS AND DTORS */ /* CTORS AND DTORS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
SHRenderGraphResource(Handle<SHRenderGraphStorage> renderGraphStorage, std::string const& name, std::initializer_list<SH_RENDER_GRAPH_RESOURCE_FLAGS> typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept; SHRenderGraphResource(Handle<SHRenderGraphStorage> renderGraphStorage, std::string const& name, std::initializer_list<SH_RENDER_GRAPH_RESOURCE_FLAGS> 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(SHRenderGraphResource&& rhs) noexcept;
SHRenderGraphResource& operator=(SHRenderGraphResource&& rhs) noexcept; SHRenderGraphResource& operator=(SHRenderGraphResource&& rhs) noexcept;
~SHRenderGraphResource(void) noexcept; ~SHRenderGraphResource(void) noexcept;

View File

@ -77,6 +77,7 @@ namespace SHADE
, name { rhs.name } , name { rhs.name }
, viewport {rhs.viewport} , viewport {rhs.viewport}
, renderer {rhs.renderer} , renderer {rhs.renderer}
, companionSubpass {rhs.companionSubpass}
{ {
} }
@ -113,6 +114,7 @@ namespace SHADE
name = std::move(rhs.name); name = std::move(rhs.name);
renderer = rhs.renderer; renderer = rhs.renderer;
viewport = rhs.viewport; viewport = rhs.viewport;
companionSubpass = rhs.companionSubpass;
return *this; return *this;
@ -162,7 +164,7 @@ namespace SHADE
switch (attachmentDescriptionType) switch (attachmentDescriptionType)
{ {
case SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH: case SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH:
imageLayout = vk::ImageLayout::eDepthAttachmentOptimal; imageLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal;
break; break;
case SH_RENDER_GRAPH_RESOURCE_FLAGS::STENCIL: case SH_RENDER_GRAPH_RESOURCE_FLAGS::STENCIL:
imageLayout = vk::ImageLayout::eStencilAttachmentOptimal; imageLayout = vk::ImageLayout::eStencilAttachmentOptimal;
@ -211,25 +213,38 @@ namespace SHADE
{ {
commandBuffer->BeginLabeledSegment(name); commandBuffer->BeginLabeledSegment(name);
// Ensure correct transforms are provided if (!HasNoAttachments())
superBatch->UpdateBuffers(frameIndex, descPool);
if (viewport)
{ {
// set viewport and scissor // Ensure correct transforms are provided
uint32_t w = static_cast<uint32_t>(viewport->GetWidth()); superBatch->UpdateBuffers(frameIndex, descPool);
uint32_t h = static_cast<uint32_t>(viewport->GetHeight());
commandBuffer->SetViewportScissor(static_cast<float>(w), static_cast<float>(h), w, h); if (viewport)
{
// set viewport and scissor
uint32_t w = static_cast<uint32_t>(viewport->GetWidth());
uint32_t h = static_cast<uint32_t>(viewport->GetHeight());
commandBuffer->SetViewportScissor(static_cast<float>(w), static_cast<float>(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 // Draw all the exterior draw calls
for (auto& drawCall : exteriorDrawCalls) 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) for (uint32_t i = 0; i < colorReferences.size(); ++i)
{ {
if (colorReferences[i].attachment == attachmentIndex) if (colorReferences[i].attachment == attachmentIndex)
{ return true;
colorReferences.erase (colorReferences.begin() + i);
break;
}
} }
for (uint32_t i = 0; i < depthReferences.size(); ++i) for (uint32_t i = 0; i < depthReferences.size(); ++i)
{ {
if (depthReferences[i].attachment == attachmentIndex) if (depthReferences[i].attachment == attachmentIndex)
{ return true;
depthReferences.erase(depthReferences.begin() + i);
break;
}
} }
for (uint32_t i = 0; i < inputReferences.size(); ++i) for (uint32_t i = 0; i < inputReferences.size(); ++i)
{ {
if (inputReferences[i].attachment == attachmentIndex) if (inputReferences[i].attachment == attachmentIndex)
{ return true;
inputReferences.erase(inputReferences.begin() + i);
break;
}
} }
for (uint32_t i = 0; i < inputNames.size(); ++i) return false;
{
if (inputNames[i] == resourceName)
{
inputNames.erase(inputNames.begin() + i);
break;
}
}
} }
bool SHSubpass::HasNoAttachments(void) const noexcept bool SHSubpass::HasNoAttachments(void) const noexcept
@ -458,6 +457,12 @@ namespace SHADE
subpassIndex = index; subpassIndex = index;
} }
void SHSubpass::SetCompanionSubpass(Handle<SHSubpass> companion, Handle<SHVkPipeline> pipeline) noexcept
{
companionSubpass.companion = companion;
companionSubpass.pipeline = pipeline;
}
/***************************************************************************/ /***************************************************************************/
/*! /*!

View File

@ -21,12 +21,23 @@ namespace SHADE
class SHVkSampler; class SHVkSampler;
class SHRenderer; class SHRenderer;
class SHViewport; class SHViewport;
class SHVkPipeline;
class SH_API SHSubpass : public ISelfHandle<SHSubpass> class SH_API SHSubpass : public ISelfHandle<SHSubpass>
{ {
public: public:
using ExteriorDrawCallFunction = std::function<void(Handle<SHVkCommandBuffer>, Handle<SHRenderer>, uint32_t)>; using ExteriorDrawCallFunction = std::function<void(Handle<SHVkCommandBuffer>, Handle<SHRenderer>, uint32_t)>;
// Allows for subpasses to run using a companions data
struct CompanionSubpass
{
// subpass whose data will be borrowed to draw
Handle<SHSubpass> companion;
// Pipeline that will be used for all the draw calls from all batches of the companion subpass
Handle<SHVkPipeline> pipeline;
};
private: private:
/*---------------------------------------------------------------------*/ /*---------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */ /* PRIVATE MEMBER VARIABLES */
@ -94,6 +105,15 @@ namespace SHADE
// For identifying subpasses // For identifying subpasses
std::string name; 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: public:
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@ -119,7 +139,6 @@ namespace SHADE
void Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept; void Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept;
void HandleResize (void) noexcept; void HandleResize (void) noexcept;
void BindInputDescriptorSets (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t setIndex, uint32_t frameIndex) const noexcept; void BindInputDescriptorSets (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t setIndex, uint32_t frameIndex) const noexcept;
void DetachResource (std::string const& resourceName, uint32_t attachmentIndex) noexcept;
bool HasNoAttachments (void) const noexcept; bool HasNoAttachments (void) const noexcept;
void Init(SHResourceHub& resourceManager) noexcept; void Init(SHResourceHub& resourceManager) noexcept;
@ -128,19 +147,24 @@ namespace SHADE
void CreateInputDescriptors (void) noexcept; void CreateInputDescriptors (void) noexcept;
void UpdateWriteDescriptors (void) noexcept; void UpdateWriteDescriptors (void) noexcept;
/*-----------------------------------------------------------------------*/
/* GETTERS AND SETTERS */
/*-----------------------------------------------------------------------*/
private: private:
/*-----------------------------------------------------------------------*/
/* PRIVATE GETTERS AND SETTERS */
/*-----------------------------------------------------------------------*/
void SetIndex (uint32_t index) noexcept; void SetIndex (uint32_t index) noexcept;
public: public:
Handle<SHRenderGraphNode> const& GetParentNode(void) const noexcept; /*-----------------------------------------------------------------------*/
SHSubPassIndex GetIndex() const noexcept; /* PUBLIC SETTERS AND GETTERS */
Handle<SHSuperBatch> GetSuperBatch(void) const noexcept; /*-----------------------------------------------------------------------*/
void SetCompanionSubpass (Handle<SHSubpass> companion, Handle<SHVkPipeline> pipeline) noexcept;
Handle<SHRenderGraphNode> const& GetParentNode(void) const noexcept;
SHSubPassIndex GetIndex() const noexcept;
Handle<SHSuperBatch> GetSuperBatch(void) const noexcept;
std::vector<vk::AttachmentReference> const& GetColorAttachmentReferences (void) const noexcept; std::vector<vk::AttachmentReference> const& GetColorAttachmentReferences (void) const noexcept;
vk::Format GetFormatFromAttachmentReference (uint32_t attachmentReference) const noexcept; vk::Format GetFormatFromAttachmentReference (uint32_t attachmentReference) const noexcept;
const std::string& GetName() const; const std::string& GetName() const;
friend class SHRenderGraphNode; friend class SHRenderGraphNode;
friend class SHRenderGraph; friend class SHRenderGraph;