Merge pull request #166 from SHADE-DP/SP3-1-Rendering

SSAO and lighting changes
This commit is contained in:
XiaoQiDigipen 2022-11-02 17:22:39 +08:00 committed by GitHub
commit 062a6c8c10
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 771 additions and 137 deletions

View File

@ -21,7 +21,8 @@ layout(set = 4, binding = 0, rgba32f) uniform image2D positions;
layout(set = 4, binding = 1, rgba32f) uniform image2D normals; layout(set = 4, binding = 1, rgba32f) uniform image2D normals;
layout(set = 4, binding = 2, rgba8) uniform image2D albedo; layout(set = 4, binding = 2, rgba8) uniform image2D albedo;
layout(set = 4, binding = 3, r32ui) uniform uimage2D lightLayerData; layout(set = 4, binding = 3, r32ui) uniform uimage2D lightLayerData;
layout(set = 4, binding = 4, rgba8) uniform image2D targetImage; layout(set = 4, binding = 4, r8) uniform image2D ssaoBlurredImage;
layout(set = 4, binding = 5, rgba8) uniform image2D targetImage;
layout(set = 1, binding = 0) uniform LightCounts layout(set = 1, binding = 0) uniform LightCounts
{ {
@ -51,33 +52,46 @@ void main()
vec3 pixelDiffuse = imageLoad (albedo, globalThread).rgb; vec3 pixelDiffuse = imageLoad (albedo, globalThread).rgb;
// Get position of fragment in world space // Get position of fragment in world space
vec3 positionWorld = imageLoad (positions, globalThread).rgb; vec3 positionView = imageLoad (positions, globalThread).rgb;
// normal of fragment // normal of fragment
vec3 normalWorld = imageLoad(normals, globalThread).rgb; vec3 normalView = imageLoad(normals, globalThread).rgb;
// light layer index
uint lightLayer = imageLoad (lightLayerData, globalThread).r;
vec3 fragColor = vec3 (0.0f); vec3 fragColor = vec3 (0.0f);
for (int i = 0; i < lightCounts.directionalLights; ++i) for (int i = 0; i < lightCounts.directionalLights; ++i)
{ {
// get normalized direction of light if ((lightLayer & DirLightData.dLightData[i].cullingMask) != 0)
vec3 dLightNormalized = normalize (DirLightData.dLightData[i].direction); {
// get normalized direction of light
vec3 dLightNormalized = normalize (DirLightData.dLightData[i].direction);
// Get diffuse strength // Get diffuse strength
float diffuseStrength = max (0, dot (dLightNormalized, normalWorld)); float diffuseStrength = max (0, dot (dLightNormalized, normalView));
// Calculate the fragment color // Calculate the fragment color
fragColor += DirLightData.dLightData[i].diffuseColor.rgb * diffuseStrength.rrr * pixelDiffuse; fragColor += DirLightData.dLightData[i].diffuseColor.rgb * diffuseStrength.rrr * pixelDiffuse;
}
} }
for (int i = 0; i < lightCounts.ambientLights; ++i) for (int i = 0; i < lightCounts.ambientLights; ++i)
{ {
// Just do some add if ((lightLayer & AmbLightData.aLightData[i].cullingMask) != 0)
//fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (0.5f); {
fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (AmbLightData.aLightData[i].strength); // 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);
}
} }
float ssaoVal = imageLoad (ssaoBlurredImage, globalThread).r;
fragColor *= ssaoVal;
// store result into result image // store result into result image
imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(fragColor, 1.0f)); imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(fragColor.rgb, 1.0f));
//imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(ssaoVal.rrr, 1.0f));
} }

View File

@ -0,0 +1,58 @@
#version 450
#define BLUR_WIDTH 5
#define BLUR_HALF_WIDTH BLUR_WIDTH / 2
#define SHM_WIDTH BLUR_WIDTH + 16 - 1
layout(local_size_x = 16, local_size_y = 16) in;
layout(set = 4, binding = 0, r8) uniform image2D ssaoImage;
layout(set = 4, binding = 1, r8) uniform image2D ssaoBlurImage;
float GetSSAOValue(ivec2 uv, ivec2 imageSize)
{
if (uv.x >= 0 && uv.y >= 0 && uv.x < imageSize.x && uv.y < imageSize.y)
{
return imageLoad (ssaoImage, uv).r;
}
return 0.0f;
}
shared float sharedPixels[16 + BLUR_WIDTH - 1][16 + BLUR_WIDTH - 1];
void main()
{
ivec2 globalThread = ivec2 (gl_GlobalInvocationID.xy);
ivec2 localThread = ivec2 (gl_LocalInvocationID.xy);
ivec2 inputImageSize = imageSize(ssaoImage);
// Load color into shared memory
ivec2 start = ivec2 (gl_WorkGroupID) * ivec2 (gl_WorkGroupSize) - (BLUR_HALF_WIDTH);
for (int i = localThread.x; i < SHM_WIDTH; i += int (gl_WorkGroupSize.x))
{
for (int j = localThread.y; j < SHM_WIDTH; j += int (gl_WorkGroupSize.y))
{
float value = GetSSAOValue (start + ivec2 (i, j), inputImageSize);
sharedPixels[i][j] = value;
}
}
// wait for all shared memory to load
barrier();
ivec2 shmStart = ivec2 (localThread + (BLUR_HALF_WIDTH));
float sum = 0;
for (int i = -BLUR_HALF_WIDTH; i <= BLUR_HALF_WIDTH; ++i)
{
for (int j = -BLUR_HALF_WIDTH; j <= BLUR_HALF_WIDTH; ++j)
{
float sharedVal = sharedPixels[shmStart.x + i][shmStart.y + j];
sum += sharedVal;
}
}
sum /= (BLUR_WIDTH * BLUR_WIDTH);
imageStore(ssaoBlurImage, globalThread, vec4(sum.rrr, 1.0f));
}

Binary file not shown.

View File

@ -0,0 +1,3 @@
Name: SSAOBlur_CS
ID: 39760835
Type: 2

104
Assets/Shaders/SSAO_CS.glsl Normal file
View File

@ -0,0 +1,104 @@
#version 450
const uint NUM_SAMPLES = 64;
const uint NUM_ROTATIONS = 16;
const int ROTATION_KERNEL_W = 4;
const int ROTATION_KERNEL_H = 4;
// can perhaps pass in as push constant.
const float RADIUS = 0.5f;
const float BIAS = 0.025f;
layout(local_size_x = 16, local_size_y = 16) in;
layout(set = 4, binding = 0, rgba32f) uniform image2D positions;
layout(set = 4, binding = 1, rgba32f) uniform image2D normals;
layout(set = 4, binding = 2, rgba32f) uniform image2D outputImage;
// SSAO data
layout(std430, set = 5, binding = 0) buffer SSAOData
{
vec4 samples[NUM_SAMPLES];
} ssaoData;
layout (set = 5, binding = 1) uniform sampler2D noiseTexture;
layout(set = 2, binding = 0) uniform CameraData
{
vec4 position;
mat4 vpMat;
mat4 viewMat;
mat4 projMat;
} cameraData;
void main()
{
// image size of the SSAO image
ivec2 ssaoSize = imageSize (outputImage);
// global thread
ivec2 globalThread = ivec2 (gl_GlobalInvocationID.xy);
// load all the necessary variables
vec3 viewSpacePos = imageLoad (positions, globalThread).rgb;
vec3 viewSpaceNormal = normalize (imageLoad (normals, globalThread).rgb);
// Get the noise dimension. This should be 4x4
vec2 noiseDim = vec2 (textureSize(noiseTexture, 0));
// Get normlized thread UV coordinates
vec2 threadUV = (vec2(globalThread)) / vec2(ssaoSize);
vec2 noiseUVMult = vec2 (vec2(ssaoSize) / noiseDim);
noiseUVMult *= threadUV;
// sample from the noise
vec3 randomVec = texture(noiseTexture, noiseUVMult).rgb;
// Gram schmidt
vec3 tangent = normalize (randomVec - (viewSpaceNormal * dot(viewSpaceNormal, randomVec)));
vec3 bitangent = normalize (cross (tangent, viewSpaceNormal));
// matrix for tangent space to view space
mat3 TBN = mat3(tangent, bitangent, viewSpaceNormal);
float occlusion = 0.0f;
for (int i = 0; i < NUM_SAMPLES; ++i)
{
// We want to get a position at an offset from the view space position. Offset scaled by radius.
vec3 displacementVector = TBN * ssaoData.samples[i].rgb;
// Why are we adding positions?
displacementVector = viewSpacePos + displacementVector * RADIUS;
// Now we take that offset position and bring it to clip space
vec4 offsetPos = vec4 (displacementVector, 1.0f);
offsetPos = cameraData.projMat * offsetPos;
// then we do perspective division
offsetPos.xyz /= offsetPos.w;
// and bring it from [-1, 1] to screen coordinates
offsetPos.xyz = ((offsetPos.xyz * 0.5f) + 0.5f);
offsetPos.xy *= vec2(ssaoSize.xy);
// Now we attempt to get a position at that point.
float sampleDepth = imageLoad (positions, ivec2 (offsetPos.xy)).z;
// skip checks
if (sampleDepth == 0.0f)
continue;
// if sampled fragment is in front of current fragment, just occlude
float rangeCheck = smoothstep (0.0f, 1.0f, RADIUS / abs (viewSpacePos.z - sampleDepth));
occlusion += (sampleDepth <= displacementVector.z - BIAS ? 1.0f : 0.0f) * rangeCheck;
}
occlusion = 1.0f - (occlusion / float(NUM_SAMPLES));
// store result into result image
imageStore(outputImage, globalThread, occlusion.rrrr);
}

Binary file not shown.

View File

@ -0,0 +1,3 @@
Name: SSAO_CS
ID: 38430899
Type: 2

View File

