From cbc7512b0c68a02ac60f393ff70b0dcc17d8e0f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Thu, 16 Mar 2023 17:41:10 +0100 Subject: [PATCH 1/9] EEVEE-Next: Add GBuffer This only port the gbuffer creation not the lighting evaluation. --- source/blender/draw/CMakeLists.txt | 1 + .../draw/engines/eevee_next/eevee_defines.hh | 3 + .../draw/engines/eevee_next/eevee_gbuffer.hh | 87 ++++++++++++++ .../draw/engines/eevee_next/eevee_instance.hh | 2 + .../eevee_next/shaders/eevee_gbuffer_lib.glsl | 58 +++++++++ .../shaders/eevee_nodetree_lib.glsl | 2 +- .../shaders/eevee_surf_deferred_frag.glsl | 111 +++++++++++++++++- .../shaders/infos/eevee_material_info.hh | 38 +++--- 8 files changed, 284 insertions(+), 18 deletions(-) create mode 100644 source/blender/draw/engines/eevee_next/eevee_gbuffer.hh create mode 100644 source/blender/draw/engines/eevee_next/shaders/eevee_gbuffer_lib.glsl diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index e1aad7d4280..5a8635755d8 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -448,6 +448,7 @@ set(GLSL_SRC engines/eevee_next/shaders/eevee_film_cryptomatte_post_comp.glsl engines/eevee_next/shaders/eevee_film_frag.glsl engines/eevee_next/shaders/eevee_film_lib.glsl + engines/eevee_next/shaders/eevee_gbuffer_lib.glsl engines/eevee_next/shaders/eevee_geom_curves_vert.glsl engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl diff --git a/source/blender/draw/engines/eevee_next/eevee_defines.hh b/source/blender/draw/engines/eevee_next/eevee_defines.hh index bc778dc874d..c54d537db61 100644 --- a/source/blender/draw/engines/eevee_next/eevee_defines.hh +++ b/source/blender/draw/engines/eevee_next/eevee_defines.hh @@ -105,6 +105,9 @@ #define RBUFS_AOV_COLOR_SLOT 5 #define RBUFS_AOV_VALUE_SLOT 6 #define RBUFS_CRYPTOMATTE_SLOT 7 +/* G-buffer reuses render passes slots. */ +#define GBUF_CLOSURE_SLOT RBUFS_LIGHT_SLOT +#define GBUF_COLOR_SLOT RBUFS_DIFF_COLOR_SLOT /* Uniform Buffers. */ /* Only during prepass. */ diff --git a/source/blender/draw/engines/eevee_next/eevee_gbuffer.hh b/source/blender/draw/engines/eevee_next/eevee_gbuffer.hh new file mode 100644 index 00000000000..14f48ae9b5e --- /dev/null +++ b/source/blender/draw/engines/eevee_next/eevee_gbuffer.hh @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup eevee + * + * Gbuffer layout used for deferred shading pipeline. + */ + +#pragma once + +#include "DRW_render.h" + +#include "eevee_shader_shared.hh" + +namespace blender::eevee { + +class Instance; + +/** + * Fullscreen textures containing geometric and surface data. + * Used by deferred shading passes. Only one gbuffer is allocated per view + * and is reused for each deferred layer. This is why there can only be temporary + * texture inside it. + * + * Everything is stored inside two array texture, one for each format. This is to fit the + * limitation of the number of images we can bind on a single shader. + * + * First layer is always for reflection. All parameters to shoot a reflection ray are inside + * this layer. + * + * - Layer 1 : Reflection + * - R : Normal packed X + * - G : Normal packed Y + * - B : Roughness + * - A : Unused (Could be used for anisotropic roughness) + * + * Second layer is either for diffuse or transmission. Material mixing both are not + * physically based and are uncommon. So in order to save bandwidth and texture memory, we only + * store one. We use random sampling to mix between both. All parameters to shoot a refraction + * ray are inside this layer. + * + * - Layer 2 : Refraction + * - R : Normal packed X + * - G : Normal packed Y + * - B : Roughness (isotropic) + * - A : IOR + * + * - Layer 2 : Diffuse / Sub-Surface Scattering + * - R : Normal packed X + * - G : Normal packed Y + * - B : Thickness + * - A : Unused (Could be used for diffuse roughness) + * + * Layer 3 is only allocated if Sub-Surface Scattering is needed. All parameters for + * screen-space scattering are inside this layer. + * + * - Layer 3 : Sub-Surface Scattering + * - R : Scattering radius R + * - G : Scattering radius G + * - B : Scattering radius B + * - A : Object ID + * + * For each output closure, we also output the color to apply after the lighting computation. + * The color is stored with a 2 exponent that allows input color with component higher than 1. + * Color degradation is expected to happen in this case. + */ +struct GBuffer { + /* TODO(fclem): Use texture from pool once they support texture array. */ + Texture closure_tx = {"GbufferClosure"}; + Texture color_tx = {"GbufferColor"}; + + void acquire(int2 extent, eClosureBits closures_used) + { + eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE; + closure_tx.ensure_2d_array(GPU_RGBA16, extent, (closures_used & CLOSURE_SSS) ? 3 : 2, usage); + color_tx.ensure_2d_array(GPU_RGB10_A2, extent, 2, usage); + } + + void release() + { + /* TODO(fclem): Use texture from pool once they support texture array. */ + // closure_tx.release(); + // color_tx.release(); + } +}; + +} // namespace blender::eevee \ No newline at end of file diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.hh b/source/blender/draw/engines/eevee_next/eevee_instance.hh index 6bb54a37a2c..8e7855961e4 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.hh +++ b/source/blender/draw/engines/eevee_next/eevee_instance.hh @@ -19,6 +19,7 @@ #include "eevee_cryptomatte.hh" #include "eevee_depth_of_field.hh" #include "eevee_film.hh" +#include "eevee_gbuffer.hh" #include "eevee_hizbuffer.hh" #include "eevee_irradiance_cache.hh" #include "eevee_light.hh" @@ -54,6 +55,7 @@ class Instance { MotionBlurModule motion_blur; DepthOfField depth_of_field; Cryptomatte cryptomatte; + GBuffer gbuffer; HiZBuffer hiz_buffer; Sampling sampling; Camera camera; 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 new file mode 100644 index 00000000000..74e749dcc7f --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_gbuffer_lib.glsl @@ -0,0 +1,58 @@ + +/** + * G-buffer: Packing and upacking for the of the G-buffer data. + * + * See `GPU_SHADER_CREATE_INFO(eevee_surf_deferred)` for a breakdown of the G-buffer layout. + */ + +#pragma BLENDER_REQUIRE(common_view_lib.glsl) + +vec2 gbuffer_normal_pack(vec3 N) +{ + return N.xy; +} + +vec3 gbuffer_normal_unpack(vec2 N_packed) +{ + return vec3(N_packed.xy, sqrt(1.0 - sqr(N_packed.x) - sqr(N_packed.y))); +} + +float gbuffer_ior_pack(float ior) +{ + return ior; +} + +float gbuffer_ior_unpack(float ior_packed) +{ + return ior_packed; +} + +float gbuffer_thickness_pack(float thickness) +{ + return thickness; +} + +float gbuffer_thickness_unpack(float thickness_packed) +{ + return thickness_packed; +} + +vec3 gbuffer_sss_radii_pack(vec3 sss_radii) +{ + return sss_radii; +} + +vec3 gbuffer_sss_radii_unpack(vec3 sss_radii_packed) +{ + return sss_radii_packed; +} + +vec4 gbuffer_color_pack(vec3 color) +{ + return vec4(color, 1.0); +} + +vec3 gbuffer_color_unpack(vec4 color_packed) +{ + return color_packed.rgb; +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl index 965780d9bcf..62be853ab95 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl @@ -29,7 +29,7 @@ bool closure_select(float weight, inout float total_weight, inout float r) float x = weight / total_weight; bool chosen = (r < x); /* Assuming that if r is in the interval [0,x] or [x,1], it's still uniformly distributed within - * that interval, so you remapping to [0,1] again to explore this space of probability. */ + * that interval, so remapping to [0,1] again to explore this space of probability. */ r = (chosen) ? (r / x) : ((r - x) / (1.0 - x)); return chosen; } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl index 7848c4a0611..f3519d6daec 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl @@ -3,17 +3,126 @@ * Deferred lighting evaluation: Lighting is evaluated in a separate pass. * * Outputs shading parameter per pixel using a randomized set of BSDFs. - **/ + * Some render-pass are written during this pass. + */ #pragma BLENDER_REQUIRE(common_view_lib.glsl) #pragma BLENDER_REQUIRE(common_math_lib.glsl) #pragma BLENDER_REQUIRE(common_hair_lib.glsl) #pragma BLENDER_REQUIRE(eevee_surf_lib.glsl) #pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_gbuffer_lib.glsl) + +vec4 closure_to_rgba(Closure cl) +{ + /* Should never be called. */ + return vec4(0.0); +} void main() { init_globals(); + float noise = utility_tx_fetch(utility_tx, gl_FragCoord.xy, UTIL_BLUE_NOISE_LAYER).r; + g_closure_rand = fract(noise + sampling_rng_1D_get(SAMPLING_CLOSURE)); + + fragment_displacement(); + nodetree_surface(); + + g_holdout = saturate(g_holdout); + + out_transmittance = vec4(1.0 - g_holdout); + float transmittance_mono = saturate(avg(g_transmittance)); + + float thickness = nodetree_thickness(); + + g_diffuse_data.color *= g_diffuse_data.weight; + g_reflection_data.color *= g_reflection_data.weight; + g_refraction_data.color *= g_refraction_data.weight; + + /* TODO(fclem): This feels way too complex for what is it. */ + bool has_any_bsdf_weight = g_diffuse_data.weight != 0.0 || g_reflection_data.weight != 0.0 || + g_refraction_data.weight != 0.0; + vec3 out_normal = has_any_bsdf_weight ? vec3(0.0) : g_data.N; + out_normal += g_diffuse_data.N * g_diffuse_data.weight; + out_normal += g_reflection_data.N * g_reflection_data.weight; + out_normal += g_refraction_data.N * g_refraction_data.weight; + out_normal = safe_normalize(out_normal); + + vec3 specular_color = g_reflection_data.color + g_refraction_data.color; + + /* ----- Render Passes output ----- */ + + ivec2 out_texel = ivec2(gl_FragCoord.xy); +#ifdef MAT_RENDER_PASS_SUPPORT + /* Some render pass can be written during the gbuffer pass. Light passes are written later. */ + vec4 cryptomatte_output = vec4(cryptomatte_object_buf[resource_id], node_tree.crypto_hash, 0.0); + imageStore(rp_cryptomatte_img, out_texel, cryptomatte_output); + imageStore(rp_normal_img, out_texel, vec4(out_normal, 1.0)); + /* TODO(fclem): For now, just don't do anything. In the future all render passes should be in an + * array texture and have a UBO with indirection to the correct layer. */ + // imageStore(rp_diffuse_color_img, out_texel, vec4(g_diffuse_data.color, 1.0)); + imageStore(rp_specular_color_img, out_texel, vec4(specular_color, 1.0)); + imageStore(rp_emission_img, out_texel, vec4(g_emission, 1.0)); +#endif + + /* ----- GBuffer output ----- */ + + if (true) { + /* Reflection. */ + vec4 out_reflect = vec4(gbuffer_normal_pack(g_reflection_data.N), + g_reflection_data.roughness, + g_reflection_data.roughness); + imageStore(out_gbuff_closure_img, ivec3(out_texel, 0), out_reflect); + + vec4 color = gbuffer_color_pack(g_diffuse_data.color); + imageStore(out_gbuff_color_img, ivec3(out_texel, 0), color); + } + + /* TODO(fclem) other RNG. */ + float refract_rand = fract(g_closure_rand * 6.1803398875); + float combined_weight = g_refraction_data.weight + g_diffuse_data.weight; + bool output_refraction = combined_weight > 0.0 && + (refract_rand * combined_weight) < g_refraction_data.weight; + if (output_refraction) { + /* Refraction. */ + vec4 closure; + closure.xy = gbuffer_normal_pack(g_refraction_data.N); + closure.z = g_refraction_data.roughness; + closure.w = gbuffer_ior_pack(g_refraction_data.ior); + imageStore(out_gbuff_closure_img, ivec3(out_texel, 1), closure); + + vec4 color = gbuffer_color_pack(g_refraction_data.color); + imageStore(out_gbuff_color_img, ivec3(out_texel, 1), color); + } + else { + /* Diffuse. */ + vec4 closure; + closure.xy = gbuffer_normal_pack(g_diffuse_data.N); + closure.z = gbuffer_thickness_pack(thickness); + closure.w = 0.0; /* Unused. */ + imageStore(out_gbuff_closure_img, ivec3(out_texel, 1), closure); + + vec4 color = gbuffer_color_pack(g_diffuse_data.color); + imageStore(out_gbuff_color_img, ivec3(out_texel, 1), color); + } + + if (true) { + /* SubSurface Scattering. */ + vec4 closure; + closure.xyz = gbuffer_sss_radii_pack(g_refraction_data.N); + closure.w = gbuffer_ior_pack(g_refraction_data.ior); + imageStore(out_gbuff_closure_img, ivec3(out_texel, 2), closure); + } + + /* ----- Radiance output ----- */ + + /* Only output emission during the gbuffer pass. */ + out_radiance = vec4(g_emission, 0.0); + out_radiance.rgb *= 1.0 - g_holdout; + + out_transmittance.rgb = g_transmittance; + out_transmittance.a = saturate(avg(g_transmittance)); } diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh index 0ef16bf3522..3e34bed9958 100644 --- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh @@ -88,11 +88,11 @@ GPU_SHADER_CREATE_INFO(eevee_aov_out) GPU_SHADER_CREATE_INFO(eevee_render_pass_out) .define("MAT_RENDER_PASS_SUPPORT") - .image_out(RBUFS_NORMAL_SLOT, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_normal_img") - .image_array_out(RBUFS_LIGHT_SLOT, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_light_img") - .image_out(RBUFS_DIFF_COLOR_SLOT, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_diffuse_color_img") - .image_out(RBUFS_SPEC_COLOR_SLOT, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_specular_color_img") - .image_out(RBUFS_EMISSION_SLOT, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_emission_img"); + .image_out(RBUFS_NORMAL_SLOT, Qualifier::WRITE, GPU_RGBA16F, "rp_normal_img") + .image_array_out(RBUFS_LIGHT_SLOT, Qualifier::WRITE, GPU_RGBA16F, "rp_light_img") + .image_out(RBUFS_DIFF_COLOR_SLOT, Qualifier::WRITE, GPU_RGBA16F, "rp_diffuse_color_img") + .image_out(RBUFS_SPEC_COLOR_SLOT, Qualifier::WRITE, GPU_RGBA16F, "rp_specular_color_img") + .image_out(RBUFS_EMISSION_SLOT, Qualifier::WRITE, GPU_RGBA16F, "rp_emission_img"); GPU_SHADER_CREATE_INFO(eevee_cryptomatte_out) .storage_buf(CRYPTOMATTE_BUF_SLOT, Qualifier::READ, "vec2", "cryptomatte_object_buf[]") @@ -101,23 +101,29 @@ GPU_SHADER_CREATE_INFO(eevee_cryptomatte_out) GPU_SHADER_CREATE_INFO(eevee_surf_deferred) .vertex_out(eevee_surf_iface) /* NOTE: This removes the possibility of using gl_FragDepth. */ - // .early_fragment_test(true) - /* Direct output. */ + .early_fragment_test(true) + /* Direct output. (Emissive, Holdout) */ .fragment_out(0, Type::VEC4, "out_radiance", DualBlend::SRC_0) .fragment_out(0, Type::VEC4, "out_transmittance", DualBlend::SRC_1) - /* Gbuffer. */ - // .image_out(0, Qualifier::WRITE, GPU_R11F_G11F_B10F, "gbuff_transmit_color") - // .image_out(1, Qualifier::WRITE, GPU_R11F_G11F_B10F, "gbuff_transmit_data") - // .image_out(2, Qualifier::WRITE, GPU_RGBA16F, "gbuff_transmit_normal") - // .image_out(3, Qualifier::WRITE, GPU_R11F_G11F_B10F, "gbuff_reflection_color") - // .image_out(4, Qualifier::WRITE, GPU_RGBA16F, "gbuff_reflection_normal") - // .image_out(5, Qualifier::WRITE, GPU_R11F_G11F_B10F, "gbuff_emission") - /* Render-passes. */ - // .image_out(6, Qualifier::READ_WRITE, GPU_RGBA16F, "rpass_volume_light") + /* Everything is stored inside a two layered target, one for each format. This is to fit the + * limitation of the number of images we can bind on a single shader. */ + .image_array_out(GBUF_CLOSURE_SLOT, Qualifier::WRITE, GPU_RGBA16, "out_gbuff_closure_img") + .image_array_out(GBUF_COLOR_SLOT, Qualifier::WRITE, GPU_RGB10_A2, "out_gbuff_color_img") + /* Render-passes need to be declared manually to avoid overlap with the G-buffer which reuse + * some of binding points. */ + .image_out(RBUFS_NORMAL_SLOT, Qualifier::WRITE, GPU_RGBA16F, "rp_normal_img") + // .image_array_out(RBUFS_LIGHT_SLOT, Qualifier::WRITE, GPU_RGBA16F, "rp_light_img") + /* TODO(fclem): Merge all render-pass into the same texture array. */ + // .image_out(RBUFS_DIFF_COLOR_SLOT, Qualifier::WRITE, GPU_RGBA16F, "rp_diffuse_color_img") + .image_array_out(RBUFS_SPEC_COLOR_SLOT, Qualifier::WRITE, GPU_RGBA16F, "rp_specular_color_img") + .image_out(RBUFS_EMISSION_SLOT, Qualifier::WRITE, GPU_RGBA16F, "rp_emission_img") .fragment_source("eevee_surf_deferred_frag.glsl") .additional_info("eevee_camera", "eevee_utility_texture", "eevee_sampling_data", + /* Added manually to avoid overlap. */ + // "eevee_render_pass_out", + "eevee_cryptomatte_out", "eevee_aov_out"); GPU_SHADER_CREATE_INFO(eevee_surf_forward) -- 2.30.2 From 36131b0aff0b087aee34ef9648d28f6862514bd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Thu, 16 Mar 2023 22:57:27 +0100 Subject: [PATCH 2/9] EEVEE-Next: Implement deferred pipeline Lighting isn't implemented yet. --- .../draw/engines/eevee_next/eevee_film.cc | 2 +- .../draw/engines/eevee_next/eevee_gbuffer.hh | 6 +- .../draw/engines/eevee_next/eevee_material.cc | 4 - .../draw/engines/eevee_next/eevee_pipeline.cc | 180 ++++++++++++++++++ .../draw/engines/eevee_next/eevee_pipeline.hh | 73 ++++++- .../draw/engines/eevee_next/eevee_view.cc | 3 +- .../eevee_next/shaders/eevee_gbuffer_lib.glsl | 33 +++- .../shaders/eevee_surf_deferred_frag.glsl | 2 +- .../common/gpu_shader_common_math_utils.glsl | 19 +- 9 files changed, 294 insertions(+), 28 deletions(-) diff --git a/source/blender/draw/engines/eevee_next/eevee_film.cc b/source/blender/draw/engines/eevee_next/eevee_film.cc index beab3bdb196..d49ddd7866e 100644 --- a/source/blender/draw/engines/eevee_next/eevee_film.cc +++ b/source/blender/draw/engines/eevee_next/eevee_film.cc @@ -649,7 +649,7 @@ void Film::accumulate(const DRWView *view, GPUTexture *combined_final_tx) draw::View drw_view("MainView", view); - DRW_manager_get()->submit(accumulate_ps_, drw_view); + inst_.manager->submit(accumulate_ps_, drw_view); combined_tx_.swap(); weight_tx_.swap(); diff --git a/source/blender/draw/engines/eevee_next/eevee_gbuffer.hh b/source/blender/draw/engines/eevee_next/eevee_gbuffer.hh index 14f48ae9b5e..74a17e317f2 100644 --- a/source/blender/draw/engines/eevee_next/eevee_gbuffer.hh +++ b/source/blender/draw/engines/eevee_next/eevee_gbuffer.hh @@ -10,6 +10,7 @@ #include "DRW_render.h" +#include "eevee_material.hh" #include "eevee_shader_shared.hh" namespace blender::eevee { @@ -69,10 +70,11 @@ struct GBuffer { Texture closure_tx = {"GbufferClosure"}; Texture color_tx = {"GbufferColor"}; - void acquire(int2 extent, eClosureBits closures_used) + void acquire(int2 extent, eClosureBits closure_bits_) { + const bool use_sss = (closure_bits_ & CLOSURE_SSS) != 0; eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE; - closure_tx.ensure_2d_array(GPU_RGBA16, extent, (closures_used & CLOSURE_SSS) ? 3 : 2, usage); + closure_tx.ensure_2d_array(GPU_RGBA16, extent, use_sss ? 3 : 2, usage); color_tx.ensure_2d_array(GPU_RGB10_A2, extent, 2, usage); } diff --git a/source/blender/draw/engines/eevee_next/eevee_material.cc b/source/blender/draw/engines/eevee_next/eevee_material.cc index 43c91dc32d5..c00dd97a5d5 100644 --- a/source/blender/draw/engines/eevee_next/eevee_material.cc +++ b/source/blender/draw/engines/eevee_next/eevee_material.cc @@ -240,10 +240,6 @@ Material &MaterialModule::material_sync(Object *ob, (has_motion ? MAT_PIPE_DEFERRED_PREPASS_VELOCITY : MAT_PIPE_DEFERRED_PREPASS); - /* TEST until we have deferred pipeline up and running. */ - surface_pipe = MAT_PIPE_FORWARD; - prepass_pipe = has_motion ? MAT_PIPE_FORWARD_PREPASS_VELOCITY : MAT_PIPE_FORWARD_PREPASS; - MaterialKey material_key(blender_mat, geometry_type, surface_pipe); Material &mat = material_map_.lookup_or_add_cb(material_key, [&]() { diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc index 94ce44522ba..625503b35ea 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc @@ -278,4 +278,184 @@ void ForwardPipeline::render(View &view, /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Deferred Pipeline + * + * Closure data are written to intermediate buffer allowing screen space processing. + * \{ */ + +void DeferredLayer::sync() +{ + DRWState state_depth_only = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS; + DRWState state_depth_color = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | + DRW_STATE_WRITE_COLOR; + { + prepass_ps_.init(); + prepass_ps_.clear_stencil(0x00u); + + { + /* Common resources. */ + + /* Textures. */ + prepass_ps_.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx); + /* Uniform Buf. */ + prepass_ps_.bind_ubo(CAMERA_BUF_SLOT, inst_.camera.ubo_get()); + + inst_.velocity.bind_resources(&prepass_ps_); + inst_.sampling.bind_resources(&prepass_ps_); + } + + prepass_double_sided_static_ps_ = &prepass_ps_.sub("DoubleSided.Static"); + prepass_double_sided_static_ps_->state_set(state_depth_only); + + prepass_single_sided_static_ps_ = &prepass_ps_.sub("SingleSided.Static"); + prepass_single_sided_static_ps_->state_set(state_depth_only | DRW_STATE_CULL_BACK); + + prepass_double_sided_moving_ps_ = &prepass_ps_.sub("DoubleSided.Moving"); + prepass_double_sided_moving_ps_->state_set(state_depth_color); + + prepass_single_sided_moving_ps_ = &prepass_ps_.sub("SingleSided.Moving"); + prepass_single_sided_moving_ps_->state_set(state_depth_color | DRW_STATE_CULL_BACK); + } + { + gbuffer_ps_.init(); + + { + /* Common resources. */ + + /* G-buffer. */ + gbuffer_ps_.bind_image(GBUF_CLOSURE_SLOT, &inst_.gbuffer.closure_tx); + gbuffer_ps_.bind_image(GBUF_COLOR_SLOT, &inst_.gbuffer.color_tx); + + /* RenderPasses. */ + gbuffer_ps_.bind_image(RBUFS_NORMAL_SLOT, &inst_.render_buffers.normal_tx); + /* TODO(fclem): Pack all render pass into the same texture. */ + // gbuffer_ps_.bind_image(RBUFS_DIFF_COLOR_SLOT, &inst_.render_buffers.diffuse_color_tx); + gbuffer_ps_.bind_image(RBUFS_SPEC_COLOR_SLOT, &inst_.render_buffers.specular_color_tx); + gbuffer_ps_.bind_image(RBUFS_EMISSION_SLOT, &inst_.render_buffers.emission_tx); + /* AOVs. */ + gbuffer_ps_.bind_image(RBUFS_AOV_COLOR_SLOT, &inst_.render_buffers.aov_color_tx); + gbuffer_ps_.bind_image(RBUFS_AOV_VALUE_SLOT, &inst_.render_buffers.aov_value_tx); + /* Cryptomatte. */ + gbuffer_ps_.bind_image(RBUFS_CRYPTOMATTE_SLOT, &inst_.render_buffers.cryptomatte_tx); + /* Storage Buf. */ + gbuffer_ps_.bind_ssbo(RBUFS_AOV_BUF_SLOT, &inst_.film.aovs_info); + /* Textures. */ + gbuffer_ps_.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx); + /* Uniform Buf. */ + gbuffer_ps_.bind_ubo(CAMERA_BUF_SLOT, inst_.camera.ubo_get()); + + inst_.sampling.bind_resources(&gbuffer_ps_); + inst_.cryptomatte.bind_resources(&gbuffer_ps_); + } + + gbuffer_single_sided_ps_ = &gbuffer_ps_.sub("SingleSided"); + gbuffer_single_sided_ps_->state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | + DRW_STATE_CULL_BACK); + + gbuffer_double_sided_ps_ = &gbuffer_ps_.sub("DoubleSided"); + gbuffer_double_sided_ps_->state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); + } +} + +PassMain::Sub *DeferredLayer::prepass_add(::Material *blender_mat, + GPUMaterial *gpumat, + bool has_motion) +{ + closure_bits_ |= shader_closure_bits_from_flag(gpumat); + + PassMain::Sub *pass = (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) ? + (has_motion ? prepass_single_sided_moving_ps_ : + prepass_single_sided_static_ps_) : + (has_motion ? prepass_double_sided_moving_ps_ : + prepass_double_sided_static_ps_); + return &pass->sub(GPU_material_get_name(gpumat)); +} + +PassMain::Sub *DeferredLayer::material_add(::Material *blender_mat, GPUMaterial *gpumat) +{ + PassMain::Sub *pass = (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) ? + gbuffer_single_sided_ps_ : + gbuffer_double_sided_ps_; + return &pass->sub(GPU_material_get_name(gpumat)); +} + +void DeferredLayer::render(View &view, + Framebuffer &prepass_fb, + Framebuffer &combined_fb, + int2 extent) +{ + inst_.gbuffer.acquire(extent, closure_bits_); + + GPU_framebuffer_bind(prepass_fb); + inst_.manager->submit(prepass_ps_, view); + + inst_.hiz_buffer.set_dirty(); + + GPU_framebuffer_bind(combined_fb); + inst_.manager->submit(gbuffer_ps_, view); + + inst_.shadows.set_view(view); + inst_.manager->submit(inst_.pipelines.deferred.eval_ps_); + + /* TODO evaluate lights. */ + + inst_.gbuffer.release(); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Deferred Pipeline + * + * Closure data are written to intermediate buffer allowing screen space processing. + * \{ */ + +void DeferredPipeline::sync() +{ + opaque_layer_.sync(); + refraction_layer_.sync(); + + eval_ps_.init(); + /* TODO Lighting. */ +} + +PassMain::Sub *DeferredPipeline::prepass_add(::Material *blender_mat, + GPUMaterial *gpumat, + bool has_motion) +{ + if (blender_mat->blend_flag & MA_BL_SS_REFRACTION) { + return refraction_layer_.prepass_add(blender_mat, gpumat, has_motion); + } + else { + return opaque_layer_.prepass_add(blender_mat, gpumat, has_motion); + } +} + +PassMain::Sub *DeferredPipeline::material_add(::Material *blender_mat, GPUMaterial *gpumat) +{ + if (blender_mat->blend_flag & MA_BL_SS_REFRACTION) { + return refraction_layer_.material_add(blender_mat, gpumat); + } + else { + return opaque_layer_.material_add(blender_mat, gpumat); + } +} + +void DeferredPipeline::render(View &view, + Framebuffer &prepass_fb, + Framebuffer &combined_fb, + int2 extent) +{ + DRW_stats_group_start("Deferred.Opaque"); + opaque_layer_.render(view, prepass_fb, combined_fb, extent); + DRW_stats_group_end(); + + DRW_stats_group_start("Deferred.Refract"); + refraction_layer_.render(view, prepass_fb, combined_fb, extent); + DRW_stats_group_end(); +} + +/** \} */ + } // namespace blender::eevee diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.hh b/source/blender/draw/engines/eevee_next/eevee_pipeline.hh index a437ca8c522..516f8a0ee01 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.hh +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.hh @@ -113,6 +113,65 @@ class ForwardPipeline { /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Deferred lighting. + * \{ */ + +class DeferredLayer { + private: + Instance &inst_; + + PassMain prepass_ps_ = {"Prepass"}; + PassMain::Sub *prepass_single_sided_static_ps_ = nullptr; + PassMain::Sub *prepass_single_sided_moving_ps_ = nullptr; + PassMain::Sub *prepass_double_sided_static_ps_ = nullptr; + PassMain::Sub *prepass_double_sided_moving_ps_ = nullptr; + + PassMain gbuffer_ps_ = {"Shading"}; + PassMain::Sub *gbuffer_single_sided_ps_ = nullptr; + PassMain::Sub *gbuffer_double_sided_ps_ = nullptr; + + /* Closures bits from the materials in this pass. */ + eClosureBits closure_bits_; + + public: + DeferredLayer(Instance &inst) : inst_(inst){}; + + void sync(); + + PassMain::Sub *prepass_add(::Material *blender_mat, GPUMaterial *gpumat, bool has_motion); + PassMain::Sub *material_add(::Material *blender_mat, GPUMaterial *gpumat); + + void render(View &view, Framebuffer &prepass_fb, Framebuffer &combined_fb, int2 extent); +}; + +class DeferredPipeline { + public: + PassSimple eval_ps_ = {"EvalLighting"}; + + private: + Instance &inst_; + + /* Gbuffer filling passes. We could have an arbitrary number of them but for now we just have + * a hardcoded number of them. */ + DeferredLayer opaque_layer_; + DeferredLayer refraction_layer_; + DeferredLayer volumetric_layer_; + + public: + DeferredPipeline(Instance &inst) + : inst_(inst), opaque_layer_(inst), refraction_layer_(inst), volumetric_layer_(inst){}; + + void sync(); + + PassMain::Sub *prepass_add(::Material *material, GPUMaterial *gpumat, bool has_motion); + PassMain::Sub *material_add(::Material *material, GPUMaterial *gpumat); + + void render(View &view, Framebuffer &prepass_fb, Framebuffer &combined_fb, int2 extent); +}; + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Utility texture * @@ -197,22 +256,20 @@ class UtilityTexture : public Texture { class PipelineModule { public: WorldPipeline world; - // DeferredPipeline deferred; + DeferredPipeline deferred; ForwardPipeline forward; ShadowPipeline shadow; - // VelocityPipeline velocity; UtilityTexture utility_tx; public: - PipelineModule(Instance &inst) : world(inst), forward(inst), shadow(inst){}; + PipelineModule(Instance &inst) : world(inst), deferred(inst), forward(inst), shadow(inst){}; void sync() { - // deferred.sync(); + deferred.sync(); forward.sync(); shadow.sync(); - // velocity.sync(); } PassMain::Sub *material_add(Object *ob, @@ -222,7 +279,7 @@ class PipelineModule { { switch (pipeline_type) { case MAT_PIPE_DEFERRED_PREPASS: - // return deferred.prepass_add(blender_mat, gpumat, false); + return deferred.prepass_add(blender_mat, gpumat, false); case MAT_PIPE_FORWARD_PREPASS: if (GPU_material_flag_get(gpumat, GPU_MATFLAG_TRANSPARENT)) { return forward.prepass_transparent_add(ob, blender_mat, gpumat); @@ -230,7 +287,7 @@ class PipelineModule { return forward.prepass_opaque_add(blender_mat, gpumat, false); case MAT_PIPE_DEFERRED_PREPASS_VELOCITY: - // return deferred.prepass_add(blender_mat, gpumat, true); + return deferred.prepass_add(blender_mat, gpumat, true); case MAT_PIPE_FORWARD_PREPASS_VELOCITY: if (GPU_material_flag_get(gpumat, GPU_MATFLAG_TRANSPARENT)) { return forward.prepass_transparent_add(ob, blender_mat, gpumat); @@ -238,7 +295,7 @@ class PipelineModule { return forward.prepass_opaque_add(blender_mat, gpumat, true); case MAT_PIPE_DEFERRED: - // return deferred.material_add(blender_mat, gpumat); + return deferred.material_add(blender_mat, gpumat); case MAT_PIPE_FORWARD: if (GPU_material_flag_get(gpumat, GPU_MATFLAG_TRANSPARENT)) { return forward.material_transparent_add(ob, blender_mat, gpumat); diff --git a/source/blender/draw/engines/eevee_next/eevee_view.cc b/source/blender/draw/engines/eevee_next/eevee_view.cc index 8037af78db1..d2d8f80feb7 100644 --- a/source/blender/draw/engines/eevee_next/eevee_view.cc +++ b/source/blender/draw/engines/eevee_next/eevee_view.cc @@ -123,8 +123,7 @@ void ShadingView::render() /* TODO(fclem): Move it after the first prepass (and hiz update) once pipeline is stabilized. */ inst_.lights.set_view(render_view_new_, extent_); - // inst_.pipelines.deferred.render( - // render_view_, rt_buffer_opaque_, rt_buffer_refract_, depth_tx_, combined_tx_); + inst_.pipelines.deferred.render(render_view_new_, prepass_fb_, combined_fb_, extent_); // inst_.lightprobes.draw_cache_display(); 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 74e749dcc7f..b510114f440 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 @@ -1,58 +1,75 @@ /** - * G-buffer: Packing and upacking for the of the G-buffer data. + * G-buffer: Packing and upacking of G-buffer data. * - * See `GPU_SHADER_CREATE_INFO(eevee_surf_deferred)` for a breakdown of the G-buffer layout. + * See #GBuffer for a breakdown of the G-buffer layout. */ -#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_math_vector_lib.glsl) vec2 gbuffer_normal_pack(vec3 N) { + N /= length_manhattan(N); + N.xy = (N.z >= 0.0) ? N.xy : ((1.0 - abs(N.yx)) * sign(N.xy)); + N.xy = N.xy * 0.5 + 0.5; return N.xy; } vec3 gbuffer_normal_unpack(vec2 N_packed) { - return vec3(N_packed.xy, sqrt(1.0 - sqr(N_packed.x) - sqr(N_packed.y))); + N_packed = N_packed * 2.0 - 1.0; + vec3 N = vec3(N_packed.x, N_packed.y, 1.0 - abs(N_packed.x) - abs(N_packed.y)); + float t = clamp(-N.z, 0.0, 1.0); + N.x += (N.x >= 0.0) ? -t : t; + N.y += (N.y >= 0.0) ? -t : t; + return normalize(N); } float gbuffer_ior_pack(float ior) { - return ior; + return (ior > 1.0) ? (1.0 - 0.5 / ior) : (0.5 * ior); } float gbuffer_ior_unpack(float ior_packed) { - return ior_packed; + return (ior_packed > 0.5) ? (-1.0 / (ior_packed * 2.0 + 2.0)) : (2.0 * ior_packed); } float gbuffer_thickness_pack(float thickness) { + /* TODO */ return thickness; } float gbuffer_thickness_unpack(float thickness_packed) { + /* TODO */ return thickness_packed; } vec3 gbuffer_sss_radii_pack(vec3 sss_radii) { - return sss_radii; + /* TODO(fclem): Something better. */ + return vec3( + gbuffer_ior_pack(sss_radii.x), gbuffer_ior_pack(sss_radii.y), gbuffer_ior_pack(sss_radii.z)); } vec3 gbuffer_sss_radii_unpack(vec3 sss_radii_packed) { - return sss_radii_packed; + /* TODO(fclem): Something better. */ + return vec3(gbuffer_ior_unpack(sss_radii_packed.x), + gbuffer_ior_unpack(sss_radii_packed.y), + gbuffer_ior_unpack(sss_radii_packed.z)); } vec4 gbuffer_color_pack(vec3 color) { + /* TODO(fclem): 2 exponent inside 2bit Alpha. */ return vec4(color, 1.0); } vec3 gbuffer_color_unpack(vec4 color_packed) { + /* TODO(fclem): 2 exponent inside 2bit Alpha. */ return color_packed.rgb; } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl index f3519d6daec..cf4142fff47 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl @@ -6,13 +6,13 @@ * Some render-pass are written during this pass. */ +#pragma BLENDER_REQUIRE(eevee_gbuffer_lib.glsl) #pragma BLENDER_REQUIRE(common_view_lib.glsl) #pragma BLENDER_REQUIRE(common_math_lib.glsl) #pragma BLENDER_REQUIRE(common_hair_lib.glsl) #pragma BLENDER_REQUIRE(eevee_surf_lib.glsl) #pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl) #pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl) -#pragma BLENDER_REQUIRE(eevee_gbuffer_lib.glsl) vec4 closure_to_rgba(Closure cl) { diff --git a/source/blender/gpu/shaders/common/gpu_shader_common_math_utils.glsl b/source/blender/gpu/shaders/common/gpu_shader_common_math_utils.glsl index ca9c42f2027..ddb014cc045 100644 --- a/source/blender/gpu/shaders/common/gpu_shader_common_math_utils.glsl +++ b/source/blender/gpu/shaders/common/gpu_shader_common_math_utils.glsl @@ -1,18 +1,23 @@ /* Float Math */ +/* WORKAROUND: To be removed once we port all code to use gpu_shader_math_base_lib.glsl. */ +#ifndef GPU_SHADER_MATH_BASE_LIB_GLSL + float safe_divide(float a, float b) { return (b != 0.0) ? a / b : 0.0; } +#endif + /* fmod function compatible with OSL (copy from OSL/dual.h) */ float compatible_fmod(float a, float b) { - if (b != 0.0f) { + if (b != 0.0) { int N = int(a / b); return a - N * b; } - return 0.0f; + return 0.0; } float compatible_pow(float x, float y) @@ -59,11 +64,16 @@ vec3 wrap(vec3 a, vec3 b, vec3 c) return vec3(wrap(a.x, b.x, c.x), wrap(a.y, b.y, c.y), wrap(a.z, b.z, c.z)); } +/* WORKAROUND: To be removed once we port all code to use gpu_shader_math_base_lib.glsl. */ +#ifndef GPU_SHADER_MATH_BASE_LIB_GLSL + float hypot(float x, float y) { return sqrt(x * x + y * y); } +#endif + int floor_to_int(float x) { return int(floor(x)); @@ -76,6 +86,9 @@ int quick_floor(float x) /* Vector Math */ +/* WORKAROUND: To be removed once we port all code to use gpu_shader_math_base_lib.glsl. */ +#ifndef GPU_SHADER_MATH_BASE_LIB_GLSL + vec2 safe_divide(vec2 a, vec2 b) { return vec2(safe_divide(a.x, b.x), safe_divide(a.y, b.y)); @@ -107,6 +120,8 @@ vec4 safe_divide(vec4 a, float b) return (b != 0.0) ? a / b : vec4(0.0); } +#endif + vec3 compatible_fmod(vec3 a, vec3 b) { return vec3(compatible_fmod(a.x, b.x), compatible_fmod(a.y, b.y), compatible_fmod(a.z, b.z)); -- 2.30.2 From f3919a771fd5d899cc9cdac9c423bdf81899b35c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Fri, 17 Mar 2023 21:24:29 +0100 Subject: [PATCH 3/9] EEVEE-Next: Implemented Deferred Lighting This is a work-in-progress implementation. --- source/blender/draw/CMakeLists.txt | 1 + .../draw/engines/eevee_next/eevee_instance.cc | 3 +- .../draw/engines/eevee_next/eevee_pipeline.cc | 86 +++++++++++++---- .../draw/engines/eevee_next/eevee_pipeline.hh | 31 +++++-- .../draw/engines/eevee_next/eevee_shader.cc | 2 + .../draw/engines/eevee_next/eevee_shader.hh | 2 + .../shaders/eevee_deferred_light_frag.glsl | 93 +++++++++++++++++++ .../eevee_next/shaders/eevee_gbuffer_lib.glsl | 36 ++++++- .../shaders/eevee_shadow_tag_usage_frag.glsl | 2 +- .../shaders/eevee_surf_deferred_frag.glsl | 4 +- .../shaders/infos/eevee_deferred_info.hh | 47 ++++++++++ .../blender/draw/intern/draw_texture_pool.cc | 3 +- source/blender/gpu/CMakeLists.txt | 1 + 13 files changed, 275 insertions(+), 36 deletions(-) create mode 100644 source/blender/draw/engines/eevee_next/shaders/eevee_deferred_light_frag.glsl create mode 100644 source/blender/draw/engines/eevee_next/shaders/infos/eevee_deferred_info.hh diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 5a8635755d8..dc16818d22b 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -429,6 +429,7 @@ set(GLSL_SRC engines/eevee_next/shaders/eevee_transparency_lib.glsl engines/eevee_next/shaders/eevee_debug_surfels_vert.glsl engines/eevee_next/shaders/eevee_debug_surfels_frag.glsl + engines/eevee_next/shaders/eevee_deferred_light_frag.glsl engines/eevee_next/shaders/eevee_depth_of_field_accumulator_lib.glsl engines/eevee_next/shaders/eevee_depth_of_field_bokeh_lut_comp.glsl engines/eevee_next/shaders/eevee_depth_of_field_downsample_comp.glsl diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.cc b/source/blender/draw/engines/eevee_next/eevee_instance.cc index 491190334e1..b0a40d27982 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.cc +++ b/source/blender/draw/engines/eevee_next/eevee_instance.cc @@ -105,6 +105,7 @@ void Instance::begin_sync() velocity.begin_sync(); /* NOTE: Also syncs camera. */ lights.begin_sync(); shadows.begin_sync(); + pipelines.begin_sync(); cryptomatte.begin_sync(); gpencil_engine_enabled = false; @@ -114,7 +115,6 @@ void Instance::begin_sync() depth_of_field.sync(); motion_blur.sync(); hiz_buffer.sync(); - pipelines.sync(); main_view.sync(); world.sync(); film.sync(); @@ -206,6 +206,7 @@ void Instance::end_sync() sampling.end_sync(); film.end_sync(); cryptomatte.end_sync(); + pipelines.end_sync(); } void Instance::render_sync() diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc index 625503b35ea..3e1293ee2e4 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc @@ -284,15 +284,10 @@ void ForwardPipeline::render(View &view, * Closure data are written to intermediate buffer allowing screen space processing. * \{ */ -void DeferredLayer::sync() +void DeferredLayer::begin_sync() { - DRWState state_depth_only = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS; - DRWState state_depth_color = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | - DRW_STATE_WRITE_COLOR; { prepass_ps_.init(); - prepass_ps_.clear_stencil(0x00u); - { /* Common resources. */ @@ -305,6 +300,10 @@ void DeferredLayer::sync() inst_.sampling.bind_resources(&prepass_ps_); } + DRWState state_depth_only = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS; + DRWState state_depth_color = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | + DRW_STATE_WRITE_COLOR; + prepass_double_sided_static_ps_ = &prepass_ps_.sub("DoubleSided.Static"); prepass_double_sided_static_ps_->state_set(state_depth_only); @@ -319,6 +318,8 @@ void DeferredLayer::sync() } { gbuffer_ps_.init(); + gbuffer_ps_.clear_stencil(0x00u); + gbuffer_ps_.state_stencil(0x01u, 0x01u, 0x01u); { /* Common resources. */ @@ -326,7 +327,6 @@ void DeferredLayer::sync() /* G-buffer. */ gbuffer_ps_.bind_image(GBUF_CLOSURE_SLOT, &inst_.gbuffer.closure_tx); gbuffer_ps_.bind_image(GBUF_COLOR_SLOT, &inst_.gbuffer.color_tx); - /* RenderPasses. */ gbuffer_ps_.bind_image(RBUFS_NORMAL_SLOT, &inst_.render_buffers.normal_tx); /* TODO(fclem): Pack all render pass into the same texture. */ @@ -349,12 +349,47 @@ void DeferredLayer::sync() inst_.cryptomatte.bind_resources(&gbuffer_ps_); } + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM | DRW_STATE_DEPTH_EQUAL | + DRW_STATE_CULL_BACK | DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS; + gbuffer_single_sided_ps_ = &gbuffer_ps_.sub("SingleSided"); - gbuffer_single_sided_ps_->state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | - DRW_STATE_CULL_BACK); + gbuffer_single_sided_ps_->state_set(state | DRW_STATE_CULL_BACK); gbuffer_double_sided_ps_ = &gbuffer_ps_.sub("DoubleSided"); - gbuffer_double_sided_ps_->state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); + gbuffer_double_sided_ps_->state_set(state); + } +} + +void DeferredLayer::end_sync() +{ + /* Use stencil test to reject pixel not written by this layer. */ + /* WORKAROUND: Stencil write is only here to avoid rasterizer discard. */ + DRWState state = DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_EQUAL; + /* Allow output to combined pass for the last pass. */ + DRWState state_write_color = state | DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM; + + if (closure_bits_ & (CLOSURE_DIFFUSE | CLOSURE_REFLECTION)) { + const bool is_last_eval_pass = true; + + eval_light_ps_.init(); + eval_light_ps_.state_set(is_last_eval_pass ? state_write_color : state); + eval_light_ps_.state_stencil(0x00u, 0x01u, 0xFFu); + eval_light_ps_.shader_set(inst_.shaders.static_shader_get(DEFERRED_LIGHT)); + eval_light_ps_.bind_image("out_diffuse_light_img", &diffuse_light_tx_); + eval_light_ps_.bind_image("out_specular_light_img", &specular_light_tx_); + eval_light_ps_.bind_texture("gbuffer_closure_tx", &inst_.gbuffer.closure_tx); + eval_light_ps_.bind_texture("gbuffer_color_tx", &inst_.gbuffer.color_tx); + eval_light_ps_.push_constant("is_last_eval_pass", is_last_eval_pass); + eval_light_ps_.bind_image(RBUFS_LIGHT_SLOT, &inst_.render_buffers.light_tx); + eval_light_ps_.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx); + + inst_.lights.bind_resources(&eval_light_ps_); + inst_.shadows.bind_resources(&eval_light_ps_); + inst_.sampling.bind_resources(&eval_light_ps_); + inst_.hiz_buffer.bind_resources(&eval_light_ps_); + + eval_light_ps_.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS); + eval_light_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3); } } @@ -362,18 +397,19 @@ PassMain::Sub *DeferredLayer::prepass_add(::Material *blender_mat, GPUMaterial *gpumat, bool has_motion) { - closure_bits_ |= shader_closure_bits_from_flag(gpumat); - PassMain::Sub *pass = (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) ? (has_motion ? prepass_single_sided_moving_ps_ : prepass_single_sided_static_ps_) : (has_motion ? prepass_double_sided_moving_ps_ : prepass_double_sided_static_ps_); + return &pass->sub(GPU_material_get_name(gpumat)); } PassMain::Sub *DeferredLayer::material_add(::Material *blender_mat, GPUMaterial *gpumat) { + closure_bits_ |= shader_closure_bits_from_flag(gpumat); + PassMain::Sub *pass = (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) ? gbuffer_single_sided_ps_ : gbuffer_double_sided_ps_; @@ -395,10 +431,17 @@ void DeferredLayer::render(View &view, GPU_framebuffer_bind(combined_fb); inst_.manager->submit(gbuffer_ps_, view); - inst_.shadows.set_view(view); - inst_.manager->submit(inst_.pipelines.deferred.eval_ps_); + eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE; + diffuse_light_tx_.acquire(extent, GPU_RGBA16F, usage); + specular_light_tx_.acquire(extent, GPU_RGBA16F, usage); + diffuse_light_tx_.clear(float4(0.0f)); + specular_light_tx_.clear(float4(0.0f)); - /* TODO evaluate lights. */ + inst_.shadows.set_view(view); + inst_.manager->submit(eval_light_ps_, view); + + diffuse_light_tx_.release(); + specular_light_tx_.release(); inst_.gbuffer.release(); } @@ -411,13 +454,16 @@ void DeferredLayer::render(View &view, * Closure data are written to intermediate buffer allowing screen space processing. * \{ */ -void DeferredPipeline::sync() +void DeferredPipeline::begin_sync() { - opaque_layer_.sync(); - refraction_layer_.sync(); + opaque_layer_.begin_sync(); + refraction_layer_.begin_sync(); +} - eval_ps_.init(); - /* TODO Lighting. */ +void DeferredPipeline::end_sync() +{ + opaque_layer_.end_sync(); + refraction_layer_.end_sync(); } PassMain::Sub *DeferredPipeline::prepass_add(::Material *blender_mat, diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.hh b/source/blender/draw/engines/eevee_next/eevee_pipeline.hh index 516f8a0ee01..d390fad4775 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.hh +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.hh @@ -131,13 +131,27 @@ class DeferredLayer { PassMain::Sub *gbuffer_single_sided_ps_ = nullptr; PassMain::Sub *gbuffer_double_sided_ps_ = nullptr; + PassSimple eval_light_ps_ = {"EvalLights"}; + /* Closures bits from the materials in this pass. */ eClosureBits closure_bits_; + /** + * Accumulation textures for all stages of lighting evaluation (Light, SSR, SSSS, SSGI ...). + * These are split and separate from the main radiance buffer in order to accumulate light for + * the render passes and avoid too much bandwidth waste. Otherwise, we would have to load the + * BSDF color and do additive blending for each of the lighting step. + * + * NOTE: Not to be confused with the render passes. + */ + TextureFromPool diffuse_light_tx_ = {"diffuse_light_accum_tx"}; + TextureFromPool specular_light_tx_ = {"specular_light_accum_tx"}; + public: DeferredLayer(Instance &inst) : inst_(inst){}; - void sync(); + void begin_sync(); + void end_sync(); PassMain::Sub *prepass_add(::Material *blender_mat, GPUMaterial *gpumat, bool has_motion); PassMain::Sub *material_add(::Material *blender_mat, GPUMaterial *gpumat); @@ -146,9 +160,6 @@ class DeferredLayer { }; class DeferredPipeline { - public: - PassSimple eval_ps_ = {"EvalLighting"}; - private: Instance &inst_; @@ -162,7 +173,8 @@ class DeferredPipeline { DeferredPipeline(Instance &inst) : inst_(inst), opaque_layer_(inst), refraction_layer_(inst), volumetric_layer_(inst){}; - void sync(); + void begin_sync(); + void end_sync(); PassMain::Sub *prepass_add(::Material *material, GPUMaterial *gpumat, bool has_motion); PassMain::Sub *material_add(::Material *material, GPUMaterial *gpumat); @@ -265,13 +277,18 @@ class PipelineModule { public: PipelineModule(Instance &inst) : world(inst), deferred(inst), forward(inst), shadow(inst){}; - void sync() + void begin_sync() { - deferred.sync(); + deferred.begin_sync(); forward.sync(); shadow.sync(); } + void end_sync() + { + deferred.end_sync(); + } + PassMain::Sub *material_add(Object *ob, ::Material *blender_mat, GPUMaterial *gpumat, diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.cc b/source/blender/draw/engines/eevee_next/eevee_shader.cc index 4d9ac75687c..3fe78dbe286 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader.cc +++ b/source/blender/draw/engines/eevee_next/eevee_shader.cc @@ -86,6 +86,8 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_ return "eevee_film_comp"; case FILM_CRYPTOMATTE_POST: return "eevee_film_cryptomatte_post"; + case DEFERRED_LIGHT: + return "eevee_deferred_light"; case HIZ_DEBUG: return "eevee_hiz_debug"; case HIZ_UPDATE: diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.hh b/source/blender/draw/engines/eevee_next/eevee_shader.hh index 173dc7bfa86..d987105e3fc 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader.hh +++ b/source/blender/draw/engines/eevee_next/eevee_shader.hh @@ -30,6 +30,8 @@ enum eShaderType { FILM_COMP, FILM_CRYPTOMATTE_POST, + DEFERRED_LIGHT, + DEBUG_SURFELS, DOF_BOKEH_LUT, 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 new file mode 100644 index 00000000000..c1223380c3f --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_light_frag.glsl @@ -0,0 +1,93 @@ + +/** + * Compute light contribution using Gbuffer data. + * + * Output light . + */ + +#pragma BLENDER_REQUIRE(eevee_gbuffer_lib.glsl) +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_light_eval_lib.glsl) + +#define imageAdd(tex, coord, val) imageStore(tex, coord, imageLoad(tex, coord) + (val)) + +void main() +{ + ivec2 texel = ivec2(gl_FragCoord.xy); + + float depth = texelFetch(hiz_tx, ivec2(gl_FragCoord.xy), 0).r; + vec3 P = get_world_space_from_depth(uvcoordsvar.xy, depth); + + /* TODO(fclem): High precision derivative. */ + vec3 Ng = safe_normalize(cross(dFdx(P), dFdy(P))); + vec3 V = cameraVec(P); + float vP_z = dot(cameraForward, P) - dot(cameraForward, cameraPos); + + vec4 gbuffer_0_packed = texelFetch(gbuffer_closure_tx, ivec3(texel, 0), 0); + vec4 gbuffer_1_packed = texelFetch(gbuffer_closure_tx, ivec3(texel, 1), 0); + + ClosureReflection reflection_data; + reflection_data.N = gbuffer_normal_unpack(gbuffer_0_packed.xy); + reflection_data.roughness = gbuffer_0_packed.z; + + ClosureDiffuse diffuse_data; + diffuse_data.N = gbuffer_normal_unpack(gbuffer_1_packed.xy); + diffuse_data.sss_radius = vec3(0.0); /* Only set for SSS case. */ + diffuse_data.sss_id = 0u; /* Only set for SSS case. */ + float thickness = 0.0; /* Only set for SSS case. */ + + bool is_refraction = gbuffer_is_refraction(gbuffer_1_packed); + if (is_refraction) { + /* Still evaluate the diffuse light so that dithered SSS / Refraction combination still + * produces a complete diffuse light buffer that will be correctly convolved by the SSSS. + * The refraction pixels will just set the diffuse radiance to 0. */ + } + else if (false /* TODO */) { + vec4 gbuffer_2_packed = texelFetch(gbuffer_closure_tx, ivec3(texel, 2), 0); + diffuse_data.sss_radius = gbuffer_sss_radii_unpack(gbuffer_2_packed.xyz); + diffuse_data.sss_id = gbuffer_object_id_unorm16_unpack(gbuffer_2_packed.w); + thickness = gbuffer_thickness_pack(gbuffer_1_packed.z); + } + + vec3 diffuse_light = vec3(0.0); + vec3 reflection_light = vec3(0.0); + + light_eval( + diffuse_data, reflection_data, P, Ng, V, vP_z, thickness, diffuse_light, reflection_light); + + if (is_last_eval_pass) { + /* Apply color and output lighting to render-passes. */ + vec4 color_0_packed = texelFetch(gbuffer_color_tx, ivec3(texel, 0), 0); + vec4 color_1_packed = texelFetch(gbuffer_color_tx, ivec3(texel, 1), 0); + + reflection_data.color = gbuffer_color_unpack(color_0_packed); + diffuse_data.color = gbuffer_color_unpack(color_1_packed); + + reflection_light *= reflection_data.color; + diffuse_light *= diffuse_data.color; + /* Add radiance to light pass. */ + imageAdd( + rp_light_img, ivec3(texel, RENDER_PASS_LAYER_DIFFUSE_LIGHT), vec4(diffuse_light, 0.0)); + imageAdd( + rp_light_img, ivec3(texel, RENDER_PASS_LAYER_SPECULAR_LIGHT), vec4(reflection_light, 0.0)); + /* Add radiance to combined pass. */ + out_radiance = vec4(diffuse_light + reflection_light, 0.0); + out_transmittance = vec4(1.0); + } + else { + /* Store lighting for next deferred pass. */ + + /* Output diffuse light along with object ID for sub-surface screen space processing. */ + vec4 diffuse_radiance; + diffuse_radiance.xyz = diffuse_light; + diffuse_radiance.w = gbuffer_object_id_f16_pack(diffuse_data.sss_id); + imageStore(out_diffuse_light_img, texel, diffuse_radiance); + + imageStore(out_specular_light_img, texel, vec4(reflection_light, 0.0)); + + /* Final radiance will be amended by the last pass. + * This should do nothing as color write should be disabled in this case. */ + out_radiance = vec4(0.0); + out_transmittance = vec4(0.0); + } +} 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 b510114f440..d53626d816b 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 @@ -37,14 +37,14 @@ float gbuffer_ior_unpack(float ior_packed) float gbuffer_thickness_pack(float thickness) { - /* TODO */ - return thickness; + /* TODO(fclem): Something better. */ + return gbuffer_ior_pack(thickness); } float gbuffer_thickness_unpack(float thickness_packed) { - /* TODO */ - return thickness_packed; + /* TODO(fclem): Something better. */ + return gbuffer_ior_unpack(thickness_packed); } vec3 gbuffer_sss_radii_pack(vec3 sss_radii) @@ -73,3 +73,31 @@ vec3 gbuffer_color_unpack(vec4 color_packed) /* TODO(fclem): 2 exponent inside 2bit Alpha. */ return color_packed.rgb; } + +float gbuffer_object_id_unorm16_pack(uint object_id) +{ + return float(object_id & 0xFFFFu) / float(0xFFFF); +} + +uint gbuffer_object_id_unorm16_unpack(float object_id_packed) +{ + return uint(object_id_packed * float(0xFFFF)); +} + +float gbuffer_object_id_f16_pack(uint object_id) +{ + /* TODO(fclem): Make use of all the 16 bits in a half float. + * This here only correctly represent values up to 1024. */ + return float(object_id); +} + +uint gbuffer_object_id_f16_unpack(float object_id_packed) +{ + return uint(object_id_packed); +} + +bool gbuffer_is_refraction(vec4 gbuffer) +{ + /* TODO. */ + return false; +} \ No newline at end of file diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_frag.glsl index dd946ffb637..7bc51513da1 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_frag.glsl @@ -82,7 +82,7 @@ void main() { vec2 screen_uv = gl_FragCoord.xy / vec2(fb_resolution); - float opaque_depth = texelFetch(hiz_tx, int2(gl_FragCoord.xy), fb_lod).r; + float opaque_depth = texelFetch(hiz_tx, ivec2(gl_FragCoord.xy), fb_lod).r; vec3 ws_opaque = get_world_space_from_depth(screen_uv, opaque_depth); vec3 ws_near_plane = get_world_space_from_depth(screen_uv, 0); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl index cf4142fff47..e8c8fa96933 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl @@ -112,8 +112,8 @@ void main() if (true) { /* SubSurface Scattering. */ vec4 closure; - closure.xyz = gbuffer_sss_radii_pack(g_refraction_data.N); - closure.w = gbuffer_ior_pack(g_refraction_data.ior); + closure.xyz = gbuffer_sss_radii_pack(g_diffuse_data.sss_radius); + closure.w = gbuffer_object_id_unorm16_pack(g_diffuse_data.sss_id); imageStore(out_gbuff_closure_img, ivec3(out_texel, 2), closure); } 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 new file mode 100644 index 00000000000..f5bc967e5b6 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_deferred_info.hh @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "eevee_defines.hh" +#include "gpu_shader_create_info.hh" + +#define image_out(slot, qualifier, format, name) \ + image(slot, format, qualifier, ImageType::FLOAT_2D, name, Frequency::PASS) +#define image_array_out(slot, qualifier, format, name) \ + image(slot, format, qualifier, ImageType::FLOAT_2D_ARRAY, name, Frequency::PASS) + +/** + * Specific deferred pass accumulate the computed lighting to either: + * - a split diffuse / specular temporary light buffer. + * or to + * - the combined pass & the light render-pass (if needed). + * + * This is in order to minimize the number of blending step. + */ +GPU_SHADER_CREATE_INFO(eevee_deferred_base) + /* Early fragment test is needed to avoid processing fragments without correct GBuffer data. */ + .early_fragment_test(true) + /* Select which output to write to. */ + .push_constant(Type::BOOL, "is_last_eval_pass") + /* Combined pass output. */ + .fragment_out(0, Type::VEC4, "out_radiance", DualBlend::SRC_0) + .fragment_out(0, Type::VEC4, "out_transmittance", DualBlend::SRC_1) + /* Light pass output. */ + .image_array_out(RBUFS_LIGHT_SLOT, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_light_img") + /* Chaining to next pass. */ + .image_out(2, Qualifier::READ_WRITE, GPU_RGBA16F, "out_diffuse_light_img") + .image_out(3, Qualifier::READ_WRITE, GPU_RGBA16F, "out_specular_light_img"); + +GPU_SHADER_CREATE_INFO(eevee_deferred_light) + .fragment_source("eevee_deferred_light_frag.glsl") + .sampler(0, ImageType::FLOAT_2D_ARRAY, "gbuffer_closure_tx") + .sampler(1, ImageType::FLOAT_2D_ARRAY, "gbuffer_color_tx") + .additional_info("eevee_shared", + "eevee_utility_texture", + "eevee_light_data", + "eevee_shadow_data", + "eevee_deferred_base", + "eevee_hiz_data", + "draw_view", + "draw_fullscreen") + .do_static_compilation(true); + +#undef image_array_out diff --git a/source/blender/draw/intern/draw_texture_pool.cc b/source/blender/draw/intern/draw_texture_pool.cc index dc155399425..d572cc75b27 100644 --- a/source/blender/draw/intern/draw_texture_pool.cc +++ b/source/blender/draw/intern/draw_texture_pool.cc @@ -206,7 +206,8 @@ void DRW_texture_pool_reset(DRWTexturePool *pool) } } - BLI_assert(pool->tmp_tex_acquired.is_empty()); + BLI_assert_msg(pool->tmp_tex_acquired.is_empty(), + "Missing a TextureFromPool.release() before end of draw."); for (GPUTexture *tmp_tex : pool->tmp_tex_pruned) { GPU_texture_free(tmp_tex); } diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index bfc0a1b3c7a..329cb211c3f 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -603,6 +603,7 @@ list(APPEND INC ${CMAKE_CURRENT_BINARY_DIR}) set(SRC_SHADER_CREATE_INFOS ../draw/engines/basic/shaders/infos/basic_depth_info.hh + ../draw/engines/eevee_next/shaders/infos/eevee_deferred_info.hh ../draw/engines/eevee_next/shaders/infos/eevee_depth_of_field_info.hh ../draw/engines/eevee_next/shaders/infos/eevee_film_info.hh ../draw/engines/eevee_next/shaders/infos/eevee_hiz_info.hh -- 2.30.2 From 250a4d29dcb3760a2f3e162e787ae76840343ece Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Sat, 18 Mar 2023 12:39:44 +0100 Subject: [PATCH 4/9] EEVEE-Next: GBuffer: Implement color packing This color packing allows good color range knowing the range of color will likely never exceed 1. --- .../eevee_next/shaders/eevee_gbuffer_lib.glsl | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) 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 d53626d816b..d3c25ac35da 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 @@ -64,14 +64,18 @@ vec3 gbuffer_sss_radii_unpack(vec3 sss_radii_packed) vec4 gbuffer_color_pack(vec3 color) { - /* TODO(fclem): 2 exponent inside 2bit Alpha. */ - return vec4(color, 1.0); + float max_comp = max(color.x, max(color.y, color.z)); + /* Store 2bit exponent inside Alpha. Allows values up to 8 with some color degradation. + * Above 8, the result will be clampped when writing the data to the output buffer. */ + float exponent = (max_comp > 1) ? ((max_comp > 2) ? ((max_comp > 4) ? 3.0 : 2.0) : 1.0) : 0.0; + /* TODO(fclem): Could try dithering to avoid banding artifacts on higher exponents. */ + return vec4(color / exp2(exponent), exponent / 3.0); } vec3 gbuffer_color_unpack(vec4 color_packed) { - /* TODO(fclem): 2 exponent inside 2bit Alpha. */ - return color_packed.rgb; + float exponent = color_packed.a * 3.0; + return color_packed.rgb * exp2(exponent); } float gbuffer_object_id_unorm16_pack(uint object_id) -- 2.30.2 From d4474d5971ceec245fa63defed4955a64e9551c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Sat, 18 Mar 2023 12:41:16 +0100 Subject: [PATCH 5/9] EEVE-Next: Deferred: Fix wrong specular color --- .../engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl index e8c8fa96933..2851b211b91 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl @@ -77,7 +77,7 @@ void main() g_reflection_data.roughness); imageStore(out_gbuff_closure_img, ivec3(out_texel, 0), out_reflect); - vec4 color = gbuffer_color_pack(g_diffuse_data.color); + vec4 color = gbuffer_color_pack(g_reflection_data.color); imageStore(out_gbuff_color_img, ivec3(out_texel, 0), color); } -- 2.30.2 From 980b6413cc8b85bcc9f7be9797db2ba2630452ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Sat, 18 Mar 2023 12:42:33 +0100 Subject: [PATCH 6/9] EEVEE-Next: Fix wrong closure weighting The macro was overiding `destination.weight` with the `candidate.weight` --- .../draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl index 62be853ab95..db38baab6a4 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl @@ -36,7 +36,9 @@ bool closure_select(float weight, inout float total_weight, inout float r) #define SELECT_CLOSURE(destination, random, candidate) \ if (closure_select(candidate.weight, destination.weight, random)) { \ + float tmp = destination.weight; \ destination = candidate; \ + destination.weight = tmp; \ } float g_closure_rand; -- 2.30.2 From e75f7910ba3fb470eac82466d9ed7e2a6a1c9ae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Sat, 18 Mar 2023 13:02:43 +0100 Subject: [PATCH 7/9] EEVEE-Next: Deferred: Fix refraction appearing as diffuse --- .../eevee_next/shaders/eevee_deferred_light_frag.glsl | 9 +++++---- .../engines/eevee_next/shaders/eevee_gbuffer_lib.glsl | 3 +-- .../eevee_next/shaders/eevee_surf_deferred_frag.glsl | 6 +++++- 3 files changed, 11 insertions(+), 7 deletions(-) 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 c1223380c3f..f41534da1fc 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 @@ -32,9 +32,10 @@ void main() ClosureDiffuse diffuse_data; diffuse_data.N = gbuffer_normal_unpack(gbuffer_1_packed.xy); - diffuse_data.sss_radius = vec3(0.0); /* Only set for SSS case. */ - diffuse_data.sss_id = 0u; /* Only set for SSS case. */ - float thickness = 0.0; /* Only set for SSS case. */ + /* These are only set for SSS case. */ + diffuse_data.sss_radius = vec3(0.0); + diffuse_data.sss_id = 0u; + float thickness = 0.0; bool is_refraction = gbuffer_is_refraction(gbuffer_1_packed); if (is_refraction) { @@ -61,7 +62,7 @@ void main() vec4 color_1_packed = texelFetch(gbuffer_color_tx, ivec3(texel, 1), 0); reflection_data.color = gbuffer_color_unpack(color_0_packed); - diffuse_data.color = gbuffer_color_unpack(color_1_packed); + diffuse_data.color = is_refraction ? vec3(0.0) : gbuffer_color_unpack(color_1_packed); reflection_light *= reflection_data.color; diffuse_light *= diffuse_data.color; 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 d3c25ac35da..8156166f42f 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 @@ -102,6 +102,5 @@ uint gbuffer_object_id_f16_unpack(float object_id_packed) bool gbuffer_is_refraction(vec4 gbuffer) { - /* TODO. */ - return false; + return gbuffer.w < 1.0; } \ No newline at end of file diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl index 2851b211b91..841673bbb08 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl @@ -92,6 +92,9 @@ void main() closure.xy = gbuffer_normal_pack(g_refraction_data.N); closure.z = g_refraction_data.roughness; closure.w = gbuffer_ior_pack(g_refraction_data.ior); + /* Clamp to just bellow 1 to be able to distinguish between refraction and diffuse. + * Ceiling value is chosen by the storage format (16bit UNORM). */ + closure.w = min(closure.w, float(0xFFFFu - 1u) / float(0xFFFFu)); imageStore(out_gbuff_closure_img, ivec3(out_texel, 1), closure); vec4 color = gbuffer_color_pack(g_refraction_data.color); @@ -102,7 +105,8 @@ void main() vec4 closure; closure.xy = gbuffer_normal_pack(g_diffuse_data.N); closure.z = gbuffer_thickness_pack(thickness); - closure.w = 0.0; /* Unused. */ + /* Used to detect the refraction case. Could be used for roughness. */ + closure.w = 1.0; imageStore(out_gbuff_closure_img, ivec3(out_texel, 1), closure); vec4 color = gbuffer_color_pack(g_diffuse_data.color); -- 2.30.2 From 824c322ddb15d474fa0b1b76e9f88830f6090520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Sat, 18 Mar 2023 13:13:01 +0100 Subject: [PATCH 8/9] EEVEE-Next: Deferred: Fix double-sided geometry being backface-culled --- .../draw/engines/eevee_next/eevee_pipeline.cc | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc index 3e1293ee2e4..80bda67a4a2 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc @@ -279,9 +279,7 @@ void ForwardPipeline::render(View &view, /** \} */ /* -------------------------------------------------------------------- */ -/** \name Deferred Pipeline - * - * Closure data are written to intermediate buffer allowing screen space processing. +/** \name Deferred Layer * \{ */ void DeferredLayer::begin_sync() @@ -350,13 +348,13 @@ void DeferredLayer::begin_sync() } DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM | DRW_STATE_DEPTH_EQUAL | - DRW_STATE_CULL_BACK | DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS; - - gbuffer_single_sided_ps_ = &gbuffer_ps_.sub("SingleSided"); - gbuffer_single_sided_ps_->state_set(state | DRW_STATE_CULL_BACK); + DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS; gbuffer_double_sided_ps_ = &gbuffer_ps_.sub("DoubleSided"); gbuffer_double_sided_ps_->state_set(state); + + gbuffer_single_sided_ps_ = &gbuffer_ps_.sub("SingleSided"); + gbuffer_single_sided_ps_->state_set(state | DRW_STATE_CULL_BACK); } } -- 2.30.2 From 11293467cb7d69e7adfe859dee1947ffc45fd858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Sat, 18 Mar 2023 14:24:44 +0100 Subject: [PATCH 9/9] EEVEE-Next: Deferred: Fix render-passes support --- .../draw/engines/eevee_next/eevee_material.cc | 5 ----- .../draw/engines/eevee_next/eevee_pipeline.cc | 7 ++++--- .../draw/engines/eevee_next/eevee_shader.cc | 5 +++++ .../shaders/eevee_deferred_light_frag.glsl | 21 +++++++++++-------- .../shaders/eevee_surf_deferred_frag.glsl | 12 ++++++++--- .../shaders/infos/eevee_material_info.hh | 2 +- 6 files changed, 31 insertions(+), 21 deletions(-) diff --git a/source/blender/draw/engines/eevee_next/eevee_material.cc b/source/blender/draw/engines/eevee_next/eevee_material.cc index c00dd97a5d5..a210681517a 100644 --- a/source/blender/draw/engines/eevee_next/eevee_material.cc +++ b/source/blender/draw/engines/eevee_next/eevee_material.cc @@ -193,11 +193,6 @@ MaterialPass MaterialModule::material_pass_get(Object *ob, inst_.sampling.reset(); } - if ((pipeline_type == MAT_PIPE_DEFERRED) && - GPU_material_flag_get(matpass.gpumat, GPU_MATFLAG_SHADER_TO_RGBA)) { - pipeline_type = MAT_PIPE_FORWARD; - } - if (ELEM(pipeline_type, MAT_PIPE_FORWARD, MAT_PIPE_FORWARD_PREPASS, diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc index 80bda67a4a2..8b6f0ccfdce 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc @@ -386,7 +386,7 @@ void DeferredLayer::end_sync() inst_.sampling.bind_resources(&eval_light_ps_); inst_.hiz_buffer.bind_resources(&eval_light_ps_); - eval_light_ps_.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS); + eval_light_ps_.barrier(GPU_BARRIER_TEXTURE_FETCH | GPU_BARRIER_SHADER_IMAGE_ACCESS); eval_light_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3); } } @@ -419,12 +419,14 @@ void DeferredLayer::render(View &view, Framebuffer &combined_fb, int2 extent) { - inst_.gbuffer.acquire(extent, closure_bits_); GPU_framebuffer_bind(prepass_fb); inst_.manager->submit(prepass_ps_, view); inst_.hiz_buffer.set_dirty(); + inst_.shadows.set_view(view); + + inst_.gbuffer.acquire(extent, closure_bits_); GPU_framebuffer_bind(combined_fb); inst_.manager->submit(gbuffer_ps_, view); @@ -435,7 +437,6 @@ void DeferredLayer::render(View &view, diffuse_light_tx_.clear(float4(0.0f)); specular_light_tx_.clear(float4(0.0f)); - inst_.shadows.set_view(view); inst_.manager->submit(eval_light_ps_, view); diffuse_light_tx_.release(); diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.cc b/source/blender/draw/engines/eevee_next/eevee_shader.cc index 3fe78dbe286..116d6004642 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader.cc +++ b/source/blender/draw/engines/eevee_next/eevee_shader.cc @@ -243,6 +243,11 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu } } + /* WORKAROUND: Needed because node_tree isn't present in test shaders. */ + if (pipeline_type == MAT_PIPE_DEFERRED) { + info.define("MAT_RENDER_PASS_SUPPORT"); + } + if (GPU_material_flag_get(gpumat, GPU_MATFLAG_TRANSPARENT)) { info.define("MAT_TRANSPARENT"); /* Transparent material do not have any velocity specific pipeline. */ 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 f41534da1fc..80dcaaf67cb 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 @@ -1,16 +1,15 @@ /** - * Compute light contribution using Gbuffer data. + * Compute light objects lighting contribution using Gbuffer data. * - * Output light . + * Output light either directly to the radiance buffers or to temporary radiance accumulation + * buffer that will be processed by other deferred lighting passes. */ #pragma BLENDER_REQUIRE(eevee_gbuffer_lib.glsl) #pragma BLENDER_REQUIRE(common_view_lib.glsl) #pragma BLENDER_REQUIRE(eevee_light_eval_lib.glsl) -#define imageAdd(tex, coord, val) imageStore(tex, coord, imageLoad(tex, coord) + (val)) - void main() { ivec2 texel = ivec2(gl_FragCoord.xy); @@ -62,15 +61,19 @@ void main() vec4 color_1_packed = texelFetch(gbuffer_color_tx, ivec3(texel, 1), 0); reflection_data.color = gbuffer_color_unpack(color_0_packed); - diffuse_data.color = is_refraction ? vec3(0.0) : gbuffer_color_unpack(color_1_packed); + diffuse_data.color = gbuffer_color_unpack(color_1_packed); + + if (is_refraction) { + diffuse_data.color = vec3(0.0); + } reflection_light *= reflection_data.color; diffuse_light *= diffuse_data.color; /* Add radiance to light pass. */ - imageAdd( - rp_light_img, ivec3(texel, RENDER_PASS_LAYER_DIFFUSE_LIGHT), vec4(diffuse_light, 0.0)); - imageAdd( - rp_light_img, ivec3(texel, RENDER_PASS_LAYER_SPECULAR_LIGHT), vec4(reflection_light, 0.0)); + imageStore( + rp_light_img, ivec3(texel, RENDER_PASS_LAYER_DIFFUSE_LIGHT), vec4(diffuse_light, 1.0)); + imageStore( + rp_light_img, ivec3(texel, RENDER_PASS_LAYER_SPECULAR_LIGHT), vec4(reflection_light, 1.0)); /* Add radiance to combined pass. */ out_radiance = vec4(diffuse_light + reflection_light, 0.0); out_transmittance = vec4(1.0); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl index 841673bbb08..d84d0a030e2 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl @@ -16,8 +16,14 @@ vec4 closure_to_rgba(Closure cl) { - /* Should never be called. */ - return vec4(0.0); + vec4 out_color; + out_color.rgb = g_emission; + out_color.a = saturate(1.0 - avg(g_transmittance)); + + /* Reset for the next closure tree. */ + closure_weights_reset(); + + return out_color; } void main() @@ -56,7 +62,7 @@ void main() /* ----- Render Passes output ----- */ ivec2 out_texel = ivec2(gl_FragCoord.xy); -#ifdef MAT_RENDER_PASS_SUPPORT +#ifdef MAT_RENDER_PASS_SUPPORT /* Needed because node_tree isn't present in test shaders. */ /* Some render pass can be written during the gbuffer pass. Light passes are written later. */ vec4 cryptomatte_output = vec4(cryptomatte_object_buf[resource_id], node_tree.crypto_hash, 0.0); imageStore(rp_cryptomatte_img, out_texel, cryptomatte_output); diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh index 3e34bed9958..f16113a5efc 100644 --- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh @@ -115,7 +115,7 @@ GPU_SHADER_CREATE_INFO(eevee_surf_deferred) // .image_array_out(RBUFS_LIGHT_SLOT, Qualifier::WRITE, GPU_RGBA16F, "rp_light_img") /* TODO(fclem): Merge all render-pass into the same texture array. */ // .image_out(RBUFS_DIFF_COLOR_SLOT, Qualifier::WRITE, GPU_RGBA16F, "rp_diffuse_color_img") - .image_array_out(RBUFS_SPEC_COLOR_SLOT, Qualifier::WRITE, GPU_RGBA16F, "rp_specular_color_img") + .image_out(RBUFS_SPEC_COLOR_SLOT, Qualifier::WRITE, GPU_RGBA16F, "rp_specular_color_img") .image_out(RBUFS_EMISSION_SLOT, Qualifier::WRITE, GPU_RGBA16F, "rp_emission_img") .fragment_source("eevee_surf_deferred_frag.glsl") .additional_info("eevee_camera", -- 2.30.2