From ea971356785153ffedfc27642c02ba9756f88be7 Mon Sep 17 00:00:00 2001
From: Alexander Gauggel <agauggel@uni-koblenz.de>
Date: Wed, 23 Jun 2021 23:15:28 +0200
Subject: [PATCH] [#82] Add MSAA to moment shadow map

---
 include/vkcv/ImageConfig.hpp                  |  1 +
 .../resources/shaders/depthToMoments.comp     | 36 +++++++++
 .../resources/shaders/shadow.frag             | 17 +----
 .../resources/shaders/shadow.vert             |  5 --
 projects/voxelization/src/ShadowMapping.cpp   | 73 ++++++++++++++-----
 projects/voxelization/src/ShadowMapping.hpp   | 18 +++--
 src/vkcv/ImageConfig.cpp                      | 10 +++
 7 files changed, 111 insertions(+), 49 deletions(-)
 create mode 100644 projects/voxelization/resources/shaders/depthToMoments.comp

diff --git a/include/vkcv/ImageConfig.hpp b/include/vkcv/ImageConfig.hpp
index 8f5b46a5..2e413b97 100644
--- a/include/vkcv/ImageConfig.hpp
+++ b/include/vkcv/ImageConfig.hpp
@@ -5,4 +5,5 @@ namespace vkcv {
 	enum class Multisampling { None, MSAA2X, MSAA4X, MSAA8X };
 
 	vk::SampleCountFlagBits msaaToVkSampleCountFlag(Multisampling msaa);
+	uint32_t                msaaToSampleCount(Multisampling msaa);
 }
diff --git a/projects/voxelization/resources/shaders/depthToMoments.comp b/projects/voxelization/resources/shaders/depthToMoments.comp
new file mode 100644
index 00000000..5d327f54
--- /dev/null
+++ b/projects/voxelization/resources/shaders/depthToMoments.comp
@@ -0,0 +1,36 @@
+#version 450
+#extension GL_GOOGLE_include_directive : enable
+#extension GL_ARB_texture_multisample : enable
+
+#include "shadowMapping.inc"
+
+layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
+
+layout(set=0, binding=0)                    uniform texture2DMS     srcTexture;
+layout(set=0, binding=1)                    uniform sampler         depthSampler;                
+layout(set=0, binding=2, r11f_g11f_b10f)    uniform image2D         outImage;
+
+layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
+
+layout( push_constant ) uniform constants{
+    int msaaCount;
+};
+
+void main(){
+
+    if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(outImage)))){
+        return;
+    }
+    ivec2 uv            = ivec2(gl_GlobalInvocationID.xy);
+
+    float z = 0;
+    for(int i = 0; i < msaaCount; i++){
+        z += texelFetch(sampler2DMS(srcTexture, depthSampler), uv, i).r;
+    }
+    z /= msaaCount;
+    
+    float   z2                  = z*z;   
+    vec4    moments             = vec4(z, z2, z2*z, z2*z2);
+    vec4    momentsQuantized    = quantizeMoments(moments);
+    imageStore(outImage, uv, momentsQuantized);
+}
\ No newline at end of file
diff --git a/projects/voxelization/resources/shaders/shadow.frag b/projects/voxelization/resources/shaders/shadow.frag
index f98dc436..65592d2c 100644
--- a/projects/voxelization/resources/shaders/shadow.frag
+++ b/projects/voxelization/resources/shaders/shadow.frag
@@ -2,21 +2,6 @@
 #extension GL_ARB_separate_shader_objects : enable
 #extension GL_GOOGLE_include_directive : enable
 
-#include "lightInfo.inc"
-#include "shadowMapping.inc"
-
-layout(set=0, binding=0) uniform LightInfoBuffer {
-    LightInfo lightInfo;
-};
-
-layout(location = 0) out vec4 outMoments;
-
-layout(location = 0) in vec4 passPos;
-
 void main()	{
-    float z         = passPos.z / passPos.w;
-    float z2        = z*z;   
-    outMoments      = vec4(z, z2, z2*z, z2*z2);
-        
-    outMoments = quantizeMoments(outMoments);
+
 }
