EEVEE-Next: Deferred Pipeline #105868

Merged
Clément Foucault merged 10 commits from fclem/blender:tmp-eevee-next-deferred-pipe into main 2023-03-18 20:54:31 +01:00
13 changed files with 275 additions and 36 deletions
Showing only changes of commit f3919a771f - Show all commits

View File

@ -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

View File

@ -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()

View File

@ -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,

View File

@ -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,

View File

@ -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:

View File

@ -30,6 +30,8 @@ enum eShaderType {
FILM_COMP,
FILM_CRYPTOMATTE_POST,
DEFERRED_LIGHT,
DEBUG_SURFELS,
DOF_BOKEH_LUT,

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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