diff --git a/CMakeLists.txt b/CMakeLists.txt index 89fea60eb527a673ada7868412ae389d386d38bf..0a1af49ba57d2c8189f8387d6263cbe884daae70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -714,6 +714,7 @@ message("======================================================================= ${SRC_DIR}/utility/extern_fence.hpp ${SRC_DIR}/utility/extern_fence.cpp ${SRC_DIR}/utility/frame_capture.hpp ${SRC_DIR}/utility/frame_capture.cpp ${SRC_DIR}/utility/geometry_buffer.hpp ${SRC_DIR}/utility/geometry_buffer.cpp + ${SRC_DIR}/utility/indirect_cache.hpp ${SRC_DIR}/utility/indirect_cache.cpp ${SRC_DIR}/utility/latency.hpp ${SRC_DIR}/utility/latency.cpp ${SRC_DIR}/utility/pass_timer.hpp ${SRC_DIR}/utility/pass_timer.cpp ${SRC_DIR}/utility/shadow_cache.hpp ${SRC_DIR}/utility/shadow_cache.cpp @@ -753,13 +754,14 @@ message("======================================================================= utility/deferred_local_light.frag utility/deferred_local_light_with_shadow.frag - utility/shadow_indirect_downsample.vert - utility/shadow_indirect_downsample.geom - utility/shadow_indirect_downsample.frag + utility/indirect_capture.vert + utility/indirect_capture.frag + + utility/indirect_injection.vert + utility/indirect_injection.geom + utility/indirect_injection.frag - utility/shadow_indirect.vert - utility/shadow_indirect.geom - utility/shadow_indirect.frag + utility/indirect_propagation.comp utility/shadow.vert utility/shadow.geom diff --git a/cmake/Shaders.cmake b/cmake/Shaders.cmake index 06d9d111495a6aa23f0b7398698641bea9bdac6b..f7a56645bdcc65b71c7ecc1574a286094e9dc33b 100644 --- a/cmake/Shaders.cmake +++ b/cmake/Shaders.cmake @@ -16,6 +16,8 @@ function(shader_extension_to_name name extension) set(${name} "geometry" PARENT_SCOPE) elseif (extension STREQUAL ".frag") set(${name} "fragment" PARENT_SCOPE) + elseif (extension STREQUAL ".comp") + set(${name} "compute" PARENT_SCOPE) else () message(SEND_ERROR "Invalid extension: ${extension}") endif () diff --git a/res/dpr/data/indirect_data.inc b/res/dpr/data/indirect_data.inc new file mode 100644 index 0000000000000000000000000000000000000000..6e4a52462b7e607dccc4046788a867fc7baae772 --- /dev/null +++ b/res/dpr/data/indirect_data.inc @@ -0,0 +1,16 @@ +#ifndef SHADER_INCLUDE_INDIRECT_DATA +#define SHADER_INCLUDE_INDIRECT_DATA + +struct IndirectDomain +{ + uvec3 resolution; + float cell_size; + + vec3 min; + uint padding1; + + vec3 max; + uint padding2; +}; + +#endif \ No newline at end of file diff --git a/res/dpr/data/light_data.inc b/res/dpr/data/light_data.inc index f75a73befd98994634d8f6f81f05cb764559413e..30b641e9c267413a0b3e00df2c4e89aa72356054 100644 --- a/res/dpr/data/light_data.inc +++ b/res/dpr/data/light_data.inc @@ -31,6 +31,7 @@ struct LightData uint padding; mat4 shadow_matrix[MAX_LIGHT_SHADOW_MATRIX_COUNT]; + mat4 inv_shadow_matrix[MAX_LIGHT_SHADOW_MATRIX_COUNT]; }; #endif \ No newline at end of file diff --git a/res/dpr/data/shadow_data.inc b/res/dpr/data/shadow_data.inc index d6b58e444db91f272ea230638e049f391c3b249e..bf280dafc8636640fc67304f7e18b85fa03cb200 100644 --- a/res/dpr/data/shadow_data.inc +++ b/res/dpr/data/shadow_data.inc @@ -1,24 +1,11 @@ #ifndef SHADER_INCLUDE_SHADOW_DATA #define SHADER_INCLUDE_SHADOW_DATA -#define MAX_INDIRECT_SAMPLE_COUNT 128 - struct ShadowParameter { - uint use_directional_shadow; - uint use_directional_indirect; - uint use_spot_shadow; - uint use_point_shadow; - - uint indirect_sample_count; -}; - -struct IndirectSample -{ - vec2 coord; - float weight; - - uint padding; + uint use_directional; + uint use_spot; + uint use_point; }; #endif \ No newline at end of file diff --git a/res/dpr/utility/shadow_indirect.frag b/res/dpr/utility/indirect_capture.frag similarity index 56% rename from res/dpr/utility/shadow_indirect.frag rename to res/dpr/utility/indirect_capture.frag index 29f56f1b41f329ec56860a9451430eec45c96cc4..13f91c7c05e81b7f2d15be95d1ea644c3ede23cf 100644 --- a/res/dpr/utility/shadow_indirect.frag +++ b/res/dpr/utility/indirect_capture.frag @@ -7,21 +7,20 @@ #include "math_library.glsl" #include "material_library.glsl" -layout(location = 0) out vec4 outPosition; -layout(location = 1) out vec4 outNormal; -layout(location = 2) out vec4 outFlux; +layout(location = 0) out vec4 outFlux; +layout(location = 1) out vec2 outNormal; layout(location = 0) in vec3 inPos; layout(location = 1) in vec3 inNormal; layout(location = 2) in vec3 inTangent; layout(location = 3) in vec2 inUV; -layout(set = 0, binding = 0) uniform LightParameterBuffer +layout(set = 1, binding = 0) uniform LightParameterBuffer { LightParameter light_parameter; }; -layout(set = 0, binding = 1, std430) readonly buffer LightDataBuffer +layout(set = 1, binding = 1, std430) readonly buffer LightDataBuffer { LightData lights[]; }; @@ -29,15 +28,15 @@ layout(set = 0, binding = 1, std430) readonly buffer LightDataBuffer layout(push_constant) uniform Constants { uint light_index; - uint indirect_resolution; + uint capture_resolution; }; -float comnpute_indirect_area() +float comnpute_pixel_area() { vec2 near_size = lights[light_index].near_size; - vec2 pixel_size = near_size / float(indirect_resolution); + vec2 pixel_size = near_size / float(capture_resolution); - return pixel_size.x * pixel_size.y; //Where pixel_size is in meters + return pixel_size.x * pixel_size.y; //NOTE: Where pixel_size is in meters } void main() @@ -51,7 +50,6 @@ void main() vec3 normal = lookup_normal(inUV, inNormal, inTangent); - outPosition = vec4(inPos, 0.0); - outNormal = vec4(normalize(inNormal), 0.0); - outFlux = vec4(lights[light_index].color * base_color_opacity.xyz * comnpute_indirect_area(), 1.0); //where color is in watt/meter^2 and where outFlux is in watt + outFlux = vec4(lights[light_index].color * base_color_opacity.xyz * comnpute_pixel_area(), 1.0); //NOTE: Where color is in watt/meter^2 and where outFlux is in watt + outNormal = encode_normal(normal); } \ No newline at end of file diff --git a/res/dpr/utility/shadow_indirect.vert b/res/dpr/utility/indirect_capture.vert similarity index 82% rename from res/dpr/utility/shadow_indirect.vert rename to res/dpr/utility/indirect_capture.vert index 2eccc9c721eae4247718ace4481096620d1087da..56fa702bc96dad85633cfa672e69b79e2f32f096 100644 --- a/res/dpr/utility/shadow_indirect.vert +++ b/res/dpr/utility/indirect_capture.vert @@ -4,25 +4,25 @@ #include "light_data.inc" #include "mesh_data.inc" -layout(set = 0, binding = 0) uniform LightParameterBuffer +layout(set = 0, binding = 0) uniform MeshBuffer { - LightParameter light_parameter; + MeshData mesh; }; -layout(set = 0, binding = 1, std430) readonly buffer LightDataBuffer +layout(set = 1, binding = 0) uniform LightParameterBuffer { - LightData lights[]; + LightParameter light_parameter; }; -layout(set = 1, binding = 0) uniform MeshBuffer +layout(set = 1, binding = 1, std430) readonly buffer LightDataBuffer { - MeshData mesh; + LightData lights[]; }; layout(push_constant) uniform Constants { uint light_index; - uint indirect_resolution; + uint capture_resolution; }; layout(location = 0) in vec3 inPos; diff --git a/res/dpr/utility/indirect_injection.frag b/res/dpr/utility/indirect_injection.frag new file mode 100644 index 0000000000000000000000000000000000000000..ad92641f3d7778bb3e1df5f6347fbfbf5a9c4343 --- /dev/null +++ b/res/dpr/utility/indirect_injection.frag @@ -0,0 +1,22 @@ +#version 450 core +#extension GL_GOOGLE_include_directive : require + +#include "indirect_library.glsl" + +layout(location = 0) out vec4 outRedDistribution; +layout(location = 0) out vec4 outGreenDistribution; +layout(location = 0) out vec4 outBlueDistribution; + +layout(location = 0) in vec3 inFlux; +layout(location = 0) in vec3 inNormal; + +void main() +{ + vec3 normal = normalize(inNormal); + vec4 distribution = spherical_harmonic_cosine_lobe(normal); + + //NOTE: Where inFlux is in watt + outRedDistribution = inFlux.x * distribution; //NOTE: Additive blending + outGreenDistribution = inFlux.y * distribution; //NOTE: Additive blending + outBlueDistribution = inFlux.z * distribution; //NOTE: Additive blending +} \ No newline at end of file diff --git a/res/dpr/utility/indirect_injection.geom b/res/dpr/utility/indirect_injection.geom new file mode 100644 index 0000000000000000000000000000000000000000..4c27989fc5e2b2a845ed5cc3a9c480454ad95817 --- /dev/null +++ b/res/dpr/utility/indirect_injection.geom @@ -0,0 +1,33 @@ +#version 450 core + +#include "indirect_data.inc" + +layout(points) in; +layout(points, max_vertices = 1) out; + +layout(set = 1, binding = 3) uniform IndirectDomainBuffer +{ + IndirectDomain indirect_domain; +}; + +layout(location = 0) in vec3 inFlux[]; +layout(location = 1) in vec3 inNormal[]; + +layout(location = 0) out vec3 outFlux; +layout(location = 1) out vec3 outNormal; + +void main() +{ + vec3 position = gl_in[0].gl_Position; + position = (position - indirect_domain.min) / (indirect_domain.max - indirect_domain.min); + position.xy = position.xy * 2.0 - 1.0; + position.z = position.z * indirect_domain.resolution.z; + + outFlux = inFlux[0]; + outNormal = inNormal[0]; + gl_Position = vec3(position.xy, 0.0, 1.0); + gl_Layer = int(position.z); + + EmitVertex(); + EmitPrimitive(); +} \ No newline at end of file diff --git a/res/dpr/utility/indirect_injection.vert b/res/dpr/utility/indirect_injection.vert new file mode 100644 index 0000000000000000000000000000000000000000..bddcb199318fffba755b01ea77b2e6a85c3d021d --- /dev/null +++ b/res/dpr/utility/indirect_injection.vert @@ -0,0 +1,52 @@ +#version 450 core +#extension GL_GOOGLE_include_directive : require + +#include "light_data.inc" +#include "indirect_data.inc" +#include "math_library.glsl" + +layout(set = 0, binding = 0) uniform LightParameterBuffer +{ + LightParameter light_parameter; +}; + +layout(set = 0, binding = 1, std430) readonly buffer LightDataBuffer +{ + LightData lights[]; +}; + +layout(set = 1, binding = 0) uniform sampler2D sampler_capture_depth; +layout(set = 1, binding = 1) uniform sampler2D sampler_capture_flux; +layout(set = 1, binding = 2) uniform sampler2D sampler_capture_normal; + +layout(push_constant) uniform Constants +{ + uint light_index; + uint capture_resolution; + float cell_size; +}; + +layout(location = 0) out vec3 outFlux; +layout(location = 1) out vec3 outNormal; + +void main() +{ + ivec2 coord = ivec2(gl_VertexId / capture_resolution, gl_VertexId % capture_resolution); + + float depth = texelFetch(sampler_capture_depth, coord, 0).x; + vec3 flux = texelFetch(sampler_capture_flux, coord, 0).xyz; + vec3 normal = decode_normal(texelFetch(sampler_capture_normal, coord, 0).xy); + + vec3 screen_coord = vec3(vec2(coord + 0.5) / capture_resolution, depth); + screen_coord = (screen_coord + 1.0) / 2.0; + + vec4 position = lights[light_index].inv_shadow_matrix[0] * vec4(screen_coord, 1.0); + position /= position.w; + + //NOTE: Shift the virtual point light along the normal in order to avoid self lighting and shadowing + position += 0.5 * cell_size * normal; + + outFlux = flux; + outNormal = normal; + gl_Position = position; +} diff --git a/res/dpr/utility/indirect_library.glsl b/res/dpr/utility/indirect_library.glsl new file mode 100644 index 0000000000000000000000000000000000000000..0051b174d56e27c9cdc14587259f206e2756012b --- /dev/null +++ b/res/dpr/utility/indirect_library.glsl @@ -0,0 +1,36 @@ +#ifndef SHADER_INCLUDE_INDIRECT_LIBRARY +#define SHADER_INCLUDE_INDIRECT_LIBRARY + +#include "math_library.glsl" + +//NOTE: Standard factors for real valued spherical harmonics making them orhonormal. +#define SPHERICAL_HARMONIC_BAND0_FACTOR (0.5 * sqrt(1.0 / PI)) +#define SPHERICAL_HARMONIC_BAND1_FACTOR sqrt(3.0 / (4.0 * PI)) + +//NOTE: The given factors where computed for the function I(theta, phi) = max(cos(theta), 0) / PI. +// This function was choosen, since the integral over it is one. +// Therefore the function describes a distribution. +#define SPHERICAL_HARMONIC_COSINE_LOBE_BAND0_FACTOR (0.5 * sqrt(1.0 / PI)) +#define SPHERICAL_HARMONIC_COSINE_LOBE_BAND1_FACTOR sqrt(1.0 / (3.0 * PI)) + +//NOTE: Assume direction is allready normalize +float spherical_harmonic_evaluate(vec3 direction, vec4 spherical_harmonic) +{ + return vec4(SPHERICAL_HARMONIC_COSINE_LOBE_BAND0_FACTOR, + SPHERICAL_HARMONIC_COSINE_LOBE_BAND1_FACTOR * (-direction.y), + SPHERICAL_HARMONIC_COSINE_LOBE_BAND1_FACTOR * direction.z, + SPHERICAL_HARMONIC_COSINE_LOBE_BAND1_FACTOR * (-direction.x)); +} + +//NOTE: Assume direction is allready normalize +// The compute spherical harmonic represents the function I(theta, phi) = max(cos(theta), 0) / PI, +// when it is rotated towards "direction". +vec4 spherical_harmonic_cosine_lobe(vec3 direction) +{ + return vec4(SPHERICAL_HARMONIC_COSINE_LOBE_BAND0_FACTOR, + SPHERICAL_HARMONIC_COSINE_LOBE_BAND1_FACTOR * (-direction.y), + SPHERICAL_HARMONIC_COSINE_LOBE_BAND1_FACTOR * direction.z, + SPHERICAL_HARMONIC_COSINE_LOBE_BAND1_FACTOR * (-direction.x)); +} + +#endif \ No newline at end of file diff --git a/res/dpr/utility/indirect_propagation.comp b/res/dpr/utility/indirect_propagation.comp new file mode 100644 index 0000000000000000000000000000000000000000..787ce2759ecfc61d2762b5732f19ce89f0391084 --- /dev/null +++ b/res/dpr/utility/indirect_propagation.comp @@ -0,0 +1,138 @@ +#version 450 core +#extension GL_GOOGLE_include_directive : require + +#include "indirect_library.glsl" + +layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; + +layout(set = 0, binding = 0, rgba16f) uniform readonly image3D image_src_red_distribution; +layout(set = 0, binding = 1, rgba16f) uniform readonly image3D image_src_green_distribution; +layout(set = 0, binding = 2, rgba16f) uniform readonly image3D image_src_blue_distribution; + +layout(set = 0, binding = 3, rgba16f) uniform writeonly image3D image_dst_red_distribution; +layout(set = 0, binding = 4, rgba16f) uniform writeonly image3D image_dst_green_distribution; +layout(set = 0, binding = 5, rgba16f) uniform writeonly image3D image_dst_blue_distribution; + +layout(set = 0, binding = 6, rgba16f) uniform image3D image_red_indirect; +layout(set = 0, binding = 7, rgba16f) uniform image3D image_green_indirect; +layout(set = 0, binding = 8, rgba16f) uniform image3D image_blue_indirect; + +const ivec3 neighbour_offsets[6] = ivec3[6] +( + ivec3( 1, 0, 0), //+X + ivec3(-1, 0, 0), //-X + ivec3( 0, 1, 0), //+Y + ivec3( 0,-1, 0), //-Y + ivec3( 0, 0, 1), //+Z + ivec3( 0, 0,-1) //-Z +); + +const mat3 neighbour_orientations = mat3[6] +( + mat3(vec3(-1.0, 0.0, 0.0), vec3( 0.0, 1.0, 0.0), vec3( 0.0, 0.0, 1.0)), //+X + mat3(vec3( 1.0, 0.0, 0.0), vec3( 0.0, 1.0, 0.0), vec3( 0.0, 0.0, 1.0)), //-X + mat3(vec3( 0.0, 1.0, 0.0), vec3(-1.0, 0.0, 0.0), vec3( 0.0, 0.0, 1.0)), //+Y + mat3(vec3( 0.0, 1.0, 0.0), vec3( 1.0, 0.0, 0.0), vec3( 0.0, 0.0, 1.0)), //-Y + mat3(vec3( 0.0, 0.0, 1.0), vec3( 0.0, 1.0, 0.0), vec3(-1.0, 0.0, 0.0)), //+Z + mat3(vec3( 0.0, 0.0, 1.0), vec3( 0.0, 1.0, 0.0), vec3( 1.0, 0.0, 0.0)) //-Z +); + +//NOTE: All directions derived for the case -X +// A side eval direction correspond to the center directions of that intensity cone. +const vec3 direct_eval_direction = vec3(1.0, 0.0, 0.0); +const vec3 side_eval_directions[4] = vec3[4] +( + vec3(0.85065080, 0.52573111, 0.0), + vec3(0.85065080,-0.52573111, 0.0), + vec3(0.85065080, 0.0, 0.52573111), + vec3(0.85065080, 0.0,-0.52573111) +); + +//NOTE: All directions derived for the case -X +const vec3 direct_emit_direction = vec3(1.0, 0.0, 0.0); +const vec3 side_emit_directions[4] = vec3[4] +( + vec3(0.0, 1.0, 0.0), + vec3(0.0,-1.0, 0.0), + vec3(0.0, 0.0, 1.0), + vec3(0.0, 0.0,-1.0) +); + +//NOTE: Solid angle for direct and side face. +const float direct_solid_angle = 0.40066968; +const float side_solid_angle = 0.42343135; + +void propagate_neighbour(ivec3 cell_coord, uint neighbour, inout vec4 red_distribution, inout vec4 green_distribution, inout vec4 blue_distribution) +{ + ivec3 neighbour_coord = cell_coord + neighbour_offset[neighbour]; + mat3 neighbour_orientation = neighbour_orientations[neighbour]; + + vec4 neighbour_red_distribution = image_load(image_src_red_distribution, neighbour_coord); + vec4 neighbour_green_distribution = image_load(image_src_green_distribution, neighbour_coord); + vec4 neighbour_blue_distribution = image_load(image_src_blue_distribution, neighbour_coord); + + //----- Side Faces ---------------------------------------------- + + for(uint side = 0; side < 4; side++) + { + vec3 eval_direction = neighbour_orientation * side_eval_directions[side]; + vec3 emit_direction = neighbour_orientation * side_emit_directions[side]; + + vec3 intensity = vec3(0.0); //NOTE: Where intensity is in watt / str + intensity.x = spherical_harmonic_evaluate(eval_direction, neighbour_red_distribution); + intensity.y = spherical_harmonic_evaluate(eval_direction, neighbour_green_distribution); + intensity.z = spherical_harmonic_evaluate(eval_direction, neighbour_blue_distribution); + + //NOTE: Where side_solid_angle * intensity is in watt + red_distribution += (side_solid_angle * intensity.x) * spherical_harmonic_cosine_lobe(emit_direction); + green_distribution += (side_solid_angle * intensity.y) * spherical_harmonic_cosine_lobe(emit_direction); + bluedistribution += (side_solid_angle * intensity.z) * spherical_harmonic_cosine_lobe(emit_direction); + } + + //----- Direct Face ----------------------------------------------- + + vec3 eval_direction = neighbour_orientation * direct_eval_direction; + vec3 emit_direction = neighbour_orientation * direct_emit_direction; + + vec3 intensity = vec3(0.0); //NOTE: Where intensity is in watt / str + intensity.x = spherical_harmonic_evaluate(eval_direction, neighbour_red_distribution); + intensity.y = spherical_harmonic_evaluate(eval_direction, neighbour_green_distribution); + intensity.z = spherical_harmonic_evaluate(eval_direction, neighbour_blue_distribution); + + //NOTE: Where side_solid_angle * intensity is in watt + red_distribution += (direct_solid_angle * intensity.x) * spherical_harmonic_cosine_lobe(emit_direction); + green_distribution += (direct_solid_angle * intensity.y) * spherical_harmonic_cosine_lobe(emit_direction); + bluedistribution += (direct_solid_angle * intensity.z) * spherical_harmonic_cosine_lobe(emit_direction); + + //----------------------------------------------------------------- +} + +void main() +{ + ivec3 cell_coord = ivec3(gl_GlobalInvocationID); + + vec4 red_distribution = vec4(0.0); + vec4 green_distribution = vec4(0.0); + vec4 blue_distribution = vec4(0.0); + + for(uint neighbour = 0; neighbour < 6; neighbour++) + { + propagate_neighbour(cell_coord, neighbour, red_distribution, green_distribution, blue_distribution); + } + + image_store(image_dst_red_distribution, cell_coord, red_distribution); + image_store(image_dst_green_distribution, cell_coord, green_distribution); + image_store(image_dst_blue_distribution, cell_coord, blue_distribution); + + vec4 red_indirect = image_load(image_red_indirect, cell_coord); + vec4 green_indirect = image_load(image_green_indirect, cell_coord); + vec4 blue_indirect = image_load(image_blue_indirect, cell_coord); + + red_indirect += red_distribution; + green_indirect += green_distribution; + blue_indirect += blue_distribution; + + image_store(image_red_indirect, cell_coord, red_indirect); + image_store(image_green_indirect, cell_coord, green_indirect); + image_store(image_blue_indirect, cell_coord, blue_indirect); +} \ No newline at end of file diff --git a/res/dpr/utility/light_library.glsl b/res/dpr/utility/light_library.glsl index 562fb0eee1d175f756833b940c587a2943ed8f06..f6cd270da3e672c20193b37a120cadb2166254cd 100644 --- a/res/dpr/utility/light_library.glsl +++ b/res/dpr/utility/light_library.glsl @@ -49,71 +49,29 @@ layout(set = SHADOW_DESCRIPTOR_SET, binding = 0) uniform sampler2DArrayShadow sa layout(set = SHADOW_DESCRIPTOR_SET, binding = 1) uniform sampler2DArrayShadow sampler_shadow_spot; layout(set = SHADOW_DESCRIPTOR_SET, binding = 2) uniform samplerCubeArrayShadow sampler_shadow_point; -layout(set = SHADOW_DESCRIPTOR_SET, binding = 3) uniform sampler2DArray sampler_indirect_position_directional; -layout(set = SHADOW_DESCRIPTOR_SET, binding = 4) uniform sampler2DArray sampler_indirect_normal_directional; -layout(set = SHADOW_DESCRIPTOR_SET, binding = 5) uniform sampler2DArray sampler_indirect_flux_directional; - -layout(set = SHADOW_DESCRIPTOR_SET, binding = 6) uniform ShadowParameterBuffer +layout(set = SHADOW_DESCRIPTOR_SET, binding = 4 uniform ShadowParameterBuffer { ShadowParameter shadow_parameter; }; +#endif -layout(set = SHADOW_DESCRIPTOR_SET, binding = 7) uniform IndirectSampleBuffer +#ifdef INDIRECT_DESCRIPTOR_SET +layout(set = INDIRECT_DESCRIPTOR_SET, binding = 0) uniform sampler3D sampler_indirect_red; +layout(set = INDIRECT_DESCRIPTOR_SET, binding = 1) uniform sampler3D sampler_indirect_green; +layout(set = INDIRECT_DESCRIPTOR_SET, binding = 2) uniform sampler3D sampler_indirect_blue; + +layout(set = INDIRECT_DESCRIPTOR_SET, binding = 3) uniform IndirectDomainBuffer { - IndirectSample indirect_samples[MAX_INDIRECT_SAMPLE_COUNT]; + IndirectDomain indirect_domain; }; #endif //-- Indirect Functions ---------------------------------------------------------------------------- -#ifdef SHADOW_DESCRIPTOR_SET -//This function computes the indirect irradiance arriving at the given surface location. -//The final unit of this function is therefore (watts/meter^2). -vec2 compute_indirect_scale(uint light) +#ifdef INDIRECT_DESCRIPTOR_SET +vec3 compute_indirect(vec3 surface_position, vec3 surface_normal) { - vec2 near_size = lights[light].near_size; - return 1.0 / near_size; -} - -vec3 compute_indirect(uint light, vec3 surface_position, vec3 surface_normal) -{ - uint light_type = lights[light].type; - - if (light_type == LIGHT_TYPE_DIRECTIONAL && shadow_parameter.use_directional_indirect != 0) - { - uint layer = lights[light].type_index; - vec2 indirect_scale = compute_indirect_scale(light); - - vec4 center_position = lights[light].shadow_matrix[0] * vec4(surface_position, 1.0); - center_position /= center_position.w; - center_position.xy = (center_position.xy + 1.0) / 2.0; - - vec3 irradiance = vec3(0.0); - - for(uint index = 0; index < shadow_parameter.indirect_sample_count; index++) - { - vec2 sample_coord = center_position.xy + indirect_scale * indirect_samples[index].coord; - float sample_weight = indirect_samples[index].weight; //Assume that the sum of all weights is one - float sample_level = max(0.0, log2(length(indirect_samples[index].coord)) * 2.0); - - vec3 sample_position = textureLod(sampler_indirect_position_directional, vec3(sample_coord, layer), sample_level).xyz; - vec3 sample_normal = normalize(textureLod(sampler_indirect_normal_directional, vec3(sample_coord, layer), sample_level).xyz); - vec4 sample_flux = textureLod(sampler_indirect_flux_directional, vec3(sample_coord, layer), sample_level); - - float weight = smoothstep(0.95, 1.0, sample_flux.w); - - vec3 sample_direction = sample_position - surface_position; - float sample_distance_square = dot(sample_direction, sample_direction); - - float factor1 = 1.0;//max(0.0, dot(sample_normal, -sample_direction)); - float factor2 = max(0.0, dot(surface_normal, sample_direction)); - - irradiance += weight * (sample_flux.xyz * factor1 * factor2 * sample_weight) / pow(sample_distance_square, 2); - } - - return irradiance * 10;// * 50; - } return vec3(0.0); } @@ -165,7 +123,7 @@ float get_shadow(uint light, vec3 surface_position) { uint light_type = lights[light].type; - if (light_type == LIGHT_TYPE_DIRECTIONAL && shadow_parameter.use_directional_shadow != 0) + if (light_type == LIGHT_TYPE_DIRECTIONAL && shadow_parameter.use_directional != 0) { uint layer = lights[light].type_index; @@ -176,7 +134,7 @@ float get_shadow(uint light, vec3 surface_position) return texture(sampler_shadow_directional, vec4(shadow_position.xy, layer, shadow_position.z - 0.008)).x; } - else if (light_type == LIGHT_TYPE_SPOT && shadow_parameter.use_spot_shadow != 0) + else if (light_type == LIGHT_TYPE_SPOT && shadow_parameter.use_spot != 0) { uint layer = lights[light].type_index; @@ -187,7 +145,7 @@ float get_shadow(uint light, vec3 surface_position) return texture(sampler_shadow_spot, vec4(shadow_position.xy, layer, shadow_position.z - 0.001)).x; } - else if (light_type == LIGHT_TYPE_POINT && shadow_parameter.use_point_shadow != 0) + else if (light_type == LIGHT_TYPE_POINT && shadow_parameter.use_point != 0) { uint layer = lights[light].type_index; uint frustum = get_shadow_frustum(light, surface_position); @@ -348,9 +306,13 @@ vec3 apply_lighting(vec3 view_position, vec3 surface_position, vec3 surface_norm { vec3 lighting = material.emissive; //where emissive is in watts/meter^2 *str - if (dot(lighting, vec3(1.0)) < EPSILON) //apply direct lighting only if the material is not emissive + if (dot(lighting, vec3(1.0)) < EPSILON) //apply direct and indirect lighting only if the material is not emissive { - //lighting += material.base_color * light_parameter.ambient; //where ambient is in watts/meter^2 *str + lighting += material.base_color * light_parameter.ambient; //where ambient is in watts/meter^2 *str + +#ifdef INDIRECT_DESCRIPTOR_SET + lighting += compute_indirect(surface_position, surface_normal); +#endif for (uint light = 0; light < light_parameter.light_count; light++) { @@ -358,16 +320,11 @@ vec3 apply_lighting(vec3 view_position, vec3 surface_position, vec3 surface_norm vec3 normal_direction = normalize(surface_normal); vec3 light_direction = get_light_direction(light, surface_position); - #ifdef SHADOW_DESCRIPTOR_SET - //lighting += compute_brdf(light_direction, normal_direction, view_direction, material) * get_light_radiance(light, surface_position) * get_shadow(light, surface_position) * dot(normal_direction, light_direction); - - //Eventough the final unit of the function compute_indirect(...) is watts/meters^2, the unit can be changed to radiance. - //This is due to the fact that, that the function accumulates multiple virtual point lights. - //These virtual point light contribute like dirca impulse during the accumulation. - lighting += /*compute_brdf_diffuse(material.base_color) */ compute_indirect(light, surface_position, normal_direction); - #else +#ifdef SHADOW_DESCRIPTOR_SET + lighting += compute_brdf(light_direction, normal_direction, view_direction, material) * get_light_radiance(light, surface_position) * get_shadow(light, surface_position) * dot(normal_direction, light_direction); +#else lighting += compute_brdf(light_direction, normal_direction, view_direction, material) * get_light_radiance(light, surface_position) * dot(normal_direction, light_direction); - #endif +#endif } lighting *= (1.0 - material.occlusion); diff --git a/res/dpr/utility/shadow_indirect.geom b/res/dpr/utility/shadow_indirect.geom deleted file mode 100644 index 3e119ff410dd76cf3c0d63d06c79864fdd1d6e4e..0000000000000000000000000000000000000000 --- a/res/dpr/utility/shadow_indirect.geom +++ /dev/null @@ -1,38 +0,0 @@ -#version 450 core - -layout(triangles) in; -layout(triangle_strip, max_vertices = 3) out; - -layout(push_constant) uniform Constants -{ - uint light_index; - uint indirect_resolution; -}; - -layout(location = 0) in vec3 inPos[]; -layout(location = 1) in vec3 inNormal[]; -layout(location = 2) in vec3 inTangent[]; -layout(location = 3) in vec2 inUV[]; - -layout(location = 0) out vec3 outPos; -layout(location = 1) out vec3 outNormal; -layout(location = 2) out vec3 outTangent; -layout(location = 3) out vec2 outUV; - -void main() -{ - for (int index = 0; index < 3; index++) - { - gl_Position = gl_in[index].gl_Position; - gl_Layer = int(light_index); - - outPos = inPos[index]; - outNormal = inNormal[index]; - outTangent = inTangent[index]; - outUV = inUV[index]; - - EmitVertex(); - } - - EndPrimitive(); -} \ No newline at end of file diff --git a/res/dpr/utility/shadow_indirect_downsample.frag b/res/dpr/utility/shadow_indirect_downsample.frag deleted file mode 100644 index eef9bb708faa478c35e7cc81562aded61c2c5c13..0000000000000000000000000000000000000000 --- a/res/dpr/utility/shadow_indirect_downsample.frag +++ /dev/null @@ -1,52 +0,0 @@ -#version 450 core - -layout(location = 0) out vec4 outPosition; -layout(location = 1) out vec4 outNormal; -layout(location = 2) out vec4 outFlux; - -layout(set = 0, binding = 0) uniform sampler2DArray sampler_indirect_position; -layout(set = 0, binding = 1) uniform sampler2DArray sampler_indirect_normal; -layout(set = 0, binding = 2) uniform sampler2DArray sampler_indirect_flux; - -void main() -{ - ivec3 base_coord = ivec3(2 * ivec2(gl_FragCoord.xy), gl_Layer); - - vec3 flux = vec3(0.0); - vec3 position = vec3(0.0); - vec3 normal = vec3(0.0); - uint sample_count = 0; - - for(uint x = 0; x < 2; x++) - { - for(uint y = 0; y < 2; y++) - { - ivec3 sample_coord = base_coord + ivec3(x, y, 0); - vec3 sample_flux = texelFetch(sampler_indirect_flux, sample_coord, 0).xyz; - - if(dot(sample_flux, sample_flux) > 0.0) - { - vec3 sample_position = texelFetch(sampler_indirect_position, sample_coord, 0).xyz; - vec3 sample_normal = texelFetch(sampler_indirect_normal, sample_coord, 0).xyz; - - flux += sample_flux; - position += sample_position; - normal += normalize(sample_normal); - sample_count++; - } - } - } - - float weight = 0.0; - - if(sample_count > 0) - { - position /= float(sample_count); - normal = normalize(normal); - weight = 1.0; - } - - outPosition = vec4(position, 0.0); - outNormal = vec4(normal, 0.0); - outFlux = vec4(flux, weight); -} \ No newline at end of file diff --git a/res/dpr/utility/shadow_indirect_downsample.geom b/res/dpr/utility/shadow_indirect_downsample.geom deleted file mode 100644 index b27fe35e843b8ce51a3196ebc35d308aa6678346..0000000000000000000000000000000000000000 --- a/res/dpr/utility/shadow_indirect_downsample.geom +++ /dev/null @@ -1,19 +0,0 @@ -#version 450 core - -layout(triangles) in; -layout(triangle_strip, max_vertices = 3) out; - -layout(location = 0) in flat uint inLayer[]; - -void main() -{ - for (int index = 0; index < 3; index++) - { - gl_Position = gl_in[index].gl_Position; - gl_Layer = int(inLayer[0]); - - EmitVertex(); - } - - EndPrimitive(); -} \ No newline at end of file diff --git a/res/dpr/utility/shadow_indirect_downsample.vert b/res/dpr/utility/shadow_indirect_downsample.vert deleted file mode 100644 index 85bae227390bcc528c86f874a1d41fe2b402c2c7..0000000000000000000000000000000000000000 --- a/res/dpr/utility/shadow_indirect_downsample.vert +++ /dev/null @@ -1,11 +0,0 @@ -#version 450 core - -layout(location = 0) out flat uint outLayer; - -void main() -{ - outLayer = gl_InstanceIndex; - - vec2 coord = vec2(gl_VertexIndex % 2, gl_VertexIndex / 2); - gl_Position = vec4(coord * 2.0 - 1.0, 0.0, 1.0); -} \ No newline at end of file diff --git a/src/scene.cpp b/src/scene.cpp index 0ba440c166903ff699426e34f72e4604bc05ecba..b8c0657b1052cdb8f5a37a9a517d4a2653862be1 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -478,6 +478,16 @@ const std::vector<SceneAnimation>& Scene::get_animations() const return this->animations; } +const glm::vec3& Scene::get_scene_min() const +{ + return this->scene_min; +} + +const glm::vec3& Scene::get_scene_max() const +{ + return this->scene_max; +} + void Scene::set_vertex_input(lava::graphics_pipeline* pipeline) { pipeline->set_vertex_input_binding({ 0, sizeof(lava::vertex), VK_VERTEX_INPUT_RATE_VERTEX }); @@ -1469,14 +1479,16 @@ void Scene::compute_light_matrices(SceneLight& light) for (uint32_t index = 0; index < directions.size(); index++) { glm::mat4 view_matrix = glm::lookAt(light_data.position, light_data.position + directions[index], sides[index]); + glm::mat4 shadow_matrix = projection_matrix * view_matrix; - light_data.shadow_matrix[index] = projection_matrix * view_matrix; + light_data.shadow_matrix[index] = shadow_matrix; + light_data.inv_shadow_matrix[index] = glm::inverse(shadow_matrix); } } else if (light_data.type == LIGHT_TYPE_DIRECTIONAL) { - glm::vec3 direction = /*glm::diagonal4x4(glm::vec4(-1.0f, 1.0f, -1.0f, 1.0f)) */ glm::vec4(glm::normalize(light_data.direction), 0.0f); + glm::vec3 direction = glm::normalize(light_data.direction); glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f); if (glm::dot(direction, up) > 0.9) @@ -1514,9 +1526,11 @@ void Scene::compute_light_matrices(SceneLight& light) glm::vec2 near_size = light_max - light_min; glm::mat4 projection_matrix = glm::ortho(light_min.x, light_max.x, light_min.y, light_max.y, -light_max.z, -light_min.z); + glm::mat4 shadow_matrix = projection_matrix * view_matrix; light_data.near_size = near_size; - light_data.shadow_matrix[0] = projection_matrix * view_matrix; + light_data.shadow_matrix[0] = shadow_matrix; + light_data.inv_shadow_matrix[0] = glm::inverse(shadow_matrix); } else if (light_data.type == LIGHT_TYPE_SPOT) @@ -1537,8 +1551,10 @@ void Scene::compute_light_matrices(SceneLight& light) glm::mat4 view_matrix = glm::lookAt(position, position + direction, side); glm::mat4 projection_matrix = glm::perspective(2.0f * angle, 1.0f, 10.0f, scene_diagonal); + glm::mat4 shadow_matrix = projection_matrix * view_matrix; - light_data.shadow_matrix[0] = projection_matrix * view_matrix; + light_data.shadow_matrix[0] = shadow_matrix; + light_data.inv_shadow_matrix[0] = glm::inverse(shadow_matrix); } } diff --git a/src/scene.hpp b/src/scene.hpp index e0e3b1756c409e56d21bb905e8fd3cb9e6556299..c746abfd28d7e0aadc403bf6b07eddb5630510ba 100644 --- a/src/scene.hpp +++ b/src/scene.hpp @@ -162,6 +162,9 @@ public: const std::vector<SceneMaterial>& get_materials() const; const std::vector<SceneAnimation>& get_animations() const; + const glm::vec3& get_scene_min() const; + const glm::vec3& get_scene_max() const; + static void set_vertex_input(lava::graphics_pipeline* pipeline); static void set_vertex_input_only_position(lava::graphics_pipeline* pipeline); diff --git a/src/utility/indirect_cache.cpp b/src/utility/indirect_cache.cpp new file mode 100644 index 0000000000000000000000000000000000000000..696d75854d8997324a8d69db5409f526fe97cbc6 --- /dev/null +++ b/src/utility/indirect_cache.cpp @@ -0,0 +1,974 @@ +#include "indirect_cache.hpp" + +namespace glsl +{ + using namespace glm; + using uint = glm::uint32; + +#include "res/dpr/data/indirect_data.inc" +} + +bool IndirectCache::create(Scene::Ptr scene, const IndirectSettings& settings) +{ + lava::device_ptr device = scene->get_light_descriptor()->get_device(); + + this->compute_domain(scene, settings); + + if (!this->create_buffers(device, settings)) + { + return false; + } + + if (!this->create_images(device, settings)) + { + return false; + } + + if (!this->create_samplers(device)) + { + return false; + } + + if (!this->create_descriptors(device)) + { + return false; + } + + if (!this->create_layouts(device, scene)) + { + return false; + } + + if (!this->create_capture_pass(device, settings)) + { + return false; + } + + if (!this->create_capture_pipeline(device)) + { + return false; + } + + if (!this->create_injection_pass(device)) + { + return false; + } + + if (!this->create_injection_pipeline(device)) + { + return false; + } + + if (!this->create_propagation_pipeline(device)) + { + return false; + } + + this->scene = scene; + this->settings = settings; + + return true; +} + +void IndirectCache::destroy() +{ + //TODO: .... +} + +void IndirectCache::compute_indirect(VkCommandBuffer command_buffer, lava::index frame) +{ + const std::vector<SceneLight>& lights = this->scene->get_lights(); + + std::array<VkImageMemoryBarrier, 3> clear_begin_barriers = IndirectCache::build_barriers(0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + clear_begin_barriers[0].image = this->distribution_red_image[0]; + clear_begin_barriers[1].image = this->distribution_green_image[0]; + clear_begin_barriers[2].image = this->distribution_blue_image[0]; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, clear_begin_barriers.size(), clear_begin_barriers.data()); + + VkClearColorValue clear_color; + clear_color.float32[0] = 0.0f; + clear_color.float32[1] = 0.0f; + clear_color.float32[2] = 0.0f; + clear_color.float32[3] = 0.0f; + + VkImageSubresourceRange subresource_range; + subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + subresource_range.baseMipLevel = 0; + subresource_range.levelCount = 1; + subresource_range.baseArrayLayer = 0; + subresource_range.layerCount = 1; + + vkCmdClearColorImage(command_buffer, this->distribution_red_image[0], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color, 1, &subresource_range); + vkCmdClearColorImage(command_buffer, this->distribution_green_image[0], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color, 1, &subresource_range); + vkCmdClearColorImage(command_buffer, this->distribution_blue_image[0], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color, 1, &subresource_range); + + std::array<VkImageMemoryBarrier, 3> clear_end_barriers = IndirectCache::build_barriers(VK_ACCESS_TRANSFER_WRITE_BIT, 0, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + clear_end_barriers[0].image = this->distribution_red_image[0]; + clear_end_barriers[1].image = this->distribution_green_image[0]; + clear_end_barriers[2].image = this->distribution_blue_image[0]; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, clear_end_barriers.size(), clear_end_barriers.data()); + + for (uint32_t index = 0; index < lights.size(); index++) + { + const SceneLight& light = lights[index]; + + if (light.data.type != LIGHT_TYPE_DIRECTIONAL) + { + continue; + } + + this->frame = frame; + this->light_index = index; + this->capture_pass->process(command_buffer, 0); + this->injection_pass->process(command_buffer, 0); + } + + //NOTE: Memory barrier for source image provieded by injection render pass + // The final image layout of distribution_..._image[0] has to be VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL + + std::array<VkImageMemoryBarrier, 3> copy_barriers = IndirectCache::build_barriers(0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + copy_barriers[0].image = this->distribution_red_image[2]; + copy_barriers[1].image = this->distribution_green_image[2]; + copy_barriers[2].image = this->distribution_blue_image[2]; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, copy_barriers.size(), copy_barriers.data()); + + VkImageSubresourceLayers subresource_layers; + subresource_layers.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + subresource_layers.mipLevel = 0; + subresource_layers.baseArrayLayer = 0; + subresource_layers.layerCount = 1; + + VkOffset3D offset; + offset.x = 0; + offset.y = 0; + offset.z = 0; + + VkExtent3D extend; + extend.width = this->domain_resolution.x; + extend.height = this->domain_resolution.y; + extend.depth = this->domain_resolution.z; + + VkImageCopy image_copy; + image_copy.srcSubresource = subresource_layers; + image_copy.srcOffset = offset; + image_copy.dstSubresource = subresource_layers; + image_copy.dstOffset = offset; + image_copy.extent = extend; + + vkCmdCopyImage(command_buffer, this->distribution_red_image[0], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, this->distribution_red_image[2], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy); + vkCmdCopyImage(command_buffer, this->distribution_green_image[0], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, this->distribution_green_image[2], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy); + vkCmdCopyImage(command_buffer, this->distribution_blue_image[0], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, this->distribution_blue_image[2], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy); + + std::array<VkImageMemoryBarrier, 3> setup_src_barriers = IndirectCache::build_barriers(VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL); + setup_src_barriers[0].image = this->distribution_red_image[0]; + setup_src_barriers[1].image = this->distribution_green_image[0]; + setup_src_barriers[2].image = this->distribution_blue_image[0]; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, setup_src_barriers.size(), setup_src_barriers.data()); + + std::array<VkImageMemoryBarrier, 3> setup_dst_barriers = IndirectCache::build_barriers(0, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); + setup_dst_barriers[0].image = this->distribution_red_image[1]; + setup_dst_barriers[1].image = this->distribution_green_image[1]; + setup_dst_barriers[2].image = this->distribution_blue_image[1]; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, setup_dst_barriers.size(), setup_dst_barriers.data()); + + std::array<VkImageMemoryBarrier, 3> setup_indirect_barriers = IndirectCache::build_barriers(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL); + setup_indirect_barriers[0].image = this->distribution_red_image[2]; + setup_indirect_barriers[1].image = this->distribution_green_image[2]; + setup_indirect_barriers[2].image = this->distribution_blue_image[2]; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, setup_indirect_barriers.size(), setup_indirect_barriers.data()); + + for (uint32_t index = 0; index < this->propagation_iterations; index++) + { + uint32_t src_index = index % 2; + uint32_t dst_index = (index + 1) % 2; + + this->propagation_pipeline->bind(command_buffer); + this->propagation_layout->bind(command_buffer, this->propagation_descriptor_set[src_index]); + + vkCmdDispatch(command_buffer, this->domain_work_groups.x, this->domain_work_groups.y, this->domain_work_groups.z); + + std::array<VkImageMemoryBarrier, 3> compue_src_barriers = IndirectCache::build_barriers(VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); + compue_src_barriers[0].image = this->distribution_red_image[src_index]; + compue_src_barriers[1].image = this->distribution_green_image[src_index]; + compue_src_barriers[2].image = this->distribution_blue_image[src_index]; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, compue_src_barriers.size(), compue_src_barriers.data()); + + std::array<VkImageMemoryBarrier, 3> compute_dst_barriers = IndirectCache::build_barriers(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); + compute_dst_barriers[0].image = this->distribution_red_image[1]; + compute_dst_barriers[1].image = this->distribution_green_image[1]; + compute_dst_barriers[2].image = this->distribution_blue_image[1]; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, compute_dst_barriers.size(), compute_dst_barriers.data()); + + std::array<VkImageMemoryBarrier, 3> compute_indirect_barriers = IndirectCache::build_barriers(VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); + compute_indirect_barriers[0].image = this->distribution_red_image[2]; + compute_indirect_barriers[1].image = this->distribution_green_image[2]; + compute_indirect_barriers[2].image = this->distribution_blue_image[2]; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, compute_indirect_barriers.size(), compute_indirect_barriers.data()); + } + + std::array<VkImageMemoryBarrier, 3> final_barriers = IndirectCache::build_barriers(VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + final_barriers[0].image = this->distribution_red_image[2]; + final_barriers[1].image = this->distribution_green_image[2]; + final_barriers[2].image = this->distribution_blue_image[2]; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, final_barriers.size(), final_barriers.data()); +} + +lava::descriptor::ptr IndirectCache::get_descriptor() const +{ + return this->indirect_descriptor; +} + +VkDescriptorSet IndirectCache::get_descriptor_set() const +{ + return this->indirect_descriptor_set; +} + +const IndirectSettings& IndirectCache::get_settings() const +{ + return this->settings; +} + +void IndirectCache::compute_domain(Scene::Ptr scene, const IndirectSettings& settings) +{ + glm::vec3 scene_min = scene->get_scene_min(); + glm::vec3 scene_max = scene->get_scene_max(); + + glm::vec3 scene_center = (scene_min + scene_max) / 2.0f; + glm::vec3 scene_size = scene_max - scene_min; + + const glm::uvec3 work_group_size = glm::uvec3(16, 16, 1); + + this->domain_resolution = glm::uvec3(glm::max(glm::ceil(scene_size / settings.cell_size), glm::vec3(1.0f))); + this->domain_min = scene_center - 0.5f * settings.cell_size * glm::vec3(this->domain_resolution); + this->domain_max = scene_center + 0.5f * settings.cell_size * glm::vec3(this->domain_resolution); + this->domain_work_groups = this->domain_resolution / work_group_size; + + if ((this->domain_resolution.x % work_group_size.x) > 0) + { + this->domain_work_groups.x += 1; + } + + if ((this->domain_resolution.y % work_group_size.y) > 0) + { + this->domain_work_groups.y += 1; + } + + if ((this->domain_resolution.z % work_group_size.z) > 0) + { + this->domain_work_groups.z += 1; + } + + this->propagation_iterations = 2 * glm::max(this->domain_resolution.x, glm::max(this->domain_resolution.y, this->domain_resolution.z)); +} + +bool IndirectCache::create_buffers(lava::device_ptr device, const IndirectSettings& settings) +{ + glsl::IndirectDomain indirect_domain; + indirect_domain.resolution = this->domain_resolution; + indirect_domain.cell_size = settings.cell_size; + indirect_domain.min = this->domain_min; + indirect_domain.padding1 = 0; + indirect_domain.max = this->domain_max; + indirect_domain.padding2 = 0; + + this->domain_buffer = lava::make_buffer(); + + if (!this->domain_buffer->create_mapped(device, &indirect_domain, sizeof(indirect_domain), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)) + { + lava::log()->error("Can't create domain buffer for indirect cache!"); + + return false; + } + + return true; +} + +bool IndirectCache::create_images(lava::device_ptr device, const IndirectSettings& settings) +{ + this->capture_depth_image = lava::make_image(VK_FORMAT_D16_UNORM); + this->capture_depth_image->set_usage(VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); + + if (!this->capture_depth_image->create(device, glm::uvec2(settings.capture_resolution))) + { + lava::log()->error("Can't create depth capture image for indirect cache!"); + + return false; + } + + this->capture_flux_image = lava::make_image(VK_FORMAT_R16G16B16A16_SFLOAT); + this->capture_flux_image->set_usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); + + if (!this->capture_flux_image->create(device, glm::uvec2(settings.capture_resolution))) + { + lava::log()->error("Can't create flux capture image for indirect cache!"); + + return false; + } + + this->capture_normal_image = lava::make_image(VK_FORMAT_R16G16_UNORM); + this->capture_normal_image->set_usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); + + if (!this->capture_normal_image->create(device, glm::uvec2(settings.capture_resolution))) + { + lava::log()->error("Can't create normal capture image for indirect cache!"); + + return false; + } + + VmaAllocationCreateInfo allocation_info; + allocation_info.flags = 0; + allocation_info.usage = VMA_MEMORY_USAGE_GPU_ONLY; + allocation_info.requiredFlags = 0; + allocation_info.preferredFlags = 0; + allocation_info.memoryTypeBits = 0; + allocation_info.pool = nullptr; + allocation_info.pUserData = nullptr; + allocation_info.priority = 1.0f; + + VkImageCreateInfo image_create_info; + image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + image_create_info.pNext = nullptr; + image_create_info.flags = 0; + image_create_info.imageType = VK_IMAGE_TYPE_3D; + image_create_info.format = VK_FORMAT_R16G16B16A16_SFLOAT; + image_create_info.extent.width = this->domain_resolution.x; + image_create_info.extent.height = this->domain_resolution.y; + image_create_info.extent.depth = this->domain_resolution.z; + image_create_info.mipLevels = 1; + image_create_info.arrayLayers = 1; + image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; + image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; + image_create_info.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT; + image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + image_create_info.queueFamilyIndexCount = 0; + image_create_info.pQueueFamilyIndices = nullptr; + image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + VkImageViewCreateInfo view_create_info; + view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + view_create_info.pNext = nullptr; + view_create_info.flags = 0; + view_create_info.image = VK_NULL_HANDLE; + view_create_info.viewType = VK_IMAGE_VIEW_TYPE_3D; + view_create_info.format = VK_FORMAT_R16G16B16A16_SFLOAT; + view_create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; + view_create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + view_create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + view_create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + view_create_info.subresourceRange.baseMipLevel = 0; + view_create_info.subresourceRange.levelCount = 1; + view_create_info.subresourceRange.baseArrayLayer = 0; + view_create_info.subresourceRange.layerCount = 1; + + for (uint32_t index = 0; index < this->distribution_red_image.size(); index++) + { + VmaAllocation red_image_memory = VK_NULL_HANDLE; + VmaAllocation green_image_memory = VK_NULL_HANDLE; + VmaAllocation blue_image_memory = VK_NULL_HANDLE; + + VkImage red_image = VK_NULL_HANDLE; + VkImage green_image = VK_NULL_HANDLE; + VkImage blue_image = VK_NULL_HANDLE; + + if (vmaCreateImage(device->get_allocator()->get(), &image_create_info, &allocation_info, &red_image, &red_image_memory, nullptr) != VK_SUCCESS) + { + lava::log()->error("Can't create red distribution image for indirect cache!"); + + return false; + } + + if (vmaCreateImage(device->get_allocator()->get(), &image_create_info, &allocation_info, &green_image, &green_image_memory, nullptr) != VK_SUCCESS) + { + lava::log()->error("Can't create green distribution image for indirect cache!"); + + return false; + } + + if (vmaCreateImage(device->get_allocator()->get(), &image_create_info, &allocation_info, &blue_image, &blue_image_memory, nullptr) != VK_SUCCESS) + { + lava::log()->error("Can't create blue distribution image for indirect cache!"); + + return false; + } + + VkImageView red_image_view = VK_NULL_HANDLE; + VkImageView green_image_view = VK_NULL_HANDLE; + VkImageView blue_image_view = VK_NULL_HANDLE; + + view_create_info.image = red_image; + + if (vkCreateImageView(device->get(), &view_create_info, lava::memory::alloc(), &red_image_view) != VK_SUCCESS) + { + lava::log()->error("Can't create red distribution image view for indirect cache!"); + + return false; + } + + view_create_info.image = green_image; + + if (vkCreateImageView(device->get(), &view_create_info, lava::memory::alloc(), &green_image_view) != VK_SUCCESS) + { + lava::log()->error("Can't create green distribution image view for indirect cache!"); + + return false; + } + + view_create_info.image = blue_image; + + if (vkCreateImageView(device->get(), &view_create_info, lava::memory::alloc(), &blue_image_view) != VK_SUCCESS) + { + lava::log()->error("Can't create blue distribution image view for indirect cache!"); + + return false; + } + + this->distribution_red_image_memory[index] = red_image_memory; + this->distribution_green_image_memory[index] = green_image_memory; + this->distribution_blue_image_memory[index] = blue_image_memory; + + this->distribution_red_image[index] = red_image; + this->distribution_green_image[index] = green_image; + this->distribution_blue_image[index] = blue_image; + + this->distribution_red_image_view[index] = red_image_view; + this->distribution_green_image_view[index] = green_image_view; + this->distribution_blue_image_view[index] = blue_image_view; + } + + return true; +} + +bool IndirectCache::create_samplers(lava::device_ptr device) +{ + VkSamplerCreateInfo sampler_info; + sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + sampler_info.pNext = nullptr; + sampler_info.flags = 0; + sampler_info.magFilter = VK_FILTER_LINEAR; + sampler_info.minFilter = VK_FILTER_LINEAR; + sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + sampler_info.mipLodBias = 0.0f; + sampler_info.anisotropyEnable = VK_FALSE; + sampler_info.maxAnisotropy = 1.0f; + sampler_info.compareEnable = VK_FALSE; + sampler_info.compareOp = VK_COMPARE_OP_LESS; + sampler_info.minLod = 0.0f; + sampler_info.maxLod = VK_LOD_CLAMP_NONE; + sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; + sampler_info.unnormalizedCoordinates = VK_FALSE; + + if (vkCreateSampler(device->get(), &sampler_info, lava::memory::alloc(), &this->indirect_sampler) != VK_SUCCESS) + { + lava::log()->error("Can't create indirect sampler for indirect cache!"); + + return false; + } + + sampler_info.magFilter = VK_FILTER_NEAREST; + sampler_info.minFilter = VK_FILTER_NEAREST; + + if (vkCreateSampler(device->get(), &sampler_info, lava::memory::alloc(), &this->capture_sampler) != VK_SUCCESS) + { + lava::log()->error("Can't create capture sampler for indirect cache!"); + + return false; + } + + return true; +} + +bool IndirectCache::create_descriptors(lava::device_ptr device) +{ + lava::VkDescriptorPoolSizes descriptor_type_count = + { + { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2 }, + { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 6 }, + { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 18 } + }; + + this->descriptor_pool = lava::make_descriptor_pool(); + + if (!this->descriptor_pool->create(device, descriptor_type_count, 4)) + { + lava::log()->error("Can't create descriptor pool for indirect cache!"); + + return false; + } + + this->indirect_descriptor = lava::make_descriptor(); + this->indirect_descriptor->add_binding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT); //descriptor-binding index 0: indirect red + this->indirect_descriptor->add_binding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT); //descriptor-binding index 1: indirect green + this->indirect_descriptor->add_binding(2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT); //descriptor-binding index 2: indirect blue + this->indirect_descriptor->add_binding(3, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT); //descriptor-binding index 3: indirect domain + + if (!this->indirect_descriptor->create(device)) + { + lava::log()->error("Can't create indirect descriptor set layout for indirect cache!"); + + return false; + } + + this->injection_descriptor = lava::make_descriptor(); + this->injection_descriptor->add_binding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_VERTEX_BIT); //descriptor-binding index 0: capture depth + this->injection_descriptor->add_binding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_VERTEX_BIT); //descriptor-binding index 1: capture flux + this->injection_descriptor->add_binding(2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_VERTEX_BIT); //descriptor-binding index 2: capture normal + this->injection_descriptor->add_binding(3, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_GEOMETRY_BIT); //descriptor-binding index 3: indirect domain + + if (!this->injection_descriptor->create(device)) + { + lava::log()->error("Can't create injection descriptor set layout for indirect cache!"); + + return false; + } + + this->propagation_descriptor = lava::make_descriptor(); + this->propagation_descriptor->add_binding(0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT); //descriptor-binding index 0: image red source distribution + this->propagation_descriptor->add_binding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT); //descriptor-binding index 1: image green source distribution + this->propagation_descriptor->add_binding(2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT); //descriptor-binding index 2: image blue source distribution + + this->propagation_descriptor->add_binding(3, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT); //descriptor-binding index 3: image red destination distribution + this->propagation_descriptor->add_binding(4, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT); //descriptor-binding index 4: image green destination distribution + this->propagation_descriptor->add_binding(5, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT); //descriptor-binding index 5: image blue destination distribution + + this->propagation_descriptor->add_binding(6, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT); //descriptor-binding index 6: image red indirect + this->propagation_descriptor->add_binding(7, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT); //descriptor-binding index 7: image green indirect + this->propagation_descriptor->add_binding(8, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT); //descriptor-binding index 8: image blue indirect + + if (!this->propagation_descriptor->create(device)) + { + lava::log()->error("Can't create propagation descriptor set layout for indirect cache!"); + + return false; + } + + this->indirect_descriptor_set = this->indirect_descriptor->allocate(this->descriptor_pool->get()); + this->injection_descriptor_set = this->injection_descriptor->allocate(this->descriptor_pool->get()); + this->propagation_descriptor_set[0] = this->propagation_descriptor->allocate(this->descriptor_pool->get()); + this->propagation_descriptor_set[1] = this->propagation_descriptor->allocate(this->descriptor_pool->get()); + + std::vector<VkWriteDescriptorSet> descriptor_writes; + + //TODO: ........ + + vkUpdateDescriptorSets(device->get(), descriptor_writes.size(), descriptor_writes.data(), 0, nullptr); + + return true; +} + +bool IndirectCache::create_layouts(lava::device_ptr device, Scene::Ptr scene) +{ + VkPushConstantRange capture_range; + capture_range.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; + capture_range.offset = 0; + capture_range.size = sizeof(uint32_t) * 2; + + this->capture_layout = lava::make_pipeline_layout(); + this->capture_layout->add(scene->get_mesh_descriptor()); //set 0: mesh descriptor + this->capture_layout->add(scene->get_light_descriptor()); //set 1: light descriptor + this->capture_layout->add(scene->get_material_descriptor()); //set 2: material descriptor + this->capture_layout->add(capture_range); + + if (!this->capture_layout->create(device)) + { + lava::log()->error("Can't create capture pipeline layout for indirect cache!"); + + return false; + } + + VkPushConstantRange injection_range; + injection_range.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT; + injection_range.offset = 0; + injection_range.size = sizeof(uint32_t) * 2 + sizeof(float); + + this->injection_layout = lava::make_pipeline_layout(); + this->injection_layout->add(scene->get_light_descriptor()); //set 0: light descriptor + this->injection_layout->add(this->injection_descriptor); //set 1: injection descriptor + this->injection_layout->add(injection_range); + + if (!this->injection_layout->create(device)) + { + lava::log()->error("Can't create injection pipeline layout for indirect cache!"); + + return false; + } + + this->propagation_layout = lava::make_pipeline_layout(); + this->propagation_layout->add(this->propagation_descriptor); //set 0: propagation descriptor + + if (!this->propagation_layout->create(device)) + { + lava::log()->error("Can't create propagation pipeline layout for indirect cache!"); + + return false; + } + + return true; +} + +bool IndirectCache::create_capture_pass(lava::device_ptr device, const IndirectSettings& settings) +{ + VkClearValue clear_depth; + clear_depth.depthStencil.depth = 1.0; + clear_depth.depthStencil.stencil = 0; + + VkClearValue clear_color; + clear_color.color.float32[0] = 0.0f; + clear_color.color.float32[1] = 0.0f; + clear_color.color.float32[2] = 0.0f; + clear_color.color.float32[3] = 0.0f; + + lava::attachment::ptr depth_attachment = lava::make_attachment(VK_FORMAT_D16_UNORM); + depth_attachment->set_op(VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE); + depth_attachment->set_stencil_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE); + depth_attachment->set_layouts(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + lava::attachment::ptr flux_attachment = lava::make_attachment(VK_FORMAT_R16G16B16A16_SFLOAT); + flux_attachment->set_op(VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE); + flux_attachment->set_stencil_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE); + flux_attachment->set_layouts(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + lava::attachment::ptr normal_attachment = lava::make_attachment(VK_FORMAT_R16G16_UNORM); + normal_attachment->set_op(VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE); + normal_attachment->set_stencil_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE); + normal_attachment->set_layouts(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + VkAttachmentReference flux_attachment_reference; + flux_attachment_reference.attachment = 1; + flux_attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkAttachmentReference normal_attachment_reference; + normal_attachment_reference.attachment = 2; + normal_attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + lava::subpass::ptr subpass = lava::make_subpass(); + subpass->set_depth_stencil_attachment(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + subpass->set_color_attachments( + { + flux_attachment_reference, + normal_attachment_reference + }); + + lava::subpass_dependency::ptr subpass_begin_dependency = lava::make_subpass_dependency(VK_SUBPASS_EXTERNAL, 0); + subpass_begin_dependency->set_stage_mask(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT); + subpass_begin_dependency->set_access_mask(0, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT); + + lava::subpass_dependency::ptr subpass_end_dependency = lava::make_subpass_dependency(0, VK_SUBPASS_EXTERNAL); + subpass_end_dependency->set_stage_mask(VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + subpass_end_dependency->set_access_mask(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); + + this->capture_pass = lava::make_render_pass(device); + this->capture_pass->add(subpass); + this->capture_pass->add(subpass_begin_dependency); + this->capture_pass->add(subpass_end_dependency); + this->capture_pass->add(depth_attachment); //location 0: depth + this->capture_pass->add(flux_attachment); //location 1: flux + this->capture_pass->add(normal_attachment); //location 2: normal + this->capture_pass->set_clear_values( + { + clear_depth, + clear_color, + clear_color + }); + + lava::rect framebuffer_area = + { + glm::vec2(0.0f), + glm::vec2(settings.capture_resolution) + }; + + lava::VkImageViews framebuffer_views = + { + this->capture_depth_image->get_view(), + this->capture_flux_image->get_view(), + this->capture_normal_image->get_view() + }; + + if (!this->capture_pass->create({ framebuffer_views }, framebuffer_area)) + { + lava::log()->error("Can't create capture pass for indirect cache!"); + + return false; + } + + return true; +} + +bool IndirectCache::create_capture_pipeline(lava::device_ptr device) +{ + VkPipelineColorBlendAttachmentState blend_state; + blend_state.blendEnable = VK_FALSE; + blend_state.srcColorBlendFactor = VK_BLEND_FACTOR_ZERO; + blend_state.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; + blend_state.colorBlendOp = VK_BLEND_OP_ADD; + blend_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + blend_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + blend_state.alphaBlendOp = VK_BLEND_OP_ADD; + blend_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + this->capture_pipeline = lava::make_graphics_pipeline(device); + this->capture_pipeline->set_layout(this->capture_layout); + this->capture_pipeline->set_rasterization_front_face(VK_FRONT_FACE_CLOCKWISE); + this->capture_pipeline->set_rasterization_cull_mode(VK_CULL_MODE_BACK_BIT); + this->capture_pipeline->set_depth_test_and_write(true, true); + this->capture_pipeline->set_depth_compare_op(VK_COMPARE_OP_LESS); + this->capture_pipeline->add_color_blend_attachment(blend_state); + this->capture_pipeline->add_color_blend_attachment(blend_state); + + scene->set_vertex_input(this->capture_pipeline.get()); + + if (!this->capture_pipeline->add_shader(lava::file_data("dpr/binary/indirect_capture_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT)) + { + return false; + } + + if (!this->capture_pipeline->add_shader(lava::file_data("dpr/binary/indirect_capture_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT)) + { + return false; + } + + this->capture_pipeline->on_process = [this](VkCommandBuffer command_buffer) + { + this->pipeline_capture(command_buffer); + }; + + if (!this->capture_pipeline->create(this->capture_pass->get())) + { + return false; + } + + this->capture_pass->add_front(this->capture_pipeline); + + return true; +} + +bool IndirectCache::create_injection_pass(lava::device_ptr device) +{ + lava::attachment::ptr attachment_red = lava::make_attachment(VK_FORMAT_R16G16B16A16_SFLOAT); + attachment_red->set_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE); + attachment_red->set_stencil_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE); + attachment_red->set_layouts(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + + lava::attachment::ptr attachment_green = lava::make_attachment(VK_FORMAT_R16G16B16A16_SFLOAT); + attachment_green->set_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE); + attachment_green->set_stencil_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE); + attachment_green->set_layouts(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + + lava::attachment::ptr attachment_blue = lava::make_attachment(VK_FORMAT_R16G16B16A16_SFLOAT); + attachment_blue->set_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE); + attachment_blue->set_stencil_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE); + attachment_blue->set_layouts(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + + VkAttachmentReference attachment_red_reference; + attachment_red_reference.attachment = 0; + attachment_red_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkAttachmentReference attachment_green_reference; + attachment_green_reference.attachment = 1; + attachment_green_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkAttachmentReference attachment_blue_reference; + attachment_blue_reference.attachment = 2; + attachment_blue_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + lava::subpass::ptr subpass = lava::make_subpass(); + subpass->set_color_attachments( + { + attachment_red_reference, + attachment_green_reference, + attachment_blue_reference + }); + + lava::subpass_dependency::ptr subpass_begin_dependency = lava::make_subpass_dependency(VK_SUBPASS_EXTERNAL, 0); + subpass_begin_dependency->set_stage_mask(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); + subpass_begin_dependency->set_access_mask(0, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT); + + lava::subpass_dependency::ptr subpass_end_dependency = lava::make_subpass_dependency(0, VK_SUBPASS_EXTERNAL); + subpass_end_dependency->set_stage_mask(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + subpass_end_dependency->set_access_mask(VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT); + + this->injection_pass = lava::make_render_pass(device); + this->injection_pass->add(subpass); + this->injection_pass->add(subpass_begin_dependency); + this->injection_pass->add(subpass_end_dependency); + this->injection_pass->add(attachment_red); //location 0: distribution red + this->injection_pass->add(attachment_green); //location 1: distribution green + this->injection_pass->add(attachment_blue); //location 2: distribution blue + this->injection_pass->set_layers(this->domain_resolution.z); + + lava::rect framebuffer_area = + { + glm::vec2(0.0f), + glm::vec2(this->domain_resolution.x, this->domain_resolution.y) + }; + + lava::VkImageViews framebuffer_views = + { + this->distribution_red_image_view[0], + this->distribution_green_image_view[0], + this->distribution_blue_image_view[0], + }; + + if (!this->injection_pass->create({ framebuffer_views }, framebuffer_area)) + { + lava::log()->error("Can't create injection pass for indirect cache!"); + + return false; + } + + return true; +} + +bool IndirectCache::create_injection_pipeline(lava::device_ptr device) +{ + VkPipelineColorBlendAttachmentState blend_state; + blend_state.blendEnable = VK_TRUE; + blend_state.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; + blend_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE; + blend_state.colorBlendOp = VK_BLEND_OP_ADD; + blend_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + blend_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + blend_state.alphaBlendOp = VK_BLEND_OP_ADD; + blend_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + this->injection_pipeline = lava::make_graphics_pipeline(device); + this->injection_pipeline->set_layout(this->capture_layout); + this->injection_pipeline->set_input_assembly_topology(VK_PRIMITIVE_TOPOLOGY_POINT_LIST); + this->injection_pipeline->add_color_blend_attachment(blend_state); + this->injection_pipeline->add_color_blend_attachment(blend_state); + this->injection_pipeline->add_color_blend_attachment(blend_state); + + if (!this->injection_pipeline->add_shader(lava::file_data("dpr/binary/indirect_injection_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT)) + { + return false; + } + + if (!this->injection_pipeline->add_shader(lava::file_data("dpr/binary/indirect_injection_geometry.spirv"), VK_SHADER_STAGE_GEOMETRY_BIT)) + { + return false; + } + + if (!this->injection_pipeline->add_shader(lava::file_data("dpr/binary/indirect_injection_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT)) + { + return false; + } + + this->injection_pipeline->on_process = [this](VkCommandBuffer command_buffer) + { + this->pipeline_injection(command_buffer); + }; + + if (!this->injection_pipeline->create(this->injection_pass->get())) + { + return false; + } + + this->injection_pass->add_front(this->injection_pipeline); + + return true; +} + +bool IndirectCache::create_propagation_pipeline(lava::device_ptr device) +{ + this->propagation_pipeline = lava::make_compute_pipeline(device); + this->propagation_pipeline->set_layout(this->propagation_layout); + + if (!this->propagation_pipeline->set_shader_stage(lava::file_data("dpr/binary/indirect_propagation_compute.spirv"), VK_SHADER_STAGE_COMPUTE_BIT)) + { + return false; + } + + if (!this->propagation_pipeline->create()) + { + return false; + } + + return true; +} + +void IndirectCache::pipeline_capture(VkCommandBuffer command_buffer) +{ + std::array<uint32_t, 2> push_constants; + push_constants[0] = this->light_index; + push_constants[1] = this->settings.capture_resolution; + + vkCmdPushConstants(command_buffer, this->capture_layout->get(), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(uint32_t) * push_constants.size(), push_constants.data()); + + this->capture_layout->bind(command_buffer, this->scene->get_light_descriptor_set(this->frame), 1); + + const std::vector<SceneMaterial>& materials = this->scene->get_materials(); + + for (const SceneMesh& mesh : this->scene->get_meshes()) + { + if (!mesh.cast_shadow) + { + continue; + } + + const SceneMaterial& material = materials[mesh.material_index]; + this->capture_layout->bind(command_buffer, mesh.descriptor_set[this->frame], 0); + this->capture_layout->bind(command_buffer, material.descriptor_set, 2); + + mesh.mesh->bind_draw(command_buffer); + } +} + +void IndirectCache::pipeline_injection(VkCommandBuffer command_buffer) +{ + std::array<uint32_t, 2> push_constants; + push_constants[0] = this->light_index; + push_constants[1] = this->settings.capture_resolution; + + float cell_size = this->settings.cell_size; + + vkCmdPushConstants(command_buffer, this->capture_layout->get(), VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(uint32_t) * push_constants.size(), push_constants.data()); + vkCmdPushConstants(command_buffer, this->capture_layout->get(), VK_SHADER_STAGE_VERTEX_BIT, sizeof(uint32_t) * push_constants.size(), sizeof(cell_size), &cell_size); + + this->injection_layout->bind(command_buffer, this->scene->get_light_descriptor_set(this->frame), 0); + this->injection_layout->bind(command_buffer, this->injection_descriptor_set, 1); + + uint32_t point_count = this->settings.capture_resolution * this->settings.capture_resolution; + vkCmdDraw(command_buffer, point_count, 1, 0, 0); +} + +std::array<VkImageMemoryBarrier, 3> IndirectCache::build_barriers(VkAccessFlags src_access, VkAccessFlags dst_access, VkImageLayout old_layout, VkImageLayout new_layout) +{ + VkImageMemoryBarrier barrier; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.pNext = nullptr; + barrier.srcAccessMask = src_access; + barrier.dstAccessMask = dst_access; + barrier.oldLayout = old_layout; + barrier.newLayout = new_layout; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = VK_NULL_HANDLE; + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.subresourceRange.baseMipLevel = 0; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = 1; + + std::array<VkImageMemoryBarrier, 3> barriers; + barriers.fill(barrier); + + return barriers; +} + +IndirectCache::Ptr make_indirect_cache() +{ + return std::make_shared<IndirectCache>(); +} \ No newline at end of file diff --git a/src/utility/indirect_cache.hpp b/src/utility/indirect_cache.hpp new file mode 100644 index 0000000000000000000000000000000000000000..00a50a89e9c1e4002686f743217ebac0962c4917 --- /dev/null +++ b/src/utility/indirect_cache.hpp @@ -0,0 +1,111 @@ +#pragma once +#include <liblava/lava.hpp> +#include <glm/glm.hpp> +#include <memory> +#include <vector> +#include <array> +#include <cstdint> + +#include "scene.hpp" + +struct IndirectSettings +{ + uint32_t capture_resolution = 1024; + float cell_size = 1.0f; //Where cell size is in meters +}; + +class IndirectCache +{ +public: + typedef std::shared_ptr<IndirectCache> Ptr; + +public: + IndirectCache() = default; + + bool create(Scene::Ptr scene, const IndirectSettings& settings); + void destroy(); + + void compute_indirect(VkCommandBuffer command_buffer, lava::index frame); + + lava::descriptor::ptr get_descriptor() const; + VkDescriptorSet get_descriptor_set() const; + + const IndirectSettings& get_settings() const; + +private: + void compute_domain(Scene::Ptr scene, const IndirectSettings& settings); + + bool create_buffers(lava::device_ptr device, const IndirectSettings& settings); + bool create_images(lava::device_ptr device, const IndirectSettings& settings); + bool create_samplers(lava::device_ptr device); + bool create_descriptors(lava::device_ptr device); + bool create_layouts(lava::device_ptr device, Scene::Ptr scene); + bool create_capture_pass(lava::device_ptr device, const IndirectSettings& settings); + bool create_capture_pipeline(lava::device_ptr device); + bool create_injection_pass(lava::device_ptr device); + bool create_injection_pipeline(lava::device_ptr device); + bool create_propagation_pipeline(lava::device_ptr device); + + void pipeline_capture(VkCommandBuffer command_buffer); + void pipeline_injection(VkCommandBuffer command_buffer); + + static std::array<VkImageMemoryBarrier, 3> build_barriers(VkAccessFlags src_access, VkAccessFlags dst_access, VkImageLayout old_layout, VkImageLayout new_layout); + +private: + Scene::Ptr scene; + IndirectSettings settings; + + uint32_t frame = 0; + uint32_t light_index = 0; + + uint32_t propagation_iterations = 0; + + glm::vec3 domain_min = glm::vec3(0.0f); + glm::vec3 domain_max = glm::vec3(0.0f); + glm::uvec3 domain_resolution = glm::uvec3(0); + glm::uvec3 domain_work_groups = glm::uvec3(0); + + lava::descriptor::pool::ptr descriptor_pool; + lava::descriptor::ptr indirect_descriptor; + lava::descriptor::ptr injection_descriptor; + lava::descriptor::ptr propagation_descriptor; + + VkDescriptorSet indirect_descriptor_set = VK_NULL_HANDLE; + VkDescriptorSet injection_descriptor_set = VK_NULL_HANDLE; + std::array<VkDescriptorSet, 2> propagation_descriptor_set; + + lava::pipeline_layout::ptr capture_layout; + lava::pipeline_layout::ptr injection_layout; + lava::pipeline_layout::ptr propagation_layout; + + lava::render_pass::ptr capture_pass; + lava::render_pass::ptr injection_pass; + + lava::graphics_pipeline::ptr capture_pipeline; + lava::graphics_pipeline::ptr injection_pipeline; + lava::compute_pipeline::ptr propagation_pipeline; + + VkSampler indirect_sampler = VK_NULL_HANDLE; + VkSampler capture_sampler = VK_NULL_HANDLE; + + lava::image::ptr capture_depth_image; + lava::image::ptr capture_flux_image; + lava::image::ptr capture_normal_image; + + //NOTE: Two images for the propagation and one image for the accumulation + std::array<VmaAllocation, 3> distribution_red_image_memory; + std::array<VmaAllocation, 3> distribution_green_image_memory; + std::array<VmaAllocation, 3> distribution_blue_image_memory; + + std::array<VkImage, 3> distribution_red_image; + std::array<VkImage, 3> distribution_green_image; + std::array<VkImage, 3> distribution_blue_image; + + std::array<VkImageView, 3> distribution_red_image_view; + std::array<VkImageView, 3> distribution_green_image_view; + std::array<VkImageView, 3> distribution_blue_image_view; + + lava::buffer::ptr domain_buffer; +}; + +IndirectCache::Ptr make_indirect_cache(); \ No newline at end of file diff --git a/src/utility/shadow_cache.cpp b/src/utility/shadow_cache.cpp index 84f6c7a825200994db18967ba175e708b54092a9..e8b6df8657fa9bf4054537fe566d2b6df5ecae4a 100644 --- a/src/utility/shadow_cache.cpp +++ b/src/utility/shadow_cache.cpp @@ -1,5 +1,12 @@ #include "shadow_cache.hpp" -#include <random> + +namespace glsl +{ + using namespace glm; + using uint = glm::uint32; + +#include "res/dpr/data/shadow_data.inc" +} bool ShadowCache::create(Scene::Ptr scene, const ShadowCacheSettings& settings) { @@ -23,44 +30,16 @@ bool ShadowCache::create(Scene::Ptr scene, const ShadowCacheSettings& settings) return false; } - if (!this->create_shadow_pass(device, settings)) + if (!this->create_render_pass(device, settings)) { return false; } - if (!this->create_shadow_pipeline(device, scene)) + if (!this->create_pipeline(device, scene)) { return false; } - if (settings.use_directional_indirect) - { - if (!this->create_indirect_pass(device, settings)) - { - return false; - } - - if (!this->create_indirect_pipeline(device, scene)) - { - return false; - } - - if (!this->create_downsample_pass(device)) - { - return false; - } - - if (!this->create_downsample_pipeline(device)) - { - return false; - } - - if (!this->create_framebuffers(device, settings)) - { - return false; - } - } - return true; } @@ -73,40 +52,22 @@ void ShadowCache::destroy() lava::device_ptr device = this->scene->get_light_descriptor()->get_device(); - if (this->indirect_pipeline != nullptr) - { - this->indirect_pipeline->destroy(); - this->indirect_pipeline = nullptr; - } - - if (this->indirect_pipeline_layout != nullptr) - { - this->indirect_pipeline_layout->destroy(); - this->indirect_pipeline_layout = nullptr; - } - - if (this->indirect_pass != nullptr) - { - this->indirect_pass->destroy(); - this->indirect_pass = nullptr; - } - - if (this->shadow_pipeline != nullptr) + if (this->pipeline != nullptr) { - this->shadow_pipeline->destroy(); - this->shadow_pipeline = nullptr; + this->pipeline->destroy(); + this->pipeline = nullptr; } - if (this->shadow_pipeline_layout != nullptr) + if (this->pipeline_layout != nullptr) { - this->shadow_pipeline_layout->destroy(); - this->shadow_pipeline_layout = nullptr; + this->pipeline_layout->destroy(); + this->pipeline_layout = nullptr; } - if (this->shadow_pass != nullptr) + if (this->render_pass != nullptr) { - this->shadow_pass->destroy(); - this->shadow_pass = nullptr; + this->render_pass->destroy(); + this->render_pass = nullptr; } if (this->descriptor_set != nullptr) @@ -127,112 +88,70 @@ void ShadowCache::destroy() this->descriptor_pool = nullptr; } - if (this->shadow_view_directional != nullptr) - { - vkDestroyImageView(device->get(), this->shadow_view_directional, lava::memory::alloc()); - this->shadow_view_directional = nullptr; - } - - if (this->shadow_view_spot != nullptr) - { - vkDestroyImageView(device->get(), this->shadow_view_spot, lava::memory::alloc()); - this->shadow_view_spot = nullptr; - } - - if (this->shadow_view_point != nullptr) - { - vkDestroyImageView(device->get(), this->shadow_view_point, lava::memory::alloc()); - this->shadow_view_point = nullptr; - } - - if (this->shadow_array != nullptr) - { - this->shadow_array->destroy(); - this->shadow_array = nullptr; - } - - if (this->shadow_default_plane != nullptr) - { - this->shadow_default_plane->destroy(); - this->shadow_default_plane = nullptr; - } - - if (this->shadow_default_cube != nullptr) - { - this->shadow_default_cube->destroy(); - this->shadow_default_cube = nullptr; - } - - if (this->sampler_shadow_default != nullptr) - { - vkDestroySampler(device->get(), this->sampler_shadow_default, lava::memory::alloc()); - this->sampler_shadow_default = nullptr; - } - - if (this->sampler_shadow_directional != nullptr) + if (this->image_view_directional != nullptr) { - vkDestroySampler(device->get(), this->sampler_shadow_directional, lava::memory::alloc()); - this->sampler_shadow_directional = nullptr; + vkDestroyImageView(device->get(), this->image_view_directional, lava::memory::alloc()); + this->image_view_directional = nullptr; } - if (this->sampler_shadow_spot != nullptr) + if (this->image_view_spot != nullptr) { - vkDestroySampler(device->get(), this->sampler_shadow_spot, lava::memory::alloc()); - this->sampler_shadow_spot = nullptr; + vkDestroyImageView(device->get(), this->image_view_spot, lava::memory::alloc()); + this->image_view_spot = nullptr; } - if (this->sampler_shadow_point != nullptr) + if (this->image_view_point != nullptr) { - vkDestroySampler(device->get(), this->sampler_shadow_point, lava::memory::alloc()); - this->sampler_shadow_point = nullptr; + vkDestroyImageView(device->get(), this->image_view_point, lava::memory::alloc()); + this->image_view_point = nullptr; } - if (this->sampler_indirect_position != nullptr) + if (this->image_array != nullptr) { - vkDestroySampler(device->get(), this->sampler_indirect_position, lava::memory::alloc()); - this->sampler_indirect_position = nullptr; + this->image_array->destroy(); + this->image_array = nullptr; } - if (this->sampler_indirect_normal != nullptr) + if (this->image_default_plane != nullptr) { - vkDestroySampler(device->get(), this->sampler_indirect_normal, lava::memory::alloc()); - this->sampler_indirect_normal = nullptr; + this->image_default_plane->destroy(); + this->image_default_plane = nullptr; } - if (this->sampler_indirect_flux != nullptr) + if (this->image_default_cube != nullptr) { - vkDestroySampler(device->get(), this->sampler_indirect_flux, lava::memory::alloc()); - this->sampler_indirect_flux = nullptr; + this->image_default_cube->destroy(); + this->image_default_cube = nullptr; } - if (this->indirect_position_array != nullptr) + if (this->sampler_default != nullptr) { - this->indirect_position_array->destroy(); - this->indirect_position_array = nullptr; + vkDestroySampler(device->get(), this->sampler_default, lava::memory::alloc()); + this->sampler_default = nullptr; } - if (this->indirect_normal_array != nullptr) + if (this->sampler_directional != nullptr) { - this->indirect_normal_array->destroy(); - this->indirect_normal_array = nullptr; + vkDestroySampler(device->get(), this->sampler_directional, lava::memory::alloc()); + this->sampler_directional = nullptr; } - if (this->indirect_flux_array != nullptr) + if (this->sampler_spot != nullptr) { - this->indirect_flux_array->destroy(); - this->indirect_flux_array = nullptr; + vkDestroySampler(device->get(), this->sampler_spot, lava::memory::alloc()); + this->sampler_spot = nullptr; } - if (this->shadow_parameter_buffer != nullptr) + if (this->sampler_point != nullptr) { - this->shadow_parameter_buffer->destroy(); - this->shadow_parameter_buffer = nullptr; + vkDestroySampler(device->get(), this->sampler_point, lava::memory::alloc()); + this->sampler_point = nullptr; } - if (this->indirect_sample_buffer != nullptr) + if (this->shadow_buffer != nullptr) { - this->indirect_sample_buffer->destroy(); - this->indirect_sample_buffer = nullptr; + this->shadow_buffer->destroy(); + this->shadow_buffer = nullptr; } //Don't touch these resources. Only release the shared pointer to them. @@ -245,51 +164,24 @@ void ShadowCache::compute_shadow(VkCommandBuffer command_buffer, lava::index ind { lava::device_ptr device = scene->get_light_descriptor()->get_device(); - lava::insert_image_memory_barrier(device, command_buffer, this->shadow_default_plane->get(), 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, this->shadow_default_plane->get_subresource_range()); - lava::insert_image_memory_barrier(device, command_buffer, this->shadow_default_cube->get(), 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, this->shadow_default_cube->get_subresource_range()); - - VkClearDepthStencilValue clear_depth_value; - clear_depth_value.depth = 1.0f; - clear_depth_value.stencil = 0; + lava::insert_image_memory_barrier(device, command_buffer, this->image_default_plane->get(), 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, this->image_default_plane->get_subresource_range()); + lava::insert_image_memory_barrier(device, command_buffer, this->image_default_cube->get(), 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, this->image_default_cube->get_subresource_range()); - vkCmdClearDepthStencilImage(command_buffer, this->shadow_default_plane->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_depth_value, 1, &this->shadow_default_plane->get_subresource_range()); - vkCmdClearDepthStencilImage(command_buffer, this->shadow_default_cube->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_depth_value, 1, &this->shadow_default_plane->get_subresource_range()); + VkClearDepthStencilValue clear_value; + clear_value.depth = 1.0f; + clear_value.stencil = 0; - lava::insert_image_memory_barrier(device, command_buffer, this->shadow_default_plane->get(), VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, this->shadow_default_plane->get_subresource_range()); - lava::insert_image_memory_barrier(device, command_buffer, this->shadow_default_cube->get(), VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, this->shadow_default_cube->get_subresource_range()); + vkCmdClearDepthStencilImage(command_buffer, this->image_default_plane->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_value, 1, &this->image_default_plane->get_subresource_range()); + vkCmdClearDepthStencilImage(command_buffer, this->image_default_cube->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_value, 1, &this->image_default_cube->get_subresource_range()); - if (!this->settings.use_directional_indirect) - { - lava::insert_image_memory_barrier(device, command_buffer, this->indirect_position_array->get(), 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, this->indirect_position_array->get_subresource_range()); - lava::insert_image_memory_barrier(device, command_buffer, this->indirect_normal_array->get(), 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, this->indirect_normal_array->get_subresource_range()); - lava::insert_image_memory_barrier(device, command_buffer, this->indirect_flux_array->get(), 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, this->indirect_flux_array->get_subresource_range()); - - VkClearColorValue clear_color_value; - clear_color_value.float32[0] = 0.0f; - clear_color_value.float32[1] = 0.0f; - clear_color_value.float32[2] = 0.0f; - clear_color_value.float32[3] = 0.0f; - - vkCmdClearColorImage(command_buffer, this->indirect_position_array->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color_value, 1, &this->indirect_position_array->get_subresource_range()); - vkCmdClearColorImage(command_buffer, this->indirect_normal_array->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color_value, 1, &this->indirect_normal_array->get_subresource_range()); - vkCmdClearColorImage(command_buffer, this->indirect_flux_array->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color_value, 1, &this->indirect_flux_array->get_subresource_range()); - - lava::insert_image_memory_barrier(device, command_buffer, this->indirect_position_array->get(), VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, this->indirect_position_array->get_subresource_range()); - lava::insert_image_memory_barrier(device, command_buffer, this->indirect_normal_array->get(), VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, this->indirect_normal_array->get_subresource_range()); - lava::insert_image_memory_barrier(device, command_buffer, this->indirect_flux_array->get(), VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, this->indirect_flux_array->get_subresource_range()); - } + lava::insert_image_memory_barrier(device, command_buffer, this->image_default_plane->get(), VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, this->image_default_plane->get_subresource_range()); + lava::insert_image_memory_barrier(device, command_buffer, this->image_default_cube->get(), VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, this->image_default_cube->get_subresource_range()); this->image_default_cleared = true; } this->frame = index; - this->shadow_pass->process(command_buffer, 0); - - if (this->settings.use_directional_indirect) - { - this->indirect_pass->process(command_buffer, 0); - this->pipeline_downsample(command_buffer); - } + this->render_pass->process(command_buffer, 0); } lava::descriptor::ptr ShadowCache::get_descriptor() const @@ -307,7 +199,7 @@ const ShadowCacheSettings& ShadowCache::get_settings() const return this->settings; } -bool ShadowCache::create_image_view(lava::device_ptr device, lava::image::ptr image_array, uint32_t layer_offset, uint32_t layer_count, uint32_t level, VkImageAspectFlags aspect, VkImageViewType view_type, VkImageView& view) +bool ShadowCache::create_image_view(lava::device_ptr device, lava::image::ptr image_array, uint32_t layer_offset, uint32_t layer_count, VkImageViewType view_type, VkImageView& view) { VkComponentMapping components; components.r = VK_COMPONENT_SWIZZLE_IDENTITY; @@ -316,8 +208,8 @@ bool ShadowCache::create_image_view(lava::device_ptr device, lava::image::ptr im components.a = VK_COMPONENT_SWIZZLE_IDENTITY; VkImageSubresourceRange subresource_range; - subresource_range.aspectMask = aspect; - subresource_range.baseMipLevel = level; + subresource_range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + subresource_range.baseMipLevel = 0; subresource_range.levelCount = 1; subresource_range.baseArrayLayer = layer_offset; subresource_range.layerCount = layer_count; @@ -340,7 +232,7 @@ bool ShadowCache::create_image_view(lava::device_ptr device, lava::image::ptr im return true; } -bool ShadowCache::create_shadow_sampler(lava::device_ptr device, VkSampler& sampler) +bool ShadowCache::create_sampler(lava::device_ptr device, VkSampler& sampler) { VkSamplerCreateInfo create_info; create_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; @@ -370,58 +262,28 @@ bool ShadowCache::create_shadow_sampler(lava::device_ptr device, VkSampler& samp return true; } -bool ShadowCache::create_indirect_sampler(lava::device_ptr device, VkSampler& sampler) -{ - VkSamplerCreateInfo create_info; - create_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - create_info.pNext = nullptr; - create_info.flags = 0; - create_info.magFilter = VK_FILTER_LINEAR; - create_info.minFilter = VK_FILTER_LINEAR; - create_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - create_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - create_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - create_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - create_info.mipLodBias = 0.0f; - create_info.anisotropyEnable = VK_FALSE; - create_info.maxAnisotropy = 1.0f; - create_info.compareEnable = VK_FALSE; - create_info.compareOp = VK_COMPARE_OP_LESS; - create_info.minLod = 0; - create_info.maxLod = VK_LOD_CLAMP_NONE; - create_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; - create_info.unnormalizedCoordinates = VK_FALSE; - - if (vkCreateSampler(device->get(), &create_info, lava::memory::alloc(), &sampler) != VK_SUCCESS) - { - return false; - } - - return true; -} - bool ShadowCache::create_images(lava::device_ptr device, Scene::Ptr scene, const ShadowCacheSettings& settings) { - this->shadow_default_plane = std::make_shared<lava::image>(VK_FORMAT_D16_UNORM); - this->shadow_default_plane->set_layer_count(1); - this->shadow_default_plane->set_view_type(VK_IMAGE_VIEW_TYPE_2D_ARRAY); + this->image_default_plane = std::make_shared<lava::image>(VK_FORMAT_D16_UNORM); + this->image_default_plane->set_layer_count(1); + this->image_default_plane->set_view_type(VK_IMAGE_VIEW_TYPE_2D_ARRAY); - if (!this->shadow_default_plane->create(device, lava::uv2(1, 1))) + if (!this->image_default_plane->create(device, lava::uv2(1, 1))) { return false; } - this->shadow_default_cube = std::make_shared<lava::image>(VK_FORMAT_D16_UNORM); - this->shadow_default_cube->set_layer_count(6); - this->shadow_default_cube->set_view_type(VK_IMAGE_VIEW_TYPE_CUBE_ARRAY); - this->shadow_default_cube->set_flags(VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT); + this->image_default_cube = std::make_shared<lava::image>(VK_FORMAT_D16_UNORM); + this->image_default_cube->set_layer_count(6); + this->image_default_cube->set_view_type(VK_IMAGE_VIEW_TYPE_CUBE_ARRAY); + this->image_default_cube->set_flags(VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT); - if (!this->shadow_default_cube->create(device, lava::uv2(1, 1))) + if (!this->image_default_cube->create(device, lava::uv2(1, 1))) { return false; } - if (!this->create_shadow_sampler(device, this->sampler_shadow_default)) + if (!this->create_sampler(device, this->sampler_default)) { return false; } @@ -451,29 +313,29 @@ bool ShadowCache::create_images(lava::device_ptr device, Scene::Ptr scene, const uint32_t layer_count = directional_count + spot_count + 6 * point_count; uint32_t layer_offset = 0; - this->shadow_array = lava::make_image(VK_FORMAT_D16_UNORM); - this->shadow_array->set_layer_count(layer_count); - this->shadow_array->set_view_type(VK_IMAGE_VIEW_TYPE_2D_ARRAY); - this->shadow_array->set_usage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); + this->image_array = std::make_shared<lava::image>(VK_FORMAT_D16_UNORM); + this->image_array->set_layer_count(layer_count); + this->image_array->set_view_type(VK_IMAGE_VIEW_TYPE_2D_ARRAY); + this->image_array->set_usage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); if (point_count > 0) { - this->shadow_array->set_flags(VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT); + this->image_array->set_flags(VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT); } - if (!this->shadow_array->create(device, lava::uv2(settings.resolution))) + if (!this->image_array->create(device, lava::uv2(settings.resolution))) { return false; } if (directional_count > 0) { - if (!this->create_image_view(device, this->shadow_array, layer_offset, directional_count, 0, VK_IMAGE_ASPECT_DEPTH_BIT, VK_IMAGE_VIEW_TYPE_2D_ARRAY, this->shadow_view_directional)) + if (!this->create_image_view(device, this->image_array, layer_offset, directional_count, VK_IMAGE_VIEW_TYPE_2D_ARRAY, this->image_view_directional)) { return false; } - if (!this->create_shadow_sampler(device, this->sampler_shadow_directional)) + if (!this->create_sampler(device, this->sampler_directional)) { return false; } @@ -484,12 +346,12 @@ bool ShadowCache::create_images(lava::device_ptr device, Scene::Ptr scene, const if (spot_count > 0) { - if (!this->create_image_view(device, this->shadow_array, layer_offset, spot_count, 0, VK_IMAGE_ASPECT_DEPTH_BIT, VK_IMAGE_VIEW_TYPE_2D_ARRAY, this->shadow_view_spot)) + if (!this->create_image_view(device, this->image_array, layer_offset, spot_count, VK_IMAGE_VIEW_TYPE_2D_ARRAY, this->image_view_spot)) { return false; } - if (!this->create_shadow_sampler(device, this->sampler_shadow_spot)) + if (!this->create_sampler(device, this->sampler_spot)) { return false; } @@ -500,12 +362,12 @@ bool ShadowCache::create_images(lava::device_ptr device, Scene::Ptr scene, const if (point_count > 0) { - if (!this->create_image_view(device, this->shadow_array, layer_offset, point_count * 6, 0, VK_IMAGE_ASPECT_DEPTH_BIT, VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, this->shadow_view_point)) + if (!this->create_image_view(device, this->image_array, layer_offset, point_count * 6, VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, this->image_view_point)) { return false; } - if (!this->create_shadow_sampler(device, this->sampler_shadow_point)) + if (!this->create_sampler(device, this->sampler_point)) { return false; } @@ -514,128 +376,19 @@ bool ShadowCache::create_images(lava::device_ptr device, Scene::Ptr scene, const layer_offset += point_count * 6; } - uint32_t indirect_resolution = 1; - uint32_t indirect_layers = 1; - uint32_t indirect_levels = 1; - - if (settings.use_directional_indirect) - { - indirect_resolution = settings.resolution; - indirect_layers = glm::max(indirect_layers, directional_count); - - uint32_t mipmap_resolution = indirect_resolution; - - while (mipmap_resolution > 1) - { - mipmap_resolution >>= 1; - indirect_levels++; - } - } - - this->indirect_position_array = lava::make_image(VK_FORMAT_R16G16B16A16_SFLOAT); - this->indirect_position_array->set_layer_count(indirect_layers); - this->indirect_position_array->set_level_count(indirect_levels); - this->indirect_position_array->set_view_type(VK_IMAGE_VIEW_TYPE_2D_ARRAY); - this->indirect_position_array->set_usage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); - - if (!this->indirect_position_array->create(device, lava::uv2(indirect_resolution))) - { - return false; - } - - if (!this->create_indirect_sampler(device, this->sampler_indirect_position)) - { - return false; - } - - this->indirect_normal_array = lava::make_image(VK_FORMAT_R16G16B16A16_SFLOAT); - this->indirect_normal_array->set_layer_count(indirect_layers); - this->indirect_normal_array->set_level_count(indirect_levels); - this->indirect_normal_array->set_view_type(VK_IMAGE_VIEW_TYPE_2D_ARRAY); - this->indirect_normal_array->set_usage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); - - if (!this->indirect_normal_array->create(device, lava::uv2(indirect_resolution))) - { - return false; - } - - if (!this->create_indirect_sampler(device, this->sampler_indirect_normal)) - { - return false; - } - - this->indirect_flux_array = lava::make_image(VK_FORMAT_R16G16B16A16_SFLOAT); - this->indirect_flux_array->set_layer_count(indirect_layers); - this->indirect_flux_array->set_level_count(indirect_levels); - this->indirect_flux_array->set_view_type(VK_IMAGE_VIEW_TYPE_2D_ARRAY); - this->indirect_flux_array->set_usage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); - - if (!this->indirect_flux_array->create(device, lava::uv2(indirect_resolution))) - { - return false; - } - - if (!this->create_indirect_sampler(device, this->sampler_indirect_flux)) - { - return false; - } - - for (uint32_t level = 0; level < indirect_levels; level++) - { - VkImageView indirect_position_view = VK_NULL_HANDLE; - VkImageView indirect_normal_view = VK_NULL_HANDLE; - VkImageView indirect_flux_view = VK_NULL_HANDLE; - - if (!this->create_image_view(device, this->indirect_position_array, 0, indirect_layers, level, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_VIEW_TYPE_2D_ARRAY, indirect_position_view)) - { - return false; - } - - if (!this->create_image_view(device, this->indirect_normal_array, 0, indirect_layers, level, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_VIEW_TYPE_2D_ARRAY, indirect_normal_view)) - { - return false; - } - - if (!this->create_image_view(device, this->indirect_flux_array, 0, indirect_layers, level, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_VIEW_TYPE_2D_ARRAY, indirect_flux_view)) - { - return false; - } - - indirect_position_views.push_back(indirect_position_view); - indirect_normal_views.push_back(indirect_normal_view); - indirect_flux_views.push_back(indirect_flux_view); - } - return true; } bool ShadowCache::create_buffers(lava::device_ptr device, const ShadowCacheSettings& settings) { - if (settings.indirect_sample_count > MAX_INDIRECT_SAMPLE_COUNT) - { - lava::log()->error("Maximal number of indirect samples exceeded!"); - - return false; - } - glsl::ShadowParameter shadow_parameter; - shadow_parameter.use_directional_shadow = settings.use_directional_shadow ? 1 : 0; - shadow_parameter.use_directional_indirect = settings.use_directional_indirect ? 1 : 0; - shadow_parameter.use_spot_shadow = settings.use_spot_shadow ? 1 : 0; - shadow_parameter.use_point_shadow = settings.use_point_shadow ? 1 : 0; - shadow_parameter.indirect_sample_count = settings.indirect_sample_count; - - this->shadow_parameter_buffer = lava::make_buffer(); - - if (!this->shadow_parameter_buffer->create_mapped(device, &shadow_parameter, sizeof(glsl::ShadowParameter), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)) - { - return false; - } + shadow_parameter.use_directional = settings.use_directional ? 1 : 0; + shadow_parameter.use_spot = settings.use_spot ? 1 : 0; + shadow_parameter.use_point = settings.use_point ? 1 : 0; - std::vector<glsl::IndirectSample> samples = ShadowCache::compute_indirect_samples(settings); - this->indirect_sample_buffer = lava::make_buffer(); + this->shadow_buffer = lava::make_buffer(); - if(!this->indirect_sample_buffer->create_mapped(device, samples.data(), samples.size() * sizeof(glsl::IndirectSample), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)) + if (!this->shadow_buffer->create_mapped(device, &shadow_parameter, sizeof(glsl::ShadowParameter), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)) { return false; } @@ -645,17 +398,15 @@ bool ShadowCache::create_buffers(lava::device_ptr device, const ShadowCacheSetti bool ShadowCache::create_descriptors(lava::device_ptr device) { - uint32_t indirect_levels = this->indirect_position_views.size(); - lava::VkDescriptorPoolSizes descriptor_type_count = { - { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2 }, - { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 6 + indirect_levels * 3} + { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1 }, + { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 3 } }; this->descriptor_pool = lava::make_descriptor_pool(); - if (!this->descriptor_pool->create(device, descriptor_type_count, 1 + indirect_levels)) + if (!this->descriptor_pool->create(device, descriptor_type_count, 1)) { return false; } @@ -664,11 +415,7 @@ bool ShadowCache::create_descriptors(lava::device_ptr device) this->descriptor->add_binding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT); //descriptor-binding index 0: directional image array this->descriptor->add_binding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT); //descriptor-binding index 1: spot image array this->descriptor->add_binding(2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT); //descriptor-binding index 2: point image array - this->descriptor->add_binding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT); //descriptor-binding index 3: indirect position array - this->descriptor->add_binding(4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT); //descriptor-binding index 4: indirect normal array - this->descriptor->add_binding(5, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT); //descriptor-binding index 5: indirect flux array - this->descriptor->add_binding(6, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT); //descriptor-binding index 6: shadow parameter buffer - this->descriptor->add_binding(7, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT); //descriptor-binding index 7: indirect sample buffer + this->descriptor->add_binding(3, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT); //descriptor-binding index 3: shadow buffer if (!this->descriptor->create(device)) { @@ -677,69 +424,43 @@ bool ShadowCache::create_descriptors(lava::device_ptr device) this->descriptor_set = this->descriptor->allocate(this->descriptor_pool->get()); - std::array<VkDescriptorImageInfo, 6> image_infos; - std::array<VkDescriptorBufferInfo, 2> buffer_infos; + std::array<VkDescriptorImageInfo, 3> image_infos; VkDescriptorImageInfo& directional_image_info = image_infos[0]; - directional_image_info.sampler = this->sampler_shadow_default; - directional_image_info.imageView = this->shadow_default_plane->get_view(); + directional_image_info.sampler = this->sampler_default; + directional_image_info.imageView = this->image_default_plane->get_view(); directional_image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; VkDescriptorImageInfo& spot_image_info = image_infos[1]; - spot_image_info.sampler = this->sampler_shadow_default; - spot_image_info.imageView = this->shadow_default_plane->get_view(); + spot_image_info.sampler = this->sampler_default; + spot_image_info.imageView = this->image_default_plane->get_view(); spot_image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; VkDescriptorImageInfo& point_image_info = image_infos[2]; - point_image_info.sampler = this->sampler_shadow_default; - point_image_info.imageView = this->shadow_default_cube->get_view(); + point_image_info.sampler = this->sampler_default; + point_image_info.imageView = this->image_default_cube->get_view(); point_image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - if (this->shadow_view_directional != nullptr) + if (this->image_view_directional != nullptr) { - directional_image_info.sampler = this->sampler_shadow_directional; - directional_image_info.imageView = this->shadow_view_directional; + directional_image_info.sampler = this->sampler_directional; + directional_image_info.imageView = this->image_view_directional; } - if (this->shadow_view_spot != nullptr) + if (this->image_view_spot != nullptr) { - spot_image_info.sampler = this->sampler_shadow_spot; - spot_image_info.imageView = this->shadow_view_spot; + spot_image_info.sampler = this->sampler_spot; + spot_image_info.imageView = this->image_view_spot; } - if (this->shadow_view_point != nullptr) + if (this->image_view_point != nullptr) { - point_image_info.sampler = this->sampler_shadow_point; - point_image_info.imageView = this->shadow_view_point; + point_image_info.sampler = this->sampler_point; + point_image_info.imageView = this->image_view_point; } - VkDescriptorImageInfo& indirect_position_info = image_infos[3]; - indirect_position_info.sampler = this->sampler_indirect_position; - indirect_position_info.imageView = this->indirect_position_array->get_view(); - indirect_position_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - VkDescriptorImageInfo& indirect_normal_info = image_infos[4]; - indirect_normal_info.sampler = this->sampler_indirect_normal; - indirect_normal_info.imageView = this->indirect_normal_array->get_view(); - indirect_normal_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - VkDescriptorImageInfo& indirect_flux_info = image_infos[5]; - indirect_flux_info.sampler = this->sampler_indirect_flux; - indirect_flux_info.imageView = this->indirect_flux_array->get_view(); - indirect_flux_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - VkDescriptorBufferInfo& shadow_parameter_info = buffer_infos[0]; - shadow_parameter_info.buffer = this->shadow_parameter_buffer->get(); - shadow_parameter_info.offset = 0; - shadow_parameter_info.range = VK_WHOLE_SIZE; - - VkDescriptorBufferInfo& indirect_sample_info = buffer_infos[1]; - indirect_sample_info.buffer = this->indirect_sample_buffer->get(); - indirect_sample_info.offset = 0; - indirect_sample_info.range = VK_WHOLE_SIZE; - std::vector<VkWriteDescriptorSet> descriptor_writes; - descriptor_writes.resize(image_infos.size() + buffer_infos.size()); + descriptor_writes.resize(image_infos.size() + 1); for (uint32_t index = 0; index < image_infos.size(); index++) { @@ -756,125 +477,35 @@ bool ShadowCache::create_descriptors(lava::device_ptr device) descriptor_write.pTexelBufferView = nullptr; } - for (uint32_t index = 0; index < buffer_infos.size(); index++) - { - uint32_t offset = image_infos.size() + index; + VkDescriptorBufferInfo buffer_info; + buffer_info.buffer = this->shadow_buffer->get(); + buffer_info.offset = 0; + buffer_info.range = VK_WHOLE_SIZE; - VkWriteDescriptorSet& descriptor_write = descriptor_writes[offset]; - descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptor_write.pNext = nullptr; - descriptor_write.dstSet = this->descriptor_set; - descriptor_write.dstBinding = offset; - descriptor_write.dstArrayElement = 0; - descriptor_write.descriptorCount = 1; - descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - descriptor_write.pImageInfo = nullptr; - descriptor_write.pBufferInfo = &buffer_infos[index]; - descriptor_write.pTexelBufferView = nullptr; - } + VkWriteDescriptorSet& descriptor_write = descriptor_writes.back(); + descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptor_write.pNext = nullptr; + descriptor_write.dstSet = this->descriptor_set; + descriptor_write.dstBinding = 3; + descriptor_write.dstArrayElement = 0; + descriptor_write.descriptorCount = 1; + descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptor_write.pImageInfo = nullptr; + descriptor_write.pBufferInfo = &buffer_info; + descriptor_write.pTexelBufferView = nullptr; vkUpdateDescriptorSets(device->get(), descriptor_writes.size(), descriptor_writes.data(), 0, nullptr); - this->downsample_descriptor = lava::make_descriptor(); - this->downsample_descriptor->add_binding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT); //descriptor-binding index 0: indirect position array - this->downsample_descriptor->add_binding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT); //descriptor-binding index 1: indirect normal array - this->downsample_descriptor->add_binding(2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT); //descriptor-binding index 2: indirect flux array - - if (!this->downsample_descriptor->create(device)) - { - return false; - } - - for (uint32_t level = 0; level < indirect_levels; level++) - { - VkDescriptorSet downsample_descriptor_set = this->downsample_descriptor->allocate(this->descriptor_pool->get()); - this->downsample_descriptor_sets.push_back(downsample_descriptor_set); - - std::array<VkDescriptorImageInfo, 3> image_level_infos; - - VkDescriptorImageInfo& indirect_position_level_info = image_level_infos[0]; - indirect_position_level_info.sampler = this->sampler_indirect_position; - indirect_position_level_info.imageView = this->indirect_position_views[level]; - indirect_position_level_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - VkDescriptorImageInfo& indirect_normal_level_info = image_level_infos[1]; - indirect_normal_level_info.sampler = this->sampler_indirect_normal; - indirect_normal_level_info.imageView = this->indirect_normal_views[level]; - indirect_normal_level_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - VkDescriptorImageInfo& indirect_flux_level_info = image_level_infos[2]; - indirect_flux_level_info.sampler = this->sampler_indirect_flux; - indirect_flux_level_info.imageView = this->indirect_flux_views[level]; - indirect_flux_level_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - std::array<VkWriteDescriptorSet, 3> descriptor_level_writes; - - for (uint32_t index = 0; index < descriptor_level_writes.size(); index++) - { - VkWriteDescriptorSet& descriptor_write = descriptor_level_writes[index]; - descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptor_write.pNext = nullptr; - descriptor_write.dstSet = downsample_descriptor_set; - descriptor_write.dstBinding = index; - descriptor_write.dstArrayElement = 0; - descriptor_write.descriptorCount = 1; - descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - descriptor_write.pImageInfo = &image_level_infos[index]; - descriptor_write.pBufferInfo = nullptr; - descriptor_write.pTexelBufferView = nullptr; - } - - vkUpdateDescriptorSets(device->get(), descriptor_level_writes.size(), descriptor_level_writes.data(), 0, nullptr); - } - - return true; -} - -bool ShadowCache::create_framebuffers(lava::device_ptr device, const ShadowCacheSettings& settings) -{ - uint32_t indirect_levels = this->indirect_position_views.size(); - uint32_t indirect_layers = this->indirect_position_array->get_info().arrayLayers; - - for (uint32_t level = 0; level < indirect_levels; level++) - { - std::array<VkImageView, 3> attachments = - { - this->indirect_position_views[level], - this->indirect_normal_views[level], - this->indirect_flux_views[level] - }; - - VkFramebufferCreateInfo create_info; - create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - create_info.pNext = nullptr; - create_info.flags = 0; - create_info.renderPass = this->downsample_pass->get(); - create_info.attachmentCount = attachments.size(); - create_info.pAttachments = attachments.data(); - create_info.width = settings.resolution >> level; - create_info.height = settings.resolution >> level; - create_info.layers = indirect_layers; - - VkFramebuffer framebuffer = VK_NULL_HANDLE; - - if (vkCreateFramebuffer(device->get(), &create_info, lava::memory::alloc(), &framebuffer) != VK_SUCCESS) - { - return false; - } - - this->downsample_framebuffers.push_back(framebuffer); - } - return true; } -bool ShadowCache::create_shadow_pass(lava::device_ptr device, const ShadowCacheSettings& settings) +bool ShadowCache::create_render_pass(lava::device_ptr device, const ShadowCacheSettings& settings) { VkClearValue clear_value; clear_value.depthStencil.depth = 1.0; clear_value.depthStencil.stencil = 0; - lava::attachment::ptr attachment = lava::make_attachment(this->shadow_array->get_format()); + lava::attachment::ptr attachment = lava::make_attachment(this->image_array->get_format()); attachment->set_op(VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE); attachment->set_stencil_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE); attachment->set_layouts(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); @@ -890,13 +521,13 @@ bool ShadowCache::create_shadow_pass(lava::device_ptr device, const ShadowCacheS subpass_end_dependency->set_stage_mask(VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); subpass_end_dependency->set_access_mask(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); - this->shadow_pass = lava::make_render_pass(device); - this->shadow_pass->add(subpass); - this->shadow_pass->add(subpass_begin_dependency); - this->shadow_pass->add(subpass_end_dependency); - this->shadow_pass->add(attachment); //location 0: shadow array - this->shadow_pass->set_layers(this->shadow_array->get_info().arrayLayers); - this->shadow_pass->set_clear_values( + this->render_pass = lava::make_render_pass(device); + this->render_pass->add(subpass); + this->render_pass->add(subpass_begin_dependency); + this->render_pass->add(subpass_end_dependency); + this->render_pass->add(attachment); //location 0: image array + this->render_pass->set_layers(this->image_array->get_info().arrayLayers); + this->render_pass->set_clear_values( { clear_value }); @@ -909,10 +540,10 @@ bool ShadowCache::create_shadow_pass(lava::device_ptr device, const ShadowCacheS lava::VkImageViews framebuffer_views = { - this->shadow_array->get_view() + this->image_array->get_view() }; - if (!this->shadow_pass->create({ framebuffer_views }, framebuffer_area)) + if (!this->render_pass->create({ framebuffer_views }, framebuffer_area)) { return false; } @@ -920,422 +551,79 @@ bool ShadowCache::create_shadow_pass(lava::device_ptr device, const ShadowCacheS return true; } -bool ShadowCache::create_shadow_pipeline(lava::device_ptr device, Scene::Ptr scene) +bool ShadowCache::create_pipeline(lava::device_ptr device, Scene::Ptr scene) { VkPushConstantRange push_range; push_range.offset = 0; push_range.size = sizeof(uint32_t) * 3; //layer-index, light-index, frustum-index push_range.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT; - this->shadow_pipeline_layout = lava::make_pipeline_layout(); - this->shadow_pipeline_layout->add_push_constant_range(push_range); - this->shadow_pipeline_layout->add(scene->get_light_descriptor()); //descriptor-set index 0: light-buffer - this->shadow_pipeline_layout->add(scene->get_mesh_descriptor()); //descriptor-set index 1: mesh-buffer - - if (!this->shadow_pipeline_layout->create(device)) - { - return false; - } - - this->shadow_pipeline = lava::make_graphics_pipeline(device); - this->shadow_pipeline->set_layout(this->shadow_pipeline_layout); - this->shadow_pipeline->set_rasterization_front_face(VK_FRONT_FACE_CLOCKWISE); - this->shadow_pipeline->set_rasterization_cull_mode(VK_CULL_MODE_BACK_BIT); - this->shadow_pipeline->set_depth_test_and_write(true, true); - this->shadow_pipeline->set_depth_compare_op(VK_COMPARE_OP_LESS); - - scene->set_vertex_input_only_position(this->shadow_pipeline.get()); - - if (!this->shadow_pipeline->add_shader(lava::file_data("dpr/binary/shadow_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT)) - { - return false; - } - - if (!this->shadow_pipeline->add_shader(lava::file_data("dpr/binary/shadow_geometry.spirv"), VK_SHADER_STAGE_GEOMETRY_BIT)) - { - return false; - } - - this->shadow_pipeline->on_process = [this](VkCommandBuffer command_buffer) - { - this->pipeline_shadow(command_buffer); - }; - - if (!this->shadow_pipeline->create(this->shadow_pass->get())) - { - return false; - } - - this->shadow_pass->add_front(this->shadow_pipeline); - - return true; -} - -bool ShadowCache::create_indirect_pass(lava::device_ptr device, const ShadowCacheSettings& settings) -{ - VkClearValue clear_depth; - clear_depth.depthStencil.depth = 1.0; - clear_depth.depthStencil.stencil = 0; - - VkClearValue clear_color; - clear_color.color.float32[0] = 0.0f; - clear_color.color.float32[1] = 0.0f; - clear_color.color.float32[2] = 0.0f; - clear_color.color.float32[3] = 0.0f; - - lava::attachment::ptr depth_attachment = lava::make_attachment(this->shadow_array->get_format()); - depth_attachment->set_op(VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE); - depth_attachment->set_stencil_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE); - depth_attachment->set_layouts(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - - lava::attachment::ptr position_attachment = lava::make_attachment(this->indirect_position_array->get_format()); - position_attachment->set_op(VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE); - position_attachment->set_stencil_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE); - position_attachment->set_layouts(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - - lava::attachment::ptr normal_attachment = lava::make_attachment(this->indirect_normal_array->get_format()); - normal_attachment->set_op(VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE); - normal_attachment->set_stencil_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE); - normal_attachment->set_layouts(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - - lava::attachment::ptr flux_attachment = lava::make_attachment(this->indirect_flux_array->get_format()); - flux_attachment->set_op(VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE); - flux_attachment->set_stencil_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE); - flux_attachment->set_layouts(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - - VkAttachmentReference position_attachment_reference; - position_attachment_reference.attachment = 1; - position_attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - VkAttachmentReference normal_attachment_reference; - normal_attachment_reference.attachment = 2; - normal_attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - VkAttachmentReference flux_attachment_reference; - flux_attachment_reference.attachment = 3; - flux_attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - lava::subpass::ptr subpass = lava::make_subpass(); - subpass->set_depth_stencil_attachment(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - subpass->set_color_attachments( - { - position_attachment_reference, - normal_attachment_reference, - flux_attachment_reference - }); - - lava::subpass_dependency::ptr subpass_begin_dependency = lava::make_subpass_dependency(VK_SUBPASS_EXTERNAL, 0); - subpass_begin_dependency->set_stage_mask(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); - subpass_begin_dependency->set_access_mask(0, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT); - - lava::subpass_dependency::ptr subpass_end_dependency = lava::make_subpass_dependency(0, VK_SUBPASS_EXTERNAL); - subpass_end_dependency->set_stage_mask(VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - subpass_end_dependency->set_access_mask(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); - - this->indirect_pass = lava::make_render_pass(device); - this->indirect_pass->add(subpass); - this->indirect_pass->add(subpass_begin_dependency); - this->indirect_pass->add(subpass_end_dependency); - this->indirect_pass->add(depth_attachment); //location 0: shadow array - this->indirect_pass->add(position_attachment); //location 1: indirect position array - this->indirect_pass->add(normal_attachment); //location 2: indirect normal array - this->indirect_pass->add(flux_attachment); //location 3: indirect flux array - this->indirect_pass->set_layers(this->indirect_position_array->get_info().arrayLayers); - this->indirect_pass->set_clear_values( - { - clear_depth, - clear_color, - clear_color, - clear_color - }); - - lava::rect framebuffer_area = - { - glm::vec2(0.0f), - glm::vec2(settings.resolution) - }; - - lava::VkImageViews framebuffer_views = - { - this->shadow_view_directional, - this->indirect_position_views[0], - this->indirect_normal_views[0], - this->indirect_flux_views[0] - }; - - if (!this->indirect_pass->create({ framebuffer_views }, framebuffer_area)) - { - return false; - } - - return true; -} - -bool ShadowCache::create_indirect_pipeline(lava::device_ptr device, Scene::Ptr scene) -{ - VkPushConstantRange push_range; - push_range.offset = 0; - push_range.size = sizeof(uint32_t) * 2; //light-index, indirect-resolution - push_range.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; - - this->indirect_pipeline_layout = lava::make_pipeline_layout(); - this->indirect_pipeline_layout->add_push_constant_range(push_range); - this->indirect_pipeline_layout->add(scene->get_light_descriptor()); //descriptor-set index 0: light-buffer - this->indirect_pipeline_layout->add(scene->get_mesh_descriptor()); //descriptor-set index 1: mesh-buffer - this->indirect_pipeline_layout->add(scene->get_material_descriptor()); //descriptor-set index 2: material-buffer - - if (!this->indirect_pipeline_layout->create(device)) - { - return false; - } - - VkPipelineColorBlendAttachmentState blend_state; - blend_state.blendEnable = VK_FALSE; - blend_state.srcColorBlendFactor = VK_BLEND_FACTOR_ZERO; - blend_state.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; - blend_state.colorBlendOp = VK_BLEND_OP_ADD; - blend_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - blend_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - blend_state.alphaBlendOp = VK_BLEND_OP_ADD; - blend_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - - this->indirect_pipeline = lava::make_graphics_pipeline(device); - this->indirect_pipeline->set_layout(this->indirect_pipeline_layout); - this->indirect_pipeline->set_rasterization_front_face(VK_FRONT_FACE_CLOCKWISE); - this->indirect_pipeline->set_rasterization_cull_mode(VK_CULL_MODE_BACK_BIT); - this->indirect_pipeline->set_depth_test_and_write(true, true); - this->indirect_pipeline->set_depth_compare_op(VK_COMPARE_OP_LESS); - this->indirect_pipeline->add_color_blend_attachment(blend_state); - this->indirect_pipeline->add_color_blend_attachment(blend_state); - this->indirect_pipeline->add_color_blend_attachment(blend_state); - - scene->set_vertex_input(this->indirect_pipeline.get()); - - if (!this->indirect_pipeline->add_shader(lava::file_data("dpr/binary/shadow_indirect_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT)) - { - return false; - } - - if (!this->indirect_pipeline->add_shader(lava::file_data("dpr/binary/shadow_indirect_geometry.spirv"), VK_SHADER_STAGE_GEOMETRY_BIT)) - { - return false; - } - - if (!this->indirect_pipeline->add_shader(lava::file_data("dpr/binary/shadow_indirect_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT)) - { - return false; - } - - this->indirect_pipeline->on_process = [this](VkCommandBuffer command_buffer) - { - this->pipeline_indirect(command_buffer); - }; - - if (!this->indirect_pipeline->create(this->indirect_pass->get())) - { - return false; - } - - this->indirect_pass->add_front(this->indirect_pipeline); - - return true; -} - -bool ShadowCache::create_downsample_pass(lava::device_ptr device) -{ - lava::attachment::ptr position_attachment = lava::make_attachment(this->indirect_position_array->get_format()); - position_attachment->set_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE); - position_attachment->set_stencil_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE); - position_attachment->set_layouts(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - - lava::attachment::ptr normal_attachment = lava::make_attachment(this->indirect_normal_array->get_format()); - normal_attachment->set_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE); - normal_attachment->set_stencil_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE); - normal_attachment->set_layouts(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - - lava::attachment::ptr flux_attachment = lava::make_attachment(this->indirect_flux_array->get_format()); - flux_attachment->set_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE); - flux_attachment->set_stencil_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE); - flux_attachment->set_layouts(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - - VkAttachmentReference position_attachment_reference; - position_attachment_reference.attachment = 0; - position_attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - VkAttachmentReference normal_attachment_reference; - normal_attachment_reference.attachment = 1; - normal_attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - VkAttachmentReference flux_attachment_reference; - flux_attachment_reference.attachment = 2; - flux_attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - lava::subpass::ptr subpass = lava::make_subpass(); - subpass->set_color_attachments( - { - position_attachment_reference, - normal_attachment_reference, - flux_attachment_reference - }); - - lava::subpass_dependency::ptr subpass_begin_dependency = lava::make_subpass_dependency(VK_SUBPASS_EXTERNAL, 0); - subpass_begin_dependency->set_stage_mask(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); - subpass_begin_dependency->set_access_mask(0, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT); - - lava::subpass_dependency::ptr subpass_end_dependency = lava::make_subpass_dependency(0, VK_SUBPASS_EXTERNAL); - subpass_end_dependency->set_stage_mask(VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - subpass_end_dependency->set_access_mask(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); - - this->downsample_pass = lava::make_render_pass(device); - this->downsample_pass->add(subpass); - this->downsample_pass->add(subpass_begin_dependency); - this->downsample_pass->add(subpass_end_dependency); - this->downsample_pass->add(position_attachment); //location 0: indirect position array - this->downsample_pass->add(normal_attachment); //location 1: indirect normal array - this->downsample_pass->add(flux_attachment); //location 2: indirect flux array - this->downsample_pass->set_layers(this->indirect_position_array->get_info().arrayLayers); - - lava::rect framebuffer_area = - { - glm::vec2(0.0f), - glm::vec2(settings.resolution) - }; - - lava::VkImageViews framebuffer_views = - { - this->indirect_position_views[0], - this->indirect_normal_views[0], - this->indirect_flux_views[0] - }; + this->pipeline_layout = lava::make_pipeline_layout(); + this->pipeline_layout->add_push_constant_range(push_range); + this->pipeline_layout->add(scene->get_light_descriptor()); //descriptor-set index 0: light-buffer + this->pipeline_layout->add(scene->get_mesh_descriptor()); //descriptor-set index 1: mesh-buffer - if (!this->downsample_pass->create({ framebuffer_views }, framebuffer_area)) + if (!this->pipeline_layout->create(device)) { return false; } - return true; -} - -bool ShadowCache::create_downsample_pipeline(lava::device_ptr device) -{ - this->downsample_pipeline_layout = lava::make_pipeline_layout(); - this->downsample_pipeline_layout->add(this->downsample_descriptor); //descriptor-set index 0: downsample-info - - if (!this->downsample_pipeline_layout->create(device)) - { - return false; - } + this->pipeline = lava::make_graphics_pipeline(device); + this->pipeline->set_layout(this->pipeline_layout); + this->pipeline->set_rasterization_front_face(VK_FRONT_FACE_CLOCKWISE); + this->pipeline->set_rasterization_cull_mode(VK_CULL_MODE_BACK_BIT); + this->pipeline->set_depth_test_and_write(true, true); + this->pipeline->set_depth_compare_op(VK_COMPARE_OP_LESS); - VkPipelineColorBlendAttachmentState blend_state; - blend_state.blendEnable = VK_FALSE; - blend_state.srcColorBlendFactor = VK_BLEND_FACTOR_ZERO; - blend_state.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; - blend_state.colorBlendOp = VK_BLEND_OP_ADD; - blend_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - blend_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - blend_state.alphaBlendOp = VK_BLEND_OP_ADD; - blend_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - - this->downsample_pipeline = lava::make_graphics_pipeline(device); - this->downsample_pipeline->set_layout(this->downsample_pipeline_layout); - this->downsample_pipeline->set_input_assembly_topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP); - this->downsample_pipeline->add_color_blend_attachment(blend_state); - this->downsample_pipeline->add_color_blend_attachment(blend_state); - this->downsample_pipeline->add_color_blend_attachment(blend_state); - - if (!this->downsample_pipeline->add_shader(lava::file_data("dpr/binary/shadow_indirect_downsample_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT)) - { - return false; - } + scene->set_vertex_input_only_position(this->pipeline.get()); - if (!this->downsample_pipeline->add_shader(lava::file_data("dpr/binary/shadow_indirect_downsample_geometry.spirv"), VK_SHADER_STAGE_GEOMETRY_BIT)) + if (!this->pipeline->add_shader(lava::file_data("dpr/binary/shadow_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT)) { return false; } - if (!this->downsample_pipeline->add_shader(lava::file_data("dpr/binary/shadow_indirect_downsample_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT)) + if (!this->pipeline->add_shader(lava::file_data("dpr/binary/shadow_geometry.spirv"), VK_SHADER_STAGE_GEOMETRY_BIT)) { return false; } - this->downsample_pipeline->on_process = [this](VkCommandBuffer command_buffer) + this->pipeline->on_process = [this](VkCommandBuffer command_buffer) { - //NOTE: The render pass setup is done by hand in order to use different framebuffers + this->pipline_function(command_buffer); }; - if (!this->downsample_pipeline->create(this->downsample_pass->get())) + if (!this->pipeline->create(this->render_pass->get())) { return false; } - this->downsample_pass->add_front(this->downsample_pipeline); + this->render_pass->add_front(this->pipeline); return true; } -std::vector<glsl::IndirectSample> ShadowCache::compute_indirect_samples(const ShadowCacheSettings& settings) -{ - std::default_random_engine random_engine(0); - std::uniform_real_distribution<float> distrubution(0.0f, 1.0f); - - uint32_t sample_count = settings.indirect_sample_count; - std::vector<glsl::IndirectSample> samples(sample_count); - float weight_sum = 0.0f; - - for (uint32_t index = 0; index < sample_count; index++) - { - float random1 = distrubution(random_engine); - float random2 = distrubution(random_engine); - - glm::vec2 coord; - coord.x = settings.indirect_radius * random1 * glm::sin(glm::two_pi<float>() * random2); - coord.y = settings.indirect_radius * random1 * glm::cos(glm::two_pi<float>() * random2); - - float weight = random1 * random1; - - samples[index].coord = coord; - samples[index].weight = weight; - samples[index].padding = 0; - - weight_sum += weight; - } - - if(weight_sum > 0.0f) - { - for(glsl::IndirectSample& sample : samples) - { - sample.weight /= weight_sum; - } - } - - return samples; -} - -void ShadowCache::pipeline_shadow(VkCommandBuffer command_buffer) +void ShadowCache::pipline_function(VkCommandBuffer command_buffer) { - this->shadow_pipeline_layout->bind(command_buffer, this->scene->get_light_descriptor_set(this->frame), 0); + this->pipeline_layout->bind(command_buffer, this->scene->get_light_descriptor_set(this->frame), 0); const std::vector<SceneLight>& lights = this->scene->get_lights(); - if(!this->settings.use_directional_indirect) + for (uint32_t light_index = 0; light_index < lights.size(); light_index++) { - for (uint32_t light_index = 0; light_index < lights.size(); light_index++) - { - const SceneLight& light = lights[light_index]; + const SceneLight& light = lights[light_index]; - if (light.data.type == LIGHT_TYPE_DIRECTIONAL) - { - uint32_t layer_index = this->directional_offset + light.data.type_index; + if (light.data.type == LIGHT_TYPE_DIRECTIONAL) + { + uint32_t layer_index = this->directional_offset + light.data.type_index; - std::array<uint32_t, 3> constants; - constants[0] = layer_index; - constants[1] = light_index; - constants[2] = 0; + std::array<uint32_t, 3> constants; + constants[0] = layer_index; + constants[1] = light_index; + constants[2] = 0; - vkCmdPushConstants(command_buffer, this->shadow_pipeline_layout->get(), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT, 0, sizeof(uint32_t) * constants.size(), constants.data()); + vkCmdPushConstants(command_buffer, this->pipeline_layout->get(), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT, 0, sizeof(uint32_t) * constants.size(), constants.data()); - this->pipeline_scene_shadow(command_buffer); - } + this->pipline_scene(command_buffer); } } @@ -1352,9 +640,9 @@ void ShadowCache::pipeline_shadow(VkCommandBuffer command_buffer) constants[1] = light_index; constants[2] = 0; - vkCmdPushConstants(command_buffer, this->shadow_pipeline_layout->get(), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT, 0, sizeof(uint32_t) * constants.size(), constants.data()); + vkCmdPushConstants(command_buffer, this->pipeline_layout->get(), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT, 0, sizeof(uint32_t) * constants.size(), constants.data()); - this->pipeline_scene_shadow(command_buffer); + this->pipline_scene(command_buffer); } } @@ -1373,91 +661,16 @@ void ShadowCache::pipeline_shadow(VkCommandBuffer command_buffer) constants[1] = light_index; constants[2] = frustum_index; - vkCmdPushConstants(command_buffer, this->shadow_pipeline_layout->get(), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT, 0, sizeof(uint32_t) * constants.size(), constants.data()); + vkCmdPushConstants(command_buffer, this->pipeline_layout->get(), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT, 0, sizeof(uint32_t) * constants.size(), constants.data()); - this->pipeline_scene_shadow(command_buffer); + this->pipline_scene(command_buffer); } } } } -void ShadowCache::pipeline_indirect(VkCommandBuffer command_buffer) -{ - if(!this->settings.use_directional_indirect) - { - return; - } - - this->indirect_pipeline_layout->bind(command_buffer, this->scene->get_light_descriptor_set(this->frame), 0); - - const std::vector<SceneLight>& lights = this->scene->get_lights(); - - for (uint32_t light_index = 0; light_index < lights.size(); light_index++) - { - const SceneLight& light = lights[light_index]; - - if (light.data.type == LIGHT_TYPE_DIRECTIONAL) - { - std::array<uint32_t, 2> constants; - constants[0] = light_index; - constants[1] = this->settings.resolution; - - vkCmdPushConstants(command_buffer, this->indirect_pipeline_layout->get(), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(uint32_t) * constants.size(), constants.data()); - - this->pipeline_scene_indirect(command_buffer); - } - } -} - -void ShadowCache::pipeline_downsample(VkCommandBuffer command_buffer) -{ - uint32_t indirect_levels = this->indirect_position_views.size(); - uint32_t indirect_layers = this->indirect_position_array->get_info().arrayLayers; - - for (uint32_t level = 1; level < indirect_levels; level++) - { - VkRenderPassBeginInfo begin_info; - begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - begin_info.pNext = nullptr; - begin_info.renderPass = this->downsample_pass->get(); - begin_info.framebuffer = this->downsample_framebuffers[level]; - begin_info.renderArea.offset.x = 0; - begin_info.renderArea.offset.y = 0; - begin_info.renderArea.extent.width = this->settings.resolution >> level; - begin_info.renderArea.extent.height = this->settings.resolution >> level; - begin_info.clearValueCount = 0; - begin_info.pClearValues = nullptr; - - vkCmdBeginRenderPass(command_buffer, &begin_info, VK_SUBPASS_CONTENTS_INLINE); - - vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, this->downsample_pipeline->get()); - vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, this->downsample_pipeline_layout->get(), 0, 1, &this->downsample_descriptor_sets[level - 1], 0, nullptr); - - vkCmdDraw(command_buffer, 4, indirect_layers, 0, 0); //draw fullscreen quad - - vkCmdEndRenderPass(command_buffer); - } -} - -void ShadowCache::pipeline_scene_shadow(VkCommandBuffer command_buffer) -{ - for (const SceneMesh& mesh : this->scene->get_meshes()) - { - if (!mesh.cast_shadow) - { - continue; - } - - this->shadow_pipeline_layout->bind(command_buffer, mesh.descriptor_set[this->frame], 1); - - mesh.mesh->bind_draw(command_buffer); - } -} - -void ShadowCache::pipeline_scene_indirect(VkCommandBuffer command_buffer) +void ShadowCache::pipline_scene(VkCommandBuffer command_buffer) { - const std::vector<SceneMaterial>& materials = this->scene->get_materials(); - for (const SceneMesh& mesh : this->scene->get_meshes()) { if (!mesh.cast_shadow) @@ -1465,9 +678,7 @@ void ShadowCache::pipeline_scene_indirect(VkCommandBuffer command_buffer) continue; } - const SceneMaterial& material = materials[mesh.material_index]; - this->indirect_pipeline_layout->bind(command_buffer, mesh.descriptor_set[this->frame], 1); - this->indirect_pipeline_layout->bind(command_buffer, material.descriptor_set, 2); + this->pipeline_layout->bind(command_buffer, mesh.descriptor_set[this->frame], 1); mesh.mesh->bind_draw(command_buffer); } diff --git a/src/utility/shadow_cache.hpp b/src/utility/shadow_cache.hpp index 710951d15fc820e55aeec289f7886522dd3289b4..895bbe73fa6e2bbb2220f745b90f156e0ef758d2 100644 --- a/src/utility/shadow_cache.hpp +++ b/src/utility/shadow_cache.hpp @@ -38,25 +38,13 @@ #include "scene.hpp" -namespace glsl -{ - using namespace glm; - using uint = glm::uint32; - -#include "res/dpr/data/shadow_data.inc" -} - struct ShadowCacheSettings { uint32_t resolution = 1024; - bool use_directional_shadow = true; - bool use_directional_indirect = true; - bool use_spot_shadow = true; - bool use_point_shadow = true; - - uint32_t indirect_sample_count = 32; - float indirect_radius = 5.0; + bool use_directional = true; + bool use_spot = true; + bool use_point = true; }; class ShadowCache @@ -78,28 +66,17 @@ public: const ShadowCacheSettings& get_settings() const; private: - bool create_image_view(lava::device_ptr device, lava::image::ptr image_array, uint32_t layer_offset, uint32_t layer_count, uint32_t level, VkImageAspectFlags aspect, VkImageViewType view_type, VkImageView& view); - bool create_shadow_sampler(lava::device_ptr device, VkSampler& sampler); - bool create_indirect_sampler(lava::device_ptr device, VkSampler& sampler); + bool create_image_view(lava::device_ptr device, lava::image::ptr image_array, uint32_t layer_offset, uint32_t layer_count, VkImageViewType view_type, VkImageView& view); + bool create_sampler(lava::device_ptr device, VkSampler& sampler); bool create_images(lava::device_ptr device, Scene::Ptr scene, const ShadowCacheSettings& settings); bool create_buffers(lava::device_ptr device, const ShadowCacheSettings& settings); bool create_descriptors(lava::device_ptr device); - bool create_framebuffers(lava::device_ptr device, const ShadowCacheSettings& settings); - - bool create_shadow_pass(lava::device_ptr device, const ShadowCacheSettings& settings); - bool create_shadow_pipeline(lava::device_ptr device, Scene::Ptr scene); - bool create_indirect_pass(lava::device_ptr device, const ShadowCacheSettings& settings); - bool create_indirect_pipeline(lava::device_ptr device, Scene::Ptr scene); - bool create_downsample_pass(lava::device_ptr device); - bool create_downsample_pipeline(lava::device_ptr device); - - void pipeline_shadow(VkCommandBuffer command_buffer); - void pipeline_indirect(VkCommandBuffer command_buffer); - void pipeline_downsample(VkCommandBuffer command_buffer); - void pipeline_scene_shadow(VkCommandBuffer command_buffer); - void pipeline_scene_indirect(VkCommandBuffer command_buffer); - static std::vector<glsl::IndirectSample> compute_indirect_samples(const ShadowCacheSettings& settings); + bool create_render_pass(lava::device_ptr device, const ShadowCacheSettings& settings); + bool create_pipeline(lava::device_ptr device, Scene::Ptr scene); + + void pipline_function(VkCommandBuffer command_buffer); + void pipline_scene(VkCommandBuffer command_buffer); private: Scene::Ptr scene; @@ -110,53 +87,29 @@ private: uint32_t spot_offset = 0; uint32_t point_offset = 0; - lava::image::ptr shadow_default_plane; - lava::image::ptr shadow_default_cube; + lava::image::ptr image_default_plane; + lava::image::ptr image_default_cube; bool image_default_cleared = false; - lava::image::ptr shadow_array; - VkImageView shadow_view_directional = nullptr; - VkImageView shadow_view_spot = nullptr; - VkImageView shadow_view_point = nullptr; - - lava::image::ptr indirect_position_array; - lava::image::ptr indirect_normal_array; - lava::image::ptr indirect_flux_array; - - std::vector<VkImageView> indirect_position_views; - std::vector<VkImageView> indirect_normal_views; - std::vector<VkImageView> indirect_flux_views; + lava::image::ptr image_array; + VkImageView image_view_directional = nullptr; + VkImageView image_view_spot = nullptr; + VkImageView image_view_point = nullptr; - VkSampler sampler_shadow_default = nullptr; - VkSampler sampler_shadow_directional = nullptr; - VkSampler sampler_shadow_spot = nullptr; - VkSampler sampler_shadow_point = nullptr; - VkSampler sampler_indirect_position = nullptr; - VkSampler sampler_indirect_normal = nullptr; - VkSampler sampler_indirect_flux = nullptr; + VkSampler sampler_default = nullptr; + VkSampler sampler_directional = nullptr; + VkSampler sampler_spot = nullptr; + VkSampler sampler_point = nullptr; - lava::buffer::ptr shadow_parameter_buffer; - lava::buffer::ptr indirect_sample_buffer; + lava::buffer::ptr shadow_buffer; lava::descriptor::pool::ptr descriptor_pool; lava::descriptor::ptr descriptor; VkDescriptorSet descriptor_set = nullptr; - lava::pipeline_layout::ptr shadow_pipeline_layout; - lava::graphics_pipeline::ptr shadow_pipeline; - lava::render_pass::ptr shadow_pass; - - lava::pipeline_layout::ptr indirect_pipeline_layout; - lava::graphics_pipeline::ptr indirect_pipeline; - lava::render_pass::ptr indirect_pass; - - lava::descriptor::ptr downsample_descriptor; - std::vector<VkDescriptorSet> downsample_descriptor_sets; - - lava::pipeline_layout::ptr downsample_pipeline_layout; - lava::graphics_pipeline::ptr downsample_pipeline; - lava::render_pass::ptr downsample_pass; - std::vector<VkFramebuffer> downsample_framebuffers; + lava::pipeline_layout::ptr pipeline_layout; + lava::graphics_pipeline::ptr pipeline; + lava::render_pass::ptr render_pass; }; ShadowCache::Ptr make_shadow_cache(); \ No newline at end of file