@ -33,18 +33,31 @@ layout(set = 2, binding = 0) uniform CameraData
{ {
vec4 position; vec4 position;
mat4 vpMat; mat4 vpMat;
mat4 viewMat;
mat4 projMat;
} cameraData; } cameraData;
void main() void main()
{ {
Out2.materialIndex = gl_InstanceIndex; Out2.materialIndex = gl_InstanceIndex;
Out2.eid = integerData[0]; Out2.eid = integerData[0];
Out2.lightLayerIndex = integerData[1]; Out2.lightLayerIndex = integerData[1];
Out.vertPos = worldTransform * vec4(aVertexPos, 1.0f); // for transforming gBuffer position and normal data
mat4 modelViewMat = cameraData.viewMat * worldTransform;
// gBuffer position will be in view space
Out.vertPos = modelViewMat * vec4(aVertexPos, 1.0f);
// uvs for texturing in fragment shader
Out.uv = aUV; Out.uv = aUV;
Out.normal.rgb = mat3(transpose(inverse(worldTransform))) * aNormal.rgb;
mat3 transposeInv = mat3 (transpose(inverse(modelViewMat)));
// normals are also in view space
Out.normal.rgb = transposeInv * aNormal.rgb;
Out.normal.rgb = normalize (Out.normal.rgb); Out.normal.rgb = normalize (Out.normal.rgb);
// clip space for rendering
gl_Position = cameraData.vpMat * worldTransform * vec4 (aVertexPos, 1.0f); gl_Position = cameraData.vpMat * worldTransform * vec4 (aVertexPos, 1.0f);
} }

Binary file not shown.

View File

@ -131,6 +131,9 @@ namespace Sandbox
SHSceneManager::InitSceneManager<SBTestScene>("TestScene"); SHSceneManager::InitSceneManager<SBTestScene>("TestScene");
SHFrameRateController::UpdateFRC(); SHFrameRateController::UpdateFRC();
// Link up SHDebugDraw
SHDebugDraw::Init(SHSystemManager::GetSystem<SHDebugDrawSystem>());
} }
void SBApplication::Update(void) void SBApplication::Update(void)

View File

@ -64,6 +64,11 @@ namespace SHADE
return bufferUsageFlags; return bufferUsageFlags;
} }
uint32_t SHVkBuffer::GetSizeStored(void) const noexcept
{
return sizeStored;
}
/***************************************************************************/ /***************************************************************************/
/*! /*!

View File

@ -102,8 +102,9 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */ /* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
vk::Buffer GetVkBuffer (void) const noexcept; vk::Buffer GetVkBuffer (void) const noexcept;
vk::BufferUsageFlags GetUsageBits(void) const noexcept; vk::BufferUsageFlags GetUsageBits(void) const noexcept;
uint32_t GetSizeStored (void) const noexcept;
template <typename T> template <typename T>
T GetDataFromMappedPointer(uint32_t index) const noexcept T GetDataFromMappedPointer(uint32_t index) const noexcept

View File

@ -119,6 +119,18 @@ namespace SHADE
return setIndex; return setIndex;
} }
uint32_t SHVkDescriptorSetLayout::GetNumDynamicOffsetsRequired(void) const noexcept
{
uint32_t numDynamicBindings = 0;
for (auto& binding : layoutDesc)
{
if (binding.Type == vk::DescriptorType::eUniformBufferDynamic || binding.Type == vk::DescriptorType::eStorageBufferDynamic)
++numDynamicBindings;
}
return numDynamicBindings;
}
SHVkDescriptorSetLayout& SHVkDescriptorSetLayout::operator=(SHVkDescriptorSetLayout&& rhs) noexcept SHVkDescriptorSetLayout& SHVkDescriptorSetLayout::operator=(SHVkDescriptorSetLayout&& rhs) noexcept
{ {
if (&rhs == this) if (&rhs == this)

View File

@ -99,6 +99,7 @@ namespace SHADE
inline const vk::DescriptorSetLayout& GetVkHandle() const { return setLayout; } inline const vk::DescriptorSetLayout& GetVkHandle() const { return setLayout; }
std::vector<Binding> const& GetBindings (void) const noexcept; std::vector<Binding> const& GetBindings (void) const noexcept;
SetIndex GetSetIndex (void) const noexcept; SetIndex GetSetIndex (void) const noexcept;
uint32_t GetNumDynamicOffsetsRequired (void) const noexcept;
private: private:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/

View File

@ -79,7 +79,7 @@ namespace SHADE
SHVkDescriptorSetLayout::Binding cameraDataBinding SHVkDescriptorSetLayout::Binding cameraDataBinding
{ {
.Type = vk::DescriptorType::eUniformBufferDynamic, .Type = vk::DescriptorType::eUniformBufferDynamic,
.Stage = vk::ShaderStageFlagBits::eVertex, .Stage = vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eCompute,
.BindPoint = SHGraphicsConstants::DescriptorSetBindings::CAMERA_DATA, .BindPoint = SHGraphicsConstants::DescriptorSetBindings::CAMERA_DATA,
.DescriptorCount = 1, .DescriptorCount = 1,
}; };

View File

@ -70,7 +70,17 @@ namespace SHADE
*/ */
/***************************************************************************/ /***************************************************************************/
static constexpr uint32_t RENDERGRAPH_RESOURCE = 4; 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, 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;
}; };
@ -119,6 +129,7 @@ namespace SHADE
*/ */
/***************************************************************************/ /***************************************************************************/
static constexpr uint32_t BATCHED_PER_INST_DATA = 0; static constexpr uint32_t BATCHED_PER_INST_DATA = 0;
}; };
struct VertexBufferBindings struct VertexBufferBindings

View File