\ No newline at end of file
diff --git a/projects/voxelization/resources/shaders/shadow.vert b/projects/voxelization/resources/shaders/shadow.vert
index f6b99c39..d800c547 100644
--- a/projects/voxelization/resources/shaders/shadow.vert
+++ b/projects/voxelization/resources/shaders/shadow.vert
@@ -3,17 +3,12 @@
 
 #extension GL_GOOGLE_include_directive : enable
 
-#include "lightInfo.inc"
-
 layout(location = 0) in vec3 inPosition;
 
 layout( push_constant ) uniform constants{
     mat4 mvp;
 };
 
-layout(location = 0) out vec4 passPos;
-
 void main()	{
 	gl_Position = mvp * vec4(inPosition, 1.0);
-    passPos = gl_Position;
 }
\ No newline at end of file
diff --git a/projects/voxelization/src/ShadowMapping.cpp b/projects/voxelization/src/ShadowMapping.cpp
index e6af48c5..72add6d5 100644
--- a/projects/voxelization/src/ShadowMapping.cpp
+++ b/projects/voxelization/src/ShadowMapping.cpp
@@ -15,6 +15,16 @@ vkcv::ShaderProgram loadShadowShader() {
 	return shader;
 }
 
+vkcv::ShaderProgram loadDepthToMomentsShader() {
+	vkcv::ShaderProgram shader;
+	vkcv::shader::GLSLCompiler compiler;
+	compiler.compile(vkcv::ShaderStage::COMPUTE, "resources/shaders/depthToMoments.comp",
+		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+		shader.addShader(shaderStage, path);
+	});
+	return shader;
+}
+
 glm::mat4 computeShadowViewProjectionMatrix(
 	const glm::vec3&            lightDirection, 
 	const vkcv::camera::Camera& camera, 
@@ -103,30 +113,24 @@ glm::mat4 computeShadowViewProjectionMatrix(
 	return vulkanCorrectionMatrix * crop * view;
 }
 
-const vk::Format    shadowMapFormat      = vk::Format::eR16G16B16A16Unorm;
-const vk::Format    shadowMapDepthFormat = vk::Format::eD16Unorm;
-const uint32_t      shadowMapResolution  = 2048;
+const vk::Format            shadowMapFormat         = vk::Format::eR16G16B16A16Unorm;
+const vk::Format            shadowMapDepthFormat    = vk::Format::eD32Sfloat;
+const uint32_t              shadowMapResolution     = 2048;
+const vkcv::Multisampling   msaa                    = vkcv::Multisampling::MSAA4X;
 
 ShadowMapping::ShadowMapping(vkcv::Core* corePtr, const vkcv::VertexLayout& vertexLayout) : 
 	m_corePtr(corePtr),
-	m_shadowMap(corePtr->createImage(shadowMapFormat, shadowMapResolution, shadowMapResolution, 1, false, false, true)),
-	m_shadowMapDepth(corePtr->createImage(shadowMapDepthFormat, shadowMapResolution, shadowMapResolution)),
+	m_shadowMap(corePtr->createImage(shadowMapFormat, shadowMapResolution, shadowMapResolution, 1, false, true)),
+	m_shadowMapDepth(corePtr->createImage(shadowMapDepthFormat, shadowMapResolution, shadowMapResolution, 1, false, false, false, msaa)),
 	m_lightInfoBuffer(corePtr->createBuffer<LightInfo>(vkcv::BufferType::UNIFORM, sizeof(glm::vec3))){
 
 	vkcv::ShaderProgram shadowShader = loadShadowShader();
 
-	// descriptor set
-	m_shadowDescriptorSet = corePtr->createDescriptorSet(shadowShader.getReflectedDescriptors()[0]);
-	vkcv::DescriptorWrites shadowDescriptorWrites;
-	shadowDescriptorWrites.uniformBufferWrites = { vkcv::UniformBufferDescriptorWrite(0, m_lightInfoBuffer.getHandle()) };
-	corePtr->writeDescriptorSet(m_shadowDescriptorSet, shadowDescriptorWrites);
-
 	// pass
 	const std::vector<vkcv::AttachmentDescription> shadowAttachments = {
-		vkcv::AttachmentDescription(vkcv::AttachmentOperation::STORE, vkcv::AttachmentOperation::CLEAR, shadowMapFormat),
 		vkcv::AttachmentDescription(vkcv::AttachmentOperation::STORE, vkcv::AttachmentOperation::CLEAR, shadowMapDepthFormat)
 	};
-	const vkcv::PassConfig shadowPassConfig(shadowAttachments);
+	vkcv::PassConfig shadowPassConfig(shadowAttachments, msaa);
 	m_shadowMapPass = corePtr->createPass(shadowPassConfig);
 
 	// pipeline
@@ -136,9 +140,10 @@ ShadowMapping::ShadowMapping(vkcv::Core* corePtr, const vkcv::VertexLayout& vert
 		shadowMapResolution,
 		m_shadowMapPass,
 		vertexLayout,
-		{ corePtr->getDescriptorSet(m_shadowDescriptorSet).layout },
+		{},
 		false
 	};
+	shadowPipeConfig.m_multisampling = msaa;
 	shadowPipeConfig.m_EnableDepthClamping = true;
 	m_shadowMapPipe = corePtr->createGraphicsPipeline(shadowPipeConfig);
 
@@ -148,10 +153,21 @@ ShadowMapping::ShadowMapping(vkcv::Core* corePtr, const vkcv::VertexLayout& vert
 		vkcv::SamplerMipmapMode::NEAREST,
 		vkcv::SamplerAddressMode::CLAMP_TO_EDGE
 	);
+
+	// depth to moments
+	vkcv::ShaderProgram depthToMomentsShader    = loadDepthToMomentsShader();
+	m_depthToMomentsDescriptorSet               = corePtr->createDescriptorSet(depthToMomentsShader.getReflectedDescriptors()[0]);
+	m_depthToMomentsPipe                        = corePtr->createComputePipeline(depthToMomentsShader, { corePtr->getDescriptorSet(m_depthToMomentsDescriptorSet).layout });
+
+	vkcv::DescriptorWrites depthToMomentDescriptorWrites;
+	depthToMomentDescriptorWrites.sampledImageWrites    = { vkcv::SampledImageDescriptorWrite(0, m_shadowMapDepth.getHandle()) };
+	depthToMomentDescriptorWrites.samplerWrites         = { vkcv::SamplerDescriptorWrite(1, m_shadowSampler) };
+	depthToMomentDescriptorWrites.storageImageWrites    = { vkcv::StorageImageDescriptorWrite(2, m_shadowMap.getHandle()) };
+	corePtr->writeDescriptorSet(m_depthToMomentsDescriptorSet, depthToMomentDescriptorWrites);
 }
 
 void ShadowMapping::recordShadowMapRendering(
-	const vkcv::CommandStreamHandle&    cmdStream, 
+	const vkcv::CommandStreamHandle&    cmdStream,
 	const glm::vec2&                    lightAngleRadian,
 	const glm::vec3&                    lightColor,
 	float                               lightStrength,
@@ -165,9 +181,9 @@ void ShadowMapping::recordShadowMapRendering(
 	float                               voxelVolumeExtent) {
 
 	LightInfo lightInfo;
-	lightInfo.sunColor      = lightColor;
-	lightInfo.sunStrength   = lightStrength;
-	lightInfo.direction     = glm::normalize(glm::vec3(
+	lightInfo.sunColor = lightColor;
+	lightInfo.sunStrength = lightStrength;
+	lightInfo.direction = glm::normalize(glm::vec3(
 		std::cos(lightAngleRadian.x) * std::cos(lightAngleRadian.y),
 		std::sin(lightAngleRadian.x),
 		std::cos(lightAngleRadian.x) * std::sin(lightAngleRadian.y)));
@@ -190,7 +206,7 @@ void ShadowMapping::recordShadowMapRendering(
 
 	std::vector<vkcv::DrawcallInfo> drawcalls;
 	for (const auto& mesh : meshes) {
-		drawcalls.push_back(vkcv::DrawcallInfo(mesh, { vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_shadowDescriptorSet).vulkanHandle) }));
+		drawcalls.push_back(vkcv::DrawcallInfo(mesh, {}));
 	}
 
 	m_corePtr->recordDrawcallsToCmdStream(
@@ -199,7 +215,24 @@ void ShadowMapping::recordShadowMapRendering(
 		m_shadowMapPipe,
 		shadowPushConstantData,
 		drawcalls,
-		{ m_shadowMap.getHandle(), m_shadowMapDepth.getHandle() });
+		{ m_shadowMapDepth.getHandle() });
+	m_corePtr->prepareImageForSampling(cmdStream, m_shadowMapDepth.getHandle());
+
+	// depth to moments
+	uint32_t dispatchCount[3];
+	dispatchCount[0] = (uint32_t)std::ceilf(shadowMapResolution / 8.f);
+	dispatchCount[1] = (uint32_t)std::ceilf(shadowMapResolution / 8.f);
+	dispatchCount[2] = 1;
+
+	const uint32_t msaaSampleCount = msaaToSampleCount(msaa);
+
+	m_corePtr->prepareImageForStorage(cmdStream, m_shadowMap.getHandle());
+	m_corePtr->recordComputeDispatchToCmdStream(
+		cmdStream,
+		m_depthToMomentsPipe,
+		dispatchCount,
+		{ vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_depthToMomentsDescriptorSet).vulkanHandle) },
+		vkcv::PushConstantData((void*)&msaaSampleCount, sizeof(msaaSampleCount)));
 	m_corePtr->prepareImageForSampling(cmdStream, m_shadowMap.getHandle());
 }
 
diff --git a/projects/voxelization/src/ShadowMapping.hpp b/projects/voxelization/src/ShadowMapping.hpp
index 1478755d..e9ad792c 100644
--- a/projects/voxelization/src/ShadowMapping.hpp
+++ b/projects/voxelization/src/ShadowMapping.hpp
@@ -42,12 +42,14 @@ public:
 private:
 	vkcv::Core* m_corePtr;
 
-	vkcv::Image             m_shadowMap;
-	vkcv::Image             m_shadowMapDepth;
-	vkcv::SamplerHandle     m_shadowSampler;
-	vkcv::Buffer<LightInfo> m_lightInfoBuffer;
-	vkcv::DescriptorSetHandle m_shadowDescriptorSet;
-
-	vkcv::PassHandle        m_shadowMapPass;
-	vkcv::PipelineHandle    m_shadowMapPipe;
+	vkcv::Image                 m_shadowMap;
+	vkcv::Image                 m_shadowMapDepth;
+	vkcv::SamplerHandle         m_shadowSampler;
+	vkcv::Buffer<LightInfo>     m_lightInfoBuffer;
+
+	vkcv::PassHandle            m_shadowMapPass;
+	vkcv::PipelineHandle        m_shadowMapPipe;
+
+	vkcv::PipelineHandle        m_depthToMomentsPipe;
+	vkcv::DescriptorSetHandle   m_depthToMomentsDescriptorSet;
 };
\ No newline at end of file
diff --git a/src/vkcv/ImageConfig.cpp b/src/vkcv/ImageConfig.cpp
index a9d6a36f..80aeac3d 100644
--- a/src/vkcv/ImageConfig.cpp
+++ b/src/vkcv/ImageConfig.cpp
@@ -11,4 +11,14 @@ namespace vkcv {
 		default: vkcv_log(vkcv::LogLevel::ERROR, "Unknown Multisampling enum setting"); return vk::SampleCountFlagBits::e1;
 		}
 	}
+
+	uint32_t msaaToSampleCount(Multisampling msaa) {
+		switch (msaa) {
+		case Multisampling::None:   return 1;
+		case Multisampling::MSAA2X: return 2;
+		case Multisampling::MSAA4X: return 4;
+		case Multisampling::MSAA8X: return 8;
+		default: vkcv_log(vkcv::LogLevel::ERROR, "Unknown Multisampling enum setting"); return 1;
+		}
+	}
 }
\ No newline at end of file
-- 
GitLab