From f6561ab7989adb3df6bd16762de5811e9df01949 Mon Sep 17 00:00:00 2001
From: Alexander Gauggel <agauggel@uni-koblenz.de>
Date: Wed, 23 Jun 2021 13:42:58 +0200
Subject: [PATCH] [#82] Implement custom MSAA resolve per compute

---
 .../resources/shaders/msaa4XResolve.comp      | 85 +++++++++++++++++++
 projects/voxelization/src/main.cpp            | 65 ++++++++++++--
 2 files changed, 141 insertions(+), 9 deletions(-)
 create mode 100644 projects/voxelization/resources/shaders/msaa4XResolve.comp

diff --git a/projects/voxelization/resources/shaders/msaa4XResolve.comp b/projects/voxelization/resources/shaders/msaa4XResolve.comp
new file mode 100644
index 00000000..746e0b1e
--- /dev/null
+++ b/projects/voxelization/resources/shaders/msaa4XResolve.comp
@@ -0,0 +1,85 @@
+#version 450
+#extension GL_ARB_texture_multisample : enable
+
+layout(set=0, binding=0)                    uniform texture2DMS     srcTexture;
+layout(set=0, binding=1)                    uniform sampler         MSAASampler;                
+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;
+
+float computeLuma(vec3 c){
+    return dot(c, vec3(0.21, 0.72, 0.07));
+}
+
+vec3 tonemap(vec3 c){
+    return c / (1 + computeLuma(c));
+}
+
+vec3 tonemapReverse(vec3 c){
+    return c / (1 - computeLuma(c));
+}
+
+float reconstructionFilter(float d){
+    // gauß filter, tuned so that distance of one has weight around 20%
+    float a = 1.6; 
+    return exp(-a * d*d);
+}
+
+void main(){
+
+    if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(outImage)))){
+        return;
+    }
+    ivec2 uv            = ivec2(gl_GlobalInvocationID.xy);
+    
+    vec2 samplePositions[4] = {
+     vec2(0.375, 0.125),
+     vec2(0.875, 0.375),
+     vec2(0.125, 0.625),
+     vec2(0.625, 0.875)};
+    
+    vec3    color   = vec3(0);
+    float   wTotal  = 0;
+    
+    // four samples from main pixel
+    for(int i = 0; i < 4; i++){
+        vec3 msaaSample = texelFetch(sampler2DMS(srcTexture, MSAASampler), uv, i).rgb;
+        float d         = distance(vec2(0.5), samplePositions[i]);
+        float w         = reconstructionFilter(d);
+        color           += tonemap(msaaSample) * w;
+        wTotal          += w;
+    }
+    
+    ivec2 neighbourOffsets[4] = {
+        ivec2( 1,  0),   // right
+        ivec2(-1,  0),   // left
+        ivec2( 0,  1),   // top
+        ivec2( 0, -1)    // bot
+    };
+    
+    int neighbourSampleIndices[8] = {
+        0, 2, // left  samples of right neighbour
+        1, 3, // right samples of left  neighbour
+        2, 3, // bot   samples of top   neighbour
+        0, 1  // top   samples of bot   neighbour
+    };
+    
+    // two additional samples from each neighbour
+    for(int neighbour = 0; neighbour < 4; neighbour++){
+        for(int i = 0; i < 2; i++){
+            int     sampleIndex = neighbourSampleIndices[neighbour * 2 + i];
+            ivec2   pixelOffset = neighbourOffsets[neighbour];
+            ivec2   pixelUV     = uv + pixelOffset;
+            vec3    msaaSample  = texelFetch(sampler2DMS(srcTexture, MSAASampler), pixelUV, sampleIndex).rgb;
+            float   d           = distance(vec2(0.5), samplePositions[sampleIndex] + pixelOffset);
+            float   w           = reconstructionFilter(d);
+            color               += tonemap(msaaSample) * w;
+            wTotal              += w;
+        }
+    }    
+    color /= wTotal;
+    color = tonemapReverse(color);
+    
+    imageStore(outImage, uv, vec4(color, 0.f));
+}
\ No newline at end of file
diff --git a/projects/voxelization/src/main.cpp b/projects/voxelization/src/main.cpp
index f5095e42..6c116738 100644
--- a/projects/voxelization/src/main.cpp
+++ b/projects/voxelization/src/main.cpp
@@ -276,6 +276,24 @@ int main(int argc, const char** argv) {
 		tonemappingProgram,
 		{ core.getDescriptorSet(tonemappingDescriptorSet).layout });
 
+	// resolve compute shader
+	vkcv::ShaderProgram resolveProgram;
+	compiler.compile(vkcv::ShaderStage::COMPUTE, "resources/shaders/msaa4XResolve.comp",
+		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+		resolveProgram.addShader(shaderStage, path);
+	});
+	vkcv::DescriptorSetHandle resolveDescriptorSet = core.createDescriptorSet(
+		resolveProgram.getReflectedDescriptors()[0]);
+	vkcv::PipelineHandle resolvePipeline = core.createComputePipeline(
+		resolveProgram,
+		{ core.getDescriptorSet(resolveDescriptorSet).layout });
+
+	vkcv::SamplerHandle resolveSampler = core.createSampler(
+		vkcv::SamplerFilterType::NEAREST,
+		vkcv::SamplerFilterType::NEAREST,
+		vkcv::SamplerMipmapMode::NEAREST,
+		vkcv::SamplerAddressMode::CLAMP_TO_EDGE);
+
 	// model matrices per mesh
 	std::vector<glm::mat4> modelMatrices;
 	modelMatrices.resize(scene.vertexGroups.size(), glm::mat4(1.f));