@ -40,6 +40,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Assets/SHAssetManager.h" #include "Assets/SHAssetManager.h"
#include "Resource/SHResourceManager.h" #include "Resource/SHResourceManager.h"
#include "Graphics/SHVkUtil.h" #include "Graphics/SHVkUtil.h"
#include "Graphics/RenderGraph/SHRenderGraphNodeCompute.h"
namespace SHADE namespace SHADE
{ {
@ -115,6 +116,8 @@ namespace SHADE
static constexpr AssetID VS_DEBUG = 48002439; debugVertShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(VS_DEBUG); static constexpr AssetID VS_DEBUG = 48002439; debugVertShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(VS_DEBUG);
static constexpr AssetID FS_DEBUG = 36671027; debugFragShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(FS_DEBUG); static constexpr AssetID FS_DEBUG = 36671027; debugFragShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(FS_DEBUG);
static constexpr AssetID CS_COMPOSITE = 45072428; deferredCompositeShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(CS_COMPOSITE); static constexpr AssetID CS_COMPOSITE = 45072428; deferredCompositeShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(CS_COMPOSITE);
static constexpr AssetID SSAO = 38430899; ssaoShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(SSAO);
static constexpr AssetID SSAO_BLUR = 39760835; ssaoBlurShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(SSAO_BLUR);
} }
void SHGraphicsSystem::InitSceneRenderGraph(void) noexcept void SHGraphicsSystem::InitSceneRenderGraph(void) noexcept
@ -153,39 +156,64 @@ namespace SHADE
renderContextCmdPools[i] = renderContext.GetFrameData(i).cmdPoolHdls[0]; renderContextCmdPools[i] = renderContext.GetFrameData(i).cmdPoolHdls[0];
} }
/*-----------------------------------------------------------------------*/
/* SCENE RENDER GRAPH RESOURCES */
/*-----------------------------------------------------------------------*/
// Initialize world render graph // Initialize world render graph
worldRenderGraph->Init(device, swapchain); worldRenderGraph->Init(device, swapchain);
worldRenderGraph->AddResource("Position", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); worldRenderGraph->AddResource("Position", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat);
worldRenderGraph->AddResource("Normals", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); worldRenderGraph->AddResource("Normals", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat);
//worldRenderGraph->AddResource("Tangents", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat);
worldRenderGraph->AddResource("Albedo", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second); worldRenderGraph->AddResource("Albedo", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second);
worldRenderGraph->AddResource("Depth Buffer", { SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL }, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint); worldRenderGraph->AddResource("Depth Buffer", { SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL }, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint);
worldRenderGraph->AddResource("Entity ID", { SH_ATT_DESC_TYPE_FLAGS::COLOR }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); worldRenderGraph->AddResource("Entity ID", { SH_ATT_DESC_TYPE_FLAGS::COLOR }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc);
worldRenderGraph->AddResource("Light Layer Indices", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); worldRenderGraph->AddResource("Light Layer Indices", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc);
worldRenderGraph->AddResource("Scene", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second); worldRenderGraph->AddResource("Scene", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second);
worldRenderGraph->AddResource("SSAO", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR8Unorm);
worldRenderGraph->AddResource("SSAO Blur", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR8Unorm);
/*-----------------------------------------------------------------------*/
/* MAIN NODE */
/*-----------------------------------------------------------------------*/
auto gBufferNode = worldRenderGraph->AddNode("G-Buffer", auto gBufferNode = worldRenderGraph->AddNode("G-Buffer",
{ {
"Position", "Position",
"Entity ID", "Entity ID",
"Light Layer Indices", "Light Layer Indices",
"Normals", "Normals",
//"Tangents",
"Albedo", "Albedo",
"Depth Buffer", "Depth Buffer",
"Scene" "Scene",
"SSAO",
"SSAO Blur"
}, },
{}); // no predecessors {}); // no predecessors
/*-----------------------------------------------------------------------*/
/* G-BUFFER SUBPASS INIT */
/*-----------------------------------------------------------------------*/
auto gBufferSubpass = gBufferNode->AddSubpass("G-Buffer Write"); auto gBufferSubpass = gBufferNode->AddSubpass("G-Buffer Write");
gBufferSubpass->AddColorOutput("Position"); gBufferSubpass->AddColorOutput("Position");
gBufferSubpass->AddColorOutput("Entity ID"); gBufferSubpass->AddColorOutput("Entity ID");
gBufferSubpass->AddColorOutput("Light Layer Indices"); gBufferSubpass->AddColorOutput("Light Layer Indices");
gBufferSubpass->AddColorOutput("Normals"); gBufferSubpass->AddColorOutput("Normals");
//gBufferSubpass->AddColorOutput("Tangents");
gBufferSubpass->AddColorOutput("Albedo"); gBufferSubpass->AddColorOutput("Albedo");
gBufferSubpass->AddDepthOutput("Depth Buffer", SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL); gBufferSubpass->AddDepthOutput("Depth Buffer", SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL);
// deferred composite /*-----------------------------------------------------------------------*/
gBufferNode->AddNodeCompute(deferredCompositeShader, { "Position", "Normals", "Albedo", "Light Layer Indices", "Scene" }); /* SSAO PASS AND DATA INIT */
/*-----------------------------------------------------------------------*/
ssaoStorage = resourceManager.Create<SHSSAO>();
ssaoTransferCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
ssaoTransferCmdBuffer->BeginRecording();
ssaoStorage->Init(device, ssaoTransferCmdBuffer);
ssaoTransferCmdBuffer->EndRecording();
graphicsQueue->SubmitCommandBuffer({ ssaoTransferCmdBuffer });
// Set up Debug Draw Passes // Set up Debug Draw Passes
// - Depth Tested // - Depth Tested
auto debugDrawNodeDepth = worldRenderGraph->AddNode("Debug Draw with Depth", { "Scene", "Depth Buffer" }, {"G-Buffer"}); auto debugDrawNodeDepth = worldRenderGraph->AddNode("Debug Draw with Depth", { "Scene", "Depth Buffer" }, {"G-Buffer"});
@ -197,14 +225,40 @@ namespace SHADE
auto debugDrawSubpass = debugDrawNode->AddSubpass("Debug Draw"); auto debugDrawSubpass = debugDrawNode->AddSubpass("Debug Draw");
debugDrawSubpass->AddColorOutput("Scene"); debugDrawSubpass->AddColorOutput("Scene");
graphicsQueue->WaitIdle();
ssaoStorage->PrepareRotationVectorsVkData(device);
Handle<SHRenderGraphNodeCompute> ssaoPass = gBufferNode->AddNodeCompute(ssaoShader, {"Position", "Normals", "SSAO"});
auto ssaoDataBuffer = ssaoStorage->GetBuffer();
ssaoPass->ModifyWriteDescBufferComputeResource(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_NODE_COMPUTE_RESOURCE, SHSSAO::DESC_SET_BUFFER_BINDING, { &ssaoDataBuffer, 1 }, 0, ssaoStorage->GetBuffer()->GetSizeStored());
auto viewSamplerLayout = ssaoStorage->GetViewSamplerLayout();
ssaoPass->ModifyWriteDescImageComputeResource(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_NODE_COMPUTE_RESOURCE, SHSSAO::DESC_SET_IMAGE_BINDING, {&viewSamplerLayout, 1});
Handle<SHRenderGraphNodeCompute> ssaoBlurPass = gBufferNode->AddNodeCompute(ssaoBlurShader, { "SSAO", "SSAO Blur"});
/*-----------------------------------------------------------------------*/
/* DEFERRED COMPOSITE SUBPASS INIT */
/*-----------------------------------------------------------------------*/
gBufferNode->AddNodeCompute(deferredCompositeShader, { "Position", "Normals", "Albedo", "Light Layer Indices", "SSAO Blur", "Scene" });
// Dummy Node // Dummy Node
auto dummyNode = worldRenderGraph->AddNode("Dummy Pass", { "Scene" }, { "Debug Draw" }); // no predecessors auto dummyNode = worldRenderGraph->AddNode("Dummy Pass", { "Scene" }, { "Debug Draw" }); // no predecessors
auto dummySubpass = dummyNode->AddSubpass("Dummy Subpass"); auto dummySubpass = dummyNode->AddSubpass("Dummy Subpass");
dummySubpass->AddInput("Scene"); dummySubpass->AddInput("Scene");
/*-----------------------------------------------------------------------*/
/* GENERATE RENDER GRAPH */
/*-----------------------------------------------------------------------*/
// Generate world render graph // Generate world render graph
worldRenderGraph->Generate(); worldRenderGraph->Generate();
/*-----------------------------------------------------------------------*/
/* BIND RENDER GRAPH TO RENDERER */
/*-----------------------------------------------------------------------*/
// Add world renderer to default viewport // Add world renderer to default viewport
worldRenderer = worldViewport->AddRenderer(resourceManager, swapchain->GetNumImages(), renderContextCmdPools, descPool, SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS], worldRenderGraph); worldRenderer = worldViewport->AddRenderer(resourceManager, swapchain->GetNumImages(), renderContextCmdPools, descPool, SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS], worldRenderGraph);
worldRenderer->SetCamera(worldCamera); worldRenderer->SetCamera(worldCamera);
@ -255,6 +309,7 @@ namespace SHADE
lightingSubSystem = resourceManager.Create<SHLightingSubSystem>(); lightingSubSystem = resourceManager.Create<SHLightingSubSystem>();
lightingSubSystem->Init(device, descPool); lightingSubSystem->Init(device, descPool);
} }
#ifdef SHEDITOR #ifdef SHEDITOR
@ -360,6 +415,17 @@ namespace SHADE
auto cameraSystem = SHSystemManager::GetSystem<SHCameraSystem>(); auto cameraSystem = SHSystemManager::GetSystem<SHCameraSystem>();
{
#ifdef SHEDITOR
auto editorSystem = SHSystemManager::GetSystem<SHEditor>();
if (editorSystem->editorState != SHEditor::State::PLAY)
lightingSubSystem->Run(cameraSystem->GetEditorCamera()->GetViewMatrix(), frameIndex);
else
lightingSubSystem->Run(worldRenderer->GetCameraDirector()->GetViewMatrix(), frameIndex);
#else
lightingSubSystem->Run(worldRenderer->GetCameraDirector()->GetViewMatrix(), frameIndex);
#endif
}
// For every viewport // For every viewport
for (int vpIndex = 0; vpIndex < static_cast<int>(viewports.size()); ++vpIndex) for (int vpIndex = 0; vpIndex < static_cast<int>(viewports.size()); ++vpIndex)
@ -396,8 +462,7 @@ namespace SHADE
currentCmdBuffer->BindIndexBuffer(buffer, 0); currentCmdBuffer->BindIndexBuffer(buffer, 0);
} }
// Bind the descriptor set for lights lightingSubSystem->BindDescSet(currentCmdBuffer, frameIndex);
lightingSubSystem->Run(currentCmdBuffer, frameIndex);
// Bind textures // Bind textures
auto textureDescSet = texLibrary.GetTextureDescriptorSetGroup(); auto textureDescSet = texLibrary.GetTextureDescriptorSetGroup();
@ -421,7 +486,7 @@ namespace SHADE
{ {
auto editorSystem = SHSystemManager::GetSystem<SHEditor>(); auto editorSystem = SHSystemManager::GetSystem<SHEditor>();
if (editorSystem->editorState != SHEditor::State::PLAY) if (editorSystem->editorState != SHEditor::State::PLAY)
worldRenderer->UpdateDataAndBind(currentCmdBuffer, frameIndex, SHMatrix::Transpose(cameraSystem->GetEditorCamera()->GetProjMatrix() * cameraSystem->GetEditorCamera()->GetViewMatrix())); worldRenderer->UpdateDataAndBind(currentCmdBuffer, frameIndex, cameraSystem->GetEditorCamera()->GetViewMatrix(), cameraSystem->GetEditorCamera()->GetProjMatrix());
else else
renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex); renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex);
} }

View File

