EEVEE-Next: HiZBuffer: Add support for 2nd layer
This allows for parallel processing of refraction. Also fix a limitation of using AO node in refraction materials. This is needed for the grouping of raytracing passes. This increases VRAM consumption a bit (8MB for fullHD frame) but has no impact on performance. This include a needed fix to the `draw::Texture::swap`. ### Later work - Limit the memory overhead to the cases where it is needed. Pull Request: https://projects.blender.org/blender/blender/pulls/115912
This commit is contained in:
committed by
Clément Foucault
parent
a355488993
commit
71f6228876
@@ -23,9 +23,12 @@ void HiZBuffer::sync()
|
||||
int2 dispatch_size = math::divide_ceil(hiz_extent, int2(HIZ_GROUP_SIZE));
|
||||
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE;
|
||||
hiz_tx_.ensure_2d(GPU_R32F, hiz_extent, usage, nullptr, HIZ_MIP_COUNT);
|
||||
hiz_tx_.ensure_mip_views();
|
||||
GPU_texture_mipmap_mode(hiz_tx_, true, false);
|
||||
for ([[maybe_unused]] const int i : IndexRange(hiz_tx_.size())) {
|
||||
hiz_tx_.current().ensure_2d(GPU_R32F, hiz_extent, usage, nullptr, HIZ_MIP_COUNT);
|
||||
hiz_tx_.current().ensure_mip_views();
|
||||
GPU_texture_mipmap_mode(hiz_tx_.current(), true, false);
|
||||
hiz_tx_.swap();
|
||||
}
|
||||
|
||||
data_.uv_scale = float2(render_extent) / float2(hiz_extent);
|
||||
|
||||
@@ -36,13 +39,13 @@ void HiZBuffer::sync()
|
||||
pass.bind_ssbo("finished_tile_counter", atomic_tile_counter_);
|
||||
/* TODO(fclem): Should be a parameter to avoid confusion. */
|
||||
pass.bind_texture("depth_tx", &src_tx_, with_filter);
|
||||
pass.bind_image("out_mip_0", hiz_tx_.mip_view(0));
|
||||
pass.bind_image("out_mip_1", hiz_tx_.mip_view(1));
|
||||
pass.bind_image("out_mip_2", hiz_tx_.mip_view(2));
|
||||
pass.bind_image("out_mip_3", hiz_tx_.mip_view(3));
|
||||
pass.bind_image("out_mip_4", hiz_tx_.mip_view(4));
|
||||
pass.bind_image("out_mip_5", hiz_tx_.mip_view(5));
|
||||
pass.bind_image("out_mip_6", hiz_tx_.mip_view(6));
|
||||
pass.bind_image("out_mip_0", &hiz_mip_ref_[0]);
|
||||
pass.bind_image("out_mip_1", &hiz_mip_ref_[1]);
|
||||
pass.bind_image("out_mip_2", &hiz_mip_ref_[2]);
|
||||
pass.bind_image("out_mip_3", &hiz_mip_ref_[3]);
|
||||
pass.bind_image("out_mip_4", &hiz_mip_ref_[4]);
|
||||
pass.bind_image("out_mip_5", &hiz_mip_ref_[5]);
|
||||
pass.bind_image("out_mip_6", &hiz_mip_ref_[6]);
|
||||
/* TODO(@fclem): There might be occasions where we might not want to
|
||||
* copy mip 0 for performance reasons if there is no need for it. */
|
||||
pass.push_constant("update_mip_0", true);
|
||||
@@ -56,13 +59,13 @@ void HiZBuffer::sync()
|
||||
pass.bind_ssbo("finished_tile_counter", atomic_tile_counter_);
|
||||
/* TODO(fclem): Should be a parameter to avoid confusion. */
|
||||
pass.bind_texture("depth_layered_tx", &src_tx_, with_filter);
|
||||
pass.bind_image("out_mip_0", hiz_tx_.mip_view(0));
|
||||
pass.bind_image("out_mip_1", hiz_tx_.mip_view(1));
|
||||
pass.bind_image("out_mip_2", hiz_tx_.mip_view(2));
|
||||
pass.bind_image("out_mip_3", hiz_tx_.mip_view(3));
|
||||
pass.bind_image("out_mip_4", hiz_tx_.mip_view(4));
|
||||
pass.bind_image("out_mip_5", hiz_tx_.mip_view(5));
|
||||
pass.bind_image("out_mip_6", hiz_tx_.mip_view(6));
|
||||
pass.bind_image("out_mip_0", &hiz_mip_ref_[0]);
|
||||
pass.bind_image("out_mip_1", &hiz_mip_ref_[1]);
|
||||
pass.bind_image("out_mip_2", &hiz_mip_ref_[2]);
|
||||
pass.bind_image("out_mip_3", &hiz_mip_ref_[3]);
|
||||
pass.bind_image("out_mip_4", &hiz_mip_ref_[4]);
|
||||
pass.bind_image("out_mip_5", &hiz_mip_ref_[5]);
|
||||
pass.bind_image("out_mip_6", &hiz_mip_ref_[6]);
|
||||
/* TODO(@fclem): There might be occasions where we might not want to
|
||||
* copy mip 0 for performance reasons if there is no need for it. */
|
||||
pass.push_constant("update_mip_0", true);
|
||||
@@ -87,6 +90,9 @@ void HiZBuffer::update()
|
||||
}
|
||||
|
||||
src_tx_ = *src_tx_ptr_;
|
||||
for (const int i : IndexRange(HIZ_MIP_COUNT)) {
|
||||
hiz_mip_ref_[i] = hiz_tx_.current().mip_view(i);
|
||||
}
|
||||
|
||||
if (layer_id_ == -1) {
|
||||
inst_.manager->submit(hiz_update_ps_);
|
||||
|
||||
@@ -28,8 +28,16 @@ class HiZBuffer {
|
||||
private:
|
||||
Instance &inst_;
|
||||
|
||||
/** The texture containing the hiz mip chain. */
|
||||
Texture hiz_tx_ = {"hiz_tx_"};
|
||||
/** Contains depth pyramid of the current pass and the previous pass. */
|
||||
SwapChain<Texture, 2> hiz_tx_;
|
||||
/** References to the textures in the swap-chain. */
|
||||
/* Closest surface depth of the current layer. */
|
||||
GPUTexture *hiz_front_ref_tx_ = nullptr;
|
||||
/* Closest surface depth of the layer below. */
|
||||
GPUTexture *hiz_back_ref_tx_ = nullptr;
|
||||
/** References to the mip views of the current (front) HiZ texture. */
|
||||
std::array<GPUTexture *, HIZ_MIP_COUNT> hiz_mip_ref_;
|
||||
|
||||
/**
|
||||
* Atomic counter counting the number of tile that have finished down-sampling.
|
||||
* The last one will process the last few mip level.
|
||||
@@ -45,8 +53,8 @@ class HiZBuffer {
|
||||
/** Dirty flag to check if the update is necessary. */
|
||||
bool is_dirty_ = true;
|
||||
/** Reference to the depth texture to downsample. */
|
||||
GPUTexture *src_tx_;
|
||||
GPUTexture **src_tx_ptr_;
|
||||
GPUTexture *src_tx_ = nullptr;
|
||||
GPUTexture **src_tx_ptr_ = nullptr;
|
||||
|
||||
HiZData &data_;
|
||||
|
||||
@@ -59,7 +67,8 @@ class HiZBuffer {
|
||||
void sync();
|
||||
|
||||
/**
|
||||
* Set source texture for the hiz downsampling.
|
||||
* Set source texture for the hiz down-sampling.
|
||||
* Need to be called once at the start of a pipeline or view.
|
||||
*/
|
||||
void set_source(GPUTexture **texture, int layer = -1)
|
||||
{
|
||||
@@ -68,7 +77,21 @@ class HiZBuffer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag the buffer for update if needed.
|
||||
* Swap front and back layer.
|
||||
* Internally set front layer to be dirty.
|
||||
* IMPORTANT: Before the second swap (and the second update)
|
||||
* the content of the back hi-z buffer is undefined.
|
||||
*/
|
||||
void swap_layer()
|
||||
{
|
||||
hiz_tx_.swap();
|
||||
hiz_back_ref_tx_ = hiz_tx_.previous();
|
||||
hiz_front_ref_tx_ = hiz_tx_.current();
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag the front buffer for update if needed.
|
||||
*/
|
||||
void set_dirty()
|
||||
{
|
||||
@@ -76,7 +99,7 @@ class HiZBuffer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the content of the HiZ buffer with the depth render target.
|
||||
* Update the content of the HiZ buffer with the source depth set by `set_source()`.
|
||||
* Noop if the buffer has not been tagged as dirty.
|
||||
* Should be called before each passes that needs to read the hiz buffer.
|
||||
*/
|
||||
@@ -84,14 +107,17 @@ class HiZBuffer {
|
||||
|
||||
void debug_draw(View &view, GPUFrameBuffer *view_fb);
|
||||
|
||||
void bind_resources(DRWShadingGroup *grp)
|
||||
{
|
||||
DRW_shgroup_uniform_texture_ref(grp, "hiz_tx", &hiz_tx_);
|
||||
}
|
||||
enum class Type {
|
||||
/* Previous layer depth (ex: For refraction). */
|
||||
BACK,
|
||||
/* Previous layer depth. */
|
||||
FRONT,
|
||||
};
|
||||
|
||||
template<typename PassType> void bind_resources(PassType &pass)
|
||||
template<typename PassType> void bind_resources(PassType &pass, Type type = Type::FRONT)
|
||||
{
|
||||
pass.bind_texture(HIZ_TEX_SLOT, &hiz_tx_);
|
||||
pass.bind_texture(HIZ_TEX_SLOT,
|
||||
(type == Type::FRONT) ? &hiz_front_ref_tx_ : &hiz_back_ref_tx_);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -655,18 +655,8 @@ void DeferredLayer::render(View &main_view,
|
||||
GPU_framebuffer_bind(prepass_fb);
|
||||
inst_.manager->submit(prepass_ps_, render_view);
|
||||
|
||||
if (closure_bits_ & CLOSURE_AMBIENT_OCCLUSION) {
|
||||
/* If the shader needs Ambient Occlusion, we need to update the HiZ here. */
|
||||
if (do_screen_space_refraction) {
|
||||
/* TODO(fclem): This update conflicts with the refraction screen tracing which need the depth
|
||||
* behind the refractive surface. In this case, we do not update the Hi-Z and only consider
|
||||
* surfaces already in the Hi-Z buffer for the ambient occlusion computation. This might be
|
||||
* solved (if really problematic) by having another copy of the Hi-Z buffer. */
|
||||
}
|
||||
else {
|
||||
inst_.hiz_buffer.update();
|
||||
}
|
||||
}
|
||||
inst_.hiz_buffer.swap_layer();
|
||||
inst_.hiz_buffer.update();
|
||||
|
||||
if (/* FIXME(fclem): Vulkan doesn't implement load / store config yet. */
|
||||
GPU_backend_get_type() == GPU_BACKEND_VULKAN)
|
||||
@@ -710,15 +700,6 @@ void DeferredLayer::render(View &main_view,
|
||||
|
||||
inst_.irradiance_cache.set_view(render_view);
|
||||
|
||||
RayTraceResult refract_result = inst_.raytracing.trace(rt_buffer,
|
||||
radiance_behind_tx_,
|
||||
render_view.persmat(),
|
||||
closure_bits_,
|
||||
CLOSURE_REFRACTION,
|
||||
main_view,
|
||||
render_view,
|
||||
!do_screen_space_refraction);
|
||||
|
||||
/* Only update the HiZ after refraction tracing. */
|
||||
inst_.hiz_buffer.update();
|
||||
|
||||
@@ -733,6 +714,15 @@ void DeferredLayer::render(View &main_view,
|
||||
GPU_framebuffer_bind(combined_fb);
|
||||
inst_.manager->submit(eval_light_ps_, render_view);
|
||||
|
||||
RayTraceResult refract_result = inst_.raytracing.trace(rt_buffer,
|
||||
radiance_behind_tx_,
|
||||
render_view.persmat(),
|
||||
closure_bits_,
|
||||
CLOSURE_REFRACTION,
|
||||
main_view,
|
||||
render_view,
|
||||
!do_screen_space_refraction);
|
||||
|
||||
RayTraceResult diffuse_result = inst_.raytracing.trace(rt_buffer,
|
||||
radiance_feedback_tx_,
|
||||
radiance_feedback_persmat_,
|
||||
|
||||
@@ -119,6 +119,8 @@ void RayTraceModule::sync()
|
||||
sub.dispatch(ray_dispatch_buf_);
|
||||
sub.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
|
||||
}
|
||||
HiZBuffer::Type hiz_type = (&pass == &trace_refract_ps_) ? HiZBuffer::Type::BACK :
|
||||
HiZBuffer::Type::FRONT;
|
||||
pass.shader_set(inst_.shaders.static_shader_get(SHADER_VARIATION(RAY_TRACE_SCREEN_, type)));
|
||||
pass.bind_ssbo("tiles_coord_buf", &ray_tiles_buf_);
|
||||
pass.bind_image("ray_data_img", &ray_data_tx_);
|
||||
@@ -127,7 +129,7 @@ void RayTraceModule::sync()
|
||||
pass.bind_texture("depth_tx", &depth_tx);
|
||||
pass.bind_image("ray_radiance_img", &ray_radiance_tx_);
|
||||
inst_.bind_uniform_data(&pass);
|
||||
inst_.hiz_buffer.bind_resources(pass);
|
||||
inst_.hiz_buffer.bind_resources(pass, hiz_type);
|
||||
inst_.sampling.bind_resources(pass);
|
||||
inst_.irradiance_cache.bind_resources(pass);
|
||||
inst_.reflection_probes.bind_resources(pass);
|
||||
|
||||
@@ -975,8 +975,12 @@ class Texture : NonCopyable {
|
||||
*/
|
||||
static void swap(Texture &a, Texture &b)
|
||||
{
|
||||
SWAP(GPUTexture *, a.tx_, b.tx_);
|
||||
SWAP(const char *, a.name_, b.name_);
|
||||
std::swap(a.tx_, b.tx_);
|
||||
std::swap(a.name_, b.name_);
|
||||
std::swap(a.stencil_view_, b.stencil_view_);
|
||||
std::swap(a.layer_range_view_, b.layer_range_view_);
|
||||
std::swap(a.mip_views_, b.mip_views_);
|
||||
std::swap(a.layer_views_, b.layer_views_);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Reference in New Issue
Block a user