diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2021-10-19 18:40:10 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2021-10-24 17:13:04 +0300 |
commit | 3db3006d4c22917cf25c12ca137d33594e323344 (patch) | |
tree | bfda4c4e37ffcd9040d2ba307bc56b2d65537056 /source/blender/draw | |
parent | 008fb3eed9b8c318a8b50dc5a7e84e9cfb030656 (diff) |
EEVEE: Port back HiZbuffer
Pretty much identical.
Texture format is now always `GPU_R32F` to remove some workarounds.
Diffstat (limited to 'source/blender/draw')
16 files changed, 395 insertions, 60 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index f102141e7d2..e0343cffb01 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -120,6 +120,7 @@ set(SRC engines/eevee/eevee_film.cc engines/eevee/eevee_gpencil.cc engines/eevee/eevee_hair.cc + engines/eevee/eevee_hizbuffer.cc engines/eevee/eevee_id_map.cc engines/eevee/eevee_instance.cc engines/eevee/eevee_light.cc @@ -253,6 +254,8 @@ data_to_c_simple(engines/eevee/shaders/eevee_deferred_holdout_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/eevee_deferred_transparent_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/eevee_deferred_volume_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/eevee_depth_clear_frag.glsl SRC) +data_to_c_simple(engines/eevee/shaders/eevee_hiz_copy_frag.glsl SRC) +data_to_c_simple(engines/eevee/shaders/eevee_hiz_downsample_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/eevee_depth_of_field_accumulator_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/eevee_depth_of_field_bokeh_lut_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/eevee_depth_of_field_filter_frag.glsl SRC) diff --git a/source/blender/draw/engines/eevee/eevee_hizbuffer.cc b/source/blender/draw/engines/eevee/eevee_hizbuffer.cc new file mode 100644 index 00000000000..24f0c8261e8 --- /dev/null +++ b/source/blender/draw/engines/eevee/eevee_hizbuffer.cc @@ -0,0 +1,101 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2021, Blender Foundation. + */ + +/** \file + * \ingroup eevee + * + * The Hierarchical-Z buffer is texture containing a copy of the depth buffer with mipmaps. + * Each mip contains the maximum depth of each 4 pixels on the upper level. + * The size of the texture is padded to avoid messing with the mipmap pixels alignments. + */ + +#include "eevee_instance.hh" + +#include "eevee_hizbuffer.hh" + +namespace blender::eevee { + +/* -------------------------------------------------------------------- */ +/** \name Hierarchical-Z buffer + * + * \{ */ + +void HiZBufferModule::sync(void) +{ + { + hiz_copy_ps_ = DRW_pass_create("HizCopy", DRW_STATE_WRITE_COLOR); + GPUShader *sh = inst_.shaders.static_shader_get(HIZ_COPY); + DRWShadingGroup *grp = DRW_shgroup_create(sh, hiz_copy_ps_); + DRW_shgroup_uniform_texture_ref(grp, "depth_tx", &input_depth_tx_); + DRW_shgroup_call_procedural_triangles(grp, nullptr, 1); + } + { + hiz_downsample_ps_ = DRW_pass_create("HizDownsample", DRW_STATE_WRITE_COLOR); + GPUShader *sh = inst_.shaders.static_shader_get(HIZ_DOWNSAMPLE); + DRWShadingGroup *grp = DRW_shgroup_create(sh, hiz_downsample_ps_); + DRW_shgroup_uniform_texture_ref(grp, "depth_tx", &input_depth_tx_); + DRW_shgroup_uniform_vec2(grp, "texel_size", texel_size_, 1); + DRW_shgroup_call_procedural_triangles(grp, nullptr, 1); + } +} + +void HiZBuffer::prepare(GPUTexture *depth_src_tx) +{ + int div = 1 << mip_count_; + vec2 extent_src(GPU_texture_width(depth_src_tx), GPU_texture_height(depth_src_tx)); + vec2 extent_hiz(divide_ceil_u(extent_src.x, div) * div, divide_ceil_u(extent_src.y, div) * div); + + inst_.hiz.texel_size_ = 1.0f / extent_hiz; + inst_.hiz.data_.uv_scale = extent_src / extent_hiz; + + inst_.hiz.data_.push_update(); + + /* TODO/OPTI(fclem): Share it between similar views. + * Not possible right now because request_tmp does not support mipmaps. */ + hiz_tx_.ensure("HiZ", UNPACK2(extent_hiz), mip_count_, GPU_R32F); + hiz_fb_.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(hiz_tx_)); + + GPU_texture_mipmap_mode(hiz_tx_, true, false); +} + +void HiZBuffer::recursive_downsample(void *thunk, int UNUSED(lvl)) +{ + HiZBufferModule &hiz = *reinterpret_cast<HiZBufferModule *>(thunk); + hiz.texel_size_ *= 2.0f; + DRW_draw_pass(hiz.hiz_downsample_ps_); +} + +void HiZBuffer::update(GPUTexture *depth_src_tx) +{ + DRW_stats_group_start("Hiz"); + + inst_.hiz.texel_size_ = 1.0f / vec2(GPU_texture_width(hiz_tx_), GPU_texture_height(hiz_tx_)); + + inst_.hiz.input_depth_tx_ = depth_src_tx; + GPU_framebuffer_bind(hiz_fb_); + DRW_draw_pass(inst_.hiz.hiz_copy_ps_); + + inst_.hiz.input_depth_tx_ = hiz_tx_; + GPU_framebuffer_recursive_downsample(hiz_fb_, mip_count_, &recursive_downsample, &inst_.hiz); + + DRW_stats_group_end(); +} + +/** \} */ + +} // namespace blender::eevee diff --git a/source/blender/draw/engines/eevee/eevee_hizbuffer.hh b/source/blender/draw/engines/eevee/eevee_hizbuffer.hh new file mode 100644 index 00000000000..80bd7be912c --- /dev/null +++ b/source/blender/draw/engines/eevee/eevee_hizbuffer.hh @@ -0,0 +1,103 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2021, Blender Foundation. + */ + +/** \file + * \ingroup eevee + * + * The Hierarchical-Z buffer is texture containing a copy of the depth buffer with mipmaps. + * Each mip contains the maximum depth of each 4 pixels on the upper level. + * The size of the texture is padded to avoid messing with the mipmap pixels alignments. + */ + +#pragma once + +#include "DRW_render.h" + +#include "eevee_shader_shared.hh" + +namespace blender::eevee { + +class Instance; + +/* -------------------------------------------------------------------- */ +/** \name Hierarchical-Z buffer + * \{ */ + +class HiZBuffer { + private: + Instance &inst_; + /** Framebuffer use for recursive downsampling. */ + /* TODO(fclem) Remove this and use a compute shader instead. */ + Framebuffer hiz_fb_ = Framebuffer("DepthHiz"); + /** Max mip to downsample to. We ensure the hiz has enough padding to never + * have to compensate the mipmap alignments. */ + constexpr static int mip_count_ = 6; + /** TODO/OPTI(fclem): Share it between similar views. */ + Texture hiz_tx_; + + public: + HiZBuffer(Instance &inst) : inst_(inst){}; + + void prepare(GPUTexture *depth_src); + void update(GPUTexture *depth_src); + + GPUTexture *texture_get(void) const + { + return hiz_tx_; + } + + private: + static void recursive_downsample(void *thunk, int lvl); +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Hierarchical-Z buffer Module + * \{ */ + +class HiZBufferModule { + friend HiZBuffer; + + private: + Instance &inst_; + + HiZDataBuf data_; + /** Copy input depth to hiz-buffer with border padding. */ + DRWPass *hiz_copy_ps_; + /** Downsample one mipmap level. */ + DRWPass *hiz_downsample_ps_; + /** References only. */ + GPUTexture *input_depth_tx_ = nullptr; + /** Pixel size of the render target during hiz downsampling. */ + vec2 texel_size_; + + public: + HiZBufferModule(Instance &inst) : inst_(inst){}; + + void sync(void); + + const GPUUniformBuf *ubo_get(void) const + { + return data_.ubo_get(); + } +}; + +/** \} */ + +} // namespace blender::eevee diff --git a/source/blender/draw/engines/eevee/eevee_instance.cc b/source/blender/draw/engines/eevee/eevee_instance.cc index 9aea6e301af..8c042ae062b 100644 --- a/source/blender/draw/engines/eevee/eevee_instance.cc +++ b/source/blender/draw/engines/eevee/eevee_instance.cc @@ -125,6 +125,7 @@ void Instance::begin_sync() shading_passes.sync(); main_view.sync(); world.sync(); + hiz.sync(); lookdev.sync_background(); lookdev.sync_overlay(); diff --git a/source/blender/draw/engines/eevee/eevee_instance.hh b/source/blender/draw/engines/eevee/eevee_instance.hh index 22a5ad1f57a..24c1fae5515 100644 --- a/source/blender/draw/engines/eevee/eevee_instance.hh +++ b/source/blender/draw/engines/eevee/eevee_instance.hh @@ -29,6 +29,7 @@ #include "DRW_render.h" #include "eevee_film.hh" +#include "eevee_hizbuffer.hh" #include "eevee_id_map.hh" #include "eevee_light.hh" #include "eevee_lightprobe.hh" @@ -69,6 +70,7 @@ class Instance { MotionBlurModule motion_blur; LightModule lights; LightProbeModule lightprobes; + HiZBufferModule hiz; /* TODO(fclem) Move it to scene layer data. */ ShadowModule shadows; SubsurfaceModule subsurface; @@ -110,6 +112,7 @@ class Instance { motion_blur(*this), lights(*this), lightprobes(*this), + hiz(*this), shadows(*this), subsurface(*this), sync(*this), diff --git a/source/blender/draw/engines/eevee/eevee_shader.cc b/source/blender/draw/engines/eevee/eevee_shader.cc index 654a01cac80..8c8262f5893 100644 --- a/source/blender/draw/engines/eevee/eevee_shader.cc +++ b/source/blender/draw/engines/eevee/eevee_shader.cc @@ -54,6 +54,8 @@ extern char datatoc_eevee_deferred_holdout_frag_glsl[]; extern char datatoc_eevee_deferred_transparent_frag_glsl[]; extern char datatoc_eevee_deferred_volume_frag_glsl[]; extern char datatoc_eevee_depth_clear_frag_glsl[]; +extern char datatoc_eevee_hiz_copy_frag_glsl[]; +extern char datatoc_eevee_hiz_downsample_frag_glsl[]; extern char datatoc_eevee_depth_of_field_accumulator_lib_glsl[]; extern char datatoc_eevee_depth_of_field_bokeh_lut_frag_glsl[]; extern char datatoc_eevee_depth_of_field_downsample_frag_glsl[]; @@ -214,6 +216,8 @@ ShaderModule::ShaderModule() SHADER_FULLSCREEN(DEFERRED_EVAL_VOLUME, eevee_deferred_volume_frag); SHADER(DEFERRED_MESH, eevee_surface_mesh_vert, nullptr, eevee_surface_deferred_frag, nullptr); SHADER(DEFERRED_VOLUME, eevee_volume_vert, nullptr, eevee_volume_deferred_frag, nullptr); + SHADER_FULLSCREEN(HIZ_COPY, eevee_hiz_copy_frag); + SHADER_FULLSCREEN(HIZ_DOWNSAMPLE, eevee_hiz_downsample_frag); SHADER_FULLSCREEN(DOF_BOKEH_LUT, eevee_depth_of_field_bokeh_lut_frag); SHADER_FULLSCREEN(DOF_FILTER, eevee_depth_of_field_filter_frag); SHADER_FULLSCREEN_DEFINES(DOF_GATHER_BACKGROUND_LUT, diff --git a/source/blender/draw/engines/eevee/eevee_shader.hh b/source/blender/draw/engines/eevee/eevee_shader.hh index 792248540f7..4d0dc93d616 100644 --- a/source/blender/draw/engines/eevee/eevee_shader.hh +++ b/source/blender/draw/engines/eevee/eevee_shader.hh @@ -77,6 +77,9 @@ enum eShaderType { FILM_RESOLVE, FILM_RESOLVE_DEPTH, + HIZ_COPY, + HIZ_DOWNSAMPLE, + LIGHTPROBE_DISPLAY_CUBEMAP, LIGHTPROBE_DISPLAY_IRRADIANCE, diff --git a/source/blender/draw/engines/eevee/eevee_shader_shared.hh b/source/blender/draw/engines/eevee/eevee_shader_shared.hh index d566212c49b..05e4ded136e 100644 --- a/source/blender/draw/engines/eevee/eevee_shader_shared.hh +++ b/source/blender/draw/engines/eevee/eevee_shader_shared.hh @@ -613,6 +613,20 @@ BLI_STATIC_ASSERT_ALIGN(LightProbeInfoData, 16) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Hierarchical-Z Buffer + * \{ */ + +struct HiZData { + /** Scale factor to remove HiZBuffer padding. */ + vec2 uv_scale; + int _pad0; + int _pad1; +}; +BLI_STATIC_ASSERT_ALIGN(HiZData, 16) + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Subsurface * \{ */ @@ -699,6 +713,7 @@ using CubemapDataBuf = StructArrayBuffer<CubemapData, CULLING_ITEM_BATCH>; using CullingDataBuf = StructBuffer<CullingData>; using DepthOfFieldDataBuf = StructBuffer<DepthOfFieldData>; using GridDataBuf = StructArrayBuffer<GridData, GRID_MAX>; +using HiZDataBuf = StructBuffer<HiZData>; using LightDataBuf = StructArrayBuffer<LightData, CULLING_ITEM_BATCH>; using LightProbeFilterDataBuf = StructBuffer<LightProbeFilterData>; using LightProbeInfoDataBuf = StructBuffer<LightProbeInfoData>; diff --git a/source/blender/draw/engines/eevee/eevee_shading.cc b/source/blender/draw/engines/eevee/eevee_shading.cc index 948ff9ba524..16c03731dee 100644 --- a/source/blender/draw/engines/eevee/eevee_shading.cc +++ b/source/blender/draw/engines/eevee/eevee_shading.cc @@ -273,40 +273,57 @@ void DeferredLayer::volume_add(Object *ob) DRW_shgroup_call(grp, DRW_cache_cube_get(), ob); } -void DeferredLayer::render(GBuffer &gbuffer, GPUFrameBuffer *view_fb) +void DeferredLayer::render(GBuffer &gbuffer, HiZBuffer &hiz, GPUFrameBuffer *view_fb) { + DeferredPass &deferred_pass = inst_.shading_passes.deferred; + const bool no_surfaces = DRW_pass_is_empty(gbuffer_ps_); const bool no_volumes = DRW_pass_is_empty(volume_ps_); if (no_surfaces && no_volumes) { return; } + /* TODO(fclem): detect these cases. */ + const bool use_refraction = true; + const bool use_glossy = true; + const bool use_ao = false; + + gbuffer.prepare((eClosureBits)0xFFFFFFFFu); + hiz.prepare(gbuffer.depth_tx); - gbuffer.bind((eClosureBits)0xFFFFFFFFu); + update_pass_inputs(gbuffer, hiz); + + if (use_refraction) { + /* TODO(fclem) Only update if needed. + * i.e: No need when SSR from previous layer has already updated hiz. */ + hiz.update(gbuffer.depth_tx); + } + + gbuffer.bind(); if (!no_surfaces) { DRW_draw_pass(prepass_ps_); + + /* TODO(fclem): Ambient Occlusion texture node. */ + /* NOTE(fclem): Needs a separate hiz if used at the same time as refraction. */ + if (use_ao) { + hiz.update(gbuffer.depth_tx); + gbuffer.bind(); + } + DRW_draw_pass(gbuffer_ps_); } - DeferredPass &deferred_pass = inst_.shading_passes.deferred; - deferred_pass.input_combined_tx = gbuffer.combined_tx; - deferred_pass.input_emission_data_tx_ = gbuffer.emission_tx; - deferred_pass.input_transmit_color_tx_ = gbuffer.transmit_color_tx; - deferred_pass.input_transmit_normal_tx_ = gbuffer.transmit_normal_tx; - deferred_pass.input_transmit_data_tx_ = gbuffer.transmit_data_tx; - deferred_pass.input_reflect_color_tx_ = gbuffer.reflect_color_tx; - deferred_pass.input_reflect_normal_tx_ = gbuffer.reflect_normal_tx; - deferred_pass.input_diffuse_tx_ = gbuffer.diffuse_tx; - deferred_pass.input_transparency_data_tx_ = gbuffer.transparency_tx; - deferred_pass.input_volume_data_tx_ = gbuffer.volume_tx; - deferred_pass.input_depth_tx_ = gbuffer.depth_copy_tx; - - if (!no_volumes) { - gbuffer.copy_depth_behind(); - deferred_pass.input_depth_behind_tx_ = gbuffer.depth_behind_tx; + if (use_refraction) { + // if (inst_.raytracing.enabled()) { + // DRW_draw_pass(deferred_pass.trace_refraction_ps_); + // } + // DRW_draw_pass(deferred_pass.eval_refraction_ps_); } if (!no_volumes) { + // gbuffer.copy_depth_behind(); + // deferred_pass.input_depth_behind_tx_ = gbuffer.depth_behind_tx; + for (auto index : inst_.lights.index_range()) { inst_.lights.bind_batch(index); @@ -315,7 +332,7 @@ void DeferredLayer::render(GBuffer &gbuffer, GPUFrameBuffer *view_fb) } } - gbuffer.copy_depth(); + hiz.update(gbuffer.depth_tx); if (true) { gbuffer.bind_holdout(); @@ -348,6 +365,26 @@ void DeferredLayer::render(GBuffer &gbuffer, GPUFrameBuffer *view_fb) GPU_framebuffer_bind(view_fb); DRW_draw_pass(deferred_pass.eval_subsurface_ps_); } + + // if (use_glossy && inst_.raytracing.enabled()) { + // inst_.raytracing.trace_reflection(gbuffer); + // } +} + +void DeferredLayer::update_pass_inputs(GBuffer &gbuffer, HiZBuffer &hiz) +{ + DeferredPass &deferred_pass = inst_.shading_passes.deferred; + deferred_pass.input_combined_tx_ = gbuffer.combined_tx; + deferred_pass.input_emission_data_tx_ = gbuffer.emission_tx; + deferred_pass.input_transmit_color_tx_ = gbuffer.transmit_color_tx; + deferred_pass.input_transmit_normal_tx_ = gbuffer.transmit_normal_tx; + deferred_pass.input_transmit_data_tx_ = gbuffer.transmit_data_tx; + deferred_pass.input_reflect_color_tx_ = gbuffer.reflect_color_tx; + deferred_pass.input_reflect_normal_tx_ = gbuffer.reflect_normal_tx; + deferred_pass.input_diffuse_tx_ = gbuffer.diffuse_tx; + deferred_pass.input_transparency_data_tx_ = gbuffer.transparency_tx; + deferred_pass.input_volume_data_tx_ = gbuffer.volume_tx; + deferred_pass.input_hiz_tx_ = hiz.texture_get(); } /** \} */ @@ -399,7 +436,7 @@ void DeferredPass::sync(void) grp, "reflect_color_tx", &input_reflect_color_tx_, no_interp); DRW_shgroup_uniform_texture_ref_ex( grp, "reflect_normal_tx", &input_reflect_normal_tx_, no_interp); - DRW_shgroup_uniform_texture_ref(grp, "depth_tx", &input_depth_tx_); + DRW_shgroup_uniform_texture_ref(grp, "hiz_tx", &input_hiz_tx_); DRW_shgroup_uniform_texture_ref( grp, "sss_transmittance_tx", inst_.subsurface.transmittance_ref_get()); DRW_shgroup_stencil_set( @@ -413,7 +450,8 @@ void DeferredPass::sync(void) DRWShadingGroup *grp = DRW_shgroup_create(sh, eval_subsurface_ps_); DRW_shgroup_uniform_block(grp, "subsurface_block", inst_.subsurface.ubo_get()); DRW_shgroup_uniform_block(grp, "sampling_block", inst_.sampling.ubo_get()); - DRW_shgroup_uniform_texture_ref(grp, "depth_tx", &input_depth_tx_); + DRW_shgroup_uniform_block(grp, "hiz_block", inst_.hiz.ubo_get()); + DRW_shgroup_uniform_texture_ref(grp, "hiz_tx", &input_hiz_tx_); DRW_shgroup_uniform_texture_ref_ex(grp, "radiance_tx", &input_diffuse_tx_, no_interp); DRW_shgroup_uniform_texture_ref_ex( grp, "transmit_color_tx", &input_transmit_color_tx_, no_interp); @@ -438,7 +476,7 @@ void DeferredPass::sync(void) DRW_shgroup_uniform_texture_ref_ex( grp, "transparency_data_tx", &input_transparency_data_tx_, no_interp); DRW_shgroup_uniform_texture_ref_ex(grp, "volume_data_tx", &input_volume_data_tx_, no_interp); - DRW_shgroup_uniform_texture_ref(grp, "depth_tx", &input_depth_tx_); + DRW_shgroup_uniform_texture_ref(grp, "hiz_tx", &input_hiz_tx_); DRW_shgroup_stencil_set(grp, 0x0, 0x0, CLOSURE_VOLUME); DRW_shgroup_call_procedural_triangles(grp, nullptr, 1); } @@ -449,7 +487,7 @@ void DeferredPass::sync(void) DRWShadingGroup *grp = DRW_shgroup_create(sh, eval_transparency_ps_); DRW_shgroup_uniform_texture_ref(grp, "transparency_data_tx", &input_transparency_data_tx_); DRW_shgroup_uniform_texture_ref_ex(grp, "volume_data_tx", &input_volume_data_tx_, no_interp); - DRW_shgroup_uniform_texture_ref(grp, "depth_tx", &input_depth_tx_); + DRW_shgroup_uniform_texture_ref(grp, "hiz_tx", &input_hiz_tx_); DRW_shgroup_stencil_set(grp, 0x0, 0x0, CLOSURE_TRANSPARENCY); DRW_shgroup_call_procedural_triangles(grp, nullptr, 1); } @@ -458,7 +496,7 @@ void DeferredPass::sync(void) eval_holdout_ps_ = DRW_pass_create("DeferredHoldout", state); GPUShader *sh = inst_.shaders.static_shader_get(DEFERRED_EVAL_HOLDOUT); DRWShadingGroup *grp = DRW_shgroup_create(sh, eval_volume_homogeneous_ps_); - DRW_shgroup_uniform_texture_ref(grp, "combined_tx", &input_combined_tx); + DRW_shgroup_uniform_texture_ref(grp, "combined_tx", &input_combined_tx_); DRW_shgroup_uniform_texture_ref(grp, "transparency_data_tx", &input_transparency_data_tx_); DRW_shgroup_stencil_set(grp, 0x0, 0x0, CLOSURE_TRANSPARENCY); DRW_shgroup_call_procedural_triangles(grp, nullptr, 1); @@ -490,11 +528,11 @@ void DeferredPass::volume_add(Object *ob) volumetric_layer_.volume_add(ob); } -void DeferredPass::render(GBuffer &gbuffer, GPUFrameBuffer *view_fb) +void DeferredPass::render(GBuffer &gbuffer, HiZBuffer &hiz, GPUFrameBuffer *view_fb) { - opaque_layer_.render(gbuffer, view_fb); - refraction_layer_.render(gbuffer, view_fb); - volumetric_layer_.render(gbuffer, view_fb); + opaque_layer_.render(gbuffer, hiz, view_fb); + refraction_layer_.render(gbuffer, hiz, view_fb); + volumetric_layer_.render(gbuffer, hiz, view_fb); gbuffer.render_end(); } diff --git a/source/blender/draw/engines/eevee/eevee_shading.hh b/source/blender/draw/engines/eevee/eevee_shading.hh index 691bce3e97e..e042dea1dc6 100644 --- a/source/blender/draw/engines/eevee/eevee_shading.hh +++ b/source/blender/draw/engines/eevee/eevee_shading.hh @@ -140,10 +140,8 @@ struct GBuffer { Framebuffer holdout_fb = Framebuffer("Holdout"); Texture depth_behind_tx = Texture("DepthBehind"); - Texture depth_copy_tx = Texture("DepthCopy"); Framebuffer depth_behind_fb = Framebuffer("DepthCopy"); - Framebuffer depth_copy_fb = Framebuffer("DepthCopy"); /* Owner of this GBuffer. Used to query temp textures. */ void *owner; @@ -170,10 +168,9 @@ struct GBuffer { holdout_tx.sync_tmp(); diffuse_tx.sync_tmp(); depth_behind_tx.sync_tmp(); - depth_copy_tx.sync_tmp(); } - void bind(eClosureBits closures_used) + void prepare(eClosureBits closures_used) { ivec2 extent = {GPU_texture_width(depth_tx), GPU_texture_height(depth_tx)}; @@ -214,7 +211,6 @@ struct GBuffer { holdout_tx.acquire_tmp(UNPACK2(extent), GPU_R11F_G11F_B10F, owner); depth_behind_tx.acquire_tmp(UNPACK2(extent), GPU_DEPTH24_STENCIL8, owner); - depth_copy_tx.acquire_tmp(UNPACK2(extent), GPU_DEPTH24_STENCIL8, owner); /* Layer attachement also works with cubemap. */ gbuffer_fb.ensure(GPU_ATTACHMENT_TEXTURE_LAYER(depth_tx, layer), @@ -226,6 +222,10 @@ struct GBuffer { GPU_ATTACHMENT_TEXTURE(volume_tx), GPU_ATTACHMENT_TEXTURE(emission_tx), GPU_ATTACHMENT_TEXTURE(transparency_tx)); + } + + void bind(void) + { GPU_framebuffer_bind(gbuffer_fb); GPU_framebuffer_clear_stencil(gbuffer_fb, 0x0); } @@ -262,14 +262,6 @@ struct GBuffer { GPU_framebuffer_blit(gbuffer_fb, 0, depth_behind_fb, 0, GPU_DEPTH_BIT); } - void copy_depth(void) - { - depth_copy_fb.ensure(GPU_ATTACHMENT_TEXTURE(depth_copy_tx)); - GPU_framebuffer_bind(depth_copy_fb); - - GPU_framebuffer_blit(gbuffer_fb, 0, depth_copy_fb, 0, GPU_DEPTH_BIT); - } - void clear_radiance(void) { radiance_clear_fb.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(diffuse_tx)); @@ -292,7 +284,6 @@ struct GBuffer { holdout_tx.release_tmp(); diffuse_tx.release_tmp(); depth_behind_tx.release_tmp(); - depth_copy_tx.release_tmp(); } }; @@ -318,7 +309,10 @@ class DeferredLayer { DRWShadingGroup *material_add(::Material *blender_mat, GPUMaterial *gpumat); DRWShadingGroup *prepass_add(::Material *blender_mat, GPUMaterial *gpumat); void volume_add(Object *ob); - void render(GBuffer &gbuffer, GPUFrameBuffer *view_fb); + void render(GBuffer &gbuffer, HiZBuffer &hiz, GPUFrameBuffer *view_fb); + + private: + void update_pass_inputs(GBuffer &gbuffer, HiZBuffer &hiz); }; class DeferredPass { @@ -341,16 +335,16 @@ class DeferredPass { DRWPass *eval_volume_homogeneous_ps_ = nullptr; /* References only. */ - GPUTexture *input_combined_tx = nullptr; + GPUTexture *input_combined_tx_ = nullptr; GPUTexture *input_depth_behind_tx_ = nullptr; - GPUTexture *input_depth_tx_ = nullptr; + GPUTexture *input_diffuse_tx_ = nullptr; GPUTexture *input_emission_data_tx_ = nullptr; - GPUTexture *input_transmit_color_tx_ = nullptr; - GPUTexture *input_transmit_normal_tx_ = nullptr; - GPUTexture *input_transmit_data_tx_ = nullptr; + GPUTexture *input_hiz_tx_ = nullptr; GPUTexture *input_reflect_color_tx_ = nullptr; GPUTexture *input_reflect_normal_tx_ = nullptr; - GPUTexture *input_diffuse_tx_ = nullptr; + GPUTexture *input_transmit_color_tx_ = nullptr; + GPUTexture *input_transmit_data_tx_ = nullptr; + GPUTexture *input_transmit_normal_tx_ = nullptr; GPUTexture *input_transparency_data_tx_ = nullptr; GPUTexture *input_volume_data_tx_ = nullptr; // GPUTexture *input_volume_radiance_tx_ = nullptr; @@ -364,7 +358,7 @@ class DeferredPass { DRWShadingGroup *material_add(::Material *material, GPUMaterial *gpumat); DRWShadingGroup *prepass_add(::Material *material, GPUMaterial *gpumat); void volume_add(Object *ob); - void render(GBuffer &gbuffer, GPUFrameBuffer *view_fb); + void render(GBuffer &gbuffer, HiZBuffer &hiz, GPUFrameBuffer *view_fb); }; /** \} */ diff --git a/source/blender/draw/engines/eevee/eevee_view.cc b/source/blender/draw/engines/eevee/eevee_view.cc index 72e2baa6815..ef2cbf499ef 100644 --- a/source/blender/draw/engines/eevee/eevee_view.cc +++ b/source/blender/draw/engines/eevee/eevee_view.cc @@ -134,7 +134,7 @@ void ShadingView::render(void) inst_.shading_passes.background.render(); } - inst_.shading_passes.deferred.render(gbuffer_, view_fb_); + inst_.shading_passes.deferred.render(gbuffer_, hiz_, view_fb_); inst_.lightprobes.draw_cache_display(); @@ -248,7 +248,7 @@ void LightProbeView::render(void) if (!is_only_background_) { GPU_framebuffer_clear_depth(view_fb_, 1.0f); - inst_.shading_passes.deferred.render(gbuffer_, view_fb_); + inst_.shading_passes.deferred.render(gbuffer_, hiz_, view_fb_); inst_.shading_passes.forward.render(); } DRW_stats_group_end(); diff --git a/source/blender/draw/engines/eevee/eevee_view.hh b/source/blender/draw/engines/eevee/eevee_view.hh index 901f6c1036f..5e3afead4c0 100644 --- a/source/blender/draw/engines/eevee/eevee_view.hh +++ b/source/blender/draw/engines/eevee/eevee_view.hh @@ -37,6 +37,7 @@ #include "DRW_render.h" #include "eevee_depth_of_field.hh" +#include "eevee_hizbuffer.hh" #include "eevee_motion_blur.hh" #include "eevee_renderpasses.hh" #include "eevee_shader.hh" @@ -56,7 +57,7 @@ class Instance; class ShadingView { private: Instance &inst_; - /** Static srting pointer. Used as debug name and as UUID for texture pool. */ + /** Static string pointer. Used as debug name and as UUID for texture pool. */ const char *name_; /** Matrix to apply to the viewmat. */ const float (*face_matrix_)[4]; @@ -66,7 +67,10 @@ class ShadingView { MotionBlur mb_; Velocity velocity_; + /** GBuffer for deferred passes. */ GBuffer gbuffer_; + /** HiZBuffer for screenspace effects. */ + HiZBuffer hiz_; /** Owned resources. */ eevee::Framebuffer view_fb_; @@ -96,7 +100,8 @@ class ShadingView { face_matrix_(face_matrix), dof_(inst, name), mb_(inst, name), - velocity_(inst, name){}; + velocity_(inst, name), + hiz_(inst){}; ~ShadingView(){}; @@ -129,6 +134,8 @@ class LightProbeView { const float (*face_matrix_)[4]; /** GBuffer for deferred passes. */ GBuffer gbuffer_; + /** HiZBuffer for screenspace effects. */ + HiZBuffer hiz_; /** Owned resources. */ Framebuffer view_fb_; /** DRWView of this face. */ @@ -141,7 +148,7 @@ class LightProbeView { public: LightProbeView(Instance &inst, const char *name, const float (*face_matrix)[4], int layer_) - : inst_(inst), name_(name), face_matrix_(face_matrix), layer_(layer_){}; + : inst_(inst), name_(name), face_matrix_(face_matrix), hiz_(inst), layer_(layer_){}; ~LightProbeView(){}; diff --git a/source/blender/draw/engines/eevee/shaders/eevee_deferred_direct_frag.glsl b/source/blender/draw/engines/eevee/shaders/eevee_deferred_direct_frag.glsl index 9335970ba4d..dd4d0ba4f20 100644 --- a/source/blender/draw/engines/eevee/shaders/eevee_deferred_direct_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/eevee_deferred_direct_frag.glsl @@ -46,7 +46,7 @@ layout(std140) uniform lightprobes_info_block LightProbeInfoData probes_info; }; -uniform sampler2D depth_tx; +uniform sampler2D hiz_tx; uniform sampler2D emission_data_tx; uniform sampler2D transmit_color_tx; uniform sampler2D transmit_normal_tx; @@ -84,7 +84,7 @@ vec3 lightprobe_cubemap_eval(vec3 P, vec3 R, float roughness, float random_thres void main(void) { - float gbuffer_depth = texture(depth_tx, uvcoordsvar.xy).r; + float gbuffer_depth = texelFetch(hiz_tx, ivec2(gl_FragCoord.xy), 0).r; vec3 vP = get_view_space_from_depth(uvcoordsvar.xy, gbuffer_depth); vec3 P = point_view_to_world(vP); vec3 V = cameraVec(P); diff --git a/source/blender/draw/engines/eevee/shaders/eevee_hiz_copy_frag.glsl b/source/blender/draw/engines/eevee/shaders/eevee_hiz_copy_frag.glsl new file mode 100644 index 00000000000..f0ee9f515c9 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/eevee_hiz_copy_frag.glsl @@ -0,0 +1,17 @@ +/** + * Copy input depth texture to lower left corner of the destination, filling any padding with + * clamped texture extrapolation. + */ + +#pragma BLENDER_REQUIRE(common_view_lib.glsl) + +uniform sampler2D depth_tx; + +layout(location = 0) out float out_depth; + +void main() +{ + vec2 uv = gl_FragCoord.xy / vec2(textureSize(depth_tx, 0).xy); + + out_depth = texture(depth_tx, uv).r; +} diff --git a/source/blender/draw/engines/eevee/shaders/eevee_hiz_downsample_frag.glsl b/source/blender/draw/engines/eevee/shaders/eevee_hiz_downsample_frag.glsl new file mode 100644 index 00000000000..9a095d960b2 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/eevee_hiz_downsample_frag.glsl @@ -0,0 +1,40 @@ +/** + * Shader that down-sample depth buffer, creating a Hierarchical-Z buffer. + * Saves max value of each 2x2 texel in the mipmap above the one we are rendering to. + * Adapted from http://rastergrid.com/blog/2010/10/hierarchical-z-map-based-occlusion-culling/ + * + * Major simplification has been made since we pad the buffer to always be bigger than input to + * avoid mipmapping misalignement. + */ + +#pragma BLENDER_REQUIRE(common_math_lib.glsl) + +uniform sampler2D depth_tx; + +uniform vec2 texel_size; + +layout(location = 0) out float out_depth; + +#ifndef GPU_ARB_texture_gather +vec4 texGather(sampler2D tex, vec2 uv) +{ + vec4 ofs = vec2(0.5, 0.5, -0.5, -0.5) * texel_size.xyxy; + return vec4(texture(tex, uv + ofs.zw).r, + texture(tex, uv + ofs.zy).r, + texture(tex, uv + ofs.xw).r, + texture(tex, uv + ofs.xy).r); +} +#else +# define texGather(a, b) textureGather(a, b) +#endif + +void main() +{ + /* NOTE(@fclem): textureSize() does not work the same on all implementations + * when changing the min and max texture levels. Use uniform instead (see T87801). */ + vec2 uv = gl_FragCoord.xy * texel_size; + + vec4 samp = texGather(depth_tx, uv); + + out_depth = max_v4(samp); +} diff --git a/source/blender/draw/engines/eevee/shaders/eevee_subsurface_eval_frag.glsl b/source/blender/draw/engines/eevee/shaders/eevee_subsurface_eval_frag.glsl index 50ec88b1990..e24c2dccdbf 100644 --- a/source/blender/draw/engines/eevee/shaders/eevee_subsurface_eval_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/eevee_subsurface_eval_frag.glsl @@ -23,7 +23,12 @@ layout(std140) uniform subsurface_block SubsurfaceData sss; }; -uniform sampler2D depth_tx; +layout(std140) uniform hiz_block +{ + HiZData hiz; +}; + +uniform sampler2D hiz_tx; uniform sampler2D radiance_tx; uniform sampler2D transmit_color_tx; uniform sampler2D transmit_normal_tx; @@ -63,7 +68,8 @@ void main(void) { vec2 center_uv = uvcoordsvar.xy; - vec3 vP = get_view_space_from_depth(center_uv, texture(depth_tx, center_uv).r); + float gbuffer_depth = texelFetch(hiz_tx, ivec2(gl_FragCoord.xy), 0).r; + vec3 vP = get_view_space_from_depth(center_uv, gbuffer_depth); vec4 tra_col_in = texture(transmit_color_tx, center_uv); vec4 tra_nor_in = texture(transmit_normal_tx, center_uv); vec4 tra_dat_in = texture(transmit_data_tx, center_uv); @@ -111,7 +117,7 @@ void main(void) vec2 sample_uv = center_uv + sample_space * sss.samples[i].xy; float pdf = sss.samples[i].z; - float sample_depth = texture(depth_tx, sample_uv).r; + float sample_depth = texture(hiz_tx, sample_uv * hiz.uv_scale).r; vec3 sample_vP = get_view_space_from_depth(sample_uv, sample_depth); vec4 sample_data = texture(radiance_tx, sample_uv); |