@ -31,6 +31,7 @@ of DigiPen Institute of Technology is prohibited.
#include "../Textures/SHVkSamplerCache.h" #include "../Textures/SHVkSamplerCache.h"
#include "Graphics/MiddleEnd/Interface/SHPostOffscreenRenderSystem.h" #include "Graphics/MiddleEnd/Interface/SHPostOffscreenRenderSystem.h"
#include "Graphics/MiddleEnd/Lights/SHLightingSubSystem.h" #include "Graphics/MiddleEnd/Lights/SHLightingSubSystem.h"
#include "Graphics/MiddleEnd/PostProcessing/SHSSAO.h"
namespace SHADE namespace SHADE
{ {
@ -316,6 +317,7 @@ namespace SHADE
Handle<SHVkDescriptorPool> descPool; Handle<SHVkDescriptorPool> descPool;
Handle<SHVkCommandPool> graphicsCmdPool; Handle<SHVkCommandPool> graphicsCmdPool;
Handle<SHVkCommandBuffer> transferCmdBuffer; Handle<SHVkCommandBuffer> transferCmdBuffer;
Handle<SHVkCommandBuffer> ssaoTransferCmdBuffer;
Handle<SHVkCommandBuffer> graphicsTexCmdBuffer; Handle<SHVkCommandBuffer> graphicsTexCmdBuffer;
SHRenderContext renderContext; SHRenderContext renderContext;
std::array<Handle<SHVkSemaphore>, 2> graphSemaphores; std::array<Handle<SHVkSemaphore>, 2> graphSemaphores;
@ -352,6 +354,9 @@ namespace SHADE
Handle<SHVkShaderModule> debugVertShader; Handle<SHVkShaderModule> debugVertShader;
Handle<SHVkShaderModule> debugFragShader; Handle<SHVkShaderModule> debugFragShader;
Handle<SHVkShaderModule> deferredCompositeShader; Handle<SHVkShaderModule> deferredCompositeShader;
Handle<SHVkShaderModule> ssaoShader;
Handle<SHVkShaderModule> ssaoBlurShader;
// Built-In Materials // Built-In Materials
Handle<SHMaterial> defaultMaterial; Handle<SHMaterial> defaultMaterial;
@ -364,10 +369,11 @@ namespace SHADE
Handle<SHMousePickSystem> mousePickSystem; Handle<SHMousePickSystem> mousePickSystem;
Handle<SHPostOffscreenRenderSystem> postOffscreenRender; Handle<SHPostOffscreenRenderSystem> postOffscreenRender;
Handle<SHLightingSubSystem> lightingSubSystem; Handle<SHLightingSubSystem> lightingSubSystem;
Handle<SHSSAO> ssaoStorage;
uint32_t resizeWidth; uint32_t resizeWidth = 1;
uint32_t resizeHeight; uint32_t resizeHeight = 1;
bool restoredFromMinimize = false; bool restoredFromMinimize = false;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Helper Functions */ /* Helper Functions */

View File

@ -83,13 +83,14 @@ namespace SHADE
{ {
if (camera && cameraDirector) if (camera && cameraDirector)
{ {
UpdateDataAndBind(cmdBuffer, frameIndex, SHMatrix::Transpose(cameraDirector->GetVPMatrix())); //UpdateDataAndBind(cmdBuffer, frameIndex, SHMatrix::Transpose(cameraDirector->GetVPMatrix()));
UpdateDataAndBind(cmdBuffer, frameIndex, cameraDirector->GetViewMatrix(), cameraDirector->GetProjMatrix());
} }
} }
void SHRenderer::UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, SHMatrix exteriorMatrix) noexcept void SHRenderer::UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, SHMatrix const& viewMatrix, SHMatrix const& projMatrix) noexcept
{ {
SetViewProjectionMatrix(exteriorMatrix); SetViewProjectionMatrix(viewMatrix, projMatrix);
//cpuCameraData.viewProjectionMatrix = camera->GetViewProjectionMatrix(); //cpuCameraData.viewProjectionMatrix = camera->GetViewProjectionMatrix();
cameraBuffer->WriteToMemory(&cpuCameraData, sizeof(SHShaderCameraData), 0, cameraDataAlignedSize * frameIndex); cameraBuffer->WriteToMemory(&cpuCameraData, sizeof(SHShaderCameraData), 0, cameraDataAlignedSize * frameIndex);
@ -97,16 +98,19 @@ namespace SHADE
std::array<uint32_t, 1> dynamicOffsets{ frameIndex * cameraDataAlignedSize }; std::array<uint32_t, 1> dynamicOffsets{ frameIndex * cameraDataAlignedSize };
cmdBuffer->BindDescriptorSet(cameraDescriptorSet, SH_PIPELINE_TYPE::GRAPHICS, SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS, std::span{ dynamicOffsets.data(), 1 }); cmdBuffer->BindDescriptorSet(cameraDescriptorSet, SH_PIPELINE_TYPE::GRAPHICS, SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS, std::span{ dynamicOffsets.data(), 1 });
cmdBuffer->BindDescriptorSet(cameraDescriptorSet, SH_PIPELINE_TYPE::COMPUTE, SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS, std::span{ dynamicOffsets.data(), 1 });
} }
void SHRenderer::UpdateCameraDataToBuffer(void) noexcept void SHRenderer::UpdateCameraDataToBuffer(void) noexcept
{ {
} }
void SHRenderer::SetViewProjectionMatrix(SHMatrix const& vpMatrix) noexcept void SHRenderer::SetViewProjectionMatrix(SHMatrix const& viewMatrix, SHMatrix const& projMatrix) noexcept
{ {
//cpuCameraData.viewProjectionMatrix = camera->GetViewMatrix() * camera->GetProjectionMatrix(); //cpuCameraData.viewProjectionMatrix = camera->GetViewMatrix() * camera->GetProjectionMatrix();
cpuCameraData.viewProjectionMatrix = vpMatrix; cpuCameraData.viewProjectionMatrix = SHMatrix::Transpose(projMatrix * viewMatrix);
cpuCameraData.viewMatrix = SHMatrix::Transpose(viewMatrix);
cpuCameraData.projectionMatrix = SHMatrix::Transpose(projMatrix);
} }
Handle<SHRenderGraph> SHRenderer::GetRenderGraph(void) const noexcept Handle<SHRenderGraph> SHRenderer::GetRenderGraph(void) const noexcept
@ -119,4 +123,9 @@ namespace SHADE
return commandBuffers[frameIndex]; return commandBuffers[frameIndex];
} }
Handle<SHCameraDirector> SHRenderer::GetCameraDirector(void) const noexcept
{
return cameraDirector;
}
} }

View File

@ -46,6 +46,8 @@ namespace SHADE
{ {
SHVec4 cameraPosition; SHVec4 cameraPosition;
SHMatrix viewProjectionMatrix; SHMatrix viewProjectionMatrix;
SHMatrix viewMatrix;
SHMatrix projectionMatrix;
}; };
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -79,15 +81,16 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
void Draw(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool) noexcept; void Draw(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool) noexcept;
void UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept; void UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
void UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, SHMatrix exteriorMatrix) noexcept; void UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, SHMatrix const& viewMatrix, SHMatrix const& projMatrix) noexcept;
void UpdateCameraDataToBuffer (void) noexcept; void UpdateCameraDataToBuffer (void) noexcept;
void SetViewProjectionMatrix (SHMatrix const& vpMatrix) noexcept; void SetViewProjectionMatrix (SHMatrix const& viewMatrix, SHMatrix const& projMatrix) noexcept;
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Setters and Getters */ /* Setters and Getters */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
Handle<SHRenderGraph> GetRenderGraph (void) const noexcept; Handle<SHRenderGraph> GetRenderGraph (void) const noexcept;
Handle<SHVkCommandBuffer> GetCommandBuffer(uint32_t frameIndex) const noexcept; Handle<SHVkCommandBuffer> GetCommandBuffer(uint32_t frameIndex) const noexcept;
Handle<SHCameraDirector> GetCameraDirector (void) const noexcept;
private: private:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/

View File

