Implemented a custom physics engine #316

Merged
direnbharwani merged 95 commits from SHPhysics into main 2023-01-23 15:55:45 +08:00
50 changed files with 1396 additions and 502 deletions
Showing only changes of commit dc55c31c36 - Show all commits

View File

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

View File

@ -6,6 +6,8 @@ struct DirectionalLightStruct
uint isActive;
uint cullingMask;
vec4 diffuseColor;
mat4 pvMatrix;
uint shadowData;
};
struct AmbientLightStruct
@ -22,7 +24,10 @@ layout(set = 3, binding = 1, rgba32f) uniform image2D normals;
layout(set = 3, binding = 2, rgba8) uniform image2D albedo;
layout(set = 3, binding = 3, r32ui) uniform uimage2D lightLayerData;
layout(set = 3, binding = 4, r8) uniform image2D ssaoBlurredImage;
layout(set = 3, binding = 5, rgba8) uniform image2D targetImage;
layout(set = 3, binding = 5, rgba8) uniform image2D positionWorldSpace;
layout(set = 3, binding = 6, rgba8) uniform image2D targetImage;
layout (set = 4, binding = 0) uniform sampler2D shadowMaps[]; // for textures (global)
layout(set = 1, binding = 0) uniform LightCounts
{
@ -43,6 +48,25 @@ layout(std430, set = 1, binding = 4) buffer AmbientLightData
AmbientLightStruct aLightData[];
} AmbLightData;
float CalcShadowValue (sampler2D shadowMap, vec4 worldSpaceFragPos, mat4 lightPV)
{
vec4 fragPosLightPOV = lightPV * worldSpaceFragPos;
vec3 converted = (fragPosLightPOV.xyz / fragPosLightPOV.w) * vec3(0.5f) + vec3(0.5f);
float sampledDepth = texture(shadowMap, converted.xy).r;
if (converted.x < 0.0f || converted.x > 1.0f || converted.y < 0.0f || converted.y > 1.0f)
return 1.0f;
if (fragPosLightPOV.z > sampledDepth && fragPosLightPOV.w > 0.0f)
{
return 0.0f;
}
else
return 1.0f;
// return step (fragPosLightPOV.z, );
}
void main()
{
// convenient variables
@ -52,6 +76,9 @@ void main()
vec3 pixelDiffuse = imageLoad (albedo, globalThread).rgb;
// Get position of fragment in world space
vec4 positionWorld = vec4 (imageLoad (positionWorldSpace, globalThread).rgb, 1.0f);
// Get position of fragment in view spacee
vec3 positionView = imageLoad (positions, globalThread).rgb;
// normal of fragment
@ -62,6 +89,18 @@ void main()
vec3 fragColor = vec3 (0.0f);
vec4 shadowMapColor = vec4 (1.0f);
for (int i = 0; i < lightCounts.ambientLights; ++i)
{
if ((lightLayer & AmbLightData.aLightData[i].cullingMask) != 0)
{
// Just do some add
//fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (0.5f);
fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (AmbLightData.aLightData[i].strength);
}
}
for (int i = 0; i < lightCounts.directionalLights; ++i)
{
if ((lightLayer & DirLightData.dLightData[i].cullingMask) != 0)
@ -74,16 +113,13 @@ void main()
// Calculate the fragment color
fragColor += DirLightData.dLightData[i].diffuseColor.rgb * diffuseStrength.rrr * pixelDiffuse;
}
}
for (int i = 0; i < lightCounts.ambientLights; ++i)
// If the shadow map is enabled (test the bit)
if ((DirLightData.dLightData[i].shadowData & uint(1)) == 1)
{
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);
// calculate shadow map here
fragColor *= CalcShadowValue (shadowMaps[0], positionWorld, DirLightData.dLightData[i].pvMatrix).xxx;
}
}
}
@ -92,6 +128,12 @@ void main()
// store result into result image
imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(fragColor.rgb, 1.0f));
//imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(ssaoVal.rrr, 1.0f));
// vec2 normTexCoords = vec2 (gl_GlobalInvocationID.xy) / vec2 (1024.0f);
// vec4 shadowMapVal = texture(shadowMaps[0], normTexCoords);
// if (normTexCoords.x > 1.0f || normTexCoords.y > 1.0f)
// shadowMapVal = vec4(0.0f);
// imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), shadowMapVal.xxxx);
}

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

Binary file not shown.

View File

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

Binary file not shown.

View File

@ -270,8 +270,12 @@ namespace SHADE
camera.viewMatrix(1, 3) = -UP.Dot(camera.position + camera.offset);
camera.viewMatrix(2, 3) = -view.Dot(camera.position + camera.offset);
//SHVec3 target{ 0.0f,0.0f,-1.0f };
//target = SHVec3::RotateX(target, SHMath::DegreesToRadians(camera.pitch));
//target = SHVec3::RotateY(target, SHMath::DegreesToRadians(camera.yaw));
//target += camera.position;
//camera.viewMatrix = SHMatrix::Transpose(SHMatrix::LookAtLH(camera.position, target, SHVec3(0.0f, -1.0f, 0.0f)));
camera.dirtyView = false;
}
@ -309,7 +313,9 @@ namespace SHADE
camera.orthoProjMatrix(2, 3) = -n / (f-n);
camera.orthoProjMatrix(3, 3) = 1.0f;
//camera.orthoProjMatrix = SHMatrix::OrthographicRH(camera.GetWidth(), camera.GetHeight(), camera.GetNear(), camera.GetFar());
//camera.perspProjMatrix = SHMatrix::OrthographicLH(9.0f, 9.0f, 0.1f, 20.0f);
camera.orthoProjMatrix = SHMatrix::OrthographicRH(camera.GetWidth(), camera.GetHeight(), camera.GetNear(), camera.GetFar());
//camera.perspProjMatrix = SHMatrix::OrthographicLH(5.0f, 5.0f, 0.1f, 20.0f);
//camera.projMatrix.Transpose();
camera.dirtyProj = false;

View File

@ -262,6 +262,13 @@ namespace SHADE
}
}
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("AssetID: %zu | Path: %s", asset->id, asset->path.c_str());
ImGui::EndTooltip();
}
//TODO: Combine Draw asset and Draw Folder recursive drawing
const ImColor treeLineColor = ImGui::GetColorU32(ImGuiCol_CheckMark);
const float horizontalOffset = 0.0f;

View File