@@ -349,6 +367,8 @@ int main(int argc, const char** argv) {
 	int     voxelVisualisationMip   = 0;
 	float   voxelizationExtent      = 30.f;
 
+	bool msaaCustomResolve = true;
+
 	auto start = std::chrono::system_clock::now();
 	const auto appStartTime = start;
 	while (window.isWindowOpen()) {
@@ -384,6 +404,13 @@ int main(int argc, const char** argv) {
 			vkcv::StorageImageDescriptorWrite(1, swapchainInput) };
 		core.writeDescriptorSet(tonemappingDescriptorSet, tonemappingDescriptorWrites);
 
+		// update resolve descriptor, color images could be changed
+		vkcv::DescriptorWrites resolveDescriptorWrites;
+		resolveDescriptorWrites.sampledImageWrites  = { vkcv::SampledImageDescriptorWrite(0, colorBuffer) };
+		resolveDescriptorWrites.samplerWrites       = { vkcv::SamplerDescriptorWrite(1, resolveSampler) };
+		resolveDescriptorWrites.storageImageWrites  = { vkcv::StorageImageDescriptorWrite(2, resolvedColorBuffer) };
+		core.writeDescriptorSet(resolveDescriptorSet, resolveDescriptorWrites);
+
 		start = end;
 		cameraManager.update(0.000001 * static_cast<double>(deltatime.count()));
 		cameraPosBuffer.fill({ cameraManager.getActiveCamera().getPosition() });
@@ -439,24 +466,41 @@ int main(int argc, const char** argv) {
 			voxelization.renderVoxelVisualisation(cmdStream, viewProjectionCamera, renderTargets, voxelVisualisationMip);
 		}
 
-		if (usingMsaa) {
-			core.resolveMSAAImage(cmdStream, colorBuffer, resolvedColorBuffer);
-		}
-
-		const uint32_t tonemappingLocalGroupSize = 8;
-		const uint32_t tonemappingDispatchCount[3] = {
-			static_cast<uint32_t>(glm::ceil(windowWidth / static_cast<float>(tonemappingLocalGroupSize))),
-			static_cast<uint32_t>(glm::ceil(windowHeight / static_cast<float>(tonemappingLocalGroupSize))),
+		const uint32_t fullscreenLocalGroupSize = 8;
+		const uint32_t fulsscreenDispatchCount[3] = {
+			static_cast<uint32_t>(glm::ceil(windowWidth  / static_cast<float>(fullscreenLocalGroupSize))),
+			static_cast<uint32_t>(glm::ceil(windowHeight / static_cast<float>(fullscreenLocalGroupSize))),
 			1
 		};
 
+		if (usingMsaa) {
+			if (msaaCustomResolve) {
+
+				core.prepareImageForSampling(cmdStream, colorBuffer);
+				core.prepareImageForStorage(cmdStream, resolvedColorBuffer);
+
+				assert(msaa == vkcv::Multisampling::MSAA4X);	// shaders is written for msaa 4x
+				core.recordComputeDispatchToCmdStream(
+					cmdStream,
+					resolvePipeline,
+					fulsscreenDispatchCount,
+					{ vkcv::DescriptorSetUsage(0, core.getDescriptorSet(resolveDescriptorSet).vulkanHandle) },
+					vkcv::PushConstantData(nullptr, 0));
+
+				core.recordImageMemoryBarrier(cmdStream, resolvedColorBuffer);
+			}
+			else {
+				core.resolveMSAAImage(cmdStream, colorBuffer, resolvedColorBuffer);
+			}
+		}
+
 		core.prepareImageForStorage(cmdStream, swapchainInput);
 		core.prepareImageForStorage(cmdStream, resolvedColorBuffer);
 
 		core.recordComputeDispatchToCmdStream(
 			cmdStream, 
 			tonemappingPipeline, 
-			tonemappingDispatchCount,
+			fulsscreenDispatchCount,
 			{ vkcv::DescriptorSetUsage(0, core.getDescriptorSet(tonemappingDescriptorSet).vulkanHandle) },
 			vkcv::PushConstantData(nullptr, 0));
 
@@ -468,6 +512,9 @@ int main(int argc, const char** argv) {
 		gui.beginGUI();
 
 		ImGui::Begin("Settings");
+
+		ImGui::Checkbox("MSAA custom resolve", &msaaCustomResolve);
+
 		ImGui::DragFloat2("Light angles",           &lightAnglesDegree.x);
 		ImGui::ColorEdit3("Sun color",              &lightColor.x);
 		ImGui::DragFloat("Sun strength",            &lightStrength);
-- 
GitLab