From 34051fcc12f388375697dcfc6da53e9909058fe1 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 13 Sep 2022 15:03:04 +0200 Subject: EEVEE: Fix volumetric resolve in large scenes. On NVIDIA volumetric resolve failed for large production scenes. The result would remove most color from the final render. The cause seems to be a faulty driver. This change ported the fragment shader to a compute shader which would select a different compiler branch and didn't show the error. --- source/blender/draw/CMakeLists.txt | 1 + source/blender/draw/engines/eevee/eevee_private.h | 1 + source/blender/draw/engines/eevee/eevee_shaders.c | 16 +++++++ source/blender/draw/engines/eevee/eevee_volumes.c | 54 ++++++++++++++++------ .../eevee/shaders/volumetric_resolve_comp.glsl | 38 +++++++++++++++ source/blender/draw/intern/DRW_render.h | 4 ++ source/blender/draw/intern/draw_manager_shader.c | 12 +++++ source/blender/draw/tests/shaders_test.cc | 2 + 8 files changed, 113 insertions(+), 15 deletions(-) create mode 100644 source/blender/draw/engines/eevee/shaders/volumetric_resolve_comp.glsl (limited to 'source') diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 32103692421..e6b532ed25a 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -388,6 +388,7 @@ set(GLSL_SRC engines/eevee/shaders/volumetric_frag.glsl engines/eevee/shaders/volumetric_geom.glsl engines/eevee/shaders/volumetric_vert.glsl + engines/eevee/shaders/volumetric_resolve_comp.glsl engines/eevee/shaders/volumetric_resolve_frag.glsl engines/eevee/shaders/volumetric_scatter_frag.glsl engines/eevee/shaders/volumetric_integration_frag.glsl diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 8c6d96254ae..573c29b78a1 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -1261,6 +1261,7 @@ struct GPUShader *EEVEE_shaders_volumes_scatter_sh_get(void); struct GPUShader *EEVEE_shaders_volumes_scatter_with_lights_sh_get(void); struct GPUShader *EEVEE_shaders_volumes_integration_sh_get(void); struct GPUShader *EEVEE_shaders_volumes_resolve_sh_get(bool accum); +struct GPUShader *EEVEE_shaders_volumes_resolve_comp_sh_get(bool float_target); struct GPUShader *EEVEE_shaders_volumes_accum_sh_get(void); struct GPUShader *EEVEE_shaders_ggx_lut_sh_get(void); struct GPUShader *EEVEE_shaders_ggx_refraction_lut_sh_get(void); diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c index 04d1168a30d..a7290b3894e 100644 --- a/source/blender/draw/engines/eevee/eevee_shaders.c +++ b/source/blender/draw/engines/eevee/eevee_shaders.c @@ -133,6 +133,7 @@ static struct { struct GPUShader *scatter_with_lights_sh; struct GPUShader *volumetric_integration_sh; struct GPUShader *volumetric_resolve_sh[2]; + struct GPUShader *volumetric_resolve_comp_sh[2]; struct GPUShader *volumetric_accum_sh; /* Shader strings */ @@ -261,6 +262,7 @@ extern char datatoc_volumetric_frag_glsl[]; extern char datatoc_volumetric_geom_glsl[]; extern char datatoc_volumetric_integration_frag_glsl[]; extern char datatoc_volumetric_lib_glsl[]; +extern char datatoc_volumetric_resolve_comp_glsl[]; extern char datatoc_volumetric_resolve_frag_glsl[]; extern char datatoc_volumetric_scatter_frag_glsl[]; extern char datatoc_volumetric_vert_glsl[]; @@ -903,6 +905,20 @@ struct GPUShader *EEVEE_shaders_volumes_resolve_sh_get(bool accum) return e_data.volumetric_resolve_sh[index]; } +struct GPUShader *EEVEE_shaders_volumes_resolve_comp_sh_get(bool float_target) +{ + const int index = (float_target ? 1 : 0); + if (e_data.volumetric_resolve_comp_sh[index] == NULL) { + e_data.volumetric_resolve_comp_sh[index] = DRW_shader_create_compute_with_shaderlib( + datatoc_volumetric_resolve_comp_glsl, + e_data.lib, + float_target ? "#define TARGET_IMG_FLOAT\n" SHADER_DEFINES : SHADER_DEFINES, + __func__); + } + + return e_data.volumetric_resolve_comp_sh[index]; +} + struct GPUShader *EEVEE_shaders_volumes_accum_sh_get() { if (e_data.volumetric_accum_sh == NULL) { diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index 2d96cffb4ba..b2e5a0abe94 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -396,18 +396,37 @@ void EEVEE_volumes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) grp, NULL, USE_VOLUME_OPTI ? 1 : common_data->vol_tex_size[2]); DRW_PASS_CREATE(psl->volumetric_resolve_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM); - grp = DRW_shgroup_create(EEVEE_shaders_volumes_resolve_sh_get(false), - psl->volumetric_resolve_ps); - DRW_shgroup_uniform_texture_ref(grp, "inScattering", &txl->volume_scatter); - DRW_shgroup_uniform_texture_ref(grp, "inTransmittance", &txl->volume_transmit); - DRW_shgroup_uniform_texture_ref(grp, "inSceneDepth", &e_data.depth_src); - DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); - DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); - DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); - DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); + if (GPU_compute_shader_support() && GPU_shader_image_load_store_support()) { + const bool use_float_target = DRW_state_is_image_render(); + grp = DRW_shgroup_create(EEVEE_shaders_volumes_resolve_comp_sh_get(use_float_target), + psl->volumetric_resolve_ps); + DRW_shgroup_uniform_texture_ref(grp, "inScattering", &txl->volume_scatter); + DRW_shgroup_uniform_texture_ref(grp, "inTransmittance", &txl->volume_transmit); + DRW_shgroup_uniform_texture_ref(grp, "inSceneDepth", &e_data.depth_src); + DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); + DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); + DRW_shgroup_uniform_image_ref(grp, "target_img", &txl->color); - DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + const float *size = DRW_viewport_size_get(); + DRW_shgroup_call_compute(grp, size[0], size[1], 1); + } + else { + grp = DRW_shgroup_create(EEVEE_shaders_volumes_resolve_sh_get(false), + psl->volumetric_resolve_ps); + DRW_shgroup_uniform_texture_ref(grp, "inScattering", &txl->volume_scatter); + DRW_shgroup_uniform_texture_ref(grp, "inTransmittance", &txl->volume_transmit); + DRW_shgroup_uniform_texture_ref(grp, "inSceneDepth", &e_data.depth_src); + DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); + DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); + + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } } } @@ -546,11 +565,16 @@ void EEVEE_volumes_resolve(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *veda } /* Apply for opaque geometry. */ - GPU_framebuffer_bind(fbl->main_color_fb); - DRW_draw_pass(psl->volumetric_resolve_ps); + if (GPU_compute_shader_support() && GPU_shader_image_load_store_support()) { + DRW_draw_pass(psl->volumetric_resolve_ps); + } + else { + GPU_framebuffer_bind(fbl->main_color_fb); + DRW_draw_pass(psl->volumetric_resolve_ps); - /* Restore. */ - GPU_framebuffer_bind(fbl->main_fb); + /* Restore. */ + GPU_framebuffer_bind(fbl->main_fb); + } } } diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_resolve_comp.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_resolve_comp.glsl new file mode 100644 index 00000000000..2b0139ff923 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/volumetric_resolve_comp.glsl @@ -0,0 +1,38 @@ + +#pragma BLENDER_REQUIRE(volumetric_lib.glsl) + +/* Based on Frosbite Unified Volumetric. + * https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */ + +/* Step 4 : Apply final integration on top of the scene color. */ + +uniform sampler2D inSceneDepth; + +layout(local_size_x = 1, local_size_y = 1) in; + +#ifdef TARGET_IMG_FLOAT +layout(binding = 0, rgba32f) uniform image2D target_img; +#else +layout(binding = 0, rgba16f) uniform image2D target_img; +#endif + +void main() +{ + ivec2 co = ivec2(gl_GlobalInvocationID.xy); + vec2 uvs = co / vec2(textureSize(inSceneDepth, 0)); + float scene_depth = texture(inSceneDepth, uvs).r; + + vec3 transmittance, scattering; + volumetric_resolve(uvs, scene_depth, transmittance, scattering); + + /* Approximate volume alpha by using a monochromatic transmittance + * and adding it to the scene alpha. */ + float alpha = dot(transmittance, vec3(1.0 / 3.0)); + + vec4 color0 = vec4(scattering, 1.0 - alpha); + vec4 color1 = vec4(transmittance, alpha); + + vec4 color_in = imageLoad(target_img, co); + vec4 color_out = color0 + color1 * color_in; + imageStore(target_img, co, color_out); +} diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 7b80ffd2b88..b49203d85f6 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -207,6 +207,10 @@ struct GPUShader *DRW_shader_create_with_lib_ex(const char *vert, const char *lib, const char *defines, const char *name); +struct GPUShader *DRW_shader_create_compute_with_shaderlib(const char *comp, + const DRWShaderLibrary *lib, + const char *defines, + const char *name); struct GPUShader *DRW_shader_create_with_shaderlib_ex(const char *vert, const char *geom, const char *frag, diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c index 4bc3898c5e7..1ada99093c6 100644 --- a/source/blender/draw/intern/draw_manager_shader.c +++ b/source/blender/draw/intern/draw_manager_shader.c @@ -297,6 +297,18 @@ GPUShader *DRW_shader_create_with_lib_ex(const char *vert, return sh; } +GPUShader *DRW_shader_create_compute_with_shaderlib(const char *comp, + const DRWShaderLibrary *lib, + const char *defines, + const char *name) +{ + char *comp_with_lib = DRW_shader_library_create_shader_string(lib, comp); + GPUShader *sh = GPU_shader_create_compute(comp_with_lib, NULL, defines, name); + MEM_SAFE_FREE(comp_with_lib); + + return sh; +} + GPUShader *DRW_shader_create_with_shaderlib_ex(const char *vert, const char *geom, const char *frag, diff --git a/source/blender/draw/tests/shaders_test.cc b/source/blender/draw/tests/shaders_test.cc index e7baac63aae..892fd999fb5 100644 --- a/source/blender/draw/tests/shaders_test.cc +++ b/source/blender/draw/tests/shaders_test.cc @@ -360,6 +360,8 @@ static void test_eevee_glsl_shaders_static() EXPECT_NE(EEVEE_shaders_volumes_integration_sh_get(), nullptr); EXPECT_NE(EEVEE_shaders_volumes_resolve_sh_get(false), nullptr); EXPECT_NE(EEVEE_shaders_volumes_resolve_sh_get(true), nullptr); + EXPECT_NE(EEVEE_shaders_volumes_resolve_comp_sh_get(false), nullptr); + EXPECT_NE(EEVEE_shaders_volumes_resolve_comp_sh_get(true), nullptr); EXPECT_NE(EEVEE_shaders_volumes_accum_sh_get(), nullptr); EXPECT_NE(EEVEE_shaders_studiolight_probe_sh_get(), nullptr); EXPECT_NE(EEVEE_shaders_studiolight_background_sh_get(), nullptr); -- cgit v1.2.3