@ -489,7 +489,7 @@ namespace SHADE
//auto const& renderers = gfxSystem->GetDefaultViewport()->GetRenderers();
auto renderGraph = gfxSystem->GetRenderGraph();
auto renderPass = renderGraph->GetNode("ImGui Node")->GetRenderpass();
auto renderPass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::IMGUI_PASS.data())->GetRenderpass();
if(ImGui_ImplVulkan_Init(&initInfo, renderPass->GetVkRenderpass()) == false)
{
@ -508,7 +508,7 @@ namespace SHADE
ImGui_ImplVulkan_DestroyFontUploadObjects();
renderGraph->GetNode("ImGui Node")->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle<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");
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].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
@ -200,6 +221,28 @@ namespace SHADE
}
void SHVkDescriptorSetGroup::UpdateDescriptorSetImage(uint32_t set, uint32_t binding, uint32_t descArrayIndex) noexcept
{
vk::WriteDescriptorSet writeDescSet{};
// Get binding + set hash
BindingAndSetHash bsHash = SHVkUtil::GenBindingSetHash(set, binding);
// to index a write for a binding
uint32_t writeInfoIndex = updater.writeHashMap[bsHash];
// Initialize info for write
writeDescSet.descriptorType = layoutsUsed[set]->GetBindings()[binding].Type;
writeDescSet.dstArrayElement = descArrayIndex;
writeDescSet.dstSet = descSets[set];
writeDescSet.dstBinding = binding;
writeDescSet.pImageInfo = updater.writeInfos[writeInfoIndex].descImageInfos.data() + descArrayIndex;
writeDescSet.descriptorCount = 1u;
device->UpdateDescriptorSet(writeDescSet);
}
void SHVkDescriptorSetGroup::UpdateDescriptorSetImages(uint32_t set, uint32_t binding) noexcept
{
vk::WriteDescriptorSet writeDescSet{};

View File

@ -63,10 +63,12 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/
/* Public member functions */
/*-----------------------------------------------------------------------------*/
void UpdateDescriptorSetImage (uint32_t set, uint32_t binding, uint32_t descArrayIndex) noexcept;
void UpdateDescriptorSetImages(uint32_t set, uint32_t binding) noexcept;
void UpdateDescriptorSetBuffer(uint32_t set, uint32_t binding) noexcept;
void ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span<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;

View File

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

View File

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

View File

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

View File

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

View File

@ -87,7 +87,7 @@ namespace SHADE
void UpdateTransformBuffer(uint32_t frameIndex);
void UpdateInstancedIntegerBuffer(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 */

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
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 UpdateBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
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 */

View File

@ -13,6 +13,8 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/
std::vector<Handle<SHVkDescriptorSetLayout>> SHGraphicsPredefinedData::predefinedLayouts;
SHVertexInputState SHGraphicsPredefinedData::defaultVertexInputState;
SHVertexInputState SHGraphicsPredefinedData::shadowMapVertexInputState;
std::vector<SHGraphicsPredefinedData::PerSystem> SHGraphicsPredefinedData::perSystemData;
//SHGraphicsPredefinedData::PerSystem SHGraphicsPredefinedData::batchingSystemData;
@ -150,12 +152,26 @@ namespace SHADE
Handle<SHVkDescriptorSetLayout> fontDataDescSetLayout = logicalDevice->CreateDescriptorSetLayout({ fontBitmapBinding, fontMatrixBinding });
SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSetLayout, fontDataDescSetLayout->GetVkHandle(), "[Descriptor Set Layout] Font Data");
// descriptor binding for storing shadow maps
SHVkDescriptorSetLayout::Binding shadowMapBinding
{
.Type = vk::DescriptorType::eCombinedImageSampler,
.Stage = vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment | vk::ShaderStageFlagBits::eCompute,
.BindPoint = SHGraphicsConstants::DescriptorSetBindings::IMAGE_AND_SAMPLERS_DATA,
.DescriptorCount = 200, // we can have up to 200 textures for now
.flags = vk::DescriptorBindingFlagBits::eVariableDescriptorCount,
};
// For global data (generic data and textures)
Handle<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(lightDataDescSetLayout);
predefinedLayouts.push_back(cameraDataGlobalLayout);
predefinedLayouts.push_back(materialDataPerInstanceLayout);
predefinedLayouts.push_back(fontDataDescSetLayout);
predefinedLayouts.push_back(shadowMapDescLayout);
perSystemData[SHUtilities::ConvertEnum(SystemType::BATCHING)].descSetLayouts = GetPredefinedDescSetLayouts
(
@ -179,7 +195,7 @@ namespace SHADE
);
}
void SHGraphicsPredefinedData::InitDefaultVertexInputState(void) noexcept
void SHGraphicsPredefinedData::InitPredefinedVertexInputState(void) noexcept
{
defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D) }); // positions at binding 0
defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_2D) }); // UVs at binding 1
@ -187,13 +203,16 @@ namespace SHADE
defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D) }); // Tangents at binding 3
defaultVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::MAT_4D) }); // Transform at binding 4 - 7 (4 slots)
defaultVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::UINT32_2D) }); // Instanced integer data at index 8
shadowMapVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D)});
shadowMapVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::MAT_4D) }, 4, 4); // Transform at binding 4 - 7 (4 slots)
}
void SHGraphicsPredefinedData::Init(Handle<SHVkLogicalDevice> logicalDevice) noexcept
{
perSystemData.resize(SHUtilities::ConvertEnum(SystemType::NUM_TYPES));
InitDescSetLayouts(logicalDevice);
InitDefaultVertexInputState();
InitPredefinedVertexInputState();
InitDescMappings();
InitDummyPipelineLayouts (logicalDevice);
}
@ -217,6 +236,11 @@ namespace SHADE
}
SHVertexInputState const& SHGraphicsPredefinedData::GetShadowMapViState(void) noexcept
{
return shadowMapVertexInputState;
}
SHGraphicsPredefinedData::PerSystem const& SHGraphicsPredefinedData::GetSystemData(SystemType systemType) noexcept
{
return perSystemData[static_cast<uint32_t>(systemType)];

View File

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

View File

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

View File

@ -101,7 +101,7 @@ namespace SHADE
// Register function for subpass
//auto const& RENDERERS = gfxSystem->GetDefaultViewport()->GetRenderers();
auto renderGraph = gfxSystem->GetRenderGraph();
auto subPass = renderGraph->GetNode("Debug Draw")->GetSubpass("Debug Draw");
auto subPass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW.data())->GetSubpass("Debug Draw");
subPass->AddExteriorDrawCalls([this](Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex)
{
// Set line width first
@ -129,7 +129,7 @@ namespace SHADE
}
cmdBuffer->EndLabeledSegment();
});
auto subPassWithDepth = renderGraph->GetNode("Debug Draw with Depth")->GetSubpass("Debug Draw with Depth");
auto subPassWithDepth = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW_DEPTH_PASS.data())->GetSubpass("Debug Draw with Depth");
subPassWithDepth->AddExteriorDrawCalls([this](Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex)
{
// Set line width first

View File

@ -31,68 +31,91 @@ namespace SHADE
static constexpr uint32_t EDITOR = 0;
};
//struct DescriptorSetIndex
//{
// /***************************************************************************/
// /*!
// \brief
// DescriptorSet Index for static global values like generic data, and
// texture samplers
// */
// /***************************************************************************/
// static constexpr uint32_t STATIC_GLOBALS = 0;
// /***************************************************************************/
// /*!
// \brief
// DescriptorSet Index for dynamic global values like lights.
// */
// /***************************************************************************/
// static constexpr uint32_t DYNAMIC_GLOBALS = 1;
// /***************************************************************************/
// /*!
// \brief
// DescriptorSet Index for high frequency changing global values like
// camera matrices.
// */
// /***************************************************************************/
// static constexpr uint32_t HIGH_FREQUENCY_GLOBALS = 2;
// /***************************************************************************/
// /*!
// \brief
// DescriptorSet Index for per-instance/material changing values.
// */
// /***************************************************************************/
// static constexpr uint32_t PER_INSTANCE = 3;
// /***************************************************************************/
// /*!
// \brief
// DescriptorSet Index for render graph resources. Unlike the sets from
// 1 to 3 and 6, this set index does not have hard coded bindings and is
// NOT part of the layouts included in the global data.
// */
// /***************************************************************************/
// static constexpr uint32_t RENDERGRAPH_RESOURCE = 4;
// /***************************************************************************/
// /*!
// \brief
// DescriptorSet Index for render graph node compute resources. For data
// that we wish to pass to compute shaders in the render graph, this is
// the set to use. Unlike the sets from 1 to 3 and 6, this set index does not have
// hard coded bindings and is NOT part of the layouts included in the global
// data.
// */
// /***************************************************************************/
// static constexpr uint32_t RENDERGRAPH_NODE_COMPUTE_RESOURCE = 5;
struct RenderGraphEntityNames
{
/***************************************************************************/
/*!
// /***************************************************************************/
// /*!
// \brief
// To store font data.
//
// */
// /***************************************************************************/
// static constexpr uint32_t FONT_DATA = 4;
//};
\brief
Name of G-Buffer render graph node.
*/
/***************************************************************************/
static constexpr std::string_view GBUFFER_PASS = "G-Buffer";
/***************************************************************************/
/*!
\brief
Name of shadow map render graph node.
*/
/***************************************************************************/
static constexpr std::string_view SHADOW_MAP_PASS = "Shadow Map Pass";
/***************************************************************************/
/*!
\brief
Name of deferred composite render graph node.
*/
/***************************************************************************/
static constexpr std::string_view DEFERRED_COMPOSITE_PASS = "Deferred Comp Pass";
/***************************************************************************/
/*!
\brief
Name of Debug Draw with Depth render graph node.
*/
/***************************************************************************/
static constexpr std::string_view DEBUG_DRAW_DEPTH_PASS = "Debug Draw with Depth Pass";
/***************************************************************************/
/*!
\brief
Name of Debug Draw render graph node.
*/
/***************************************************************************/
static constexpr std::string_view DEBUG_DRAW = "Debug Draw Pass";
/***************************************************************************/
/*!
\brief
Name of screen space pass render graph node.
*/
/***************************************************************************/
static constexpr std::string_view SCREEN_SPACE_PASS = "Screen Space Pass";
/***************************************************************************/
/*!
\brief
Name of ImGui pass render graph node.
*/
/***************************************************************************/
static constexpr std::string_view IMGUI_PASS = "ImGui Pass";
/***************************************************************************/
/*!
\brief
Name of deferred composite compute.
*/
/***************************************************************************/
static constexpr std::string_view DEFERRED_COMPOSITE_COMPUTE = "Deferred Composite";
};
struct DescriptorSetBindings
{
@ -158,6 +181,16 @@ namespace SHADE
/***************************************************************************/
static constexpr uint32_t FONT_MATRIX_DATA = 1;
/***************************************************************************/
/*!
\brief
Descriptor set binding for shadow map images.
*/
/***************************************************************************/
static constexpr uint32_t SHADOW_MAP_IMAGE_SAMPLER_DATA = 0;
};
struct VertexBufferBindings

View File

@ -44,6 +44,9 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/MiddleEnd/TextRendering/SHFreetypeInstance.h"
#include "Graphics/MiddleEnd/TextRendering/SHTextRenderingSubSystem.h"
#include "Graphics/MiddleEnd/GlobalData/SHGlobalDescriptorSets.h"
#include "Events/SHEvent.h"
#include "Graphics/MiddleEnd/Lights/SHLightComponent.h"
#include "Input/SHInputManager.h"
namespace SHADE
{
@ -124,6 +127,13 @@ namespace SHADE
SHFreetypeInstance::Init();
SHAssetManager::CompileAsset("../../Assets/Shaders/DeferredComposite_CS.glsl", false);
SHAssetManager::CompileAsset("../../Assets/Shaders/SSAO_CS.glsl", false);
SHAssetManager::CompileAsset("../../Assets/Shaders/SSAOBlur_CS.glsl", false);
SHAssetManager::CompileAsset("../../Assets/Shaders/PureCopy_CS.glsl", false);
SHAssetManager::CompileAsset("../../Assets/Shaders/TestCube_VS.glsl", false);
SHAssetManager::CompileAsset("../../Assets/Shaders/TestCube_FS.glsl", false);
// Load Built In Shaders
static constexpr AssetID VS_DEFAULT = 39210065; defaultVertShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(VS_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 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 SHADOW_MAP_VS = 44646107; shadowMapVS = SHResourceManager::LoadOrGet<SHVkShaderModule>(SHADOW_MAP_VS);
}
void SHGraphicsSystem::InitRenderGraph(void) noexcept
@ -169,6 +181,8 @@ namespace SHADE
// Create Default Viewport
worldViewport = AddViewport(vk::Viewport(0.0f, 0.0f, static_cast<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() };
for (uint32_t i = 0; i < renderContextCmdPools.size(); ++i)
{
@ -183,22 +197,24 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
// Initialize world render graph
renderGraph->Init("World Render Graph", device, swapchain, &resourceManager, renderContextCmdPools);
renderGraph->AddResource("Position", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat);
renderGraph->AddResource("Normals", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat);
renderGraph->AddResource("Position", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat);
renderGraph->AddResource("Position World Space", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat);
renderGraph->AddResource("Normals", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat);
//worldRenderGraph->AddResource("Tangents", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat);
renderGraph->AddResource("Albedo", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second);
renderGraph->AddResource("Depth Buffer", { SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL }, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint);
renderGraph->AddResource("Entity ID", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc);
renderGraph->AddResource("Light Layer Indices", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc);
renderGraph->AddResource("Scene", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE, SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED }, windowDims.first, windowDims.second);
renderGraph->AddResource("SSAO", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR8Unorm);
renderGraph->AddResource("SSAO Blur", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR8Unorm);
renderGraph->AddResource("Present", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT }, windowDims.first, windowDims.second);
renderGraph->AddResource("Albedo", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second);
renderGraph->AddResource("Depth Buffer", { SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL }, true, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint);
renderGraph->AddResource("Entity ID", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED }, true, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc);
renderGraph->AddResource("Light Layer Indices", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc);
renderGraph->AddResource("Scene", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE, SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED }, true, windowDims.first, windowDims.second);
renderGraph->AddResource("SSAO", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR8Unorm);
renderGraph->AddResource("SSAO Blur", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR8Unorm);
renderGraph->AddResource("Present", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT }, true, windowDims.first, windowDims.second);
/*-----------------------------------------------------------------------*/
/* MAIN NODE */
/*-----------------------------------------------------------------------*/
auto gBufferNode = renderGraph->AddNode("G-Buffer",
auto gBufferNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(),
//auto gBufferNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data()
{
"Position",
"Entity ID",
@ -207,7 +223,8 @@ namespace SHADE
"Albedo",
"Depth Buffer",
"SSAO",
"SSAO Blur"
"SSAO Blur",
"Position World Space"
},
{}); // no predecessors
@ -220,6 +237,7 @@ namespace SHADE
gBufferSubpass->AddColorOutput("Light Layer Indices");
gBufferSubpass->AddColorOutput("Normals");
gBufferSubpass->AddColorOutput("Albedo");
gBufferSubpass->AddColorOutput("Position World Space");
gBufferSubpass->AddDepthOutput("Depth Buffer", SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL);
@ -254,53 +272,52 @@ namespace SHADE
// Add another pass to blur SSAO
Handle<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 */
/*-----------------------------------------------------------------------*/
// This pass will facilitate both lighting and shadows in 1 single pass.
auto deferredCompositeNode = renderGraph->AddNode("Deferred Comp Pass",
auto deferredCompositeNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data(),
{
"Position",
"Light Layer Indices",
"Normals",
"Albedo",
"Scene",
"SSAO Blur"
"SSAO Blur",
"Position World Space"
},
{"G-Buffer"});
{ SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS .data()});
/*-----------------------------------------------------------------------*/
/* DEFERRED COMPOSITE SUBPASS INIT */
/*-----------------------------------------------------------------------*/
deferredCompositeNode->AddNodeCompute("Deferred Composite", deferredCompositeShader, { "Position", "Normals", "Albedo", "Light Layer Indices", "SSAO Blur", "Scene" });
auto deferredCompositeCompute = deferredCompositeNode->AddNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data(), deferredCompositeShader, {"Position", "Normals", "Albedo", "Light Layer Indices", "SSAO Blur", "Position World Space", "Scene"}, {}, SHLightingSubSystem::MAX_SHADOWS);
deferredCompositeCompute->AddPreComputeFunction([=](Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex)
{
lightingSubSystem->PrepareShadowMapsForRead(cmdBuffer);
});
/*-----------------------------------------------------------------------*/
/* DEBUG DRAW PASS INIT */
/*-----------------------------------------------------------------------*/
// Set up Debug Draw Passes
// - Depth Tested
auto debugDrawNodeDepth = renderGraph->AddNode("Debug Draw with Depth", { "Scene", "Depth Buffer" }, {"G-Buffer", "Deferred Comp Pass"});
auto debugDrawNodeDepth = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW_DEPTH_PASS.data(), {"Scene", "Depth Buffer"}, {SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data()});
auto debugDrawDepthSubpass = debugDrawNodeDepth->AddSubpass("Debug Draw with Depth", worldViewport, worldRenderer);
debugDrawDepthSubpass->AddColorOutput("Scene");
debugDrawDepthSubpass->AddDepthOutput("Depth Buffer");
// - No Depth Test
auto debugDrawNode = renderGraph->AddNode("Debug Draw", { "Scene" }, { "Debug Draw with Depth" });
auto debugDrawNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW.data(), {"Scene"}, {SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW_DEPTH_PASS.data()});
auto debugDrawSubpass = debugDrawNode->AddSubpass("Debug Draw", worldViewport, worldRenderer);
debugDrawSubpass->AddColorOutput("Scene");
/*-----------------------------------------------------------------------*/
/* SCREEN SPACE PASS */
/*-----------------------------------------------------------------------*/
auto screenSpaceNode = renderGraph->AddNode("Screen Space Pass", { "Scene", "Entity ID" }, {"Deferred Comp Pass", "G-Buffer", "Debug Draw" });
auto screenSpaceNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS.data(), {"Scene", "Entity ID"}, {SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW.data()});
auto uiSubpass = screenSpaceNode->AddSubpass("UI", worldViewport, screenRenderer);
uiSubpass->AddColorOutput("Scene");
uiSubpass->AddColorOutput("Entity ID");
@ -315,16 +332,16 @@ namespace SHADE
#ifdef SHEDITOR
{
// Dummy Node to transition scene render graph resource
auto dummyNode = renderGraph->AddNode("Dummy Pass", { "Scene" }, { "Screen Space Pass" });
auto dummyNode = renderGraph->AddNode("Dummy Pass", { "Scene" }, { SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS .data()});
auto dummySubpass = dummyNode->AddSubpass("Dummy Subpass", {}, {});
dummySubpass->AddInput("Scene");
auto imGuiNode = renderGraph->AddNode("ImGui Node", { "Present" }, {});
auto imGuiNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::IMGUI_PASS.data(), {"Present"}, {});
auto imGuiSubpass = imGuiNode->AddSubpass("ImGui Draw", {}, {});
imGuiSubpass->AddColorOutput("Present");
}
#else
renderGraph->AddRenderToSwapchainNode("Scene", "Present", { "Screen Space Pass" }, { renderToSwapchainVS, renderToSwapchainFS });
renderGraph->AddRenderToSwapchainNode("Scene", "Present", { SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS .data()}, {renderToSwapchainVS, renderToSwapchainFS});
#endif
@ -393,12 +410,16 @@ namespace SHADE
postOffscreenRenderSubSystem->Init(device, renderGraph->GetRenderGraphResource("Scene"), descPool);
lightingSubSystem = resourceManager.Create<SHLightingSubSystem>();
lightingSubSystem->Init(device, descPool);
lightingSubSystem->Init(device, descPool, &resourceManager, samplerCache.GetSampler (device, SHVkSamplerParams
{
.addressMode = vk::SamplerAddressMode::eClampToBorder,
})
);
textRenderingSubSystem = resourceManager.Create<SHTextRenderingSubSystem>();
// initialize the text renderer
auto uiNode = renderGraph->GetNode("Screen Space Pass");
auto uiNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS.data());
textRenderingSubSystem->Init(device, uiNode->GetRenderpass(), uiNode->GetSubpass("UI"), descPool, textVS, textFS);
SHGlobalDescriptorSets::SetLightingSubSystem(lightingSubSystem);
@ -426,7 +447,7 @@ namespace SHADE
defaultMaterial = AddMaterial
(
defaultVertShader, defaultFragShader,
renderGraph->GetNode("G-Buffer")->GetSubpass("G-Buffer Write")
renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data())->GetSubpass("G-Buffer Write")
);
defaultMaterial->SetProperty("data.textureIndex", defaultTexture->TextureArrayIndex);
}
@ -451,6 +472,7 @@ namespace SHADE
InitMiddleEnd();
InitSubsystems();
InitBuiltInResources();
InitEvents();
}
void SHGraphicsSystem::Exit(void)
@ -546,6 +568,15 @@ namespace SHADE
#endif
}
if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::B))
{
auto& lightComps = SHComponentManager::GetDense<SHLightComponent>();
for (auto& comp : lightComps)
{
comp.SetEnableShadow(true);
}
}
renderGraph->Begin(frameIndex);
auto cmdBuffer = renderGraph->GetCommandBuffer(frameIndex);
@ -726,16 +757,61 @@ namespace SHADE
renderers.erase(iter);
}
SHEventHandle SHGraphicsSystem::ReceiveLightEnableShadowEvent(SHEventPtr event) noexcept
SHEventHandle SHGraphicsSystem::ReceiveLightEnableShadowEvent(SHEventPtr eventPtr) noexcept
{
// we need to wait for the device to finish using the graph first
device->WaitIdle();
auto const& EVENT_DATA = reinterpret_cast<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
renderGraph->AddResource(resourceName, {SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT}, false, SHLightingSubSystem::SHADOW_MAP_WIDTH, SHLightingSubSystem::SHADOW_MAP_HEIGHT, vk::Format::eD32Sfloat);
// link resource to node. This means linking the resource and regenerating the node's renderpass and framebuffer.
auto shadowMapNode = renderGraph->AddNodeAfter(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data() + resourceName, {resourceName.c_str()}, SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data());
// Add a subpass to render to that shadow map
auto newSubpass = shadowMapNode->RuntimeAddSubpass(resourceName + " Subpass", shadowMapViewport, lightComp->GetRenderer());
newSubpass->AddDepthOutput(resourceName, SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH);
//renderGraph->GetNode ();
return event->handle;
// 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
// add the shadow map to the lighting system
uint32_t const NEW_SHADOW_MAP_INDEX = lightingSubSystem->AddShadowMap(renderGraph->GetRenderGraphResource(resourceName), EVENT_DATA->lightEntity);
auto nodeCompute = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data())->GetNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data());
nodeCompute->ModifyWriteDescImageComputeResource(SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA, lightingSubSystem->GetViewSamplerLayout(NEW_SHADOW_MAP_INDEX), NEW_SHADOW_MAP_INDEX);
return eventPtr->handle;
}
Handle<SHMaterial> SHGraphicsSystem::AddMaterial(Handle<SHVkShaderModule> vertShader, Handle<SHVkShaderModule> fragShader, Handle<SHSubpass> subpass)
@ -1047,6 +1123,7 @@ namespace SHADE
mousePickSubSystem->HandleResize();
postOffscreenRenderSubSystem->HandleResize();
//lightingSubSystem->HandleResize(renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data())->GetNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data()));
worldViewport->SetWidth(static_cast<float>(resizeWidth));
worldViewport->SetHeight(static_cast<float>(resizeHeight));
@ -1079,7 +1156,7 @@ namespace SHADE
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

