diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000000000000000000000000000000000000..540b00747eee74a94be3c987d1ac4c8595738a09 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,20 @@ +Alexander Gauggel +Artur Wasmut +Josch Morgenstern +Katharina Krämer +Lars Hoerttrich +Leonie Franken +Mara Vogt +Mark O. Mints +Sebastian Gaida +Simeon Hermann +Susanne Dötsch +Tobias Frisch +Trevor Hollmann +Vanessa Karolek + + + + + + diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a0858b970dead0233261c4f3c126a0bf64732f7..5f82b94af2a98dfb6700fb098a6b2a84adf7b9a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,9 @@ endif() # configure everything to use the required dependencies include(${vkcv_config}/Libraries.cmake) +# set macro to enable vulkan debug labels +list(APPEND vkcv_definitions VULKAN_DEBUG_LABELS) + # set the compile definitions aka preprocessor variables add_compile_definitions(${vkcv_definitions}) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..c1f3c5685b29d78b26dcc8c9e454b74c33f73ba5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Universität Koblenz + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/projects/CMakeLists.txt b/projects/CMakeLists.txt index 5cdcaeffe1c6cc7b159afd46f86ab79f96650abf..d1acdbcbf011aab7de96f060aeb55ede83c516eb 100644 --- a/projects/CMakeLists.txt +++ b/projects/CMakeLists.txt @@ -7,4 +7,5 @@ add_subdirectory(particle_simulation) add_subdirectory(sph) add_subdirectory(voxelization) add_subdirectory(mesh_shader) -add_subdirectory(indirect_dispatch) +add_subdirectory(saf_r) +add_subdirectory(indirect_dispatch) \ No newline at end of file diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp index 5ef277dfedbfa823a2b6fa55c5a6303117ddaa52..0871631827b87539bbe9b0050420088e199a39af 100644 --- a/projects/first_mesh/src/main.cpp +++ b/projects/first_mesh/src/main.cpp @@ -101,7 +101,7 @@ int main(int argc, const char** argv) { // since we only use one descriptor set (namely, desc set 0), directly address it // recreate copies of the bindings and the handles (to check whether they are properly reused instead of actually recreated) - std::unordered_map<uint32_t, vkcv::DescriptorBinding> set0Bindings = firstMeshProgram.getReflectedDescriptors().at(0); + const vkcv::DescriptorBindings& set0Bindings = firstMeshProgram.getReflectedDescriptors().at(0); auto set0BindingsExplicitCopy = set0Bindings; vkcv::DescriptorSetLayoutHandle setLayoutHandle = core.createDescriptorSetLayout(set0Bindings); diff --git a/projects/indirect_dispatch/assets/shaders/motionVectorMinMax.comp b/projects/indirect_dispatch/assets/shaders/motionVectorMinMax.comp index 4ad350b0d5300aa63a66d7aceb00ea0b642d07ee..06b1b98f37579ae33406691bf19999d42ab7eb83 100644 --- a/projects/indirect_dispatch/assets/shaders/motionVectorMinMax.comp +++ b/projects/indirect_dispatch/assets/shaders/motionVectorMinMax.comp @@ -12,6 +12,7 @@ layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; void main(){ ivec2 outImageRes = imageSize(outMotionMax); + ivec2 inImageRes = textureSize(sampler2D(inMotion, textureSampler), 0); ivec2 motionTileCoord = ivec2(gl_GlobalInvocationID.xy); if(any(greaterThanEqual(motionTileCoord, outImageRes))) @@ -28,6 +29,14 @@ void main(){ for(int x = 0; x < motionTileSize; x++){ for(int y = 0; y < motionTileSize; y++){ ivec2 sampleCoord = motionBufferBaseCoord + ivec2(x, y); + + bool sampleIsOutsideImage = false; + sampleIsOutsideImage = sampleIsOutsideImage || any(greaterThanEqual(sampleCoord, inImageRes)); + sampleIsOutsideImage = sampleIsOutsideImage || any(lessThan(sampleCoord, ivec2(0))); + + if(sampleIsOutsideImage) + continue; + vec2 motionSample = texelFetch(sampler2D(inMotion, textureSampler), sampleCoord, 0).rg; float velocitySample = length(motionSample); diff --git a/projects/indirect_dispatch/assets/shaders/motionVectorMinMaxNeighbourhood.comp b/projects/indirect_dispatch/assets/shaders/motionVectorMinMaxNeighbourhood.comp index 4d6e7c0af6115e816ba087570e5585ffde23b1e6..3f836341a97a683efe88f41416d541624be03a0e 100644 --- a/projects/indirect_dispatch/assets/shaders/motionVectorMinMaxNeighbourhood.comp +++ b/projects/indirect_dispatch/assets/shaders/motionVectorMinMaxNeighbourhood.comp @@ -12,6 +12,7 @@ layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; void main(){ ivec2 outImageRes = imageSize(outMotionMaxNeighbourhood); + ivec2 inImageRes = textureSize(sampler2D(inMotionMax, textureSampler), 0); ivec2 motionTileCoord = ivec2(gl_GlobalInvocationID.xy); if(any(greaterThanEqual(motionTileCoord, outImageRes))) @@ -27,6 +28,13 @@ void main(){ for(int y = -1; y <= 1; y++){ ivec2 sampleCoord = motionTileCoord + ivec2(x, y); + bool sampleIsOutsideImage = false; + sampleIsOutsideImage = sampleIsOutsideImage || any(greaterThanEqual(sampleCoord, inImageRes)); + sampleIsOutsideImage = sampleIsOutsideImage || any(lessThan(sampleCoord, ivec2(0))); + + if(sampleIsOutsideImage) + continue; + vec2 motionSampleMax = texelFetch(sampler2D(inMotionMax, textureSampler), sampleCoord, 0).rg; float velocitySampleMax = length(motionSampleMax); diff --git a/projects/indirect_dispatch/assets/shaders/motionVectorVisualisation.comp b/projects/indirect_dispatch/assets/shaders/motionVectorVisualisation.comp index 1cfb09c87e8288b8ea80c6ddfbe5f0d4918b7f2e..fdceb575feaf24e7114bbcf223585a28955f45b8 100644 --- a/projects/indirect_dispatch/assets/shaders/motionVectorVisualisation.comp +++ b/projects/indirect_dispatch/assets/shaders/motionVectorVisualisation.comp @@ -21,7 +21,10 @@ void main(){ if(any(greaterThanEqual(coord, outImageRes))) return; - vec2 motionVector = texelFetch(sampler2D(inMotion, textureSampler), coord / motionTileSize, 0).rg; + vec2 uv = (coord + 0.5) / vec2(outImageRes); + ivec2 inTextureRes = textureSize(sampler2D(inMotion, textureSampler), 0); + + vec2 motionVector = texelFetch(sampler2D(inMotion, textureSampler), ivec2(uv * inTextureRes), 0).rg; vec2 motionVectorNormalized = clamp(motionVector / range, -1, 1); vec2 color = motionVectorNormalized * 0.5 + 0.5; diff --git a/projects/indirect_dispatch/src/App.cpp b/projects/indirect_dispatch/src/App.cpp index d4afc61c7421bd45c773bbdbc3da796b868869d2..532cef11db5b2bb8b5d741f6505507ff23fa4163 100644 --- a/projects/indirect_dispatch/src/App.cpp +++ b/projects/indirect_dispatch/src/App.cpp @@ -28,7 +28,7 @@ App::App() : VK_MAKE_VERSION(0, 0, 1), { vk::QueueFlagBits::eGraphics ,vk::QueueFlagBits::eCompute , vk::QueueFlagBits::eTransfer }, { VK_KHR_SWAPCHAIN_EXTENSION_NAME })), - m_windowHandle(m_core.createWindow(m_applicationName, m_windowWidth, m_windowHeight, false)), + m_windowHandle(m_core.createWindow(m_applicationName, m_windowWidth, m_windowHeight, true)), m_cameraManager(m_core.getWindow(m_windowHandle)){} bool App::initialize() { diff --git a/projects/saf_r/.gitignore b/projects/saf_r/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..ff3dff30031efafa24269a9ac0ef93f64f63ded1 --- /dev/null +++ b/projects/saf_r/.gitignore @@ -0,0 +1 @@ +saf_r \ No newline at end of file diff --git a/projects/saf_r/CMakeLists.txt b/projects/saf_r/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..61ede8ae5a5cedac78ff5781aec20973854a3df7 --- /dev/null +++ b/projects/saf_r/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.16) +project(saf_r) + +# setting c++ standard for the project +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# this should fix the execution path to load local files from the project +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + +# adding source files to the project +add_executable(saf_r + src/main.cpp + "src/safrScene.hpp" + ) + +# this should fix the execution path to load local files from the project (for MSVC) +if(MSVC) + set_target_properties(saf_r PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + set_target_properties(saf_r PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + + # in addition to setting the output directory, the working directory has to be set + # by default visual studio sets the working directory to the build directory, when using the debugger + set_target_properties(saf_r PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) +endif() + +# including headers of dependencies and the VkCV framework +target_include_directories(saf_r SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_testing_include} ${vkcv_asset_loader_include} ${vkcv_camera_include} ${vkcv_shader_compiler_include}) + +# linking with libraries from all dependencies and the VkCV framework +target_link_libraries(saf_r vkcv vkcv_testing vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera vkcv_shader_compiler) diff --git a/projects/saf_r/shaders/raytracing.comp b/projects/saf_r/shaders/raytracing.comp new file mode 100644 index 0000000000000000000000000000000000000000..a7c6b92a646e5c2f753946f74fe7ab78aea44fe6 --- /dev/null +++ b/projects/saf_r/shaders/raytracing.comp @@ -0,0 +1,292 @@ +#version 450 core +#extension GL_ARB_separate_shader_objects : enable + +// defines constants +const float pi = 3.1415926535897932384626433832795; +const float hitBias = 0.01; // used to offset hits to avoid self intersection + +layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; + +//structs of materials, lights, spheres and intersection for use in compute shader +struct Material { + vec3 albedo; + vec3 diffuseColor; + float specularExponent; + float refractiveIndex; +}; + +struct Light{ + vec3 position; + float intensity; +}; + +struct Sphere{ + vec3 center; + float radius; + Material material; +}; + +struct Intersection{ + bool hit; + vec3 pos; + vec3 N; + Material material; +}; + + +//incoming light data +layout(std430, binding = 0) coherent buffer lights{ + Light inLights[]; +}; + +// incoming sphere data +layout(std430, binding = 1) coherent buffer spheres{ + Sphere inSpheres[]; +}; + +// output store image as swapchain input +layout(set=0, binding = 2, rgba8) uniform image2D outImage; + +// incoming constants, because size of dynamic arrays cannot be computed on gpu +layout( push_constant ) uniform constants{ + mat4 viewToWorld; + int lightCount; + int sphereCount; +}; + +/* +* safrReflect computes the new reflected or refracted ray depending on the material +* @param vec3: raydirection vector +* @param vec3: normalvector on which should be reflected or refracted +* @param float: degree of refraction. In case of simple reflection it is 1.0 +* @return vec3: new ray that is the result of the reflection or refraction +*/ +vec3 safrReflect(vec3 V, vec3 N, float refractIndex){ + if(refractIndex != 1.0){ + // Snell's law + float cosi = - max(-1.f, min(1.f, dot(V,N))); + float etai = 1; + float etat = refractIndex; + vec3 n = N; + float swap; + if(cosi < 0){ + cosi = -cosi; + n = -N; + swap = etai; + etai = etat; + etat = swap; + } + float eta = etai / etat; + float k = 1 - eta * eta * (1 - cosi * cosi); + if(k < 0){ + return vec3(0,0,0); + } else { + return V * eta + n * (eta * cosi - sqrt(k)); + } + }else{ + return reflect(V, N); + } +} + +/* +* the rayIntersect function checks, if a ray from the raytracer passes through the sphere, hits the sphere or passes by the the sphere +* @param vec3: origin of ray +* @param vec3: direction of ray +* @param float: distance of the ray to the sphere (out because there are no references in shaders) +* @return bool: if ray interesects sphere or not (out because there are no references in shaders) +*/ + +bool rayIntersect(const vec3 origin, const vec3 dir, out float t0, const int id){ + vec3 L = inSpheres[id].center - origin; + float tca = dot(L, dir); + float d2 = dot(L, L) - tca * tca; + if (d2 > inSpheres[id].radius * inSpheres[id].radius){ + return false; + } + float thc = float(sqrt(inSpheres[id].radius * inSpheres[id].radius - d2)); + t0 = tca - thc; + float t1 = tca + thc; + if (t0 < 0) { + t0 = t1; + } + if (t0 < 0){ + return false; + } + return true; +} + +/* +* sceneIntersect iterates over whole scene (over every single object) to check for intersections +* @param vec3: Origin of the ray +* @param vec3: direction of the ray +* @return: Intersection struct with hit(bool) position, normal and material of sphere +*/ + +Intersection sceneIntersect(const vec3 rayOrigin, const vec3 rayDirection) { + //distance if spheres will be rendered + float min_d = 1.0 / 0.0; // lets start with something big + + Intersection intersection; + intersection.hit = false; + + //go over every sphere, check if sphere is hit by ray, save if hit is near enough into intersection struct + for (int i = 0; i < sphereCount; i++) { + float d; + if (rayIntersect(rayOrigin, rayDirection, d, i)) { + + intersection.hit = true; + + if(d < min_d){ + min_d = d; + intersection.pos = rayOrigin + rayDirection * d; + intersection.N = normalize(intersection.pos - inSpheres[i].center); + intersection.material = inSpheres[i].material; + } + } + } + + float checkerboard_dist = min_d; + if (abs(rayDirection.y)>1e-3) { + float d = -(rayOrigin.y + 4) / rayDirection.y; // the checkerboard plane has equation y = -4 + vec3 pt = rayOrigin + rayDirection * d; + if (d > 0 && abs(pt.x) < 10 && pt.z<-10 && pt.z>-30 && d < min_d) { + checkerboard_dist = d; + intersection.hit = true; + intersection.pos = pt; + intersection.N = vec3(0, 1, 0); + intersection.material = inSpheres[0].material; + } + } + return intersection; +} + +/* +* biasHitPosition computes the new hitposition with respect to the raydirection and a bias +* @param vec3: Hit Position +* @param vec3: direction of ray +* @param vec3: N(ormal) +* @return vec3: new Hit position depending on hitBias (used to offset hits to avoid self intersection) +*/ +vec3 biasHitPosition(vec3 hitPos, vec3 rayDirection, vec3 N){ + return hitPos + sign(dot(rayDirection, N)) * N * hitBias; +} + +/* +* computeHitLighting iterates over all lights to compute the color for every ray +* @param Intersection: struct with all the data of the intersection +* @param vec3: Raydirection +* @param float: material albedo of the intersection +* @return colour/shadows of sphere with illumination +*/ +vec3 computeHitLighting(Intersection intersection, vec3 V, out float outReflectionThroughput){ + + float lightIntensityDiffuse = 0; + float lightIntensitySpecular = 0; + + //iterate over every light source to compute sphere colours/shadows + for (int i = 0; i < lightCount; i++) { + + //compute normal + distance between light and intersection + vec3 L = normalize(inLights[i].position - intersection.pos); + float d = distance(inLights[i].position, intersection.pos); + + //compute shadows + vec3 shadowOrigin = biasHitPosition(intersection.pos, L, intersection.N); + Intersection shadowIntersection = sceneIntersect(shadowOrigin, L); + bool isShadowed = false; + if(shadowIntersection.hit){ + isShadowed = distance(shadowIntersection.pos, shadowOrigin) < d; + } + if(isShadowed){ + continue; + } + + lightIntensityDiffuse += inLights[i].intensity * max(0.f, dot(L, intersection.N)); + lightIntensitySpecular += pow(max(0.f, dot(safrReflect(V, intersection.N, intersection.material.refractiveIndex), L)), intersection.material.specularExponent) * inLights[i].intensity; + } + + outReflectionThroughput = intersection.material.albedo[2]; + return intersection.material.diffuseColor * lightIntensityDiffuse * intersection.material.albedo[0] + lightIntensitySpecular * intersection.material.albedo[1]; +} + +/* +* castRay throws a ray out of the initial origin with respect to the initial direction checks for intersection and refelction +* @param vec3: initial origin of ray +* @param vec3: initial direction of ray +* @param int: max depth o ray reflection +* @return s +*/ + +vec3 castRay(const vec3 initialOrigin, const vec3 initialDirection, int max_depth) { + + vec3 skyColor = vec3(0.2, 0.7, 0.8); + vec3 rayOrigin = initialOrigin; + vec3 rayDirection = initialDirection; + + float reflectionThroughput = 1; + vec3 color = vec3(0); + + //iterate to max depth of reflections + for(int i = 0; i < max_depth; i++){ + + Intersection intersection = sceneIntersect(rayOrigin, rayDirection); + + vec3 hitColor; + float hitReflectionThroughput; + + if(intersection.hit){ + hitColor = computeHitLighting(intersection, rayDirection, hitReflectionThroughput); + }else{ + hitColor = skyColor; + } + + color += hitColor * reflectionThroughput; + reflectionThroughput *= hitReflectionThroughput; + + //if there is no intersection of a ray with a sphere, break out of the loop + if(!intersection.hit){ + break; + } + + //compute new direction and origin of the reflected ray + rayDirection = normalize(safrReflect(rayDirection, intersection.N, intersection.material.refractiveIndex)); + rayOrigin = biasHitPosition(intersection.pos, rayDirection, intersection.N); + } + + return color; +} + +/* +* computeDirection transforms the pixel coords to worldspace coords +* @param ivec2: pixel coordinates +* @return vec3: world coordinates +*/ +vec3 computeDirection(ivec2 coord){ + + ivec2 outImageRes = imageSize(outImage); + float fovDegree = 45; + float fov = fovDegree * pi / 180; + + vec2 uv = coord / vec2(outImageRes); + vec2 ndc = 2 * uv - 1; + + float tanFovHalf = tan(fov / 2.f); + float aspectRatio = outImageRes.x / float(outImageRes.y); + float x = ndc.x * tanFovHalf * aspectRatio; + float y = -ndc.y * tanFovHalf; + + vec3 directionViewSpace = normalize(vec3(x, y, 1)); + vec3 directionWorldSpace = mat3(viewToWorld) * directionViewSpace; + return directionWorldSpace; +} + +// the main function +void main(){ + ivec2 coord = ivec2(gl_GlobalInvocationID.xy); + int max_depth = 4; + vec3 direction = computeDirection(coord); + vec3 cameraPos = viewToWorld[3].xyz; + vec3 color = castRay(cameraPos, direction, max_depth); + + imageStore(outImage, coord, vec4(color, 0.f)); +} \ No newline at end of file diff --git a/projects/saf_r/shaders/shader.frag b/projects/saf_r/shaders/shader.frag new file mode 100644 index 0000000000000000000000000000000000000000..64b45eb26b9831f6504e69882018e46120615615 --- /dev/null +++ b/projects/saf_r/shaders/shader.frag @@ -0,0 +1,13 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 fragColor; +layout(location = 1) in vec2 texCoord; + +layout(location = 0) out vec3 outColor; + +layout(set=0, binding=1) uniform sampler textureSampler; + +void main() { + outColor = fragColor; +} \ No newline at end of file diff --git a/projects/saf_r/shaders/shader.vert b/projects/saf_r/shaders/shader.vert new file mode 100644 index 0000000000000000000000000000000000000000..b6419f5e348ddeca66d1c8b0eb0a4cf32e2e80c4 --- /dev/null +++ b/projects/saf_r/shaders/shader.vert @@ -0,0 +1,32 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) out vec3 fragColor; +layout(location = 1) out vec2 texCoord; + +layout( push_constant ) uniform constants{ + mat4 mvp; + mat4 proj; +}; + +void main() { + vec3 positions[3] = { + vec3(-1, -1, -1), + vec3( 3, -1, -1), + vec3(-1, 3, -1) + }; + + vec3 colors[3] = { + vec3(1, 0, 0), + vec3(0, 1, 0), + vec3(0, 0, 1) + }; + + vec4 position = mvp * vec4(positions[gl_VertexIndex], 1.0); + gl_Position = position; + + texCoord.x = ((proj * vec4(positions[gl_VertexIndex], 1.0)).x + 1.0) * 0.5; + texCoord.y = ((proj * vec4(positions[gl_VertexIndex], 1.0)).y + 1.0) * 0.5; + + fragColor = colors[gl_VertexIndex]; +} \ No newline at end of file diff --git a/projects/saf_r/src/main.cpp b/projects/saf_r/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3fef073a00f8263cc08ce17f033170d0f4031dc4 --- /dev/null +++ b/projects/saf_r/src/main.cpp @@ -0,0 +1,297 @@ +#include <iostream> +#include <vkcv/Core.hpp> +#include <GLFW/glfw3.h> +#include <vkcv/camera/CameraManager.hpp> +#include <vkcv/asset/asset_loader.hpp> +#include <vkcv/shader/GLSLCompiler.hpp> +#include <chrono> +#include <limits> +#include <cmath> +#include <vector> +#include <string.h> // memcpy(3) +#include "safrScene.hpp" + + +void createQuadraticLightCluster(std::vector<safrScene::Light>& lights, int countPerDimension, float dimension, float height, float intensity) { + float distance = dimension/countPerDimension; + + for(int x = 0; x <= countPerDimension; x++) { + for (int z = 0; z <= countPerDimension; z++) { + lights.push_back(safrScene::Light(glm::vec3(x * distance, height, z * distance), + float (intensity/countPerDimension) / 10.f) // Divide by 10, because intensity is busting O.o + ); + } + } + +} + +int main(int argc, const char** argv) { + const char* applicationName = "SAF_R"; + + //window creation + const int windowWidth = 800; + const int windowHeight = 600; + + vkcv::Core core = vkcv::Core::create( + applicationName, + VK_MAKE_VERSION(0, 0, 1), + { vk::QueueFlagBits::eTransfer,vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute }, + { "VK_KHR_swapchain" } + ); + + vkcv::WindowHandle windowHandle = core.createWindow(applicationName, windowWidth, windowHeight, false); + + //configuring the compute Shader + vkcv::PassConfig computePassDefinition({}); + vkcv::PassHandle computePass = core.createPass(computePassDefinition); + + if (!computePass) + { + std::cout << "Error. Could not create renderpass. Exiting." << std::endl; + return EXIT_FAILURE; + } + + std::string shaderPathCompute = "shaders/raytracing.comp"; + + //creating the shader programs + vkcv::ShaderProgram safrShaderProgram; + vkcv::shader::GLSLCompiler compiler; + vkcv::ShaderProgram computeShaderProgram{}; + + compiler.compile(vkcv::ShaderStage::VERTEX, std::filesystem::path("shaders/shader.vert"), + [&safrShaderProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + safrShaderProgram.addShader(shaderStage, path); + }); + + compiler.compile(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("shaders/shader.frag"), + [&safrShaderProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + safrShaderProgram.addShader(shaderStage, path); + }); + + compiler.compile(vkcv::ShaderStage::COMPUTE, shaderPathCompute, [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + computeShaderProgram.addShader(shaderStage, path); + }); + + //create DescriptorSets (...) for every Shader + const vkcv::DescriptorBindings& descriptorBindings = safrShaderProgram.getReflectedDescriptors().at(0); + vkcv::DescriptorSetLayoutHandle descriptorSetLayout = core.createDescriptorSetLayout(descriptorBindings); + vkcv::DescriptorSetHandle descriptorSet = core.createDescriptorSet(descriptorSetLayout); + vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); + + const vkcv::DescriptorBindings& computeDescriptorBindings = computeShaderProgram.getReflectedDescriptors().at(0); + + vkcv::DescriptorSetLayoutHandle computeDescriptorSetLayout = core.createDescriptorSetLayout(computeDescriptorBindings); + vkcv::DescriptorSetHandle computeDescriptorSet = core.createDescriptorSet(computeDescriptorSetLayout); + + const std::vector<vkcv::VertexAttachment> computeVertexAttachments = computeShaderProgram.getVertexAttachments(); + + std::vector<vkcv::VertexBinding> computeBindings; + for (size_t i = 0; i < computeVertexAttachments.size(); i++) { + computeBindings.push_back(vkcv::VertexBinding(i, { computeVertexAttachments[i] })); + } + const vkcv::VertexLayout computeLayout(computeBindings); + + /* + * create the scene + */ + + //materials for the spheres + std::vector<safrScene::Material> materials; + safrScene::Material ivory(glm::vec4(0.6, 0.3, 0.1, 0.0), glm::vec3(0.4, 0.4, 0.3), 50., 1.0); + safrScene::Material red_rubber(glm::vec4(0.9, 0.1, 0.0, 0.0), glm::vec3(0.3, 0.1, 0.1), 10., 1.0); + safrScene::Material mirror( glm::vec4(0.0, 10.0, 0.8, 0.0), glm::vec3(1.0, 1.0, 1.0), 1425., 1.0); + safrScene::Material glass( glm::vec4(0.0, 10.0, 0.8, 0.0), glm::vec3(1.0, 1.0, 1.0), 1425., 1.5); + + materials.push_back(ivory); + materials.push_back(red_rubber); + materials.push_back(mirror); + + //spheres for the scene + std::vector<safrScene::Sphere> spheres; + spheres.push_back(safrScene::Sphere(glm::vec3(-3, 0, -16), 2, ivory)); + // spheres.push_back(safrScene::Sphere(glm::vec3(-1.0, -1.5, 12), 2, mirror)); + spheres.push_back(safrScene::Sphere(glm::vec3(-1.0, -1.5, -12), 2, glass)); + spheres.push_back(safrScene::Sphere(glm::vec3( 1.5, -0.5, -18), 3, red_rubber)); + spheres.push_back(safrScene::Sphere(glm::vec3( 7, 5, -18), 4, mirror)); + + //lights for the scene + std::vector<safrScene::Light> lights; + /* + lights.push_back(safrScene::Light(glm::vec3(-20, 20, 20), 1.5)); + lights.push_back(safrScene::Light(glm::vec3(30, 50, -25), 1.8)); + lights.push_back(safrScene::Light(glm::vec3(30, 20, 30), 1.7)); + */ + createQuadraticLightCluster(lights, 10, 2.5f, 20, 1.5f); + + + vkcv::SamplerHandle sampler = core.createSampler( + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerMipmapMode::LINEAR, + vkcv::SamplerAddressMode::REPEAT + ); + + + //create Buffer for compute shader + vkcv::Buffer<safrScene::Light> lightsBuffer = core.createBuffer<safrScene::Light>( + vkcv::BufferType::STORAGE, + lights.size() + ); + lightsBuffer.fill(lights); + + vkcv::Buffer<safrScene::Sphere> sphereBuffer = core.createBuffer<safrScene::Sphere>( + vkcv::BufferType::STORAGE, + spheres.size() + ); + sphereBuffer.fill(spheres); + + vkcv::DescriptorWrites computeWrites; + computeWrites.storageBufferWrites = { vkcv::BufferDescriptorWrite(0,lightsBuffer.getHandle()), + vkcv::BufferDescriptorWrite(1,sphereBuffer.getHandle())}; + core.writeDescriptorSet(computeDescriptorSet, computeWrites); + + + const auto& context = core.getContext(); + + auto safrIndexBuffer = core.createBuffer<uint16_t>(vkcv::BufferType::INDEX, 3, vkcv::BufferMemoryType::DEVICE_LOCAL); + uint16_t indices[3] = { 0, 1, 2 }; + safrIndexBuffer.fill(&indices[0], sizeof(indices)); + + // an example attachment for passes that output to the window + const vkcv::AttachmentDescription present_color_attachment( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + core.getSwapchain(windowHandle).getFormat()); + + vkcv::PassConfig safrPassDefinition({ present_color_attachment }); + vkcv::PassHandle safrPass = core.createPass(safrPassDefinition); + + if (!safrPass) + { + std::cout << "Error. Could not create renderpass. Exiting." << std::endl; + return EXIT_FAILURE; + } + + //create the render pipeline + compute pipeline + const vkcv::GraphicsPipelineConfig safrPipelineDefinition{ + safrShaderProgram, + (uint32_t)windowWidth, + (uint32_t)windowHeight, + safrPass, + {}, + { core.getDescriptorSetLayout(descriptorSetLayout).vulkanHandle }, + false + }; + + vkcv::GraphicsPipelineHandle safrPipeline = core.createGraphicsPipeline(safrPipelineDefinition); + + const vkcv::ComputePipelineConfig computePipelineConfig{ + computeShaderProgram, + {core.getDescriptorSetLayout(computeDescriptorSetLayout).vulkanHandle} + }; + + vkcv::ComputePipelineHandle computePipeline = core.createComputePipeline(computePipelineConfig); + + if (!safrPipeline || !computePipeline) + { + std::cout << "Error. Could not create graphics pipeline. Exiting." << std::endl; + return EXIT_FAILURE; + } + + auto start = std::chrono::system_clock::now(); + + const vkcv::Mesh renderMesh({}, safrIndexBuffer.getVulkanHandle(), 3); + vkcv::DescriptorSetUsage descriptorUsage(0, core.getDescriptorSet(descriptorSet).vulkanHandle); + vkcv::DrawcallInfo drawcall(renderMesh, { descriptorUsage }, 1); + + //create the camera + vkcv::camera::CameraManager cameraManager(core.getWindow(windowHandle)); + uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); + uint32_t camIndex1 = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL); + + cameraManager.getCamera(camIndex0).setPosition(glm::vec3(0, 0, 2)); + cameraManager.getCamera(camIndex1).setPosition(glm::vec3(0.0f, 0.0f, 0.0f)); + cameraManager.getCamera(camIndex1).setCenter(glm::vec3(0.0f, 0.0f, -1.0f)); + + float time = 0; + + while (vkcv::Window::hasOpenWindow()) + { + vkcv::Window::pollEvents(); + + uint32_t swapchainWidth, swapchainHeight; // No resizing = No problem + if (!core.beginFrame(swapchainWidth, swapchainHeight, windowHandle)) { + continue; + } + + //configure timer + auto end = std::chrono::system_clock::now(); + auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start); + start = end; + + time += 0.000001f * static_cast<float>(deltatime.count()); + + //adjust light position + /* + 639a53157e7d3936caf7c3e40379159cbcf4c89e + lights[0].position.x += std::cos(time * 3.0f) * 2.5f; + lights[1].position.z += std::cos(time * 2.5f) * 3.0f; + lights[2].position.y += std::cos(time * 1.5f) * 4.0f; + lightsBuffer.fill(lights); + */ + + spheres[0].center.y += std::cos(time * 0.5f * 3.141f) * 0.25f; + spheres[1].center.x += std::cos(time * 2.f) * 0.25f; + spheres[1].center.z += std::cos(time * 2.f + 0.5f * 3.141f) * 0.25f; + sphereBuffer.fill(spheres); + + //update camera + cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); + glm::mat4 mvp = cameraManager.getActiveCamera().getMVP(); + glm::mat4 proj = cameraManager.getActiveCamera().getProjection(); + + //create pushconstants for render + vkcv::PushConstants pushConstants(sizeof(glm::mat4) * 2); + pushConstants.appendDrawcall(std::array<glm::mat4, 2>{ mvp, proj }); + + auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); + + //configure the outImage for compute shader (render into the swapchain image) + computeWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(2, swapchainInput)}; + core.writeDescriptorSet(computeDescriptorSet, computeWrites); + core.prepareImageForStorage (cmdStream, swapchainInput); + + //fill pushconstants for compute shader + struct RaytracingPushConstantData { + glm::mat4 viewToWorld; + int32_t lightCount; + int32_t sphereCount; + }; + + RaytracingPushConstantData raytracingPushData; + raytracingPushData.lightCount = lights.size(); + raytracingPushData.sphereCount = spheres.size(); + raytracingPushData.viewToWorld = glm::inverse(cameraManager.getActiveCamera().getView()); + + vkcv::PushConstants pushConstantsCompute(sizeof(RaytracingPushConstantData)); + pushConstantsCompute.appendDrawcall(raytracingPushData); + + //dispatch compute shader + uint32_t computeDispatchCount[3] = {static_cast<uint32_t> (std::ceil( swapchainWidth/16.f)), + static_cast<uint32_t> (std::ceil(swapchainHeight/16.f)), + 1 }; // Anzahl workgroups + core.recordComputeDispatchToCmdStream(cmdStream, + computePipeline, + computeDispatchCount, + { vkcv::DescriptorSetUsage(0,core.getDescriptorSet(computeDescriptorSet).vulkanHandle) }, + pushConstantsCompute); + + core.recordBufferMemoryBarrier(cmdStream, lightsBuffer.getHandle()); + + core.prepareSwapchainImageForPresent(cmdStream); + core.submitCommandStream(cmdStream); + + core.endFrame(windowHandle); + } + return 0; +} diff --git a/projects/saf_r/src/safrScene.hpp b/projects/saf_r/src/safrScene.hpp new file mode 100644 index 0000000000000000000000000000000000000000..33a298f82121971021d1912e6c1205e9c48a49f0 --- /dev/null +++ b/projects/saf_r/src/safrScene.hpp @@ -0,0 +1,51 @@ +#include <iostream> +#include <vkcv/Core.hpp> +#include <GLFW/glfw3.h> +#include <vkcv/camera/CameraManager.hpp> +#include <vkcv/asset/asset_loader.hpp> +#include <vkcv/shader/GLSLCompiler.hpp> +#include <chrono> +#include <limits> +#include <cmath> +#include <vector> +#include <string.h> // memcpy(3) + +class safrScene { + +public: + + /* + * Light struct with a position and intensity of the light source + */ + struct Light { + Light(const glm::vec3& p, const float& i) : position(p), intensity(i) {} + glm::vec3 position; + float intensity; + }; + + /* + * Material struct with defuse color, albedo and specular component + */ + struct Material { + Material(const glm::vec4& a, const glm::vec3& color, const float& spec, const float& r) : albedo(a), diffuse_color(color), specular_exponent(spec), refractive_index(r) {} + Material() : refractive_index(1), albedo(1, 0, 0, 0), diffuse_color(), specular_exponent() {} + glm::vec4 albedo; + alignas(16) glm::vec3 diffuse_color; + float specular_exponent; + float refractive_index; + }; + + /* + * the sphere is defined by it's center, the radius and the material + */ + struct Sphere { + glm::vec3 center; + float radius; + Material material; + + Sphere(const glm::vec3& c, const float& r, const Material& m) : center(c), radius(r), material(m) {} + + }; + + +}; \ No newline at end of file diff --git a/projects/voxelization/assets/shaders/depthToMoments.comp b/projects/voxelization/assets/shaders/depthToMoments.comp index 5a78d0cb9b748187d12057708fcd0de7658a61ed..79e47cdef02143ed97d53e533f47e822db8c0f6f 100644 --- a/projects/voxelization/assets/shaders/depthToMoments.comp +++ b/projects/voxelization/assets/shaders/depthToMoments.comp @@ -28,9 +28,11 @@ void main(){ z += texelFetch(sampler2DMS(srcTexture, depthSampler), uv, i).r; } z /= msaaCount; - + z = 2 * z - 1; // algorithm expects depth in range [-1:1] + 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/assets/shaders/shadowBlur.inc b/projects/voxelization/assets/shaders/shadowBlur.inc index 06147415f118dca9badd15813b431a68682ce0b0..ed4994ed1ace34afdafff15920d18a2433a3c0a4 100644 --- a/projects/voxelization/assets/shaders/shadowBlur.inc +++ b/projects/voxelization/assets/shaders/shadowBlur.inc @@ -3,7 +3,7 @@ vec4 blurMomentShadowMap1D(ivec2 coord, ivec2 blurDirection, texture2D srcTexture, sampler depthSampler){ - int blurRadius = 9; + int blurRadius = 7; int minOffset = -(blurRadius-1) / 2; int maxOffset = -minOffset; diff --git a/projects/voxelization/assets/shaders/shadowBlurX.comp b/projects/voxelization/assets/shaders/shadowBlurX.comp index 45b91aad71673347dbf607fecef92463ef1c3c88..41d127fdf5ce46dec883d49af4f284b5787d5d38 100644 --- a/projects/voxelization/assets/shaders/shadowBlurX.comp +++ b/projects/voxelization/assets/shaders/shadowBlurX.comp @@ -18,6 +18,6 @@ void main(){ } ivec2 coord = ivec2(gl_GlobalInvocationID.xy); vec4 moments = blurMomentShadowMap1D(coord, ivec2(1, 0), srcTexture, depthSampler); - + // moments = texelFetch(sampler2D(srcTexture, depthSampler), coord, 0); imageStore(outImage, coord, moments); } \ No newline at end of file diff --git a/projects/voxelization/assets/shaders/shadowBlurY.comp b/projects/voxelization/assets/shaders/shadowBlurY.comp index 51d4df054b0d99e54149863a5967143518f61dd2..c1710d7d6c75ef0093fecfe708272f56f9541eaf 100644 --- a/projects/voxelization/assets/shaders/shadowBlurY.comp +++ b/projects/voxelization/assets/shaders/shadowBlurY.comp @@ -16,10 +16,8 @@ void main(){ if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(outImage)))){ return; } - ivec2 coord = ivec2(gl_GlobalInvocationID.xy); - vec2 pixelSize = vec2(1) / textureSize(sampler2D(srcTexture, depthSampler), 0); - + ivec2 coord = ivec2(gl_GlobalInvocationID.xy); vec4 moments = blurMomentShadowMap1D(coord, ivec2(0, 1), srcTexture, depthSampler); - + // moments = texelFetch(sampler2D(srcTexture, depthSampler), coord, 0); imageStore(outImage, coord, moments); } \ No newline at end of file diff --git a/projects/voxelization/assets/shaders/shadowMapping.inc b/projects/voxelization/assets/shaders/shadowMapping.inc index c56ae8985c5c5fcef780b622d8b888f1081af74c..9124a05c310c2cc16e6b02802f5adb36bde42804 100644 --- a/projects/voxelization/assets/shaders/shadowMapping.inc +++ b/projects/voxelization/assets/shaders/shadowMapping.inc @@ -6,7 +6,8 @@ // nice math blob from the moment shadow mapping presentation float ComputeMSMShadowIntensity(vec4 _4Moments, float FragmentDepth, float DepthBias, float MomentBias) { - vec4 b=mix(_4Moments, vec4(0.5),MomentBias); + vec4 b=mix(_4Moments, vec4(0, 0.63, 0, 0.63),MomentBias); + vec3 z; z[0]=FragmentDepth-DepthBias; float L32D22=fma(-b[0], b[1], b[2]); @@ -39,24 +40,23 @@ float ComputeMSMShadowIntensity(vec4 _4Moments, float FragmentDepth, float Depth } vec4 quantizeMoments(vec4 moments){ - mat4 T = mat4( - -2.07224649, 13.7948857237, 0.105877704, 9.7924062118, - 32.23703778, -59.4683975703, -1.9077466311, -33.7652110555, - -68.571074599, 82.0359750338, 9.3496555107, 47.9456096605, - 39.3703274134, -35.364903257, -6.6543490743, -23.9728048165); - vec4 quantized = T * moments; - quantized[0] += 0.0359558848; - return quantized; + vec4 quantized; + quantized.r = 1.5 * moments.r - 2 * moments.b + 0.5; + quantized.g = 4 * moments.g - 4 * moments.a; + quantized.b = sqrt(3)/2 * moments.r - sqrt(12)/9 * moments.b + 0.5; + quantized.a = 0.5 * moments.g + 0.5 * moments.a; + + return quantized; } vec4 unquantizeMoments(vec4 moments){ - moments[0] -= 0.0359558848; - mat4 T = mat4( - 0.2227744146, 0.1549679261, 0.1451988946, 0.163127443, - 0.0771972861, 0.1394629426, 0.2120202157, 0.2591432266, - 0.7926986636, 0.7963415838, 0.7258694464, 0.6539092497, - 0.0319417555, -0.1722823173, -0.2758014811, -0.3376131734); - return T * moments; + moments -= vec4(0.5, 0, 0.5, 0); + vec4 unquantized; + unquantized.r = -1.f / 3 * moments.r + sqrt(3) * moments.b; + unquantized.g = 0.125 * moments.g + moments.a; + unquantized.b = -0.75 * moments.r + 0.75 * sqrt(3) * moments.b; + unquantized.a = -0.125 * moments.g + moments.a; + return unquantized / 0.98; // division reduces light bleeding } float rescaleRange(float a, float b, float v) @@ -78,18 +78,20 @@ float shadowTest(vec3 worldPos, LightInfo lightInfo, texture2D shadowMap, sample if(any(lessThan(lightPos.xy, vec2(0))) || any(greaterThan(lightPos.xy, vec2(1)))){ return 1; } - + lightPos.z = clamp(lightPos.z, 0, 1); + lightPos.z = 2 * lightPos.z - 1; // algorithm expects depth in range [-1:1] vec4 shadowMapSample = texture(sampler2D(shadowMap, shadowMapSampler), lightPos.xy); shadowMapSample = unquantizeMoments(shadowMapSample); float depthBias = 0.f; - float momentBias = 0.0003; + float momentBias = 0.0006; float shadow = ComputeMSMShadowIntensity(shadowMapSample, lightPos.z, depthBias, momentBias); - return reduceLightBleeding(shadow, 0.1f); + return clamp(shadow, 0, 1); + // return reduceLightBleeding(shadow, 0.1f); } #endif // #ifndef SHADOW_MAPPING_INC \ No newline at end of file diff --git a/projects/voxelization/src/BloomAndFlares.cpp b/projects/voxelization/src/BloomAndFlares.cpp index d47f61d0dc7fea4e38508b7b1d6c040595e2944a..2014d7a0219141ec6363b38a5311cb924b6b6a45 100644 --- a/projects/voxelization/src/BloomAndFlares.cpp +++ b/projects/voxelization/src/BloomAndFlares.cpp @@ -127,6 +127,8 @@ void BloomAndFlares::execDownsamplePipe(const vkcv::CommandStreamHandle &cmdStre 1 }; + p_Core->recordBeginDebugLabel(cmdStream, "Bloom downsample", { 1, 1, 1, 1 }); + // downsample dispatch of original color attachment p_Core->prepareImageForSampling(cmdStream, colorAttachment); p_Core->prepareImageForStorage(cmdStream, m_Blur.getHandle()); @@ -182,10 +184,14 @@ void BloomAndFlares::execDownsamplePipe(const vkcv::CommandStreamHandle &cmdStre // image barrier between mips p_Core->recordImageMemoryBarrier(cmdStream, m_Blur.getHandle()); } + + p_Core->recordEndDebugLabel(cmdStream); } void BloomAndFlares::execUpsamplePipe(const vkcv::CommandStreamHandle &cmdStream) { + p_Core->recordBeginDebugLabel(cmdStream, "Bloom upsample", { 1, 1, 1, 1 }); + // upsample dispatch p_Core->prepareImageForStorage(cmdStream, m_Blur.getHandle()); @@ -227,10 +233,14 @@ void BloomAndFlares::execUpsamplePipe(const vkcv::CommandStreamHandle &cmdStream // image barrier between mips p_Core->recordImageMemoryBarrier(cmdStream, m_Blur.getHandle()); } + + p_Core->recordEndDebugLabel(cmdStream); } void BloomAndFlares::execLensFeaturePipe(const vkcv::CommandStreamHandle &cmdStream) { + p_Core->recordBeginDebugLabel(cmdStream, "Lense flare generation", { 1, 1, 1, 1 }); + // lens feature generation descriptor writes p_Core->prepareImageForSampling(cmdStream, m_Blur.getHandle()); p_Core->prepareImageForStorage(cmdStream, m_LensFeatures.getHandle()); @@ -295,11 +305,15 @@ void BloomAndFlares::execLensFeaturePipe(const vkcv::CommandStreamHandle &cmdStr // image barrier between mips p_Core->recordImageMemoryBarrier(cmdStream, m_LensFeatures.getHandle()); } + + p_Core->recordEndDebugLabel(cmdStream); } void BloomAndFlares::execCompositePipe(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle& colorAttachment, const uint32_t attachmentWidth, const uint32_t attachmentHeight, const glm::vec3& cameraForward) { + p_Core->recordBeginDebugLabel(cmdStream, "Bloom/lense flare composition", { 1, 1, 1, 1 }); + p_Core->prepareImageForSampling(cmdStream, m_Blur.getHandle()); p_Core->prepareImageForSampling(cmdStream, m_LensFeatures.getHandle()); p_Core->prepareImageForStorage(cmdStream, colorAttachment); @@ -329,11 +343,13 @@ void BloomAndFlares::execCompositePipe(const vkcv::CommandStreamHandle &cmdStrea // bloom composite dispatch p_Core->recordComputeDispatchToCmdStream( - cmdStream, - m_CompositePipe, - compositeDispatchCount, - {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_CompositeDescSet).vulkanHandle)}, - pushConstants); + cmdStream, + m_CompositePipe, + compositeDispatchCount, + {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_CompositeDescSet).vulkanHandle)}, + pushConstants); + + p_Core->recordEndDebugLabel(cmdStream); } void BloomAndFlares::execWholePipeline(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle &colorAttachment, diff --git a/projects/voxelization/src/ShadowMapping.cpp b/projects/voxelization/src/ShadowMapping.cpp index d8041c1e9935d148ded8fb1ca8f0e4d8b79fce71..ce4261ff2403139d10b9d677e7aa216a3e41178f 100644 --- a/projects/voxelization/src/ShadowMapping.cpp +++ b/projects/voxelization/src/ShadowMapping.cpp @@ -266,6 +266,7 @@ void ShadowMapping::recordShadowMapRendering( drawcalls.push_back(vkcv::DrawcallInfo(mesh, {})); } + m_corePtr->recordBeginDebugLabel(cmdStream, "Shadow map depth", {1, 1, 1, 1}); m_corePtr->recordDrawcallsToCmdStream( cmdStream, m_shadowMapPass, @@ -275,6 +276,7 @@ void ShadowMapping::recordShadowMapRendering( { m_shadowMapDepth.getHandle() }, windowHandle); m_corePtr->prepareImageForSampling(cmdStream, m_shadowMapDepth.getHandle()); + m_corePtr->recordEndDebugLabel(cmdStream); // depth to moments uint32_t dispatchCount[3]; @@ -287,6 +289,8 @@ void ShadowMapping::recordShadowMapRendering( vkcv::PushConstants msaaPushConstants (sizeof(msaaSampleCount)); msaaPushConstants.appendDrawcall(msaaSampleCount); + m_corePtr->recordBeginDebugLabel(cmdStream, "Depth to moments", { 1, 1, 1, 1 }); + m_corePtr->prepareImageForStorage(cmdStream, m_shadowMap.getHandle()); m_corePtr->recordComputeDispatchToCmdStream( cmdStream, @@ -295,6 +299,9 @@ void ShadowMapping::recordShadowMapRendering( { vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_depthToMomentsDescriptorSet).vulkanHandle) }, msaaPushConstants); m_corePtr->prepareImageForSampling(cmdStream, m_shadowMap.getHandle()); + m_corePtr->recordEndDebugLabel(cmdStream); + + m_corePtr->recordBeginDebugLabel(cmdStream, "Moment shadow map blur", { 1, 1, 1, 1 }); // blur X m_corePtr->prepareImageForStorage(cmdStream, m_shadowMapIntermediate.getHandle()); @@ -316,6 +323,8 @@ void ShadowMapping::recordShadowMapRendering( vkcv::PushConstants(0)); m_shadowMap.recordMipChainGeneration(cmdStream); m_corePtr->prepareImageForSampling(cmdStream, m_shadowMap.getHandle()); + + m_corePtr->recordEndDebugLabel(cmdStream); } vkcv::ImageHandle ShadowMapping::getShadowMap() { diff --git a/projects/voxelization/src/Voxelization.cpp b/projects/voxelization/src/Voxelization.cpp index 3cbff0df84757fb370a0372ddd45a9df401d4b60..c023af21c673651984e945ab03d16280c18f0768 100644 --- a/projects/voxelization/src/Voxelization.cpp +++ b/projects/voxelization/src/Voxelization.cpp @@ -251,6 +251,7 @@ void Voxelization::voxelizeMeshes( vkcv::PushConstants voxelCountPushConstants (sizeof(voxelCount)); voxelCountPushConstants.appendDrawcall(voxelCount); + m_corePtr->recordBeginDebugLabel(cmdStream, "Voxel reset", { 1, 1, 1, 1 }); m_corePtr->recordComputeDispatchToCmdStream( cmdStream, m_voxelResetPipe, @@ -258,6 +259,7 @@ void Voxelization::voxelizeMeshes( { vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_voxelResetDescriptorSet).vulkanHandle) }, voxelCountPushConstants); m_corePtr->recordBufferMemoryBarrier(cmdStream, m_voxelBuffer.getHandle()); + m_corePtr->recordEndDebugLabel(cmdStream); // voxelization std::vector<vkcv::DrawcallInfo> drawcalls; @@ -270,6 +272,7 @@ void Voxelization::voxelizeMeshes( },1)); } + m_corePtr->recordBeginDebugLabel(cmdStream, "Voxelization", { 1, 1, 1, 1 }); m_corePtr->prepareImageForStorage(cmdStream, m_voxelImageIntermediate.getHandle()); m_corePtr->recordDrawcallsToCmdStream( cmdStream, @@ -279,6 +282,7 @@ void Voxelization::voxelizeMeshes( drawcalls, { m_dummyRenderTarget.getHandle() }, windowHandle); + m_corePtr->recordEndDebugLabel(cmdStream); // buffer to image const uint32_t bufferToImageGroupSize[3] = { 4, 4, 4 }; @@ -287,6 +291,7 @@ void Voxelization::voxelizeMeshes( bufferToImageDispatchCount[i] = glm::ceil(voxelResolution / float(bufferToImageGroupSize[i])); } + m_corePtr->recordBeginDebugLabel(cmdStream, "Voxel buffer to image", { 1, 1, 1, 1 }); m_corePtr->recordComputeDispatchToCmdStream( cmdStream, m_bufferToImagePipe, @@ -295,14 +300,17 @@ void Voxelization::voxelizeMeshes( vkcv::PushConstants(0)); m_corePtr->recordImageMemoryBarrier(cmdStream, m_voxelImageIntermediate.getHandle()); + m_corePtr->recordEndDebugLabel(cmdStream); // intermediate image mipchain + m_corePtr->recordBeginDebugLabel(cmdStream, "Intermediate Voxel mipmap generation", { 1, 1, 1, 1 }); m_voxelImageIntermediate.recordMipChainGeneration(cmdStream); m_corePtr->prepareImageForSampling(cmdStream, m_voxelImageIntermediate.getHandle()); + m_corePtr->recordEndDebugLabel(cmdStream); // secondary bounce + m_corePtr->recordBeginDebugLabel(cmdStream, "Voxel secondary bounce", { 1, 1, 1, 1 }); m_corePtr->prepareImageForStorage(cmdStream, m_voxelImage.getHandle()); - m_corePtr->recordComputeDispatchToCmdStream( cmdStream, m_secondaryBouncePipe, @@ -310,12 +318,14 @@ void Voxelization::voxelizeMeshes( { vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_secondaryBounceDescriptorSet).vulkanHandle) }, vkcv::PushConstants(0)); m_voxelImage.recordMipChainGeneration(cmdStream); - m_corePtr->recordImageMemoryBarrier(cmdStream, m_voxelImage.getHandle()); + m_corePtr->recordEndDebugLabel(cmdStream); // final image mipchain + m_corePtr->recordBeginDebugLabel(cmdStream, "Voxel mipmap generation", { 1, 1, 1, 1 }); m_voxelImage.recordMipChainGeneration(cmdStream); m_corePtr->prepareImageForSampling(cmdStream, m_voxelImage.getHandle()); + m_corePtr->recordEndDebugLabel(cmdStream); } void Voxelization::renderVoxelVisualisation( @@ -344,6 +354,7 @@ void Voxelization::renderVoxelVisualisation( vkcv::Mesh({}, nullptr, drawVoxelCount), { vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_visualisationDescriptorSet).vulkanHandle) },1); + m_corePtr->recordBeginDebugLabel(cmdStream, "Voxel visualisation", { 1, 1, 1, 1 }); m_corePtr->prepareImageForStorage(cmdStream, m_voxelImage.getHandle()); m_corePtr->recordDrawcallsToCmdStream( cmdStream, @@ -353,6 +364,7 @@ void Voxelization::renderVoxelVisualisation( { drawcall }, renderTargets, windowHandle); + m_corePtr->recordEndDebugLabel(cmdStream); } void Voxelization::updateVoxelOffset(const vkcv::camera::Camera& camera) { diff --git a/projects/voxelization/src/main.cpp b/projects/voxelization/src/main.cpp index a7798813a52429d31f207ae24af6a3effb90c17c..0f9e9fb870cb1277f43ea204f351103d1072f8b8 100644 --- a/projects/voxelization/src/main.cpp +++ b/projects/voxelization/src/main.cpp @@ -765,6 +765,7 @@ int main(int argc, const char** argv) { const std::vector<vkcv::ImageHandle> prepassRenderTargets = { depthBuffer }; + core.recordBeginDebugLabel(cmdStream, "Depth prepass", { 1, 1, 1, 1 }); core.recordDrawcallsToCmdStream( cmdStream, prepassPass, @@ -775,6 +776,7 @@ int main(int argc, const char** argv) { windowHandle); core.recordImageMemoryBarrier(cmdStream, depthBuffer); + core.recordEndDebugLabel(cmdStream); vkcv::PushConstants pushConstants (2 * sizeof(glm::mat4)); @@ -791,6 +793,7 @@ int main(int argc, const char** argv) { const std::vector<vkcv::ImageHandle> renderTargets = { colorBuffer, depthBuffer }; + core.recordBeginDebugLabel(cmdStream, "Forward rendering", { 1, 1, 1, 1 }); core.recordDrawcallsToCmdStream( cmdStream, forwardPass, @@ -799,6 +802,7 @@ int main(int argc, const char** argv) { drawcalls, renderTargets, windowHandle); + core.recordEndDebugLabel(cmdStream); if (renderVoxelVis) { voxelization.renderVoxelVisualisation(cmdStream, viewProjectionCamera, renderTargets, voxelVisualisationMip, windowHandle); @@ -808,6 +812,7 @@ int main(int argc, const char** argv) { skySettingsPushConstants.appendDrawcall(skySettings); // sky + core.recordBeginDebugLabel(cmdStream, "Sky", { 1, 1, 1, 1 }); core.recordDrawcallsToCmdStream( cmdStream, skyPass, @@ -816,6 +821,7 @@ int main(int argc, const char** argv) { { vkcv::DrawcallInfo(vkcv::Mesh({}, nullptr, 3), {}) }, renderTargets, windowHandle); + core.recordEndDebugLabel(cmdStream); const uint32_t fullscreenLocalGroupSize = 8; @@ -832,8 +838,8 @@ int main(int argc, const char** argv) { fulsscreenDispatchCount[2] = 1; if (usingMsaa) { + core.recordBeginDebugLabel(cmdStream, "MSAA resolve", { 1, 1, 1, 1 }); if (msaaCustomResolve) { - core.prepareImageForSampling(cmdStream, colorBuffer); core.prepareImageForStorage(cmdStream, resolvedColorBuffer); @@ -850,6 +856,7 @@ int main(int argc, const char** argv) { else { core.resolveMSAAImage(cmdStream, colorBuffer, resolvedColorBuffer); } + core.recordEndDebugLabel(cmdStream); } bloomFlares.execWholePipeline(cmdStream, resolvedColorBuffer, fsrWidth, fsrHeight, @@ -859,6 +866,7 @@ int main(int argc, const char** argv) { core.prepareImageForStorage(cmdStream, swapBuffer); core.prepareImageForSampling(cmdStream, resolvedColorBuffer); + core.recordBeginDebugLabel(cmdStream, "Tonemapping", { 1, 1, 1, 1 }); core.recordComputeDispatchToCmdStream( cmdStream, tonemappingPipeline, @@ -871,6 +879,7 @@ int main(int argc, const char** argv) { core.prepareImageForStorage(cmdStream, swapBuffer2); core.prepareImageForSampling(cmdStream, swapBuffer); + core.recordEndDebugLabel(cmdStream); if (bilinearUpscaling) { upscaling1.recordUpscaling(cmdStream, swapBuffer, swapBuffer2); @@ -895,6 +904,7 @@ int main(int argc, const char** argv) { glm::ceil(swapchainHeight / static_cast<float>(fullscreenLocalGroupSize)) ); + core.recordBeginDebugLabel(cmdStream, "Post Processing", { 1, 1, 1, 1 }); core.recordComputeDispatchToCmdStream( cmdStream, postEffectsPipeline, @@ -904,6 +914,7 @@ int main(int argc, const char** argv) { ).vulkanHandle) }, timePushConstants ); + core.recordEndDebugLabel(cmdStream); // present and end core.prepareSwapchainImageForPresent(cmdStream); diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index 00ea4a9fec2bbc49ef078074ca7e13927d146b9d..a07d25836e4b541a023665e12b902b2880027eb4 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -52,7 +52,7 @@ namespace vkcv Core::Core(Context &&context, const CommandResources& commandResources, const SyncResources& syncResources) noexcept : m_Context(std::move(context)), m_PassManager{std::make_unique<PassManager>(m_Context.m_Device)}, - m_PipelineManager{std::make_unique<GraphicsPipelineManager>(m_Context.m_Device)}, + m_PipelineManager{std::make_unique<GraphicsPipelineManager>(m_Context.m_Device, m_Context.m_PhysicalDevice)}, m_ComputePipelineManager{std::make_unique<ComputePipelineManager>(m_Context.m_Device)}, m_DescriptorManager(std::make_unique<DescriptorManager>(m_Context.m_Device)), m_BufferManager{std::unique_ptr<BufferManager>(new BufferManager())}, @@ -443,7 +443,7 @@ namespace vkcv void Core::recordBeginDebugLabel(const CommandStreamHandle &cmdStream, const std::string& label, const std::array<float, 4>& color) { -#ifndef NDEBUG + #ifdef VULKAN_DEBUG_LABELS static PFN_vkCmdBeginDebugUtilsLabelEXT beginDebugLabel = reinterpret_cast<PFN_vkCmdBeginDebugUtilsLabelEXT>( m_Context.getDevice().getProcAddr("vkCmdBeginDebugUtilsLabelEXT") ); @@ -462,11 +462,11 @@ namespace vkcv }; recordCommandsToStream(cmdStream, submitFunction, nullptr); -#endif + #endif } void Core::recordEndDebugLabel(const CommandStreamHandle &cmdStream) { -#ifndef NDEBUG + #ifdef VULKAN_DEBUG_LABELS static PFN_vkCmdEndDebugUtilsLabelEXT endDebugLabel = reinterpret_cast<PFN_vkCmdEndDebugUtilsLabelEXT>( m_Context.getDevice().getProcAddr("vkCmdEndDebugUtilsLabelEXT") ); @@ -480,7 +480,7 @@ namespace vkcv }; recordCommandsToStream(cmdStream, submitFunction, nullptr); -#endif + #endif } void Core::recordComputeIndirectDispatchToCmdStream( @@ -864,7 +864,7 @@ namespace vkcv static void setDebugObjectLabel(const vk::Device& device, const vk::ObjectType& type, uint64_t handle, const std::string& label) { -#ifndef NDEBUG +#ifndef VULKAN_DEBUG_LABELS static PFN_vkSetDebugUtilsObjectNameEXT setDebugLabel = reinterpret_cast<PFN_vkSetDebugUtilsObjectNameEXT>( device.getProcAddr("vkSetDebugUtilsObjectNameEXT") ); diff --git a/src/vkcv/GraphicsPipelineManager.cpp b/src/vkcv/GraphicsPipelineManager.cpp index cb7dd31dddd3a5c0742f95e8429175724aa26454..870220f45b52c022f7c2d445a40e99ab4a6a4a2f 100644 --- a/src/vkcv/GraphicsPipelineManager.cpp +++ b/src/vkcv/GraphicsPipelineManager.cpp @@ -5,8 +5,9 @@ namespace vkcv { - GraphicsPipelineManager::GraphicsPipelineManager(vk::Device device) noexcept : - m_Device{device}, + GraphicsPipelineManager::GraphicsPipelineManager(vk::Device device, vk::PhysicalDevice physicalDevice) noexcept : + m_Device(device), + m_physicalDevice(physicalDevice), m_Pipelines{} {} @@ -237,7 +238,9 @@ namespace vkcv * @param config sets Depth Clamping and Culling Mode * @return Pipeline Rasterization State Create Info Struct */ - vk::PipelineRasterizationStateCreateInfo createPipelineRasterizationStateCreateInfo(const GraphicsPipelineConfig &config) { + vk::PipelineRasterizationStateCreateInfo createPipelineRasterizationStateCreateInfo( + const GraphicsPipelineConfig &config, + const vk::PhysicalDeviceConservativeRasterizationPropertiesEXT& conservativeRasterProperties) { vk::CullModeFlags cullMode; switch (config.m_culling) { case CullMode::None: @@ -267,14 +270,14 @@ namespace vkcv 0.f, 1.f ); - + static vk::PipelineRasterizationConservativeStateCreateInfoEXT conservativeRasterization; if (config.m_UseConservativeRasterization) { conservativeRasterization = vk::PipelineRasterizationConservativeStateCreateInfoEXT( {}, vk::ConservativeRasterizationModeEXT::eOverestimate, - 0.f + std::max(1 - conservativeRasterProperties.primitiveOverestimationSize, 0.f) ); pipelineRasterizationStateCreateInfo.pNext = &conservativeRasterization; @@ -544,8 +547,13 @@ namespace vkcv createPipelineViewportStateCreateInfo(config); // rasterization state + vk::PhysicalDeviceConservativeRasterizationPropertiesEXT conservativeRasterProperties; + vk::PhysicalDeviceProperties deviceProperties; + vk::PhysicalDeviceProperties2 deviceProperties2(deviceProperties); + deviceProperties2.pNext = &conservativeRasterProperties; + m_physicalDevice.getProperties2(&deviceProperties2); vk::PipelineRasterizationStateCreateInfo pipelineRasterizationStateCreateInfo = - createPipelineRasterizationStateCreateInfo(config); + createPipelineRasterizationStateCreateInfo(config, conservativeRasterProperties); // multisample state vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo = diff --git a/src/vkcv/GraphicsPipelineManager.hpp b/src/vkcv/GraphicsPipelineManager.hpp index a08e64939dc967511095f22862c52de05148d7e9..782603ab0e1ffa9bde05fda96c5d2d259eff1953 100644 --- a/src/vkcv/GraphicsPipelineManager.hpp +++ b/src/vkcv/GraphicsPipelineManager.hpp @@ -20,7 +20,7 @@ namespace vkcv { public: GraphicsPipelineManager() = delete; // no default ctor - explicit GraphicsPipelineManager(vk::Device device) noexcept; // ctor + explicit GraphicsPipelineManager(vk::Device device, vk::PhysicalDevice physicalDevice) noexcept; // ctor ~GraphicsPipelineManager() noexcept; // dtor GraphicsPipelineManager(const GraphicsPipelineManager &other) = delete; // copy-ctor @@ -71,8 +71,9 @@ namespace vkcv GraphicsPipelineConfig m_config; }; - vk::Device m_Device; - std::vector<GraphicsPipeline> m_Pipelines; + vk::Device m_Device; + vk::PhysicalDevice m_physicalDevice; // needed to get infos to configure conservative rasterization + std::vector<GraphicsPipeline> m_Pipelines; void destroyPipelineById(uint64_t id);