From f2b340314540aa40bcbb3ad30cf0747921530f7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cle=CC=81ment=20Foucault?= Date: Sun, 7 Jan 2024 04:46:25 +0100 Subject: [PATCH] EEVEE-Next: Gbuffer Read optimizations This modify most shader using the GBuffer to use the `ClosureUndetermined`. This in turn reduces the amount of duplicated data in the `GBufferReader` structure. The most important part is the usage of fixed array indices to access the `GBufferReader.closures[]`. This avoid the struct to be moved from local register to device memory and remove a huge performance penalty. Pull Request: https://projects.blender.org/blender/blender/pulls/116772 --- .../shaders/eevee_debug_gbuffer_frag.glsl | 29 +- .../shaders/eevee_deferred_capture_frag.glsl | 40 ++- .../shaders/eevee_deferred_combine_frag.glsl | 5 +- .../shaders/eevee_deferred_light_frag.glsl | 31 +- .../shaders/eevee_deferred_planar_frag.glsl | 47 ++- .../eevee_deferred_tile_classify_frag.glsl | 14 +- .../eevee_deferred_tile_compact_vert.glsl | 10 +- .../eevee_next/shaders/eevee_gbuffer_lib.glsl | 329 +++++++++--------- .../shaders/eevee_gbuffer_test.glsl | 98 +++--- .../shaders/eevee_horizon_denoise_comp.glsl | 4 +- .../shaders/eevee_horizon_scan_comp.glsl | 2 +- .../shaders/eevee_horizon_setup_comp.glsl | 2 +- .../eevee_ray_denoise_bilateral_comp.glsl | 4 +- .../eevee_ray_denoise_spatial_comp.glsl | 2 +- .../shaders/eevee_ray_generate_comp.glsl | 2 +- .../shaders/eevee_ray_tile_classify_comp.glsl | 16 +- .../shaders/eevee_ray_trace_planar_comp.glsl | 2 +- .../shaders/eevee_ray_trace_screen_comp.glsl | 2 +- .../eevee_subsurface_convolve_comp.glsl | 15 +- .../shaders/eevee_subsurface_setup_comp.glsl | 9 +- .../shaders/infos/eevee_deferred_info.hh | 1 + 21 files changed, 363 insertions(+), 301 deletions(-) diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_debug_gbuffer_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_debug_gbuffer_frag.glsl index 55c26a3ddc8..0b9e398033d 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_debug_gbuffer_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_debug_gbuffer_frag.glsl @@ -18,19 +18,34 @@ void main() GBufferReader gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_normal_tx, texel); - if (gbuf.header == 0u) { + if (gbuf.closure_count == 0) { discard; return; } - float shade = saturate(drw_normal_world_to_view(gbuf.data.surface_N).z); + float shade = saturate(drw_normal_world_to_view(gbuf.surface_N).z); - uvec4 closure_types = (uvec4(gbuf.header) >> uvec4(0u, 4u, 8u, 12u)) & 15u; + uint header = texelFetch(gbuf_header_tx, texel, 0).x; + uvec4 closure_types = (uvec4(header) >> uvec4(0u, 4u, 8u, 12u)) & 15u; float storage_cost = reduce_add(vec4(not(equal(closure_types, uvec4(0u))))); - float eval_cost = reduce_add(vec4(equal(closure_types, uvec4(GBUF_REFLECTION)))) * 1.0 + - reduce_add(vec4(equal(closure_types, uvec4(GBUF_REFRACTION)))) * 1.0 + - reduce_add(vec4(equal(closure_types, uvec4(GBUF_DIFFUSE)))) * 1.0 + - reduce_add(vec4(equal(closure_types, uvec4(GBUF_SUBSURFACE)))) * 1.0; + + float eval_cost = 0.0; + for (int i = 0; i < GBUFFER_LAYER_MAX && i < gbuf.closure_count; i++) { + switch (gbuffer_closure_get(gbuf, i).type) { + case CLOSURE_BSDF_DIFFUSE_ID: + case CLOSURE_BSDF_TRANSLUCENT_ID: + case CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID: + case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: + eval_cost += 1.0; + break; + case CLOSURE_BSSRDF_BURLEY_ID: + eval_cost += 2.0; + break; + case CLOSURE_NONE_ID: + /* TODO(fclem): Assert. */ + break; + } + } switch (eDebugMode(debug_mode)) { default: diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_capture_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_capture_frag.glsl index 4ff825a283a..8329ac48e94 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_capture_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_capture_frag.glsl @@ -19,30 +19,54 @@ void main() GBufferReader gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_normal_tx, texel); - if (!gbuf.has_any_surface) { + if (gbuf.closure_count == 0) { return; } ClosureLightStack stack; - stack.cl[0].N = gbuf.data.surface_N; + stack.cl[0].N = gbuf.surface_N; stack.cl[0].ltc_mat = LTC_LAMBERT_MAT; stack.cl[0].type = LIGHT_DIFFUSE; + stack.cl[1].N = -gbuf.surface_N; + stack.cl[1].ltc_mat = LTC_LAMBERT_MAT; + stack.cl[1].type = LIGHT_DIFFUSE; + vec3 P = drw_point_screen_to_world(vec3(uvcoordsvar.xy, depth)); - vec3 Ng = stack.cl[0].N; + vec3 Ng = gbuf.surface_N; vec3 V = drw_world_incident_vector(P); float vPz = dot(drw_view_forward(), P) - dot(drw_view_forward(), drw_view_position()); /* Direct light. */ - light_eval(stack, P, Ng, V, vPz, gbuf.data.thickness); + light_eval(stack, P, Ng, V, vPz, gbuf.thickness); + /* Indirect light. */ /* Can only load irradiance to avoid dependency loop with the reflection probe. */ SphericalHarmonicL1 sh = lightprobe_irradiance_sample(P, V, Ng); - vec3 radiance = stack.cl[0].light_shadowed + spherical_harmonics_evaluate_lambert(Ng, sh); + vec3 radiance_front = stack.cl[0].light_shadowed + spherical_harmonics_evaluate_lambert(Ng, sh); + vec3 radiance_back = stack.cl[1].light_shadowed + spherical_harmonics_evaluate_lambert(-Ng, sh); - vec3 albedo = gbuf.data.diffuse.color + gbuf.data.reflection.color + gbuf.data.refraction.color + - gbuf.data.translucent.color; + vec3 albedo_front = vec3(0.0); + vec3 albedo_back = vec3(0.0); - out_radiance = vec4(radiance * albedo, 0.0); + for (int i = 0; i < GBUFFER_LAYER_MAX && i < gbuf.closure_count; i++) { + ClosureUndetermined cl = gbuffer_closure_get(gbuf, i); + switch (cl.type) { + case CLOSURE_BSSRDF_BURLEY_ID: + case CLOSURE_BSDF_DIFFUSE_ID: + case CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID: + albedo_front += cl.color; + break; + case CLOSURE_BSDF_TRANSLUCENT_ID: + case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: + albedo_back += cl.color; + break; + case CLOSURE_NONE_ID: + /* TODO(fclem): Assert. */ + break; + } + } + + out_radiance = vec4(radiance_front * albedo_front + radiance_back * albedo_back, 0.0); } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_combine_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_combine_frag.glsl index cbe21f62754..8a696627eee 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_combine_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_combine_frag.glsl @@ -68,10 +68,11 @@ void main() closure_light += load_radiance_indirect(texel, i); } - closure_light *= gbuf.closures[i].color; + ClosureUndetermined cl = gbuffer_closure_get(gbuf, i); + closure_light *= cl.color; out_combined.rgb += closure_light; - switch (gbuf.closures[i].type) { + switch (cl.type) { case CLOSURE_BSDF_TRANSLUCENT_ID: case CLOSURE_BSSRDF_BURLEY_ID: case CLOSURE_BSDF_DIFFUSE_ID: diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_light_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_light_frag.glsl index 3322b5bc5de..ed1220a4f53 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_light_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_light_frag.glsl @@ -54,23 +54,24 @@ void main() } vec3 P = drw_point_screen_to_world(vec3(uvcoordsvar.xy, depth)); - vec3 Ng = gbuf.data.surface_N; + vec3 Ng = gbuf.surface_N; vec3 V = drw_world_incident_vector(P); float vPz = dot(drw_view_forward(), P) - dot(drw_view_forward(), drw_view_position()); ClosureLightStack stack; for (int i = 0; i < LIGHT_CLOSURE_EVAL_COUNT && i < gbuf.closure_count; i++) { - stack.cl[i] = closure_light_new(gbuf.closures[i], V); + stack.cl[i] = closure_light_new(gbuffer_closure_get(gbuf, i), V); } /* TODO(fclem): Split thickness computation. */ - float thickness = (gbuf.has_translucent) ? gbuf.data.thickness : 0.0; + float thickness = gbuf.thickness; #ifdef MAT_SUBSURFACE - if (gbuf.has_sss) { + /* NOTE: BSSRDF is supposed to always be the first closure. */ + bool has_sss = gbuffer_closure_get(gbuf, 0).type == CLOSURE_BSSRDF_BURLEY_ID; + if (has_sss) { float shadow_thickness = thickness_from_shadow(P, Ng, vPz); - thickness = (shadow_thickness != THICKNESS_NO_VALUE) ? - max(shadow_thickness, gbuf.data.thickness) : - gbuf.data.thickness; + thickness = (shadow_thickness != THICKNESS_NO_VALUE) ? max(shadow_thickness, gbuf.thickness) : + gbuf.thickness; /* Add one translucent closure for all SSS closure. Reuse the same lighting. */ ClosureLight cl_light; @@ -84,12 +85,11 @@ void main() light_eval(stack, P, Ng, V, vPz, thickness); #ifdef MAT_SUBSURFACE - /* NOTE: BSSRDF is supposed to always be the first closure. */ - if (gbuf.closures[0].type == CLOSURE_BSSRDF_BURLEY_ID) { + if (has_sss) { /* Add to diffuse light for processing inside the Screen Space SSS pass. * The tranlucent light is not outputed as a separate quantity because * it is over the closure_count. */ - vec3 sss_profile = subsurface_transmission(gbuf.closures[0].data.rgb, thickness); + vec3 sss_profile = subsurface_transmission(gbuffer_closure_get(gbuf, 0).data.rgb, thickness); stack.cl[0].light_shadowed += stack.cl[gbuf.closure_count].light_shadowed * sss_profile; stack.cl[0].light_unshadowed += stack.cl[gbuf.closure_count].light_unshadowed * sss_profile; } @@ -116,25 +116,26 @@ void main() LightProbeSample samp = lightprobe_load(P, Ng, V); for (int i = 0; i < LIGHT_CLOSURE_EVAL_COUNT && i < gbuf.closure_count; i++) { - switch (gbuf.closures[i].type) { + ClosureUndetermined cl = gbuffer_closure_get(gbuf, i); + switch (cl.type) { case CLOSURE_BSDF_TRANSLUCENT_ID: /* TODO: Support in ray tracing first. Otherwise we have a discrepancy. */ stack.cl[i].light_shadowed += lightprobe_eval( - samp, to_closure_translucent(gbuf.closures[i]), P, V, noise_probe); + samp, to_closure_translucent(cl), P, V, noise_probe); break; case CLOSURE_BSSRDF_BURLEY_ID: /* TODO: Support translucency in ray tracing first. Otherwise we have a discrepancy. */ case CLOSURE_BSDF_DIFFUSE_ID: stack.cl[i].light_shadowed += lightprobe_eval( - samp, to_closure_diffuse(gbuf.closures[i]), P, V, noise_probe); + samp, to_closure_diffuse(cl), P, V, noise_probe); break; case CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID: stack.cl[i].light_shadowed += lightprobe_eval( - samp, to_closure_reflection(gbuf.closures[i]), P, V, noise_probe); + samp, to_closure_reflection(cl), P, V, noise_probe); break; case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: stack.cl[i].light_shadowed += lightprobe_eval( - samp, to_closure_refraction(gbuf.closures[i]), P, V, noise_probe); + samp, to_closure_refraction(cl), P, V, noise_probe); break; case CLOSURE_NONE_ID: /* TODO(fclem): Assert. */ diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_planar_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_planar_frag.glsl index cff207043dc..c128dd74f3a 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_planar_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_planar_frag.glsl @@ -20,32 +20,47 @@ void main() GBufferReader gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_normal_tx, texel); vec3 P = drw_point_screen_to_world(vec3(uvcoordsvar.xy, depth)); - vec3 Ng = gbuf.data.diffuse.N; + vec3 Ng = gbuf.surface_N; vec3 V = drw_world_incident_vector(P); float vPz = dot(drw_view_forward(), P) - dot(drw_view_forward(), drw_view_position()); ClosureLightStack stack; - stack.cl[0].N = gbuf.data.diffuse.N; + stack.cl[0].N = gbuf.surface_N; stack.cl[0].ltc_mat = LTC_LAMBERT_MAT; stack.cl[0].type = LIGHT_DIFFUSE; - stack.cl[1].N = gbuf.data.reflection.N; - stack.cl[1].ltc_mat = LTC_GGX_MAT(dot(gbuf.data.reflection.N, V), - gbuf.data.reflection.roughness); - stack.cl[1].type = LIGHT_SPECULAR; + stack.cl[1].N = -gbuf.surface_N; + stack.cl[1].ltc_mat = LTC_LAMBERT_MAT; + stack.cl[1].type = LIGHT_DIFFUSE; /* Direct light. */ - light_eval(stack, P, Ng, V, vPz, gbuf.data.thickness); + light_eval(stack, P, Ng, V, vPz, gbuf.thickness); /* Indirect light. */ - LightProbeSample samp = lightprobe_load(P, Ng, V); + SphericalHarmonicL1 sh = lightprobe_irradiance_sample(P, V, Ng); - vec3 radiance = vec3(0.0); - radiance += (stack.cl[0].light_shadowed + - lightprobe_eval(samp, gbuf.data.diffuse, P, V, vec2(0.0))) * - gbuf.data.diffuse.color; - radiance += (stack.cl[1].light_shadowed + - lightprobe_eval(samp, gbuf.data.reflection, P, V, vec2(0.0))) * - gbuf.data.reflection.color; + vec3 radiance_front = stack.cl[0].light_shadowed + spherical_harmonics_evaluate_lambert(Ng, sh); + vec3 radiance_back = stack.cl[1].light_shadowed + spherical_harmonics_evaluate_lambert(-Ng, sh); - out_radiance = vec4(radiance, 0.0); + vec3 albedo_front = vec3(0.0); + vec3 albedo_back = vec3(0.0); + + for (int i = 0; i < GBUFFER_LAYER_MAX && i < gbuf.closure_count; i++) { + ClosureUndetermined cl = gbuffer_closure_get(gbuf, i); + switch (cl.type) { + case CLOSURE_BSSRDF_BURLEY_ID: + case CLOSURE_BSDF_DIFFUSE_ID: + case CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID: + albedo_front += cl.color; + break; + case CLOSURE_BSDF_TRANSLUCENT_ID: + case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: + albedo_back += cl.color; + break; + case CLOSURE_NONE_ID: + /* TODO(fclem): Assert. */ + break; + } + } + + out_radiance = vec4(radiance_front * albedo_front + radiance_back * albedo_back, 0.0); } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_tile_classify_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_tile_classify_frag.glsl index 5bf149bead0..85cae886d65 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_tile_classify_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_tile_classify_frag.glsl @@ -18,22 +18,18 @@ void main() ivec2 tile_co = texel >> closure_tile_size_shift; - GBufferReader gbuf = gbuffer_read_header(in_gbuffer_header); + uint closure_count = gbuffer_closure_count(in_gbuffer_header); - if (gbuf.has_diffuse) { + if (closure_count > 0) { imageStore(tile_mask_img, ivec3(tile_co, 0), uvec4(1u)); } - if (gbuf.has_reflection) { + if (closure_count > 1) { imageStore(tile_mask_img, ivec3(tile_co, 1), uvec4(1u)); } - if (gbuf.has_refraction) { + if (closure_count > 2) { imageStore(tile_mask_img, ivec3(tile_co, 2), uvec4(1u)); } - if (gbuf.has_translucent) { - imageStore(tile_mask_img, ivec3(tile_co, 3), uvec4(1u)); - } - /* TODO(fclem): For now, override SSS if we have translucency. */ - else if (gbuf.has_sss) { + if (closure_count > 3) { imageStore(tile_mask_img, ivec3(tile_co, 3), uvec4(1u)); } } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_tile_compact_vert.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_tile_compact_vert.glsl index dbcc6f222a9..38f5969b945 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_tile_compact_vert.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_tile_compact_vert.glsl @@ -31,18 +31,14 @@ void main() uint closure_count = texelFetch(tile_mask_tx, ivec3(tile_coord, 0), 0).r + texelFetch(tile_mask_tx, ivec3(tile_coord, 1), 0).r + - // texelFetch(tile_mask_tx, ivec3(tile_coord, 2), 0).r + /* TODO: refract */ + texelFetch(tile_mask_tx, ivec3(tile_coord, 2), 0).r + texelFetch(tile_mask_tx, ivec3(tile_coord, 3), 0).r; - /* TODO(fclem): This is waiting for fully flexible evaluation pipeline. We need to refactor the - * raytracing pipeline first. */ - bool has_reflection = texelFetch(tile_mask_tx, ivec3(tile_coord, 1), 0).r != 0u; - bool has_sss = texelFetch(tile_mask_tx, ivec3(tile_coord, 3), 0).r != 0u; - if (closure_count == 3 || has_sss) { + if (closure_count == 3) { uint tile_index = atomicAdd(closure_triple_draw_buf.vertex_len, 6u) / 6u; closure_triple_tile_buf[tile_index] = packUvec2x16(uvec2(tile_coord)); } - else if (closure_count == 2 || has_reflection) { + else if (closure_count == 2) { uint tile_index = atomicAdd(closure_double_draw_buf.vertex_len, 6u) / 6u; closure_double_tile_buf[tile_index] = packUvec2x16(uvec2(tile_coord)); } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_gbuffer_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_gbuffer_lib.glsl index fb3e3e5573b..a37be65f70a 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_gbuffer_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_gbuffer_lib.glsl @@ -17,7 +17,7 @@ * * \{ */ -#define GBUFFER_LAYER_MAX 4 +#define GBUFFER_LAYER_MAX 3 #define GBUFFER_NORMAL_MAX GBUFFER_LAYER_MAX #define GBUFFER_DATA_MAX (GBUFFER_LAYER_MAX * 2) @@ -64,17 +64,14 @@ struct GBufferWriter { /* Result of loading the GBuffer. */ struct GBufferReader { - GBufferData data; - ClosureUndetermined closures[GBUFFER_LAYER_MAX]; + /* First world normal stored in the gbuffer. Only valid if `has_any_surface` is true. */ + vec3 surface_N; + /* Additional object information if any closure needs it. */ + float thickness; + uint object_id; - bool has_diffuse; - bool has_translucent; - bool has_reflection; - bool has_refraction; - bool has_sss; - bool has_any_surface; - uint header; + /* Number of valid closure encoded in the gbuffer. */ int closure_count; /* Only used for book-keeping when reading. */ int layer_data; @@ -297,51 +294,81 @@ void gbuffer_append_closure(inout GBufferWriter gbuf, GBufferMode closure_type) gbuf.header |= gbuffer_header_pack(closure_type, gbuf.closure_count); gbuf.closure_count++; } -void gbuffer_register_closure(inout GBufferReader gbuf, ClosureUndetermined cl) +void gbuffer_register_closure(inout GBufferReader gbuf, ClosureUndetermined cl, int slot) { - gbuf.closures[gbuf.closure_count] = cl; - gbuf.closure_count++; - switch (cl.type) { - case CLOSURE_NONE_ID: - /* TODO(fclem): Assert. */ + switch (slot) { +#if GBUFFER_LAYER_MAX > 0 + case 0: + gbuf.closures[0] = cl; break; - case CLOSURE_BSSRDF_BURLEY_ID: - /* TODO(fclem): BSSSRDF closure. */ - gbuf.data.diffuse.N = cl.N; - gbuf.data.diffuse.color = cl.color; - gbuf.data.diffuse.sss_radius = cl.data.xyz; - gbuf.has_diffuse = true; - gbuf.has_sss = true; +#endif +#if GBUFFER_LAYER_MAX > 1 + case 1: + gbuf.closures[1] = cl; break; - case CLOSURE_BSDF_DIFFUSE_ID: - gbuf.data.diffuse.N = cl.N; - gbuf.data.diffuse.color = cl.color; - gbuf.has_diffuse = true; - break; - case CLOSURE_BSDF_TRANSLUCENT_ID: - gbuf.data.translucent.N = cl.N; - gbuf.data.translucent.color = cl.color; - gbuf.has_translucent = true; - break; - case CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID: - gbuf.data.reflection.N = cl.N; - gbuf.data.reflection.color = cl.color; - gbuf.data.reflection.roughness = cl.data.x; - gbuf.has_reflection = true; - break; - case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: - gbuf.data.refraction.N = cl.N; - gbuf.data.refraction.color = cl.color; - gbuf.data.refraction.roughness = cl.data.x; - gbuf.data.refraction.ior = cl.data.y; - gbuf.has_refraction = true; +#endif +#if GBUFFER_LAYER_MAX > 2 + case 2: + gbuf.closures[2] = cl; break; +#endif + } +} + +ClosureUndetermined gbuffer_closure_get(GBufferReader gbuf, int i) +{ + switch (i) { +#if GBUFFER_LAYER_MAX > 0 + case 0: + return gbuf.closures[0]; +#endif +#if GBUFFER_LAYER_MAX > 1 + case 1: + return gbuf.closures[1]; +#endif +#if GBUFFER_LAYER_MAX > 2 + case 2: + return gbuf.closures[2]; +#endif + default: + return closure_new(CLOSURE_NONE_ID); } } void gbuffer_append_data(inout GBufferWriter gbuf, vec4 data) { - gbuf.data[gbuf.layer_data] = data; + switch (gbuf.layer_data) { +#if GBUFFER_DATA_MAX > 0 + case 0: + gbuf.data[0] = data; + break; +#endif +#if GBUFFER_DATA_MAX > 1 + case 1: + gbuf.data[1] = data; + break; +#endif +#if GBUFFER_DATA_MAX > 2 + case 2: + gbuf.data[2] = data; + break; +#endif +#if GBUFFER_DATA_MAX > 3 + case 3: + gbuf.data[3] = data; + break; +#endif +#if GBUFFER_DATA_MAX > 4 + case 4: + gbuf.data[4] = data; + break; +#endif +#if GBUFFER_DATA_MAX > 5 + case 5: + gbuf.data[5] = data; + break; +#endif + } gbuf.layer_data++; } vec4 gbuffer_pop_first_data(inout GBufferReader gbuf, samplerGBufferClosure closure_tx) @@ -353,7 +380,24 @@ vec4 gbuffer_pop_first_data(inout GBufferReader gbuf, samplerGBufferClosure clos void gbuffer_append_normal(inout GBufferWriter gbuf, vec3 normal) { - gbuf.N[gbuf.layer_normal] = gbuffer_normal_pack(normal); + vec2 packed_N = gbuffer_normal_pack(normal); + switch (gbuf.layer_normal) { +#if GBUFFER_NORMAL_MAX > 0 + case 0: + gbuf.N[0] = packed_N; + break; +#endif +#if GBUFFER_NORMAL_MAX > 1 + case 1: + gbuf.N[1] = packed_N; + break; +#endif +#if GBUFFER_NORMAL_MAX > 2 + case 2: + gbuf.N[2] = packed_N; + break; +#endif + } gbuf.layer_normal++; } vec3 gbuffer_pop_first_normal(inout GBufferReader gbuf, samplerGBufferNormal normal_tx) @@ -374,8 +418,8 @@ void gbuffer_additional_info_load(inout GBufferReader gbuf, samplerGBufferNormal { vec2 data_packed = fetchGBuffer(normal_tx, gbuf.texel, gbuf.layer_normal).rg; gbuf.layer_normal++; - gbuf.data.thickness = gbuffer_thickness_unpack(data_packed.x); - gbuf.data.object_id = gbuffer_object_id_unorm16_unpack(data_packed.y); + gbuf.thickness = gbuffer_thickness_unpack(data_packed.x); + gbuf.object_id = gbuffer_object_id_unorm16_unpack(data_packed.y); } /** \} */ @@ -393,6 +437,7 @@ void gbuffer_closure_diffuse_pack(inout GBufferWriter gbuf, ClosureUndetermined } void gbuffer_closure_diffuse_load(inout GBufferReader gbuf, + int layer, samplerGBufferClosure closure_tx, samplerGBufferNormal normal_tx) { @@ -402,7 +447,7 @@ void gbuffer_closure_diffuse_load(inout GBufferReader gbuf, cl.color = gbuffer_closure_color_unpack(data0); cl.N = gbuffer_pop_first_normal(gbuf, normal_tx); - gbuffer_register_closure(gbuf, cl); + gbuffer_register_closure(gbuf, cl, layer); } void gbuffer_closure_translucent_pack(inout GBufferWriter gbuf, ClosureUndetermined cl) @@ -413,6 +458,7 @@ void gbuffer_closure_translucent_pack(inout GBufferWriter gbuf, ClosureUndetermi } void gbuffer_closure_translucent_load(inout GBufferReader gbuf, + int layer, samplerGBufferClosure closure_tx, samplerGBufferNormal normal_tx) { @@ -422,7 +468,7 @@ void gbuffer_closure_translucent_load(inout GBufferReader gbuf, cl.color = gbuffer_closure_color_unpack(data0); cl.N = gbuffer_pop_first_normal(gbuf, normal_tx); - gbuffer_register_closure(gbuf, cl); + gbuffer_register_closure(gbuf, cl, layer); } void gbuffer_closure_subsurface_pack(inout GBufferWriter gbuf, ClosureUndetermined cl) @@ -434,6 +480,7 @@ void gbuffer_closure_subsurface_pack(inout GBufferWriter gbuf, ClosureUndetermin } void gbuffer_closure_subsurface_load(inout GBufferReader gbuf, + int layer, samplerGBufferClosure closure_tx, samplerGBufferNormal normal_tx) { @@ -445,7 +492,7 @@ void gbuffer_closure_subsurface_load(inout GBufferReader gbuf, cl.data.rgb = gbuffer_sss_radii_unpack(data1); cl.N = gbuffer_pop_first_normal(gbuf, normal_tx); - gbuffer_register_closure(gbuf, cl); + gbuffer_register_closure(gbuf, cl, layer); } void gbuffer_closure_reflection_pack(inout GBufferWriter gbuf, ClosureUndetermined cl) @@ -457,6 +504,7 @@ void gbuffer_closure_reflection_pack(inout GBufferWriter gbuf, ClosureUndetermin } void gbuffer_closure_reflection_load(inout GBufferReader gbuf, + int layer, samplerGBufferClosure closure_tx, samplerGBufferNormal normal_tx) { @@ -468,7 +516,7 @@ void gbuffer_closure_reflection_load(inout GBufferReader gbuf, cl.data.x = data1.x; cl.N = gbuffer_pop_first_normal(gbuf, normal_tx); - gbuffer_register_closure(gbuf, cl); + gbuffer_register_closure(gbuf, cl, layer); } void gbuffer_closure_refraction_pack(inout GBufferWriter gbuf, ClosureUndetermined cl) @@ -480,6 +528,7 @@ void gbuffer_closure_refraction_pack(inout GBufferWriter gbuf, ClosureUndetermin } void gbuffer_closure_refraction_load(inout GBufferReader gbuf, + int layer, samplerGBufferClosure closure_tx, samplerGBufferNormal normal_tx) { @@ -492,7 +541,7 @@ void gbuffer_closure_refraction_load(inout GBufferReader gbuf, cl.data.y = gbuffer_ior_unpack(data1.y); cl.N = gbuffer_pop_first_normal(gbuf, normal_tx); - gbuffer_register_closure(gbuf, cl); + gbuffer_register_closure(gbuf, cl, layer); } /** \} */ @@ -512,6 +561,7 @@ void gbuffer_closure_reflection_colorless_pack(inout GBufferWriter gbuf, Closure } void gbuffer_closure_reflection_colorless_load(inout GBufferReader gbuf, + int layer, samplerGBufferClosure closure_tx, samplerGBufferNormal normal_tx) { @@ -523,7 +573,7 @@ void gbuffer_closure_reflection_colorless_load(inout GBufferReader gbuf, cl.N = gbuffer_pop_first_normal(gbuf, normal_tx); - gbuffer_register_closure(gbuf, cl); + gbuffer_register_closure(gbuf, cl, layer); } void gbuffer_closure_refraction_colorless_pack(inout GBufferWriter gbuf, ClosureUndetermined cl) @@ -535,6 +585,7 @@ void gbuffer_closure_refraction_colorless_pack(inout GBufferWriter gbuf, Closure } void gbuffer_closure_refraction_colorless_load(inout GBufferReader gbuf, + int layer, samplerGBufferClosure closure_tx, samplerGBufferNormal normal_tx) { @@ -547,7 +598,7 @@ void gbuffer_closure_refraction_colorless_load(inout GBufferReader gbuf, cl.N = gbuffer_pop_first_normal(gbuf, normal_tx); - gbuffer_register_closure(gbuf, cl); + gbuffer_register_closure(gbuf, cl, layer); } /** \} */ @@ -586,8 +637,8 @@ void gbuffer_closure_metal_clear_coat_load(inout GBufferReader gbuf, coat.N = bottom.N = gbuffer_pop_first_normal(gbuf, normal_tx); - gbuffer_register_closure(gbuf, bottom); - gbuffer_register_closure(gbuf, coat); + gbuffer_register_closure(gbuf, bottom, 0); + gbuffer_register_closure(gbuf, coat, 1); } /** \} */ @@ -641,7 +692,8 @@ GBufferWriter gbuffer_pack(GBufferDataUndetermined data_in) } } - if (has_translucent) { + /* TODO(fclem): Allow misxing of translucent and refraction. */ + if (has_translucent && !has_refraction) { gbuffer_closure_translucent_pack(gbuf, data_in.translucent); } @@ -658,92 +710,53 @@ GBufferWriter gbuffer_pack(GBufferDataUndetermined data_in) return gbuf; } -/* Populate the GBufferReader only based on the header. The rest of the data is undefined. */ -GBufferReader gbuffer_read_header(uint header) +/* Return the number of closure as encoded in the give header value. */ +uint gbuffer_closure_count(uint header) { - GBufferReader gbuf; - gbuf.header = header; - gbuf.has_any_surface = (header != 0u); - gbuf.has_diffuse = false; - gbuf.has_reflection = false; - gbuf.has_refraction = false; - gbuf.has_translucent = false; - gbuf.has_sss = false; - gbuf.closure_count = 0; + uvec4 closure_types = (uvec4(header) >> uvec4(0u, 4u, 8u, 12u)) & 15u; - for (int layer = 0; layer < 4; layer++) { - GBufferMode mode = gbuffer_header_unpack(gbuf.header, layer); - switch (mode) { - case GBUF_NONE: - break; - case GBUF_DIFFUSE: - gbuf.has_diffuse = true; - break; - case GBUF_TRANSLUCENT: - gbuf.has_translucent = true; - break; - case GBUF_SUBSURFACE: - gbuf.has_diffuse = true; - gbuf.has_sss = true; - break; - case GBUF_METAL_CLEARCOAT: - case GBUF_REFLECTION_COLORLESS: - case GBUF_REFLECTION: - gbuf.has_reflection = true; - break; - case GBUF_REFRACTION_COLORLESS: - case GBUF_REFRACTION: - gbuf.has_refraction = true; - break; - } + if (closure_types.x == GBUF_METAL_CLEARCOAT) { + return 2u; } - - return gbuf; + return reduce_add(vec4(not(equal(closure_types, uvec4(0u))))); } GBufferReader gbuffer_read_header_closure_types(uint header) { GBufferReader gbuf; - gbuf.header = header; - gbuf.has_any_surface = (header != 0u); gbuf.closure_count = 0; - for (int layer = 0; layer < 4; layer++) { - GBufferMode mode = gbuffer_header_unpack(gbuf.header, layer); + for (int layer = 0; layer < GBUFFER_LAYER_MAX; layer++) { + GBufferMode mode = gbuffer_header_unpack(header, layer); + int closure_type = CLOSURE_NONE_ID; switch (mode) { - case GBUF_NONE: - break; case GBUF_DIFFUSE: - gbuf.closures[gbuf.closure_count].type = CLOSURE_BSDF_DIFFUSE_ID; - gbuf.closure_count += 1; + closure_type = CLOSURE_BSDF_DIFFUSE_ID; + gbuf.closure_count++; break; case GBUF_TRANSLUCENT: - gbuf.closures[gbuf.closure_count].type = CLOSURE_BSDF_TRANSLUCENT_ID; - gbuf.closure_count += 1; + closure_type = CLOSURE_BSDF_TRANSLUCENT_ID; + gbuf.closure_count++; break; case GBUF_SUBSURFACE: - gbuf.closures[gbuf.closure_count].type = CLOSURE_BSSRDF_BURLEY_ID; - gbuf.closure_count += 1; - break; - case GBUF_METAL_CLEARCOAT: - gbuf.closures[gbuf.closure_count].type = CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID; - gbuf.closure_count += 1; - gbuf.closures[gbuf.closure_count].type = CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID; - gbuf.closure_count += 1; + closure_type = CLOSURE_BSSRDF_BURLEY_ID; + gbuf.closure_count++; break; case GBUF_REFLECTION_COLORLESS: case GBUF_REFLECTION: - gbuf.closures[gbuf.closure_count].type = CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID; - gbuf.closure_count += 1; + closure_type = CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID; + gbuf.closure_count++; break; case GBUF_REFRACTION_COLORLESS: case GBUF_REFRACTION: - gbuf.closures[gbuf.closure_count].type = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; - gbuf.closure_count += 1; + closure_type = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; + gbuf.closure_count++; + break; + default: break; } + gbuffer_register_closure(gbuf, closure_new(closure_type), layer); } - return gbuf; } @@ -754,82 +767,66 @@ GBufferReader gbuffer_read(samplerGBufferHeader header_tx, { GBufferReader gbuf; gbuf.texel = texel; - gbuf.header = fetchGBuffer(header_tx, texel); - gbuf.has_any_surface = (gbuf.header != 0u); - gbuf.has_diffuse = false; - gbuf.has_reflection = false; - gbuf.has_refraction = false; - gbuf.has_translucent = false; - gbuf.has_sss = false; - gbuf.data.thickness = 0.0; + gbuf.thickness = 0.0; gbuf.closure_count = 0; + gbuf.object_id = 0u; gbuf.layer_data = 0; gbuf.layer_normal = 0; + gbuf.surface_N = vec3(0.0); - if (!gbuf.has_any_surface) { + uint header = fetchGBuffer(header_tx, texel); + if (header == 0u) { + for (int layer = 0; layer < GBUFFER_LAYER_MAX; layer++) { + gbuffer_register_closure(gbuf, closure_new(CLOSURE_NONE_ID), layer); + } return gbuf; } /* First closure is always written. */ - gbuf.data.surface_N = gbuffer_normal_unpack(fetchGBuffer(normal_tx, texel, 0).xy); - - /* Default values. */ - gbuf.data.refraction.color = vec3(0.0); - gbuf.data.refraction.N = vec3(0.0, 0.0, 1.0); - gbuf.data.refraction.roughness = 0.0; - gbuf.data.refraction.ior = 1.1; /* Avoid NaN in some places. */ - - gbuf.data.reflection.color = vec3(0.0); - gbuf.data.reflection.N = vec3(0.0, 0.0, 1.0); - gbuf.data.reflection.roughness = 0.0; - - gbuf.data.diffuse.color = vec3(0.0); - gbuf.data.diffuse.N = vec3(0.0, 0.0, 1.0); - gbuf.data.diffuse.sss_radius = vec3(0.0, 0.0, 0.0); - gbuf.data.diffuse.sss_id = 0u; - - gbuf.data.translucent.color = vec3(0.0); - gbuf.data.translucent.N = vec3(0.0, 0.0, 1.0); - - gbuf.data.thickness = 0.0; + gbuf.surface_N = gbuffer_normal_unpack(fetchGBuffer(normal_tx, texel, 0).xy); + bool has_additional_data = false; for (int layer = 0; layer < GBUFFER_LAYER_MAX; layer++) { - gbuf.closures[layer].type = CLOSURE_NONE_ID; - } - - for (int layer = 0; layer < GBUFFER_LAYER_MAX; layer++) { - GBufferMode mode = gbuffer_header_unpack(gbuf.header, layer); + GBufferMode mode = gbuffer_header_unpack(header, layer); switch (mode) { + default: case GBUF_NONE: + gbuffer_register_closure(gbuf, closure_new(CLOSURE_NONE_ID), layer); break; case GBUF_DIFFUSE: - gbuffer_closure_diffuse_load(gbuf, closure_tx, normal_tx); + gbuffer_closure_diffuse_load(gbuf, layer, closure_tx, normal_tx); + gbuf.closure_count++; break; case GBUF_TRANSLUCENT: - gbuffer_closure_translucent_load(gbuf, closure_tx, normal_tx); + gbuffer_closure_translucent_load(gbuf, layer, closure_tx, normal_tx); + gbuf.closure_count++; + has_additional_data = true; break; case GBUF_SUBSURFACE: - gbuffer_closure_subsurface_load(gbuf, closure_tx, normal_tx); + gbuffer_closure_subsurface_load(gbuf, layer, closure_tx, normal_tx); + gbuf.closure_count++; + has_additional_data = true; break; case GBUF_REFLECTION: - gbuffer_closure_reflection_load(gbuf, closure_tx, normal_tx); + gbuffer_closure_reflection_load(gbuf, layer, closure_tx, normal_tx); + gbuf.closure_count++; break; case GBUF_REFRACTION: - gbuffer_closure_refraction_load(gbuf, closure_tx, normal_tx); + gbuffer_closure_refraction_load(gbuf, layer, closure_tx, normal_tx); + gbuf.closure_count++; break; case GBUF_REFLECTION_COLORLESS: - gbuffer_closure_reflection_colorless_load(gbuf, closure_tx, normal_tx); + gbuffer_closure_reflection_colorless_load(gbuf, layer, closure_tx, normal_tx); + gbuf.closure_count++; break; case GBUF_REFRACTION_COLORLESS: - gbuffer_closure_refraction_colorless_load(gbuf, closure_tx, normal_tx); - break; - case GBUF_METAL_CLEARCOAT: - gbuffer_closure_metal_clear_coat_load(gbuf, closure_tx, normal_tx); + gbuffer_closure_refraction_colorless_load(gbuf, layer, closure_tx, normal_tx); + gbuf.closure_count++; break; } } - if (gbuf.has_sss || gbuf.has_translucent) { + if (has_additional_data) { gbuffer_additional_info_load(gbuf, normal_tx); } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_gbuffer_test.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_gbuffer_test.glsl index 91e3ebe7c76..66ab068d497 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_gbuffer_test.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_gbuffer_test.glsl @@ -46,12 +46,13 @@ void main() EXPECT_EQ(g_data_packed.layer_data, 1); EXPECT_EQ(data_out.closure_count, 1); - EXPECT_TRUE(data_out.has_any_surface); - EXPECT_TRUE(data_out.has_diffuse); + ClosureUndetermined out_diffuse = gbuffer_closure_get(data_out, 0); + + EXPECT_EQ(out_diffuse.type, CLOSURE_BSDF_DIFFUSE_ID); EXPECT_EQ(data_in.diffuse.type, CLOSURE_BSDF_DIFFUSE_ID); - EXPECT_NEAR(data_in.diffuse.color, data_out.data.diffuse.color, 1e-5); - EXPECT_NEAR(data_in.diffuse.N, data_out.data.diffuse.N, 1e-5); + EXPECT_NEAR(data_in.diffuse.color, out_diffuse.color, 1e-5); + EXPECT_NEAR(data_in.diffuse.N, out_diffuse.N, 1e-5); } TEST(eevee_gbuffer, ClosureSubsurface) @@ -68,14 +69,14 @@ void main() EXPECT_EQ(g_data_packed.layer_data, 2); EXPECT_EQ(data_out.closure_count, 1); - EXPECT_TRUE(data_out.has_any_surface); - EXPECT_TRUE(data_out.has_diffuse); - EXPECT_TRUE(data_out.has_sss); + ClosureUndetermined out_sss_burley = gbuffer_closure_get(data_out, 0); + + EXPECT_EQ(out_sss_burley.type, CLOSURE_BSSRDF_BURLEY_ID); EXPECT_EQ(data_in.diffuse.type, CLOSURE_BSSRDF_BURLEY_ID); - EXPECT_NEAR(data_in.diffuse.color, data_out.data.diffuse.color, 1e-5); - EXPECT_NEAR(data_in.diffuse.N, data_out.data.diffuse.N, 1e-5); - EXPECT_NEAR(data_in.diffuse.data.rgb, data_out.data.diffuse.sss_radius, 1e-5); + EXPECT_NEAR(data_in.diffuse.color, out_sss_burley.color, 1e-5); + EXPECT_NEAR(data_in.diffuse.N, out_sss_burley.N, 1e-5); + EXPECT_NEAR(data_in.diffuse.data.rgb, to_closure_diffuse(out_sss_burley).sss_radius, 1e-5); } TEST(eevee_gbuffer, ClosureTranslucent) @@ -91,12 +92,13 @@ void main() EXPECT_EQ(g_data_packed.layer_data, 1); EXPECT_EQ(data_out.closure_count, 1); - EXPECT_TRUE(data_out.has_any_surface); - EXPECT_TRUE(data_out.has_translucent); + ClosureUndetermined out_translucent = gbuffer_closure_get(data_out, 0); + + EXPECT_EQ(out_translucent.type, CLOSURE_BSDF_TRANSLUCENT_ID); EXPECT_EQ(data_in.translucent.type, CLOSURE_BSDF_TRANSLUCENT_ID); - EXPECT_NEAR(data_in.translucent.color, data_out.data.translucent.color, 1e-5); - EXPECT_NEAR(data_in.translucent.N, data_out.data.translucent.N, 1e-5); + EXPECT_NEAR(data_in.translucent.color, out_translucent.color, 1e-5); + EXPECT_NEAR(data_in.translucent.N, out_translucent.N, 1e-5); } TEST(eevee_gbuffer, ClosureReflection) @@ -113,13 +115,14 @@ void main() EXPECT_EQ(g_data_packed.layer_data, 2); EXPECT_EQ(data_out.closure_count, 1); - EXPECT_TRUE(data_out.has_any_surface); - EXPECT_TRUE(data_out.has_reflection); + ClosureUndetermined out_reflection = gbuffer_closure_get(data_out, 0); + + EXPECT_EQ(out_reflection.type, CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID); EXPECT_EQ(data_in.reflection.type, CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID); - EXPECT_NEAR(data_in.reflection.color, data_out.data.reflection.color, 1e-5); - EXPECT_NEAR(data_in.reflection.N, data_out.data.reflection.N, 1e-5); - EXPECT_NEAR(data_in.reflection.data.r, data_out.data.reflection.roughness, 1e-5); + EXPECT_NEAR(data_in.reflection.color, out_reflection.color, 1e-5); + EXPECT_NEAR(data_in.reflection.N, out_reflection.N, 1e-5); + EXPECT_NEAR(data_in.reflection.data.r, out_reflection.data.r, 1e-5); } TEST(eevee_gbuffer, ClosureRefraction) @@ -137,14 +140,15 @@ void main() EXPECT_EQ(g_data_packed.layer_data, 2); EXPECT_EQ(data_out.closure_count, 1); - EXPECT_TRUE(data_out.has_any_surface); - EXPECT_TRUE(data_out.has_refraction); + ClosureUndetermined out_refraction = gbuffer_closure_get(data_out, 0); + + EXPECT_EQ(out_refraction.type, CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID); EXPECT_EQ(data_in.refraction.type, CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID); - EXPECT_NEAR(data_in.refraction.color, data_out.data.refraction.color, 1e-5); - EXPECT_NEAR(data_in.refraction.N, data_out.data.refraction.N, 1e-5); - EXPECT_NEAR(data_in.refraction.data.r, data_out.data.refraction.roughness, 1e-5); - EXPECT_NEAR(data_in.refraction.data.g, data_out.data.refraction.ior, 1e-5); + EXPECT_NEAR(data_in.refraction.color, out_refraction.color, 1e-5); + EXPECT_NEAR(data_in.refraction.N, out_refraction.N, 1e-5); + EXPECT_NEAR(data_in.refraction.data.r, out_refraction.data.r, 1e-5); + EXPECT_NEAR(data_in.refraction.data.g, out_refraction.data.g, 1e-5); } TEST(eevee_gbuffer, ClosureCombination) @@ -170,20 +174,22 @@ void main() data_out = gbuffer_read(header_tx, closure_tx, normal_tx, ivec2(0)); EXPECT_EQ(data_out.closure_count, 2); - EXPECT_TRUE(data_out.has_any_surface); - EXPECT_TRUE(data_out.has_refraction); - EXPECT_TRUE(data_out.has_reflection); + ClosureUndetermined out_reflection = gbuffer_closure_get(data_out, 1); + ClosureUndetermined out_refraction = gbuffer_closure_get(data_out, 0); + + EXPECT_EQ(out_refraction.type, CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID); EXPECT_EQ(data_in.refraction.type, CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID); - EXPECT_NEAR(data_in.refraction.color, data_out.data.refraction.color, 1e-5); - EXPECT_NEAR(data_in.refraction.N, data_out.data.refraction.N, 1e-5); - EXPECT_NEAR(data_in.refraction.data.r, data_out.data.refraction.roughness, 1e-5); - EXPECT_NEAR(data_in.refraction.data.g, data_out.data.refraction.ior, 1e-5); + EXPECT_NEAR(data_in.refraction.color, out_refraction.color, 1e-5); + EXPECT_NEAR(data_in.refraction.N, out_refraction.N, 1e-5); + EXPECT_NEAR(data_in.refraction.data.r, out_refraction.data.r, 1e-5); + EXPECT_NEAR(data_in.refraction.data.g, out_refraction.data.g, 1e-5); + EXPECT_EQ(out_reflection.type, CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID); EXPECT_EQ(data_in.reflection.type, CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID); - EXPECT_NEAR(data_in.reflection.color, data_out.data.reflection.color, 1e-5); - EXPECT_NEAR(data_in.reflection.N, data_out.data.reflection.N, 1e-5); - EXPECT_NEAR(data_in.reflection.data.r, data_out.data.reflection.roughness, 1e-5); + EXPECT_NEAR(data_in.reflection.color, out_reflection.color, 1e-5); + EXPECT_NEAR(data_in.reflection.N, out_reflection.N, 1e-5); + EXPECT_NEAR(data_in.reflection.data.r, out_reflection.data.r, 1e-5); } TEST(eevee_gbuffer, ClosureColorless) @@ -209,19 +215,21 @@ void main() data_out = gbuffer_read(header_tx, closure_tx, normal_tx, ivec2(0)); EXPECT_EQ(data_out.closure_count, 2); - EXPECT_TRUE(data_out.has_any_surface); - EXPECT_TRUE(data_out.has_refraction); - EXPECT_TRUE(data_out.has_reflection); + ClosureUndetermined out_reflection = gbuffer_closure_get(data_out, 1); + ClosureUndetermined out_refraction = gbuffer_closure_get(data_out, 0); + + EXPECT_EQ(out_refraction.type, CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID); EXPECT_EQ(data_in.refraction.type, CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID); - EXPECT_NEAR(data_in.refraction.color, data_out.data.refraction.color, 1e-5); - EXPECT_NEAR(data_in.refraction.N, data_out.data.refraction.N, 1e-5); - EXPECT_NEAR(data_in.refraction.data.r, data_out.data.refraction.roughness, 1e-5); - EXPECT_NEAR(data_in.refraction.data.g, data_out.data.refraction.ior, 1e-5); + EXPECT_NEAR(data_in.refraction.color, out_refraction.color, 1e-5); + EXPECT_NEAR(data_in.refraction.N, out_refraction.N, 1e-5); + EXPECT_NEAR(data_in.refraction.data.r, out_refraction.data.r, 1e-5); + EXPECT_NEAR(data_in.refraction.data.g, out_refraction.data.g, 1e-5); + EXPECT_EQ(out_reflection.type, CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID); EXPECT_EQ(data_in.reflection.type, CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID); - EXPECT_NEAR(data_in.reflection.color, data_out.data.reflection.color, 1e-5); - EXPECT_NEAR(data_in.reflection.N, data_out.data.reflection.N, 1e-5); - EXPECT_NEAR(data_in.reflection.data.r, data_out.data.reflection.roughness, 1e-5); + EXPECT_NEAR(data_in.reflection.color, out_reflection.color, 1e-5); + EXPECT_NEAR(data_in.reflection.N, out_reflection.N, 1e-5); + EXPECT_NEAR(data_in.reflection.data.r, out_reflection.data.r, 1e-5); } } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_horizon_denoise_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_horizon_denoise_comp.glsl index 1a5843843f9..ed7722c3c7b 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_horizon_denoise_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_horizon_denoise_comp.glsl @@ -56,7 +56,7 @@ vec3 from_accumulation_space(vec3 color) vec3 load_normal(ivec2 texel) { - return gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_normal_tx, texel).data.surface_N; + return gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_normal_tx, texel).surface_N; } void main() @@ -93,7 +93,7 @@ void main() return; } - ClosureUndetermined closure_center = gbuf.closures[closure_index]; + ClosureUndetermined closure_center = gbuffer_closure_get(gbuf, closure_index); vec3 center_N = closure_center.N; float roughness = closure_apparent_roughness_get(closure_center); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_horizon_scan_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_horizon_scan_comp.glsl index 15ff2b99c87..dd41965601b 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_horizon_scan_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_horizon_scan_comp.glsl @@ -47,7 +47,7 @@ void main() } HorizonScanContext ctx; - ctx.closure = gbuf.closures[closure_index]; + ctx.closure = gbuffer_closure_get(gbuf, closure_index); ctx.closure.N = drw_normal_world_to_view(ctx.closure.N); vec3 vP = drw_point_screen_to_view(vec3(uv, depth)); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_horizon_setup_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_horizon_setup_comp.glsl index 79b7290ce0d..6746775a409 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_horizon_setup_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_horizon_setup_comp.glsl @@ -23,7 +23,7 @@ void main() gbuf_header_tx, gbuf_closure_tx, gbuf_normal_tx, texel_fullres); /* Export normal. */ - vec3 N = gbuf.data.surface_N; + vec3 N = gbuf.surface_N; if (is_zero(N)) { /* Avoid NaN. But should be fixed in any case. */ N = vec3(1.0, 0.0, 0.0); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_ray_denoise_bilateral_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_ray_denoise_bilateral_comp.glsl index 6fa388f4a35..36f2ebcc6c8 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_ray_denoise_bilateral_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_ray_denoise_bilateral_comp.glsl @@ -85,7 +85,7 @@ void main() return; } - ClosureUndetermined center_closure = gbuf.closures[closure_index]; + ClosureUndetermined center_closure = gbuffer_closure_get(gbuf, closure_index); float roughness = closure_apparent_roughness_get(center_closure); float variance = imageLoad(in_variance_img, texel_fullres).r; @@ -149,7 +149,7 @@ void main() continue; } - ClosureUndetermined sample_closure = sample_gbuf.closures[closure_index]; + ClosureUndetermined sample_closure = gbuffer_closure_get(sample_gbuf, closure_index); float depth_weight = bilateral_depth_weight(center_closure.N, center_P, sample_P); float spatial_weight = bilateral_spatial_weight(filter_size, vec2(offset)); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_ray_denoise_spatial_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_ray_denoise_spatial_comp.glsl index b0d7f5e76f1..12f236b6586 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_ray_denoise_spatial_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_ray_denoise_spatial_comp.glsl @@ -126,7 +126,7 @@ void main() vec3 P = drw_point_screen_to_world(vec3(uv, 0.5)); vec3 V = drw_world_incident_vector(P); - ClosureUndetermined closure = gbuf.closures[closure_index]; + ClosureUndetermined closure = gbuffer_closure_get(gbuf, closure_index); /* Compute filter size and needed sample count */ float apparent_roughness = closure_apparent_roughness_get(closure); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_ray_generate_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_ray_generate_comp.glsl index b7f294776a8..d8b50293213 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_ray_generate_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_ray_generate_comp.glsl @@ -35,7 +35,7 @@ void main() vec3 V = drw_world_incident_vector(P); vec2 noise = utility_tx_fetch(utility_tx, vec2(texel), UTIL_BLUE_NOISE_LAYER).rg; - BsdfSample samp = ray_generate_direction(noise.xy, gbuf.closures[closure_index], V); + BsdfSample samp = ray_generate_direction(noise.xy, gbuffer_closure_get(gbuf, closure_index), V); /* Store inverse pdf to speedup denoising. * Limit to the smallest non-0 value that the format can encode. diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_ray_tile_classify_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_ray_tile_classify_comp.glsl index b13f54502c2..f8a9db7cb23 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_ray_tile_classify_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_ray_tile_classify_comp.glsl @@ -13,8 +13,8 @@ #pragma BLENDER_REQUIRE(eevee_gbuffer_lib.glsl) #pragma BLENDER_REQUIRE(eevee_closure_lib.glsl) -shared uint tile_contains_ray_tracing[3]; -shared uint tile_contains_horizon_scan[3]; +shared uint tile_contains_ray_tracing[GBUFFER_LAYER_MAX]; +shared uint tile_contains_horizon_scan[GBUFFER_LAYER_MAX]; /* Returns a blend factor between different tracing method. */ float ray_roughness_factor(RayTraceData raytrace, float roughness) @@ -26,7 +26,7 @@ void main() { if (gl_LocalInvocationIndex == 0u) { /* Init shared variables. */ - for (int i = 0; i < 3; i++) { + for (int i = 0; i < GBUFFER_LAYER_MAX; i++) { tile_contains_ray_tracing[i] = 0; tile_contains_horizon_scan[i] = 0; } @@ -41,8 +41,12 @@ void main() if (valid_texel) { GBufferReader gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_normal_tx, texel); - for (int i = 0; i < 3 && i < gbuf.closure_count; i++) { - float roughness = closure_apparent_roughness_get(gbuf.closures[i]); + for (int i = 0; i < GBUFFER_LAYER_MAX; i++) { + ClosureUndetermined cl = gbuffer_closure_get(gbuf, i); + if (cl.type == CLOSURE_NONE_ID) { + break; + } + float roughness = closure_apparent_roughness_get(cl); float ray_roughness_fac = ray_roughness_factor(uniform_buf.raytrace, roughness); /* We don't care about race condition here. */ @@ -61,7 +65,7 @@ void main() ivec2 denoise_tile_co = ivec2(gl_WorkGroupID.xy); ivec2 tracing_tile_co = denoise_tile_co / uniform_buf.raytrace.resolution_scale; - for (int i = 0; i < 3; i++) { + for (int i = 0; i < GBUFFER_LAYER_MAX; i++) { if (tile_contains_ray_tracing[i] > 0) { imageStore(tile_raytrace_denoise_img, ivec3(denoise_tile_co, i), uvec4(1)); imageStore(tile_raytrace_tracing_img, ivec3(tracing_tile_co, i), uvec4(1)); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_ray_trace_planar_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_ray_trace_planar_comp.glsl index ec9e0b278bc..45247a2fd3e 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_ray_trace_planar_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_ray_trace_planar_comp.glsl @@ -42,7 +42,7 @@ void main() uint gbuf_header = texelFetch(gbuf_header_tx, texel_fullres, 0).r; GBufferReader gbuf = gbuffer_read_header_closure_types(gbuf_header); - uint closure_type = gbuf.closures[closure_index].type; + uint closure_type = gbuffer_closure_get(gbuf, closure_index).type; if ((closure_type == CLOSURE_BSDF_TRANSLUCENT_ID) || (closure_type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID)) diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_ray_trace_screen_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_ray_trace_screen_comp.glsl index f1905fc1e28..55155995e36 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_ray_trace_screen_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_ray_trace_screen_comp.glsl @@ -44,7 +44,7 @@ void main() uint gbuf_header = texelFetch(gbuf_header_tx, texel_fullres, 0).r; GBufferReader gbuf = gbuffer_read_header_closure_types(gbuf_header); - uint closure_type = gbuf.closures[closure_index].type; + uint closure_type = gbuffer_closure_get(gbuf, closure_index).type; bool is_reflection = true; if ((closure_type == CLOSURE_BSDF_TRANSLUCENT_ID) || diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_subsurface_convolve_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_subsurface_convolve_comp.glsl index d501aedd912..d4623162330 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_subsurface_convolve_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_subsurface_convolve_comp.glsl @@ -93,12 +93,14 @@ void main(void) vec3 vP = drw_point_screen_to_view(vec3(center_uv, depth)); GBufferReader gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_normal_tx, texel); - - if (!gbuf.has_sss) { + if (gbuffer_closure_get(gbuf, 0).type != CLOSURE_BSSRDF_BURLEY_ID) { return; } - float max_radius = reduce_max(gbuf.data.diffuse.sss_radius); + /* TODO SSS closure. */ + ClosureDiffuse closure = to_closure_diffuse(gbuffer_closure_get(gbuf, 0)); + + float max_radius = reduce_max(closure.sss_radius); float homcoord = ProjectionMatrix[2][3] * vP.z + ProjectionMatrix[3][3]; vec2 sample_scale = vec2(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) * @@ -111,10 +113,9 @@ void main(void) } /* Avoid too small radii that have float imprecision. */ - vec3 clamped_sss_radius = max(vec3(1e-4), gbuf.data.diffuse.sss_radius / max_radius) * - max_radius; + vec3 clamped_sss_radius = max(vec3(1e-4), closure.sss_radius / max_radius) * max_radius; /* Scale albedo because we can have HDR value caused by BSDF sampling. */ - vec3 albedo = gbuf.data.diffuse.color / max(1e-6, reduce_max(gbuf.data.diffuse.color)); + vec3 albedo = closure.color / max(1e-6, reduce_max(closure.color)); vec3 d = burley_setup(clamped_sss_radius, albedo); /* Do not rotate too much to avoid too much cache misses. */ @@ -132,7 +133,7 @@ void main(void) SubSurfaceSample samp = sample_neighborhood(sample_uv); /* Reject radiance from other surfaces. Avoids light leak between objects. */ - if (samp.sss_id != gbuf.data.object_id) { + if (samp.sss_id != gbuf.object_id) { continue; } /* Slide 34. */ diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_subsurface_setup_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_subsurface_setup_comp.glsl index c81cf972dce..bb858fe4b6d 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_subsurface_setup_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_subsurface_setup_comp.glsl @@ -25,14 +25,17 @@ void main(void) GBufferReader gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_normal_tx, texel); - if (gbuf.has_sss) { + if (gbuffer_closure_get(gbuf, 0).type == CLOSURE_BSSRDF_BURLEY_ID) { + /* TODO SSS closure. */ + vec3 radiance = imageLoad(direct_light_img, texel).rgb + imageLoad(indirect_light_img, texel).rgb; - float max_radius = reduce_max(gbuf.data.diffuse.sss_radius); + ClosureDiffuse closure = to_closure_diffuse(gbuffer_closure_get(gbuf, 0)); + float max_radius = reduce_max(closure.sss_radius); imageStore(radiance_img, texel, vec4(radiance, 0.0)); - imageStore(object_id_img, texel, uvec4(gbuf.data.object_id)); + imageStore(object_id_img, texel, uvec4(gbuf.object_id)); vec2 center_uv = (vec2(texel) + 0.5) / vec2(textureSize(gbuf_header_tx, 0)); float depth = texelFetch(depth_tx, texel, 0).r; diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_deferred_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_deferred_info.hh index 5c7b4304d07..d132d289033 100644 --- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_deferred_info.hh +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_deferred_info.hh @@ -127,6 +127,7 @@ GPU_SHADER_CREATE_INFO(eevee_deferred_capture_eval) /* Inputs. */ .fragment_out(0, Type::VEC4, "out_radiance") .define("SHADOW_SUBSURFACE") + .define("LIGHT_CLOSURE_EVAL_COUNT", "2") .additional_info("eevee_shared", "eevee_gbuffer_data", "eevee_utility_texture",