View File

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

View File

@ -122,4 +122,9 @@ namespace SHADE
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
#include "SHCamera.h"
#include "Resource/SHHandle.h"
#include "Graphics/RenderGraph/SHRenderGraph.h"
#include "Math/SHMath.h"
#include <vector>
#include "Graphics/Pipeline/SHPipelineType.h"
namespace SHADE
{
@ -93,6 +93,7 @@ namespace SHADE
/* Setters and Getters */
/*-----------------------------------------------------------------------------*/
Handle<SHCameraDirector> GetCameraDirector (void) const noexcept;
SHShaderCameraData GetCPUCameraData (void) const noexcept;
private:
/*-----------------------------------------------------------------------------*/

View File

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

View File

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

View File

@ -10,6 +10,13 @@
#include "SHLightComponent.h"
#include "Math/Vector/SHVec4.h"
#include "Math/SHMatrix.h"
#include "Graphics/Images/SHVkImageView.h"
#include "Graphics/MiddleEnd/Textures/SHVkSamplerCache.h"
#include "Graphics/Images/SHVkSampler.h"
#include "Graphics/Events/SHGraphicsEvents.h"
#include "Graphics/MiddleEnd/Interface/SHRenderer.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Graphics/RenderGraph/SHRenderGraphNodeCompute.h"
namespace SHADE
{
@ -50,6 +57,19 @@ namespace SHADE
//lightPtr->direction = lightData.direction;
lightPtr->diffuseColor = lightData.color;
lightPtr->active = lightComp->isActive;
// write view projection matrix if renderer is available
auto lightRenderer = lightComp->GetRenderer();
if (lightRenderer)
{
lightPtr->pvMatrix = lightRenderer->GetCPUCameraData().viewProjectionMatrix;
// Boolean to cast shadows in first 8 bits (1 byte)
lightPtr->shadowData = lightData.castShadows;
// Next 24 bits for shadow map index
lightPtr->shadowData |= (lightData.shadowMapIndex << 8);
}
break;
}
case SH_LIGHT_TYPE::POINT:
@ -365,6 +385,32 @@ namespace SHADE
}
}
void SHLightingSubSystem::UpdateShadowMapDesc(void) noexcept
{
}
SHMatrix SHLightingSubSystem::GetViewMatrix(SHLightComponent* lightComp) noexcept
{
switch (lightComp->GetLightData().type)
{
case SH_LIGHT_TYPE::DIRECTIONAL:
return SHMatrix::Transpose(SHMatrix::LookAtLH(lightComp->GetLightData().position, SHVec3::Normalise (lightComp->GetLightData().direction), SHVec3(0.0f, -1.0f, 0.0f)));
//return SHMatrix::Transpose(SHMatrix::LookAtLH(/*lightComp->GetLightData().position*/SHVec3(1.27862f, 4.78952f, 4.12811f), SHVec3(-0.280564f, -0.66262f, -0.69422f), SHVec3(0.0f, -1.0f, 0.0f)));
case SH_LIGHT_TYPE::POINT:
return {};
case SH_LIGHT_TYPE::SPOT:
return {};
case SH_LIGHT_TYPE::AMBIENT:
return {};
case SH_LIGHT_TYPE::NUM_TYPES:
return {};
default:
return {};
}
}
/***************************************************************************/
/*!
@ -375,13 +421,15 @@ namespace SHADE
*/
/***************************************************************************/
void SHLightingSubSystem::Init(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool) noexcept
void SHLightingSubSystem::Init(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, SHResourceHub* rh, Handle<SHVkSampler> inShadowMapSampler) noexcept
{
SHComponentManager::CreateComponentSparseSet<SHLightComponent>();
logicalDevice = device;
resourceHub = rh;
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::fill (variableSizes.begin(), variableSizes.end(), 1);
@ -418,7 +466,22 @@ namespace SHADE
dynamicOffsets[i].resize(NUM_LIGHT_TYPES + 1); // +1 for the count
}
#pragma endregion
#pragma region SHADOWS
//std::vector<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;
#pragma endregion
}
/***************************************************************************/
@ -452,6 +515,12 @@ namespace SHADE
for (auto& light : lightComps)
{
if (auto renderer = light.GetRenderer())
{
//SHMatrix orthoMatrix = SHMatrix::OrthographicRH()
renderer->UpdateDataManual(frameIndex, GetViewMatrix(&light), SHMatrix::OrthographicLH(10.0f, 10.0f, 1.0f, 50.0f));
}
auto enumValue = SHUtilities::ConvertEnum(light.GetLightData().type);
// First we want to make sure the light is already bound to the system. if it
@ -503,7 +572,6 @@ namespace SHADE
// so we do it anyway. #NoteToSelf: if at any point it affects performance, do a check before computing.
ComputeDynamicOffsets();
}
/***************************************************************************/
@ -526,9 +594,101 @@ namespace SHADE
}
uint32_t SHLightingSubSystem::AddShadowMap(Handle<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
{
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 "Math/Vector/SHVec3.h"
#include "Math/Vector/SHVec4.h"
#include "Math/SHMatrix.h"
#include "SHLightData.h"
#include <array>
#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
#include "Graphics/RenderGraph/SHRenderGraphResource.h"
#include "ECS_Base/SHECSMacros.h"
namespace SHADE
{
@ -16,6 +20,10 @@ namespace SHADE
class SHVkBuffer;
class SHLightComponent;
class SHVkCommandBuffer;
class SHSamplerCache;
class SHVkImageView;
class SHVkSampler;
class SHRenderGraphNodeCompute;
// Represents how the data will be interpreted in GPU. we want to copy to a container of these before passing to GPU.
struct SHDirectionalLightData
@ -34,6 +42,12 @@ namespace SHADE
//! Diffuse color emitted by the light
alignas (16) SHVec4 diffuseColor;
//! Matrix for world to projection from light's perspective
SHMatrix pvMatrix;
//! Represents boolean for casting shadows in first byte and shadow map index in the other 3.
uint32_t shadowData;
};
// Represents how the data will be interpreted in GPU. we want to copy to a container of these before passing to GPU.
@ -52,19 +66,22 @@ namespace SHADE
//! when a fragment is being evaluated, the shader will use the fragment's
//! layer value to AND with the light's. If result is 1, do lighting calculations.
uint32_t cullingMask;
};
class SH_API SHLightingSubSystem
{
public:
using DynamicOffsetArray = std::array<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:
class PerTypeData
{
public:
private:
/*-----------------------------------------------------------------------*/
/* STATIC MEMBER VARIABLES */
@ -123,6 +140,10 @@ namespace SHADE
};
private:
/*-----------------------------------------------------------------------*/
/* STATIC MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/
//! logical device used for creation
Handle<SHVkLogicalDevice> logicalDevice;
@ -150,24 +171,59 @@ namespace SHADE
//! don't do anything.
//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 */
/*-----------------------------------------------------------------------*/
void UpdateDescSet (uint32_t binding) noexcept;
void ComputeDynamicOffsets (void) noexcept;
void ResetNumLights (void) noexcept;
void UpdateShadowMapDesc (void) noexcept;
SHMatrix GetViewMatrix (SHLightComponent* lightComp) noexcept;
public:
/*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
void Init (Handle<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 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;
/*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/
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 "SHPipelineLibrary.h"
#include "Graphics/Devices/SHVkLogicalDevice.h"
#include "Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h"
#include "Graphics/RenderGraph/SHSubpass.h"
#include "Graphics/SHVkUtil.h"
namespace SHADE
{
Handle<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
{
.shaderModules = {vsFsPair.first, vsFsPair.second},
.shaderModules = std::move(modules),
.predefinedDescSetLayouts = SHGraphicsPredefinedData::GetSystemData(SHGraphicsPredefinedData::SystemType::BATCHING).descSetLayouts
};
@ -21,7 +26,7 @@ namespace SHADE
// Create the pipeline and configure the default vertex input state
auto newPipeline = logicalDevice->CreateGraphicsPipeline(pipelineLayout, nullptr, renderpass, subpass);
newPipeline->GetPipelineState().SetVertexInputState(SHGraphicsPredefinedData::GetDefaultViState());
newPipeline->GetPipelineState().SetVertexInputState(viState);
SHColorBlendState colorBlendState{};
colorBlendState.logic_op_enable = VK_FALSE;
@ -30,6 +35,7 @@ namespace SHADE
auto const& subpassColorReferences = subpass->GetColorAttachmentReferences();
colorBlendState.attachments.reserve(subpassColorReferences.size());
for (auto& att : subpassColorReferences)
{
colorBlendState.attachments.push_back(vk::PipelineColorBlendAttachmentState
@ -48,6 +54,8 @@ namespace SHADE
newPipeline->GetPipelineState().SetColorBlenState(colorBlendState);
newPipeline->GetPipelineState().SetRasterizationState(rasterState);
// Actually construct the pipeline
newPipeline->ConstructPipeline();

View File

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

View File

@ -195,7 +195,7 @@ namespace SHADE
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
bindings.emplace_back();
@ -210,7 +210,7 @@ namespace SHADE
// Offset is 0 at first (for first element)
uint32_t offset = 0;
binding.binding = static_cast<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 (auto const& attrib : inAttribs)
@ -226,10 +226,11 @@ namespace SHADE
auto& vertexAttrib = attributes.back();
// The binding for that attribute description is index of the new binding created earlier in this function
vertexAttrib.binding = static_cast<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
vertexAttrib.location = static_cast<uint32_t>(attributes.size () - 1);
//Attribute location. New index is simply + 1 of the previous. Starts from 0 obviously
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
vertexAttrib.format = format;

View File

@ -34,7 +34,7 @@ namespace SHADE
SHVertexInputState& operator= (SHVertexInputState const& rhs) noexcept;
SHVertexInputState& operator= (SHVertexInputState&& rhs) noexcept;
void AddBinding(bool instanced, bool calcOffset, std::initializer_list<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 SHVkPipeline;

View File

@ -18,6 +18,8 @@ namespace SHADE
vk::ShaderStageFlags stageFlags;
for (auto& shaderModule : shaderModules)
{
if (shaderModule)
{
// References for convenience
auto const& reflectedData = shaderModule->GetReflectedData();
@ -81,7 +83,7 @@ namespace SHADE
stageFlags |= shaderModule->GetShaderStageFlagBits();
}
}
}
// After all the sizes of the push constant blocks have been added, record the size in the interface
@ -132,6 +134,9 @@ namespace SHADE
//! Now we take descriptor set info from all shaders and prepare some bindings for the descriptor set
for (auto& shaderModule : shaderModules)
{
if (!shaderModule)
continue;
auto const& descBindingInfo = shaderModule->GetReflectedData().GetDescriptorBindingInfo();
auto const& reflectedSets = descBindingInfo.GetReflectedSets();
@ -200,11 +205,13 @@ namespace SHADE
newBinding.DescriptorCount = SHVkDescriptorSetLayout::Binding::VARIABLE_DESCRIPTOR_UPPER_BOUND;
// Set the flags for variable bindings
newBinding.flags = vk::DescriptorBindingFlagBits::eVariableDescriptorCount;
newBinding.flags = vk::DescriptorBindingFlagBits::eVariableDescriptorCount | vk::DescriptorBindingFlagBits::ePartiallyBound;
}
else
{
SHLOG_ERROR("Variable size binding is detected, but the binding is not the last binding of the set and is therefore invalid. ");
}
}
setsWithBindings[CURRENT_SET].emplace_back(newBinding);
}
@ -326,11 +333,10 @@ namespace SHADE
{
for (auto& mod : shaderModules)
{
mod->AddCallback([this]()
if (mod)
{
RecreateIfNeeded();
mod->AddCallback([this]() { 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 (w == static_cast<uint32_t>(-1) && h == static_cast<uint32_t>(-1))
@ -64,7 +64,7 @@ namespace SHADE
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);
}
@ -106,6 +106,9 @@ namespace SHADE
for (auto& affectedNode : affectedNodes)
nodes[affectedNode]->CreateFramebuffer();
renderGraphStorage->graphResources->at(resourceName).Free();
renderGraphStorage->graphResources->erase (resourceName);
/*
* IMPORTANT NOTES
*
@ -166,68 +169,7 @@ namespace SHADE
for (uint32_t i = 0; auto& node : nodes)
{
// key is handle ID, value is final layout.
std::unordered_map<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);
}
node->StandaloneConfigureAttDesc(i == nodes.size() - 1);
++i;
}
@ -333,6 +275,17 @@ namespace SHADE
}
}
void SHRenderGraph::ReindexNodes(void) noexcept
{
nodeIndexing.clear();
uint32_t i = 0;
for (auto& node : nodes)
{
nodeIndexing.emplace (node->name, i);
++i;
}
}
/***************************************************************************/
/*!
@ -473,6 +426,65 @@ namespace SHADE
return node;
}
/***************************************************************************/
/*!
\brief
This function is purely used for dynamic nodes (if such a thing were to
exist in our architecture). In other words, don't use this function unless
the new node is fully standalone and does not rely or is a prereq of
other nodes.
\param nodeName
Name of new node
\param resourceInstruction
Resources for the node
\param nodeToAddAfter
The node to add the new node after.
\return
*/
/***************************************************************************/
Handle<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
{
for (auto& node : predecessorNodes)
@ -532,10 +544,6 @@ namespace SHADE
ConfigureSubSystems();
}
void SHRenderGraph::Regenerate(void) noexcept
{
}
/***************************************************************************/
/*!
@ -571,12 +579,15 @@ namespace SHADE
auto const& descMappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::BATCHING);
for (auto& node : nodes)
{
if (node->renderpass)
{
// bind static global data
SHGlobalDescriptorSets::BindStaticGlobalData(cmdBuffer, SH_PIPELINE_TYPE::GRAPHICS, descMappings.at(SHPredefinedDescriptorTypes::STATIC_DATA));
node->Execute(cmdBuffer, descPool, frameIndex);
}
}
cmdBuffer->EndLabeledSegment();
}
@ -604,10 +615,13 @@ namespace SHADE
{
// resize resources
for (auto& [name, resource] : *renderGraphStorage->graphResources)
{
if (resource->resizeWithWindow)
{
if (!renderGraphStorage->nonOwningResourceInitialLayouts.contains (resource.GetId().Raw))
resource->HandleResize(newWidth, newHeight);
}
}
for (auto& node : nodes)
{

View File

@ -55,6 +55,7 @@ namespace SHADE
void ConfigureRenderpasses (void) noexcept;
void ConfigureSubSystems (void) noexcept;
void ConfigureFramebuffers (void) noexcept;
void ReindexNodes (void) noexcept;
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */
@ -101,6 +102,7 @@ namespace SHADE
(
std::string resourceName,
std::initializer_list<SH_RENDER_GRAPH_RESOURCE_FLAGS> typeFlags,
bool resizeWithWindow = true,
uint32_t w = static_cast<uint32_t>(-1),
uint32_t h = static_cast<uint32_t>(-1),
vk::Format format = vk::Format::eB8G8R8A8Unorm,
@ -123,6 +125,12 @@ namespace SHADE
std::initializer_list<ResourceInstruction> resourceInstruction,
std::initializer_list<std::string> predecessorNodes
) noexcept;
Handle<SHRenderGraphNode> AddNodeAfter
(
std::string nodeName,
std::initializer_list<ResourceInstruction> resourceInstruction,
std::string nodeToAddAfter
) noexcept;
void AddRenderToSwapchainNode
(
@ -134,7 +142,6 @@ namespace SHADE
) noexcept;
void Generate (void) noexcept;
void Regenerate (void) noexcept;
void CheckForNodeComputes (void) noexcept;
void Execute (uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool) noexcept;
void Begin (uint32_t frameIndex) noexcept;
@ -165,7 +172,14 @@ namespace SHADE
* that manage the resources instead and can facilitate such linking of resources. Either that, or we allow only 1 render graph,
* but different matrices (SHRenderer) can be used in different nodes.
* - There are also way too many hash maps created for ease of access. This definitely can be cut down.
* -
* - In hindsight there should have been a distinction between static and dynamic nodes. Static nodes are the ones that are accounted
* for in the generation of the render graph. Dynamic nodes begin with nothing at first, but allows for linking of resources and subpasses
* while the render graph is executing. The resources here should also be dynamic, which means it should never be used in anywhere else other
* than in the node that is using it. This would mean its initial layouts are always specified as undefined and final layouts specified as
* whatever the last subpass that is using that resource specifies in the node. Dynamic nodes are meant to render to resources that would later
* be used externally, as descriptors for example (the descriptors can be used in a render graph node compute for example). Dynamic nodes run as
* if they are the only nodes in the graph, because their resources are not used in other nodes and are thus not predecessors or successors of any
* other node.
*
*/

View File

@ -32,9 +32,12 @@ namespace SHADE
renderpass.Free();
}
if (!spDescs.empty())
{
renderpass = graphStorage->logicalDevice->CreateRenderpass(attachmentDescriptions, spDescs, spDeps);
SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eRenderPass, renderpass->GetVkRenderpass(), "[RenderPass] " + name);
}
}
/***************************************************************************/
/*!
@ -45,6 +48,8 @@ namespace SHADE
*/
/***************************************************************************/
void SHRenderGraphNode::CreateFramebuffer(void) noexcept
{
if (renderpass)
{
if (!framebuffers.empty())
{
@ -78,8 +83,11 @@ namespace SHADE
SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eFramebuffer, framebuffers[i]->GetVkFramebuffer(), "[Framebuffer] " + name + std::to_string(i));
}
}
}
void SHRenderGraphNode::HandleResize(void) noexcept
{
if (renderpass)
{
renderpass->HandleResize();
@ -114,23 +122,32 @@ namespace SHADE
nodeCompute->HandleResize();
}
}
}
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
spDescs.resize(subpasses.size());
spDeps.resize(subpasses.size());
spDescs.resize(numValidSubpasses);
spDeps.resize(numValidSubpasses);
// Now we want to loop through all attachments in all subpasses in the node and query
// the resources being used. For each resource we want to query the type and record it
// in bit fields (1 bit for each subpass).
uint32_t colorRead = 0, colorWrite = 0, depthRead = 0, depthWrite = 0, inputDependencies = 0;
uint32_t i = 0;
// For all subpasses (see above description about bit field for this).
for (auto& subpass : subpasses)
for (uint32_t i = 0; auto& subpass : subpasses)
{
// skip if subpass is not valid
if (subpass->HasNoAttachments())
continue;
// Configure subpass description
auto& desc = spDescs[i];
desc.pColorAttachments = subpass->colorReferences.data();
@ -186,8 +203,11 @@ namespace SHADE
// Loop through all subpasses again but this time we use the bit field to initialize
// the dependencies.
for (i = 0; i < subpasses.size(); ++i)
for (uint32_t i = 0; auto & subpass : subpasses)
{
if (subpass->HasNoAttachments())
continue;
vk::PipelineStageFlags srcStage;
vk::PipelineStageFlags dstStage;
vk::AccessFlags srcAccess;
@ -245,6 +265,8 @@ namespace SHADE
// initialize input descriptors
subpasses[i]->CreateInputDescriptors();
++i;
}
}
@ -343,6 +365,7 @@ namespace SHADE
, spDeps{ std::move(rhs.spDeps) }
, nodeComputes{ std::move(rhs.nodeComputes) }
, name { std::move(rhs.name) }
, ISelfHandle<SHRenderGraphNode>{std::move(rhs)}
{
rhs.renderpass = {};
@ -419,7 +442,7 @@ namespace SHADE
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
std::vector<Handle<SHRenderGraphResource>> nodeComputeResources{};
@ -435,7 +458,7 @@ namespace SHADE
std::vector<Handle<SHRenderGraphResource>> temp (nodeComputeResources);
// 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);
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
attachmentDescriptions.erase (attachmentDescriptions.begin() + index);
// erase from mapping as well
resourceAttachmentMapping->erase(resourceHandleID);
// Remove footprint of attachment from all subpasses as well
for (auto it = subpasses.begin(); it != subpasses.end(); ++it)
{
// attempt to detach resource from subpass
(*it)->DetachResource(resourceName, index);
// If the subpass ends up having no attachments after, erase it from the node
if ((*it)->HasNoAttachments())
// If the subpass uses the resource, just remove the subpass since the subpass will be invalid
if ((*it)->UsesResource(index))
{
// erase from indexing
subpassIndexing.erase((*it)->GetName());
@ -530,12 +615,32 @@ namespace SHADE
for (uint32_t i = 0; i < subpasses.size(); ++i)
subpasses[i]->SetIndex(i);
// remove node computes using the resource
for (auto it = nodeComputes.begin(); it != nodeComputes.end(); ++it)
{
if ((*it)->UsesResource(resourceHandleID))
{
it = nodeComputes.erase(it);
}
}
// recompute the barriers for the other computes
for (auto it = nodeComputes.begin(); it != nodeComputes.end(); ++it)
{
if (it == nodeComputes.begin())
(*it)->SetFollowingEndRenderpass(true);
(*it)->InitializeBarriers();
}
return true;
}
return false;
}
void SHRenderGraphNode::Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept
{
if (renderpass)
{
uint32_t framebufferIndex = (framebuffers.size() > 1) ? frameIndex : 0;
commandBuffer->BeginRenderpass(renderpass, framebuffers[framebufferIndex]);
@ -545,7 +650,7 @@ namespace SHADE
subpasses[i]->Execute(commandBuffer, descPool, frameIndex);
// Go to next subpass if not last subpass
if (i != static_cast<uint32_t>(subpasses.size()) - 1u)
if (i != static_cast<uint32_t>(subpasses.size()) - 1u && !subpasses[i]->HasNoAttachments())
commandBuffer->NextSubpass();
}
@ -569,6 +674,7 @@ namespace SHADE
for (auto& sbCompute : nodeComputes)
sbCompute->Execute(commandBuffer, frameIndex);
}
}
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);
}
/***************************************************************************/
/*!
\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;
}
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 HandleResize (void) noexcept;
void ConfigureSubpasses (void) noexcept;
bool DetachResource(std::string const& resourceName, uint64_t resourceHandleID) noexcept;
void AddDummySubpassIfNeeded(void) noexcept;
void StandaloneConfigureAttDesc (bool isLastNode) noexcept;
public:
/*-----------------------------------------------------------------------*/
@ -106,15 +109,17 @@ namespace SHADE
/* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
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;
void AddDummySubpassIfNeeded (void) noexcept;
bool DetachResource (std::string const& resourceName, uint64_t resourceHandleID) 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;
// TODO: RemoveSubpass()
void Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept;
Handle<SHVkPipeline> GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> subpass) noexcept;
void FinaliseBatch(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
// Runtime functions that don't affect the renderpass
void RuntimeLinkResource(std::string resourceName) noexcept;
Handle<SHSubpass> RuntimeAddSubpass(std::string subpassName, Handle<SHViewport> viewport, Handle<SHRenderer> renderer) noexcept;
void RuntimeStandaloneRegenerate (void) noexcept;
/*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/
@ -122,6 +127,7 @@ namespace SHADE
Handle<SHSubpass> GetSubpass(std::string_view subpassName) const noexcept;
Handle<SHRenderGraphResource> GetResource (uint32_t resourceIndex) const noexcept;
std::vector<Handle<SHRenderGraphResource>> const& GetResources (void) const noexcept;
Handle<SHRenderGraphNodeCompute> GetNodeCompute (std::string nodeComputeName) const noexcept;
friend class SHRenderGraph;
};

View File

@ -14,7 +14,56 @@
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{}
, pipelineLayout{}
, resources{}
@ -68,10 +117,12 @@ namespace SHADE
// check if all layouts are there
if (layouts.size() == descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE) + 1)
{
Handle<SHVkDescriptorSetLayout> computeResourceLayout = {};
computeResourceLayout = layouts[descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE)];
// create compute resources
computeResource = graphStorage->resourceHub->Create<ComputeResource>();
auto computeResourceLayout = layouts[descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE)];
computeResource->descSet = graphStorage->descriptorPool->Allocate({ computeResourceLayout }, { 1 });
computeResource->descSet = graphStorage->descriptorPool->Allocate({ computeResourceLayout }, {variableDescCount});
#ifdef _DEBUG
for (auto set : computeResource->descSet->GetVkHandle())
SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eDescriptorSet, set, "[Descriptor Set] " + name + " Resources");
@ -91,6 +142,11 @@ namespace SHADE
void SHRenderGraphNodeCompute::Execute(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
{
for (auto& fn : preComputeFunctions)
{
fn (cmdBuffer, frameIndex);
}
// bind the compute pipeline
cmdBuffer->BindPipeline(computePipeline);
@ -157,35 +213,7 @@ namespace SHADE
groupSizeX = maxWidth / workGroupSizeX;
groupSizeY = maxHeight / workGroupSizeY;
for (uint32_t i = 0; auto& barriers : memoryBarriers)
{
barriers.clear();
for (auto& resource : resources)
{
vk::AccessFlags srcAccessMask = (followingEndRenderpass) ? vk::AccessFlagBits::eInputAttachmentRead : (vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite);
barriers.push_back(vk::ImageMemoryBarrier
{
.srcAccessMask = srcAccessMask,
.dstAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite,
.oldLayout = vk::ImageLayout::eGeneral,
.newLayout = vk::ImageLayout::eGeneral,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = resource->GetImage((resource->resourceTypeFlags & static_cast<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;
}
InitializeBarriers();
}
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
{
public:
using PreComputeFunction = std::function<void(Handle<SHVkCommandBuffer>, uint32_t)>;
private:
// Binding of set SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_NODE_COMPUTE_RESOURCE
struct ComputeResource
@ -73,8 +77,23 @@ namespace SHADE
//! Name of this node
std::string name;
std::vector<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:
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 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 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 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}
, resourceTypeFlags{ }
, resourceFormat{ format }
@ -88,6 +88,7 @@ namespace SHADE
, height{ h }
, mipLevels{ levels }
, resourceName{ name }
, resizeWithWindow { inResizeWithWindow }
{
// If the resource type is an arbitrary image and not swapchain image
if (typeFlags.size() == 1 && *typeFlags.begin() == SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)
@ -210,6 +211,7 @@ namespace SHADE
, imageAspectFlags{ rhs.imageAspectFlags }
, graphStorage{rhs.graphStorage}
, infoTracker {std::move (rhs.infoTracker)}
, resizeWithWindow{rhs.resizeWithWindow}
{
}
@ -242,7 +244,8 @@ namespace SHADE
mipLevels = rhs.mipLevels;
imageAspectFlags = rhs.imageAspectFlags;
graphStorage = rhs.graphStorage;
infoTracker = std::move(infoTracker);
infoTracker = std::move(rhs.infoTracker);
resizeWithWindow = rhs.resizeWithWindow;
return *this;
}

View File

@ -96,11 +96,14 @@ namespace SHADE
//! For tracking resource states in stages of the render graphs
Handle<InfoTracker> infoTracker;
//! Whether or not to resize (recreate vulkan image) when window resizes
bool resizeWithWindow;
public:
/*-----------------------------------------------------------------------*/
/* 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& operator=(SHRenderGraphResource&& rhs) noexcept;
~SHRenderGraphResource(void) noexcept;

View File

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

View File

@ -21,12 +21,23 @@ namespace SHADE
class SHVkSampler;
class SHRenderer;
class SHViewport;
class SHVkPipeline;
class SH_API SHSubpass : public ISelfHandle<SHSubpass>
{
public:
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 MEMBER VARIABLES */
@ -94,6 +105,15 @@ namespace SHADE
// For identifying subpasses
std::string name;
//! Optional component to a companion subpass. If the subpass handle of this object
//! is valid, the subpass will be drawn using this companion's data.
CompanionSubpass companionSubpass;
private:
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
bool UsesResource(uint32_t attachmentIndex) noexcept;
public:
/*-----------------------------------------------------------------------*/
@ -119,7 +139,6 @@ namespace SHADE
void Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept;
void HandleResize (void) 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;
void Init(SHResourceHub& resourceManager) noexcept;
@ -128,13 +147,18 @@ namespace SHADE
void CreateInputDescriptors (void) noexcept;
void UpdateWriteDescriptors (void) noexcept;
/*-----------------------------------------------------------------------*/
/* GETTERS AND SETTERS */
/*-----------------------------------------------------------------------*/
private:
/*-----------------------------------------------------------------------*/
/* PRIVATE GETTERS AND SETTERS */
/*-----------------------------------------------------------------------*/
void SetIndex (uint32_t index) noexcept;
public:
/*-----------------------------------------------------------------------*/
/* PUBLIC SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/
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;