@ -9,9 +9,9 @@ namespace SHADE
{ {
lightData.Reset(); lightData.Reset();
SetType(SH_LIGHT_TYPE::DIRECTIONAL); SetType(SH_LIGHT_TYPE::DIRECTIONAL);
indexInBuffer = std::numeric_limits<uint32_t>::max(); //indexInBuffer = std::numeric_limits<uint32_t>::max();
isActive = true; isActive = true;
Unbind(); //Unbind();
} }
@ -23,28 +23,28 @@ namespace SHADE
void SHLightComponent::SetPosition(SHVec3 const& position) noexcept void SHLightComponent::SetPosition(SHVec3 const& position) noexcept
{ {
lightData.position = position; lightData.position = position;
MakeDirty(); //MakeDirty();
} }
void SHLightComponent::SetType(SH_LIGHT_TYPE type) noexcept void SHLightComponent::SetType(SH_LIGHT_TYPE type) noexcept
{ {
lightData.type = type; lightData.type = type;
MakeDirty(); //MakeDirty();
} }
void SHLightComponent::SetDirection(SHVec3 const& direction) noexcept void SHLightComponent::SetDirection(SHVec3 const& direction) noexcept
{ {
lightData.direction = direction; lightData.direction = direction;
MakeDirty(); //MakeDirty();
} }
void SHLightComponent::SetColor(SHVec4 const& color) noexcept void SHLightComponent::SetColor(SHVec4 const& color) noexcept
{ {
lightData.color = color; lightData.color = color;
MakeDirty(); //MakeDirty();
} }
void SHLightComponent::ModifyCullingMask(uint8_t layerIndex, bool value) noexcept void SHLightComponent::ModifyCullingMask(uint8_t layerIndex, bool value) noexcept
@ -54,7 +54,7 @@ namespace SHADE
else else
lightData.cullingMask &= ~(1u << layerIndex); lightData.cullingMask &= ~(1u << layerIndex);
MakeDirty(); //MakeDirty();
} }
void SHLightComponent::SetCullingMask(uint32_t const& value) noexcept void SHLightComponent::SetCullingMask(uint32_t const& value) noexcept
@ -65,43 +65,43 @@ namespace SHADE
void SHLightComponent::SetAllLayers(void) noexcept void SHLightComponent::SetAllLayers(void) noexcept
{ {
lightData.cullingMask = std::numeric_limits<uint32_t>::max(); lightData.cullingMask = std::numeric_limits<uint32_t>::max();
MakeDirty(); //MakeDirty();
} }
void SHLightComponent::ClearAllLayers(void) noexcept void SHLightComponent::ClearAllLayers(void) noexcept
{ {
lightData.cullingMask = 0; lightData.cullingMask = 0;
MakeDirty(); //MakeDirty();
} }
void SHLightComponent::MakeDirty(void) noexcept //void SHLightComponent::MakeDirty(void) noexcept
{ //{
dirty = true; // dirty = true;
} //}
void SHLightComponent::ClearDirtyFlag(void) noexcept //void SHLightComponent::ClearDirtyFlag(void) noexcept
{ //{
dirty = false; // dirty = false;
} //}
void SHLightComponent::Unbind(void) noexcept // void SHLightComponent::Unbind(void) noexcept
{ // {
bound = false; // bound = false;
MakeDirty(); // MakeDirty();
} // }
//
void SHLightComponent::SetBound(uint32_t inIndexInBuffer) noexcept // void SHLightComponent::SetBound(uint32_t inIndexInBuffer) noexcept
{ //{
bound = true; // bound = true;
indexInBuffer = inIndexInBuffer; // indexInBuffer = inIndexInBuffer;
} // }
void SHLightComponent::SetStrength(float value) noexcept void SHLightComponent::SetStrength(float value) noexcept
{ {
lightData.strength = value; lightData.strength = value;
MakeDirty(); //MakeDirty();
} }
SHLightData const& SHLightComponent::GetLightData(void) const noexcept SHLightData const& SHLightComponent::GetLightData(void) const noexcept
@ -135,20 +135,20 @@ namespace SHADE
} }
bool SHLightComponent::IsDirty(void) const noexcept //bool SHLightComponent::IsDirty(void) const noexcept
{ //{
return dirty; // return dirty;
} //}
bool SHLightComponent::GetBound(void) const noexcept //bool SHLightComponent::GetBound(void) const noexcept
{ //{
return bound; // return bound;
} //}
uint32_t SHLightComponent::GetIndexInBuffer(void) const noexcept //uint32_t SHLightComponent::GetIndexInBuffer(void) const noexcept
{ //{
return indexInBuffer; // return indexInBuffer;
} //}
float SHLightComponent::GetStrength(void) const noexcept float SHLightComponent::GetStrength(void) const noexcept
{ {

View File

@ -17,13 +17,13 @@ namespace SHADE
//! Since the lighting system is gonna be self contained and light weight, we store this //! Since the lighting system is gonna be self contained and light weight, we store this
//! so that we only write this to the CPU buffer when this light component change, we don't //! so that we only write this to the CPU buffer when this light component change, we don't
//! rewrite everything. However we still write to the GPU buffer when everything changes. //! rewrite everything. However we still write to the GPU buffer when everything changes.
uint32_t indexInBuffer; //uint32_t indexInBuffer;
//! If the light component changed some value we mark this true. ////! If the light component changed some value we mark this true.
bool dirty; //bool dirty;
//! If the light's data is already in the buffers, this will be set to true. ////! If the light's data is already in the buffers, this will be set to true.
bool bound; //bool bound;
public: public:
@ -44,10 +44,10 @@ namespace SHADE
void SetCullingMask (uint32_t const& value) noexcept; void SetCullingMask (uint32_t const& value) noexcept;
void SetAllLayers (void) noexcept; // serialized void SetAllLayers (void) noexcept; // serialized
void ClearAllLayers (void) noexcept; // serialized void ClearAllLayers (void) noexcept; // serialized
void MakeDirty (void) noexcept; //void MakeDirty (void) noexcept;
void ClearDirtyFlag (void) noexcept; //void ClearDirtyFlag (void) noexcept;
void Unbind (void) noexcept; //void Unbind (void) noexcept;
void SetBound (uint32_t inIndexInBuffer) noexcept; //void SetBound (uint32_t inIndexInBuffer) noexcept;
void SetStrength (float value) noexcept; // serialized void SetStrength (float value) noexcept; // serialized
@ -57,8 +57,8 @@ namespace SHADE
SHVec3 const& GetDirection (void) const noexcept; // serialized SHVec3 const& GetDirection (void) const noexcept; // serialized
SHVec4 const& GetColor (void) const noexcept; // serialized SHVec4 const& GetColor (void) const noexcept; // serialized
uint32_t const& GetCullingMask (void) const noexcept; // serialized uint32_t const& GetCullingMask (void) const noexcept; // serialized
bool IsDirty (void) const noexcept; //bool IsDirty (void) const noexcept;
bool GetBound (void) const noexcept; //bool GetBound (void) const noexcept;
uint32_t GetIndexInBuffer (void) const noexcept; uint32_t GetIndexInBuffer (void) const noexcept;
float GetStrength (void) const noexcept; float GetStrength (void) const noexcept;
RTTR_ENABLE() RTTR_ENABLE()

View File

@ -8,6 +8,8 @@
#include "SHLightComponent.h" #include "SHLightComponent.h"
#include "ECS_Base/Managers/SHComponentManager.h" #include "ECS_Base/Managers/SHComponentManager.h"
#include "SHLightComponent.h" #include "SHLightComponent.h"
#include "Math/Vector/SHVec4.h"
#include "Math/SHMatrix.h"
namespace SHADE namespace SHADE
{ {
@ -31,7 +33,7 @@ namespace SHADE
*/ */
/***************************************************************************/ /***************************************************************************/
void SHLightingSubSystem::PerTypeData::WriteLightToAddress(void* address, SHLightComponent* lightComp) noexcept void SHLightingSubSystem::PerTypeData::WriteLightToAddress(void* address, SHMatrix const& viewMat, SHLightComponent* lightComp) noexcept
{ {
auto const& lightData = lightComp->GetLightData(); auto const& lightData = lightComp->GetLightData();
switch (lightData.type) switch (lightData.type)
@ -40,8 +42,12 @@ namespace SHADE
{ {
SHDirectionalLightData* lightPtr = reinterpret_cast<SHDirectionalLightData*>(address); SHDirectionalLightData* lightPtr = reinterpret_cast<SHDirectionalLightData*>(address);
// #NoteToSelf: NEED TO TRANSPOSE HERE BECAUSE MULTIPLICATION IS ROW MAJOR.
SHVec4 transformedDir = SHMatrix::Transpose(viewMat) * SHVec4(lightData.direction[0], lightData.direction[1], lightData.direction[2], 0.0f);
lightPtr->cullingMask = lightData.cullingMask; lightPtr->cullingMask = lightData.cullingMask;
lightPtr->direction = lightData.direction; lightPtr->direction = SHVec3 (transformedDir.x, transformedDir.y, transformedDir.z);
//lightPtr->direction = lightData.direction;
lightPtr->diffuseColor = lightData.color; lightPtr->diffuseColor = lightData.color;
lightPtr->active = lightComp->isActive; lightPtr->active = lightComp->isActive;
break; break;
@ -240,7 +246,7 @@ namespace SHADE
*/ */
/***************************************************************************/ /***************************************************************************/
void SHLightingSubSystem::PerTypeData::AddLight(Handle<SHVkLogicalDevice> logicalDevice, SHLightComponent* unboundLight, bool expanded) noexcept void SHLightingSubSystem::PerTypeData::AddLight(Handle<SHVkLogicalDevice> logicalDevice, SHLightComponent* unboundLight, SHMatrix const& viewMat, bool& expanded) noexcept
{ {
if (unboundLight) if (unboundLight)
{ {
@ -259,10 +265,10 @@ namespace SHADE
void* writeLocation = reinterpret_cast<uint8_t*>(intermediateData.get()) + (lightDataAlignedSize * numLights); void* writeLocation = reinterpret_cast<uint8_t*>(intermediateData.get()) + (lightDataAlignedSize * numLights);
// Write the light data to address // Write the light data to address
WriteLightToAddress(writeLocation, unboundLight); WriteLightToAddress(writeLocation, viewMat, unboundLight);
// Set the light component to be bound to that location // Set the light component to be bound to that location
unboundLight->SetBound(numLights); //unboundLight->SetBound(numLights);
// Increase light count // Increase light count
++numLights; ++numLights;
@ -280,11 +286,11 @@ namespace SHADE
*/ */
/***************************************************************************/ /***************************************************************************/
void SHLightingSubSystem::PerTypeData::ModifyLight(SHLightComponent* lightComp) noexcept //void SHLightingSubSystem::PerTypeData::ModifyLight(SHLightComponent* lightComp) noexcept
{ //{
void* writeLocation = reinterpret_cast<uint8_t*>(intermediateData.get()) + (lightDataAlignedSize * lightComp->GetIndexInBuffer()); // void* writeLocation = reinterpret_cast<uint8_t*>(intermediateData.get()) + (lightDataAlignedSize * lightComp->GetIndexInBuffer());
WriteLightToAddress(writeLocation, lightComp); // WriteLightToAddress(writeLocation, lightComp);
} //}
void SHLightingSubSystem::PerTypeData::WriteToGPU(uint32_t frameIndex) noexcept void SHLightingSubSystem::PerTypeData::WriteToGPU(uint32_t frameIndex) noexcept
{ {
@ -406,7 +412,7 @@ namespace SHADE
dynamicOffsets[i].resize(NUM_LIGHT_TYPES + 1); // +1 for the count dynamicOffsets[i].resize(NUM_LIGHT_TYPES + 1); // +1 for the count
} }
numLightComponents = 0; //numLightComponents = 0;
} }
/***************************************************************************/ /***************************************************************************/
@ -419,21 +425,25 @@ namespace SHADE
*/ */
/***************************************************************************/ /***************************************************************************/
void SHLightingSubSystem::Run(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept void SHLightingSubSystem::Run(SHMatrix const& viewMat, uint32_t frameIndex) noexcept
{ {
static uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ToUnderlying(SH_LIGHT_TYPE::NUM_TYPES); static uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ToUnderlying(SH_LIGHT_TYPE::NUM_TYPES);
auto& lightComps = SHComponentManager::GetDense<SHLightComponent>(); auto& lightComps = SHComponentManager::GetDense<SHLightComponent>();
bool expanded = false; bool expanded = false;
bool rewrite = false;
if (numLightComponents > lightComps.size()) // First we reset the number of lights. We do this every frame so that we can count how many lights we have
{ ResetNumLights();
rewrite = true;
ResetNumLights();
}
numLightComponents = lightComps.size(); //bool rewrite = false;
//if (numLightComponents > lightComps.size())
//{
// rewrite = true;
// ResetNumLights();
//}
//numLightComponents = lightComps.size();
for (auto& light : lightComps) for (auto& light : lightComps)
{ {
@ -441,22 +451,22 @@ namespace SHADE
// First we want to make sure the light is already bound to the system. if it // First we want to make sure the light is already bound to the system. if it
// isn't, we write it to the correct buffer. // isn't, we write it to the correct buffer.
if (!light.GetBound() || rewrite) //if (!light.GetBound() || rewrite)
{ {
perTypeData[enumValue].AddLight(logicalDevice, &light, expanded); perTypeData[enumValue].AddLight(logicalDevice, &light, viewMat, expanded);
//// add to light count // add to light count
//++lightCountsData[enumValue]; //++lightCountsData[enumValue];
} }
// if there was modification to the light data // if there was modification to the light data
if (light.IsDirty()) //if (light.IsDirty())
{ {
// Write the data to the CPU // Write the data to the CPU
perTypeData[enumValue].ModifyLight(&light); //perTypeData[enumValue].ModifyLight(&light);
// Light is now updated in the container // Light is now updated in the container
light.ClearDirtyFlag(); //light.ClearDirtyFlag();
} }
} }
@ -488,8 +498,6 @@ namespace SHADE
// so we do it anyway. #NoteToSelf: if at any point it affects performance, do a check before computing. // so we do it anyway. #NoteToSelf: if at any point it affects performance, do a check before computing.
ComputeDynamicOffsets(); ComputeDynamicOffsets();
// Bind descriptor set (We bind at an offset because the buffer holds NUM_FRAME_BUFFERS sets of data).
cmdBuffer->BindDescriptorSet(lightingDataDescSet, SH_PIPELINE_TYPE::COMPUTE, SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, {dynamicOffsets[frameIndex]});
} }
@ -505,4 +513,12 @@ namespace SHADE
{ {
} }
void SHLightingSubSystem::BindDescSet(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
{
//Bind descriptor set(We bind at an offset because the buffer holds NUM_FRAME_BUFFERS sets of data).
cmdBuffer->BindDescriptorSet(lightingDataDescSet, SH_PIPELINE_TYPE::COMPUTE, SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, { dynamicOffsets[frameIndex] });
}
} }

View File

@ -95,15 +95,15 @@ namespace SHADE
//! to the GPU that stores NUM_FRAME_BUFFERS copies. //! to the GPU that stores NUM_FRAME_BUFFERS copies.
std::unique_ptr<uint8_t[]> intermediateData; std::unique_ptr<uint8_t[]> intermediateData;
void WriteLightToAddress (void* address, SHLightComponent* lightComp) noexcept; void WriteLightToAddress (void* address, SHMatrix const& viewMat, SHLightComponent* lightComp) noexcept;
public: public:
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */ /* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
void InitializeData (Handle<SHVkLogicalDevice> logicalDevice, SH_LIGHT_TYPE type) noexcept; void InitializeData (Handle<SHVkLogicalDevice> logicalDevice, SH_LIGHT_TYPE type) noexcept;
void Expand (Handle<SHVkLogicalDevice> logicalDevice) noexcept; void Expand (Handle<SHVkLogicalDevice> logicalDevice) noexcept;
void AddLight (Handle<SHVkLogicalDevice> logicalDevice, SHLightComponent* unboundLight, bool expanded) noexcept; void AddLight (Handle<SHVkLogicalDevice> logicalDevice, SHLightComponent* unboundLight, SHMatrix const& viewMat, bool& expanded) noexcept;
void ModifyLight (SHLightComponent* lightComp) noexcept; //void ModifyLight (SHLightComponent* lightComp) noexcept;
void WriteToGPU (uint32_t frameIndex) noexcept; void WriteToGPU (uint32_t frameIndex) noexcept;
void ResetNumLights (void) noexcept; void ResetNumLights (void) noexcept;
@ -144,7 +144,7 @@ namespace SHADE
//! Number of SHLightComponents recorded. If at the beginning of the run function the size returned by the dense //! Number of SHLightComponents recorded. If at the beginning of the run function the size returned by the dense
//! set is less than the size recorded, rewrite all light components into the its respective buffers. If its more, //! set is less than the size recorded, rewrite all light components into the its respective buffers. If its more,
//! don't do anything. //! don't do anything.
uint32_t numLightComponents; //uint32_t numLightComponents;
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER FUNCTIONS */ /* PRIVATE MEMBER FUNCTIONS */
@ -159,8 +159,10 @@ namespace SHADE
/* PUBLIC MEMBER FUNCTIONS */ /* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
void Init (Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool) noexcept; void Init (Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool) noexcept;
void Run (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept; void Run (SHMatrix const& viewMat, uint32_t frameIndex) noexcept;
void Exit (void) noexcept; void Exit (void) noexcept;
void BindDescSet (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
}; };
} }

View File

@ -0,0 +1,138 @@
#include "SHpch.h"
#include "SHSSAO.h"
#include "Graphics/Devices/SHVkLogicalDevice.h"
#include "Graphics/Buffers/SHVkBuffer.h"
#include "Graphics/Images/SHVkImage.h"
#include "Graphics/Images/SHVkSampler.h"
#include <random>
namespace SHADE
{
void SHSSAO::Init(Handle<SHVkLogicalDevice> logicalDevice, Handle<SHVkCommandBuffer> cmdBuffer) noexcept
{
// Initialize a distribution to get values from 0 to 1
std::uniform_real_distribution<float> distrib{0.0f, 1.0f};
// generator for random number
std::default_random_engine generator;
// generate samples
for (uint32_t i = 0; i < NUM_SAMPLES; ++i)
{
//SHVec3 temp
//{
// distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f
// distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f
// distrib(generator), // 0.0f - 1.0f so that sample space is a hemisphere
//};
//temp = SHVec3::Normalise(temp);
//temp *= distrib(generator);
//// This makes sure that most points are closer to fragment's position
//float scale = 1.0f / static_cast<float>(NUM_SAMPLES);
//scale = std::lerp(0.1f, 1.0f, scale * scale);
//temp *= scale;
//samples[i] = SHVec4 (temp.x, temp.y, temp.z, 0.0f);
samples[i] = SHVec4
{
distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f
distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f
distrib(generator), // 0.0f - 1.0f so that sample space is a hemisphere
0.0f
};
// This makes sure that most points are closer to fragment's position
float scale = 1.0f / static_cast<float>(NUM_SAMPLES);
scale = std::lerp(0.1f, 1.0f, scale * scale);
samples[i] *= scale;
}
// generate rotation vector
for (uint32_t i = 0; i < NUM_ROTATION_VECTORS; ++i)
{
rotationVectors[i] = SHVec4
{
distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f
distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f
0.0f, // we want to rotate about the z axis in tangent space
0.0f
};
}
SHImageCreateParams imageDetails =
{
.imageType = vk::ImageType::e2D,
.width = NUM_ROTATION_VECTORS_W,
.height = NUM_ROTATION_VECTORS_H,
.depth = 1,
.levels = 1,
.arrayLayers = 1,
.imageFormat = vk::Format::eR32G32B32A32Sfloat,
.usageFlags = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst,
.createFlags = {}
};
uint32_t mipOffset = 0;
rotationVectorsImage = logicalDevice->CreateImage(imageDetails, reinterpret_cast<unsigned char*>( rotationVectors.data()), static_cast<uint32_t>(sizeof(rotationVectors)), {&mipOffset, 1}, VMA_MEMORY_USAGE_AUTO, {});
vk::ImageMemoryBarrier transferBarrier{};
rotationVectorsImage->PrepareImageTransitionInfo(vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, transferBarrier);
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, {transferBarrier});
rotationVectorsImage->TransferToDeviceResource(cmdBuffer);
vk::ImageMemoryBarrier shaderReadBarrier{};
rotationVectorsImage->PrepareImageTransitionInfo(vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal, shaderReadBarrier);
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eComputeShader, {}, {}, {}, { shaderReadBarrier });
// Get aligned size for buffer
uint32_t alignedSize = logicalDevice->PadSSBOSize(sizeof (samples));
// Create buffer
ssaoDataBuffer = logicalDevice->CreateBuffer(alignedSize, samples.data(), alignedSize, vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eTransferDst, VMA_MEMORY_USAGE_AUTO, {});
ssaoDataBuffer->TransferToDeviceResource(cmdBuffer);
}
void SHSSAO::PrepareRotationVectorsVkData(Handle<SHVkLogicalDevice> logicalDevice) noexcept
{
SHImageViewDetails DETAILS =
{
.viewType = vk::ImageViewType::e2D,
.format = vk::Format::eR32G32B32A32Sfloat,
.imageAspectFlags = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.mipLevelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1
};
rotationVectorsImageView = rotationVectorsImage->CreateImageView(logicalDevice, rotationVectorsImage, DETAILS);
SHVkSamplerParams samplerParams
{
.minFilter = vk::Filter::eNearest,
.magFilter = vk::Filter::eNearest,
.addressMode = vk::SamplerAddressMode::eRepeat,
.mipmapMode = vk::SamplerMipmapMode::eNearest,
.maxLod = 1u
};
rotationVectorsSampler = logicalDevice->CreateSampler(samplerParams);
}
SHVkDescriptorSetGroup::viewSamplerLayout SHSSAO::GetViewSamplerLayout(void) const noexcept
{
return std::make_tuple(rotationVectorsImageView, rotationVectorsSampler, vk::ImageLayout::eShaderReadOnlyOptimal);
}
Handle<SHVkBuffer> SHSSAO::GetBuffer(void) const noexcept
{
return ssaoDataBuffer;
}
}

View File

@ -0,0 +1,49 @@
#pragma once
#include "Resource/SHHandle.h"
#include "Graphics/SHVulkanIncludes.h"
#include "Math/Vector/SHVec4.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
namespace SHADE
{
class SHVkBuffer;
class SHVkLogicalDevice;
class SHVkCommandBuffer;
class SHVkImage;
class SHVkImageView;
class SHVkSampler;
class SHSSAO
{
public:
static constexpr uint32_t DESC_SET_BUFFER_BINDING = 0;
static constexpr uint32_t DESC_SET_IMAGE_BINDING = 1;
private:
static constexpr uint32_t NUM_SAMPLES = 64;
static constexpr uint32_t NUM_ROTATION_VECTORS_W = 4;
static constexpr uint32_t NUM_ROTATION_VECTORS_H = 4;
static constexpr uint32_t NUM_ROTATION_VECTORS = NUM_ROTATION_VECTORS_W * NUM_ROTATION_VECTORS_H;
private:
//! distances from a pixel we want to sample
std::array<SHVec4, NUM_SAMPLES> samples;
//! For passing SSAO samples and kernel to GPU
Handle<SHVkBuffer> ssaoDataBuffer;
std::array<SHVec4, NUM_ROTATION_VECTORS> rotationVectors;
Handle<SHVkImage> rotationVectorsImage;
Handle<SHVkImageView> rotationVectorsImageView;
Handle<SHVkSampler> rotationVectorsSampler;
public:
void Init (Handle<SHVkLogicalDevice> logicalDevice, Handle<SHVkCommandBuffer> cmdBuffer) noexcept;
void PrepareRotationVectorsVkData (Handle<SHVkLogicalDevice> logicalDevice) noexcept;
SHVkDescriptorSetGroup::viewSamplerLayout GetViewSamplerLayout (void) const noexcept;
Handle<SHVkBuffer> GetBuffer (void) const noexcept;
};
}

View File

@ -2,8 +2,10 @@
#define SH_PIPELINE_LAYOUT_PARAMS_H #define SH_PIPELINE_LAYOUT_PARAMS_H
#include "Graphics/SHVulkanIncludes.h" #include "Graphics/SHVulkanIncludes.h"
#include "Graphics/SHVulkanDefines.h"
#include "Resource/SHHandle.h" #include "Resource/SHHandle.h"
#include "Graphics/Descriptors/SHVkDescriptorSetLayout.h" #include "Graphics/Descriptors/SHVkDescriptorSetLayout.h"
#include <unordered_set>
namespace SHADE namespace SHADE
{ {
@ -24,6 +26,12 @@ namespace SHADE
//! want to use the layout to initialize the pipeline layout but we do not //! want to use the layout to initialize the pipeline layout but we do not
//! want to use it for allocating descriptor sets. //! want to use it for allocating descriptor sets.
std::vector<Handle<SHVkDescriptorSetLayout>> const& globalDescSetLayouts = {}; std::vector<Handle<SHVkDescriptorSetLayout>> const& globalDescSetLayouts = {};
//! Since both SPIRV-Reflect and GLSL don't provide ways to describe UBOs or
//! SSBOs as dynamic, we need to do it ourselves. This will store bindings
//! which we will use when parsing for descriptor set layouts. If a parsed
//! binding is in this container, we make that binding's descriptor dynamic.
std::unordered_set<BindingAndSetHash> dynamicBufferBindings;
}; };
struct SHPipelineLayoutParamsDummy struct SHPipelineLayoutParamsDummy

View File

@ -165,6 +165,28 @@ namespace SHADE
newBinding.Stage = shaderModule->GetShaderStageFlagBits(); newBinding.Stage = shaderModule->GetShaderStageFlagBits();
newBinding.Type = descBindingInfo.ConvertFromReflectDescType(reflectedBinding->descriptor_type); newBinding.Type = descBindingInfo.ConvertFromReflectDescType(reflectedBinding->descriptor_type);
// Here we want to check if a binding is supposed to be dynamic. If it is, make it dynamic.
if (newBinding.Type == vk::DescriptorType::eUniformBuffer || newBinding.Type == vk::DescriptorType::eStorageBuffer)
{
for (auto& bsHash : dynamicBufferBindings)
{
uint32_t set = static_cast<uint32_t>(bsHash >> 32);
uint32_t binding = static_cast<uint32_t>(bsHash & 0xFFFFFFFF);
if (set == CURRENT_SET && binding == newBinding.BindPoint)
{
switch (newBinding.Type)
{
case vk::DescriptorType::eUniformBuffer:
newBinding.Type = vk::DescriptorType::eUniformBufferDynamic;
break;
case vk::DescriptorType::eStorageBuffer:
newBinding.Type = vk::DescriptorType::eStorageBufferDynamic;
break;
}
}
}
}
// In reality, the check for variable descriptor sets do not exists in spirv-reflect. Fortunately, when a shader // In reality, the check for variable descriptor sets do not exists in spirv-reflect. Fortunately, when a shader
// defines a boundless descriptor binding in the shader, the information reflected makes the array dimensions // defines a boundless descriptor binding in the shader, the information reflected makes the array dimensions
// contain a 1 element of value 1. Knowing that having an array [1] doesn't make sense, we can use this to // contain a 1 element of value 1. Knowing that having an array [1] doesn't make sense, we can use this to
@ -300,6 +322,7 @@ namespace SHADE
, vkDescriptorSetLayoutsAllocate{} , vkDescriptorSetLayoutsAllocate{}
, descriptorSetLayoutsPipeline{} , descriptorSetLayoutsPipeline{}
, vkDescriptorSetLayoutsPipeline{} , vkDescriptorSetLayoutsPipeline{}
, dynamicBufferBindings{std::move (pipelineLayoutParams.dynamicBufferBindings)}
{ {
for (auto& mod : shaderModules) for (auto& mod : shaderModules)
{ {

View File

@ -29,6 +29,9 @@ namespace SHADE
//! Push constant interface //! Push constant interface
SHPushConstantInterface pushConstantInterface; SHPushConstantInterface pushConstantInterface;
//! See SHPipelineLayoutParams for details
std::unordered_set<BindingAndSetHash> dynamicBufferBindings;
//! Push constant ranges //! Push constant ranges
std::vector<vk::PushConstantRange> vkPcRanges; std::vector<vk::PushConstantRange> vkPcRanges;

View File

@ -129,4 +129,9 @@ namespace SHADE
return vkQueue; return vkQueue;
} }
void SHVkQueue::WaitIdle(void) const noexcept
{
vkQueue.waitIdle();
}
} }

View File

@ -50,6 +50,8 @@ namespace SHADE
void SubmitCommandBuffer (std::initializer_list<Handle<SHVkCommandBuffer>> cmdBuffers, std::initializer_list<Handle<SHVkSemaphore>> signalSems = {}, std::initializer_list<Handle<SHVkSemaphore>> waitSems = {}, vk::PipelineStageFlags waitDstStageMask = {}, Handle<SHVkFence> const& fence = {}) noexcept; void SubmitCommandBuffer (std::initializer_list<Handle<SHVkCommandBuffer>> cmdBuffers, std::initializer_list<Handle<SHVkSemaphore>> signalSems = {}, std::initializer_list<Handle<SHVkSemaphore>> waitSems = {}, vk::PipelineStageFlags waitDstStageMask = {}, Handle<SHVkFence> const& fence = {}) noexcept;
vk::Result Present (Handle<SHVkSwapchain> const& swapchain, std::initializer_list<Handle<SHVkSemaphore>> waitSems, uint32_t frameIndex) noexcept; vk::Result Present (Handle<SHVkSwapchain> const& swapchain, std::initializer_list<Handle<SHVkSemaphore>> waitSems, uint32_t frameIndex) noexcept;
vk::Queue GetVkQueue() noexcept; vk::Queue GetVkQueue() noexcept;
void WaitIdle (void) const noexcept;
}; };
} }

View File

@ -263,7 +263,7 @@ namespace SHADE
return subpass; return subpass;
} }
Handle<SHRenderGraphNodeCompute> SHRenderGraphNode::AddNodeCompute(Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, float numWorkGroupScale/* = 1.0f*/) noexcept Handle<SHRenderGraphNodeCompute> SHRenderGraphNode::AddNodeCompute(Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings, float numWorkGroupScale/* = 1.0f*/) noexcept
{ {
// Look for the required resources in the graph // Look for the required resources in the graph
std::vector<Handle<SHRenderGraphResource>> nodeComputeResources{}; std::vector<Handle<SHRenderGraphResource>> nodeComputeResources{};
@ -276,7 +276,7 @@ namespace SHADE
} }
// Create the subpass compute with the resources // Create the subpass compute with the resources
auto nodeCompute = graphStorage->resourceManager->Create<SHRenderGraphNodeCompute>(graphStorage, computeShaderModule, std::move(nodeComputeResources), nodeComputes.empty()); auto nodeCompute = graphStorage->resourceManager->Create<SHRenderGraphNodeCompute>(graphStorage, computeShaderModule, std::move(nodeComputeResources), std::move (dynamicBufferBindings), nodeComputes.empty());
nodeComputes.push_back(nodeCompute); nodeComputes.push_back(nodeCompute);
return nodeCompute; return nodeCompute;

View File

@ -100,7 +100,7 @@ namespace SHADE
/* PUBLIC MEMBER FUNCTIONS */ /* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
Handle<SHSubpass> AddSubpass(std::string subpassName) noexcept; Handle<SHSubpass> AddSubpass(std::string subpassName) noexcept;
Handle<SHRenderGraphNodeCompute> AddNodeCompute(Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, float numWorkGroupScale = 1.0f) noexcept; Handle<SHRenderGraphNodeCompute> AddNodeCompute(Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings = {}, float numWorkGroupScale = 1.0f) noexcept;
void AddDummySubpassIfNeeded (void) noexcept; void AddDummySubpassIfNeeded (void) noexcept;
// TODO: RemoveSubpass() // TODO: RemoveSubpass()

View File

@ -13,7 +13,7 @@
namespace SHADE namespace SHADE
{ {
SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(Handle<SHRenderGraphStorage> graphStorage, Handle<SHVkShaderModule> computeShaderModule, std::vector<Handle<SHRenderGraphResource>>&& subpassComputeResources, bool followingEndRP, float inNumWorkGroupScale/* = 1.0f*/) noexcept SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(Handle<SHRenderGraphStorage> graphStorage, Handle<SHVkShaderModule> computeShaderModule, std::vector<Handle<SHRenderGraphResource>>&& subpassComputeResources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings, bool followingEndRP, float inNumWorkGroupScale/* = 1.0f*/) noexcept
: computePipeline{} : computePipeline{}
, pipelineLayout{} , pipelineLayout{}
, resources{} , resources{}
@ -21,11 +21,13 @@ namespace SHADE
, groupSizeY{0} , groupSizeY{0}
, followingEndRenderpass {followingEndRP} , followingEndRenderpass {followingEndRP}
, numWorkGroupScale {std::clamp(inNumWorkGroupScale, 0.0f, 1.0f)} , numWorkGroupScale {std::clamp(inNumWorkGroupScale, 0.0f, 1.0f)}
, computeResource{}
{ {
SHPipelineLayoutParams pipelineLayoutParams SHPipelineLayoutParams pipelineLayoutParams
{ {
.shaderModules = {computeShaderModule}, .shaderModules = {computeShaderModule},
.globalDescSetLayouts = SHGraphicsGlobalData::GetDescSetLayouts() .globalDescSetLayouts = SHGraphicsGlobalData::GetDescSetLayouts(),
.dynamicBufferBindings = std::move(dynamicBufferBindings),
}; };
// Create pipeline layout from parameters // Create pipeline layout from parameters
@ -42,16 +44,31 @@ namespace SHADE
//Get the descriptor set layouts required to allocate. We only want the ones for allocate because //Get the descriptor set layouts required to allocate. We only want the ones for allocate because
//global descriptors are already bound in the main system. //global descriptors are already bound in the main system.
auto const& layouts = computePipeline->GetPipelineLayout()->GetDescriptorSetLayoutsAllocate(); auto const& graphResourceLayout = computePipeline->GetPipelineLayout()->GetDescriptorSetLayoutsPipeline()[SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE];
//Variable counts for the descriptor sets (all should be 1).
std::vector<uint32_t> variableCounts{ static_cast<uint32_t>(layouts.size()) };
std::fill(variableCounts.begin(), variableCounts.end(), 0);
// Allocate descriptor sets to hold the images for reading (STORAGE_IMAGE) // Allocate descriptor sets to hold the images for reading (STORAGE_IMAGE)
for (uint32_t i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i) for (uint32_t i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
{ {
descSetGroups[i] = graphStorage->descriptorPool->Allocate(layouts, variableCounts); graphResourceDescSets[i] = graphStorage->descriptorPool->Allocate({graphResourceLayout}, { 1 });
}
auto const& layouts = computePipeline->GetPipelineLayout()->GetDescriptorSetLayoutsPipeline();
if (layouts.size() == SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_NODE_COMPUTE_RESOURCE + 1)
{
// create compute resources
computeResource = graphStorage->resourceManager->Create<ComputeResource>();
auto computeResourceLayout = layouts[SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_NODE_COMPUTE_RESOURCE];
computeResource->descSet = graphStorage->descriptorPool->Allocate({ computeResourceLayout }, { 1 });
// Allocate for descriptor offsets
for (uint32_t i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
computeResource->dynamicOffsets[i].resize(computeResourceLayout->GetNumDynamicOffsetsRequired());
// 1st set all start at 0
for (auto& index : computeResource->dynamicOffsets[0])
index = 0;
} }
HandleResize(); HandleResize();
@ -63,7 +80,12 @@ namespace SHADE
cmdBuffer->BindPipeline(computePipeline); cmdBuffer->BindPipeline(computePipeline);
// bind descriptor sets // bind descriptor sets
cmdBuffer->BindDescriptorSet(descSetGroups[frameIndex], SH_PIPELINE_TYPE::COMPUTE, SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, {}); cmdBuffer->BindDescriptorSet(graphResourceDescSets[frameIndex], SH_PIPELINE_TYPE::COMPUTE, SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, {});
if (computeResource)
{
cmdBuffer->BindDescriptorSet(computeResource->descSet, SH_PIPELINE_TYPE::COMPUTE, SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_NODE_COMPUTE_RESOURCE, computeResource->dynamicOffsets[frameIndex]);
}
// dispatch compute // dispatch compute
cmdBuffer->ComputeDispatch(groupSizeX, groupSizeY, 1); cmdBuffer->ComputeDispatch(groupSizeX, groupSizeY, 1);
@ -89,8 +111,8 @@ namespace SHADE
uint32_t imageIndex = (resources[i]->resourceTypeFlags & static_cast<uint32_t>(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)) ? frameIndex : 0; uint32_t imageIndex = (resources[i]->resourceTypeFlags & static_cast<uint32_t>(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)) ? frameIndex : 0;
SHVkDescriptorSetGroup::viewSamplerLayout vsl = std::make_tuple(resources[i]->GetImageView(imageIndex), Handle<SHVkSampler>{}, vk::ImageLayout::eGeneral); SHVkDescriptorSetGroup::viewSamplerLayout vsl = std::make_tuple(resources[i]->GetImageView(imageIndex), Handle<SHVkSampler>{}, vk::ImageLayout::eGeneral);
descSetGroups[frameIndex]->ModifyWriteDescImage(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint, { &vsl, 1 }); graphResourceDescSets[frameIndex]->ModifyWriteDescImage(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint, { &vsl, 1 });
descSetGroups[frameIndex]->UpdateDescriptorSetImages(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint); graphResourceDescSets[frameIndex]->UpdateDescriptorSetImages(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint);
++i; ++i;
} }
} }
@ -137,4 +159,27 @@ namespace SHADE
} }
} }
void SHRenderGraphNodeCompute::SetDynamicOffsets(std::span<uint32_t> perFrameSizes) noexcept
{
for (uint32_t i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
{
auto dynamicOffsets = computeResource->dynamicOffsets[i];
for (uint32_t j = 0; j < perFrameSizes.size(); ++j)
dynamicOffsets[j] = perFrameSizes[j] * i;
}
}
void SHRenderGraphNodeCompute::ModifyWriteDescBufferComputeResource(uint32_t set, uint32_t binding, std::span<Handle<SHVkBuffer>> const& buffers, uint32_t offset, uint32_t range) noexcept
{
computeResource->descSet->ModifyWriteDescBuffer(set, binding, buffers, offset, range);
computeResource->descSet->UpdateDescriptorSetBuffer(set, binding);
}
void SHRenderGraphNodeCompute::ModifyWriteDescImageComputeResource(uint32_t set, uint32_t binding, std::span<SHVkDescriptorSetGroup::viewSamplerLayout> const& viewSamplerLayouts) noexcept
{
computeResource->descSet->ModifyWriteDescImage(set, binding, viewSamplerLayouts);
computeResource->descSet->UpdateDescriptorSetImages(set, binding);
}
} }

View File

@ -2,6 +2,7 @@
#include "Resource/SHHandle.h" #include "Resource/SHHandle.h"
#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" #include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "Graphics/SHVulkanIncludes.h" #include "Graphics/SHVulkanIncludes.h"
#include <initializer_list> #include <initializer_list>
#include <string> #include <string>
@ -10,7 +11,6 @@
namespace SHADE namespace SHADE
{ {
class SHVkPipeline; class SHVkPipeline;
class SHVkDescriptorSetGroup;
class SHVkDescriptorPool; class SHVkDescriptorPool;
class SHVkLogicalDevice; class SHVkLogicalDevice;
class SHVkPipelineLayout; class SHVkPipelineLayout;
@ -18,9 +18,22 @@ namespace SHADE
class SHRenderGraphResource; class SHRenderGraphResource;
class SHVkShaderModule; class SHVkShaderModule;
class SHVkCommandBuffer; class SHVkCommandBuffer;
class SHVkBuffer;
class SHRenderGraphNodeCompute class SHRenderGraphNodeCompute
{ {
private:
// Binding of set SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_NODE_COMPUTE_RESOURCE
struct ComputeResource
{
//! Descriptor set (initialized by parent class)
Handle<SHVkDescriptorSetGroup> descSet {};
//! Dynamic offsets into these resources (initialized from the outside).
std::array<std::vector<uint32_t>, SHGraphicsConstants::NUM_FRAME_BUFFERS> dynamicOffsets {};
};
private: private:
static constexpr uint32_t workGroupSizeX = 16; static constexpr uint32_t workGroupSizeX = 16;
static constexpr uint32_t workGroupSizeY = 16; static constexpr uint32_t workGroupSizeY = 16;
@ -32,7 +45,10 @@ namespace SHADE
Handle<SHVkPipelineLayout> pipelineLayout; Handle<SHVkPipelineLayout> pipelineLayout;
//! Descriptor set group to hold the images for reading (STORAGE_IMAGE) //! Descriptor set group to hold the images for reading (STORAGE_IMAGE)
std::array<Handle<SHVkDescriptorSetGroup>, SHGraphicsConstants::NUM_FRAME_BUFFERS> descSetGroups; std::array<Handle<SHVkDescriptorSetGroup>, SHGraphicsConstants::NUM_FRAME_BUFFERS> graphResourceDescSets;
//! Compute resources
Handle<ComputeResource> computeResource;
//! vector of resources needed by the subpass compute //! vector of resources needed by the subpass compute
std::vector<Handle<SHRenderGraphResource>> resources; std::vector<Handle<SHRenderGraphResource>> resources;
@ -50,11 +66,17 @@ namespace SHADE
std::array<std::vector<vk::ImageMemoryBarrier>, SHGraphicsConstants::NUM_FRAME_BUFFERS> memoryBarriers; std::array<std::vector<vk::ImageMemoryBarrier>, SHGraphicsConstants::NUM_FRAME_BUFFERS> memoryBarriers;
public: public:
SHRenderGraphNodeCompute(Handle<SHRenderGraphStorage> graphStorage, Handle<SHVkShaderModule> computeShaderModule, std::vector<Handle<SHRenderGraphResource>>&& subpassComputeResources, bool followingEndRP, float inNumWorkGroupScale = 1.0f) noexcept; SHRenderGraphNodeCompute(Handle<SHRenderGraphStorage> graphStorage, Handle<SHVkShaderModule> computeShaderModule, std::vector<Handle<SHRenderGraphResource>>&& subpassComputeResources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings, bool followingEndRP, float inNumWorkGroupScale = 1.0f) noexcept;
void Execute (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept; void Execute (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
void HandleResize (void) noexcept; void HandleResize (void) noexcept;
void SetDynamicOffsets (std::span<uint32_t> perFrameSizes) noexcept;
void ModifyWriteDescBufferComputeResource (uint32_t set, uint32_t binding, std::span<Handle<SHVkBuffer>> const& buffers, uint32_t offset, uint32_t range) noexcept;
void ModifyWriteDescImageComputeResource(uint32_t set, uint32_t binding, std::span<SHVkDescriptorSetGroup::viewSamplerLayout> const& viewSamplerLayouts) noexcept;
friend class SHRenderGraph; friend class SHRenderGraph;
friend class SHRenderGraphNode; friend class SHRenderGraphNode;
}; };

View File

@ -142,6 +142,16 @@ namespace SHADE
case SpvOp::SpvOpTypeRuntimeArray: case SpvOp::SpvOpTypeRuntimeArray:
recurseForInfo(&member, interfaceHdl, member.offset, biggestAlignment, parentVarName + std::string(member.name) + "."); recurseForInfo(&member, interfaceHdl, member.offset, biggestAlignment, parentVarName + std::string(member.name) + ".");
break; break;
case SpvOp::SpvOpTypeArray:
interfaceHdl->AddVariable(parentVarName + std::string (member.name),
SHShaderBlockInterface::Variable
(
parentOffset + member.offset,
SHShaderBlockInterface::Variable::Type::OTHER
)
);
biggestAlignment = std::max(biggestAlignment, member.size);
break;
} }
} }
}; };