From fe39456ba5f452ffbc04f4e0935da4162059cce5 Mon Sep 17 00:00:00 2001 From: Miguel Pozo Date: Fri, 6 Oct 2023 15:31:44 +0200 Subject: [PATCH] Workbench: Fix: Performance Regressions Optimize Workbench performance so it's on par with the previous implementation. Most of these changes are barely noticeable on powerful GPUs, but can cause a notable performance improvement on old or low-end hardware. * Avoid unnecessary texture copies and draw directly to the viewport textures. * Optimize-out depth/stencil reads, using stencil testing instead. * Avoid using `Texture::clear` and use framebuffer clears instead. * Avoid framebuffer state changes (always use the same attachments). * Avoid constant variation of acquired `TextureFromPool`s. Fix #113010 Pull Request: https://projects.blender.org/blender/blender/pulls/113251 --- .../shaders/infos/workbench_composite_info.hh | 24 ++-- .../shaders/infos/workbench_depth_info.hh | 2 - .../shaders/workbench_composite_frag.glsl | 65 ++++----- .../shaders/workbench_merge_depth_frag.glsl | 8 +- .../shaders/workbench_overlay_depth_frag.glsl | 13 +- .../workbench_effect_antialiasing.cc | 125 +++++++++--------- .../engines/workbench/workbench_engine.cc | 64 ++++----- .../workbench/workbench_mesh_passes.cc | 88 ++++++------ .../engines/workbench/workbench_private.hh | 41 ++++-- .../workbench/workbench_shader_cache.cc | 10 +- .../draw/engines/workbench/workbench_state.cc | 2 + 11 files changed, 214 insertions(+), 228 deletions(-) diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_composite_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_composite_info.hh index f4a46f76a49..d44c29abf1a 100644 --- a/source/blender/draw/engines/workbench/shaders/infos/workbench_composite_info.hh +++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_composite_info.hh @@ -10,10 +10,9 @@ * \{ */ GPU_SHADER_CREATE_INFO(workbench_composite) - .sampler(3, ImageType::FLOAT_2D, "normal_tx") - .sampler(4, ImageType::FLOAT_2D, "material_tx") - .sampler(5, ImageType::DEPTH_2D, "depth_tx") - .sampler(6, ImageType::UINT_2D, "stencil_tx") + .sampler(3, ImageType::DEPTH_2D, "depth_tx") + .sampler(4, ImageType::FLOAT_2D, "normal_tx") + .sampler(5, ImageType::FLOAT_2D, "material_tx") .uniform_buf(WB_WORLD_SLOT, "WorldData", "world_data") .typedef_source("workbench_shader_shared.h") .push_constant(Type::BOOL, "forceShadowing") @@ -35,23 +34,32 @@ GPU_SHADER_CREATE_INFO(workbench_resolve_opaque_flat).define("WORKBENCH_LIGHTING GPU_SHADER_CREATE_INFO(workbench_resolve_curvature) .define("WORKBENCH_CURVATURE") - .sampler(7, ImageType::UINT_2D, "object_id_tx"); + .sampler(6, ImageType::UINT_2D, "object_id_tx"); GPU_SHADER_CREATE_INFO(workbench_resolve_cavity) .define("WORKBENCH_CAVITY") /* TODO(@pragma37): GPU_SAMPLER_EXTEND_MODE_REPEAT is set in CavityEffect, * it doesn't work here? */ - .sampler(8, ImageType::FLOAT_2D, "jitter_tx") + .sampler(7, ImageType::FLOAT_2D, "jitter_tx") .uniform_buf(5, "vec4", "cavity_samples[512]"); +GPU_SHADER_CREATE_INFO(workbench_resolve_shadow) + .define("WORKBENCH_SHADOW") + .sampler(8, ImageType::UINT_2D, "stencil_tx"); + /* Variations */ #define WORKBENCH_FINAL_VARIATION(name, ...) \ GPU_SHADER_CREATE_INFO(name).additional_info(__VA_ARGS__).do_static_compilation(true); +#define WORKBENCH_RESOLVE_SHADOW_VARIATION(prefix, ...) \ + WORKBENCH_FINAL_VARIATION(prefix##_shadow, "workbench_resolve_shadow", __VA_ARGS__) \ + WORKBENCH_FINAL_VARIATION(prefix##_no_shadow, __VA_ARGS__) + #define WORKBENCH_CURVATURE_VARIATIONS(prefix, ...) \ - WORKBENCH_FINAL_VARIATION(prefix##_curvature, "workbench_resolve_curvature", __VA_ARGS__) \ - WORKBENCH_FINAL_VARIATION(prefix##_no_curvature, __VA_ARGS__) + WORKBENCH_RESOLVE_SHADOW_VARIATION( \ + prefix##_curvature, "workbench_resolve_curvature", __VA_ARGS__) \ + WORKBENCH_RESOLVE_SHADOW_VARIATION(prefix##_no_curvature, __VA_ARGS__) #define WORKBENCH_CAVITY_VARIATIONS(prefix, ...) \ WORKBENCH_CURVATURE_VARIATIONS(prefix##_cavity, "workbench_resolve_cavity", __VA_ARGS__) \ diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_depth_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_depth_info.hh index 92ab9f26d4c..2d471595090 100644 --- a/source/blender/draw/engines/workbench/shaders/infos/workbench_depth_info.hh +++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_depth_info.hh @@ -12,8 +12,6 @@ GPU_SHADER_CREATE_INFO(workbench_merge_depth) .do_static_compilation(true); GPU_SHADER_CREATE_INFO(workbench_overlay_depth) - .sampler(0, ImageType::DEPTH_2D, "depth_tx") - .sampler(1, ImageType::UINT_2D, "stencil_tx") .fragment_source("workbench_overlay_depth_frag.glsl") .additional_info("draw_fullscreen") .depth_write(DepthWrite::ANY) diff --git a/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl index 4c555252503..9777c025246 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl @@ -12,73 +12,58 @@ void main() { vec2 uv = uvcoordsvar.st; + + float depth = texture(depth_tx, uv).r; + if (depth == 1.0) { + /* Skip the background. */ + discard; + return; + } + /* Normal and Incident vector are in view-space. Lighting is evaluated in view-space. */ vec3 V = get_view_vector_from_screen_uv(uv); vec3 N = workbench_normal_decode(texture(normal_tx, uv)); vec4 mat_data = texture(material_tx, uv); - float depth = texture(depth_tx, uv).r; vec3 base_color = mat_data.rgb; - vec4 color = world_data.background_color; + vec4 color = vec4(1.0); - /* Background pixels. */ - if (depth != 1.0) { #ifdef WORKBENCH_LIGHTING_MATCAP - /* When using matcaps, mat_data.a is the back-face sign. */ - N = (mat_data.a > 0.0) ? N : -N; - color.rgb = get_matcap_lighting(matcap_tx, base_color, N, V); + /* When using matcaps, mat_data.a is the back-face sign. */ + N = (mat_data.a > 0.0) ? N : -N; + color.rgb = get_matcap_lighting(matcap_tx, base_color, N, V); #endif #ifdef WORKBENCH_LIGHTING_STUDIO - float roughness, metallic; - workbench_float_pair_decode(mat_data.a, roughness, metallic); - color.rgb = get_world_lighting(base_color, roughness, metallic, N, V); + float roughness, metallic; + workbench_float_pair_decode(mat_data.a, roughness, metallic); + color.rgb = get_world_lighting(base_color, roughness, metallic, N, V); #endif #ifdef WORKBENCH_LIGHTING_FLAT - color.rgb = base_color; + color.rgb = base_color; #endif #if defined(WORKBENCH_CAVITY) || defined(WORKBENCH_CURVATURE) - float cavity = 0.0, edges = 0.0, curvature = 0.0; + float cavity = 0.0, edges = 0.0, curvature = 0.0; # ifdef WORKBENCH_CAVITY - cavity_compute(uv, depth_tx, normal_tx, cavity, edges); + cavity_compute(uv, depth_tx, normal_tx, cavity, edges); # endif # ifdef WORKBENCH_CURVATURE - curvature_compute(uv, object_id_tx, normal_tx, curvature); + curvature_compute(uv, object_id_tx, normal_tx, curvature); # endif - float final_cavity_factor = clamp( - (1.0 - cavity) * (1.0 + edges) * (1.0 + curvature), 0.0, 4.0); + float final_cavity_factor = clamp((1.0 - cavity) * (1.0 + edges) * (1.0 + curvature), 0.0, 4.0); - color.rgb *= final_cavity_factor; + color.rgb *= final_cavity_factor; #endif - bool shadow = texture(stencil_tx, uv).r != 0; - color.rgb *= get_shadow(N, shadow); - - color.a = 1.0f; - } - -#ifdef WORKBENCH_OUTLINE - vec3 offset = vec3(world_data.viewport_size_inv, 0.0) * world_data.ui_scale; - - uint center_id = texture(object_id_tx, uv).r; - uvec4 adjacent_ids = uvec4(texture(object_id_tx, uv + offset.zy).r, - texture(object_id_tx, uv - offset.zy).r, - texture(object_id_tx, uv + offset.xz).r, - texture(object_id_tx, uv - offset.xz).r); - - float outline_opacity = 1.0 - dot(vec4(equal(uvec4(center_id), adjacent_ids)), vec4(0.25)); - color = mix(color, world_data.object_outline_color, outline_opacity); +#ifdef WORKBENCH_SHADOW + bool shadow = texture(stencil_tx, uv).r != 0; + color.rgb *= get_shadow(N, shadow); #endif - if (all(equal(color, world_data.background_color))) { - discard; - } - else { - fragColor = color; - } + fragColor = color; } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_merge_depth_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_merge_depth_frag.glsl index 2b3bac742d5..fd23402b48f 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_merge_depth_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_merge_depth_frag.glsl @@ -4,11 +4,5 @@ void main() { - float depth = texture(depth_tx, uvcoordsvar.xy).r; - if (depth != 1.0) { - gl_FragDepth = depth; - } - else { - discard; - } + gl_FragDepth = texture(depth_tx, uvcoordsvar.xy).r; } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_overlay_depth_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_overlay_depth_frag.glsl index ed9dda5f4b7..acd90d67e1f 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_overlay_depth_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_overlay_depth_frag.glsl @@ -6,14 +6,7 @@ void main() { - uint stencil = texelFetch(stencil_tx, ivec2(gl_FragCoord.xy), 0).r; - if (stencil != 0) { - /* Set the depth to 0 for "In Front" objects, - * so the Overlay engine doesn't draw on top of them. */ - gl_FragDepth = 0.0; - } - else { - float depth = texelFetch(depth_tx, ivec2(gl_FragCoord.xy), 0).r; - gl_FragDepth = depth; - } + /* Set the depth to 0 for "In Front" objects, + * so the Overlay engine doesn't draw on top of them. */ + gl_FragDepth = 0.0; } diff --git a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.cc b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.cc index a7d2c0adffc..f21e2cbd3cc 100644 --- a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.cc +++ b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.cc @@ -139,17 +139,15 @@ AntiAliasingPass::~AntiAliasingPass() void AntiAliasingPass::init(const SceneState &scene_state) { enabled_ = scene_state.draw_aa; - sample_ = scene_state.sample; - samples_len_ = scene_state.samples_len; } -void AntiAliasingPass::sync(SceneResources &resources, int2 resolution) +void AntiAliasingPass::sync(const SceneState &scene_state, SceneResources &resources) { overlay_depth_ps_.init(); - overlay_depth_ps_.state_set(DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS); + overlay_depth_ps_.state_set(DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS | + DRW_STATE_STENCIL_EQUAL); + overlay_depth_ps_.state_stencil(0x00, 0xFF, uint8_t(StencilBits::OBJECT_IN_FRONT)); overlay_depth_ps_.shader_set(overlay_depth_sh_); - overlay_depth_ps_.bind_texture("depth_tx", &resources.depth_tx); - overlay_depth_ps_.bind_texture("stencil_tx", &stencil_tx_); overlay_depth_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3); if (!enabled_) { @@ -158,17 +156,23 @@ void AntiAliasingPass::sync(SceneResources &resources, int2 resolution) return; } - taa_accumulation_tx_.ensure_2d( - GPU_RGBA16F, resolution, GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT); + smaa_viewport_metrics_ = float4(float2(1.0f / float2(scene_state.resolution)), + scene_state.resolution); + smaa_mix_factor_ = 1.0f - clamp_f(scene_state.sample / 4.0f, 0.0f, 1.0f); + + taa_accumulation_tx_.ensure_2d(GPU_RGBA16F, + scene_state.resolution, + GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT); sample0_depth_tx_.ensure_2d(GPU_DEPTH24_STENCIL8, - resolution, + scene_state.resolution, GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT); sample0_depth_in_front_tx_.ensure_2d( - GPU_DEPTH24_STENCIL8, resolution, GPU_TEXTURE_USAGE_ATTACHMENT); + GPU_DEPTH24_STENCIL8, scene_state.resolution, GPU_TEXTURE_USAGE_ATTACHMENT); taa_accumulation_ps_.init(); - taa_accumulation_ps_.state_set(sample_ == 0 ? DRW_STATE_WRITE_COLOR : - DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD_FULL); + taa_accumulation_ps_.state_set(scene_state.sample == 0 ? + DRW_STATE_WRITE_COLOR : + DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD_FULL); taa_accumulation_ps_.shader_set(taa_accumulation_sh_); taa_accumulation_ps_.bind_texture("colorBuffer", &resources.color_tx); taa_accumulation_ps_.push_constant("samplesWeights", weights_, 9); @@ -204,7 +208,7 @@ void AntiAliasingPass::sync(SceneResources &resources, int2 resolution) smaa_resolve_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3); } -void AntiAliasingPass::setup_view(View &view, int2 resolution) +void AntiAliasingPass::setup_view(View &view, const SceneState &scene_state) { if (!enabled_) { return; @@ -213,22 +217,22 @@ void AntiAliasingPass::setup_view(View &view, int2 resolution) const TaaSamples &taa_samples = get_taa_samples(); float2 sample_offset; - switch (samples_len_) { + switch (scene_state.samples_len) { default: case 5: - sample_offset = taa_samples.x5[sample_]; + sample_offset = taa_samples.x5[scene_state.sample]; break; case 8: - sample_offset = taa_samples.x8[sample_]; + sample_offset = taa_samples.x8[scene_state.sample]; break; case 11: - sample_offset = taa_samples.x11[sample_]; + sample_offset = taa_samples.x11[scene_state.sample]; break; case 16: - sample_offset = taa_samples.x16[sample_]; + sample_offset = taa_samples.x16[scene_state.sample]; break; case 32: - sample_offset = taa_samples.x32[sample_]; + sample_offset = taa_samples.x32[scene_state.sample]; break; } @@ -242,43 +246,58 @@ void AntiAliasingPass::setup_view(View &view, int2 resolution) DRW_view_viewmat_get(default_view, viewmat.ptr(), false); DRW_view_persmat_get(default_view, persmat.ptr(), false); - window_translate_m4( - winmat.ptr(), persmat.ptr(), sample_offset.x / resolution.x, sample_offset.y / resolution.y); + window_translate_m4(winmat.ptr(), + persmat.ptr(), + sample_offset.x / scene_state.resolution.x, + sample_offset.y / scene_state.resolution.y); view.sync(viewmat, winmat); } void AntiAliasingPass::draw(Manager &manager, View &view, - SceneResources &resources, - int2 resolution, - GPUTexture *depth_tx, - GPUTexture *depth_in_front_tx, - GPUTexture *color_tx) + const SceneState &scene_state, + SceneResources &resources) { - auto draw_overlay_depth = [&](GPUTexture *target) { - stencil_tx_ = resources.stencil_view.extract(manager, resources.depth_tx); - overlay_depth_fb_.ensure(GPU_ATTACHMENT_TEXTURE(target)); + if (resources.depth_in_front_tx.is_valid() && scene_state.sample == 0 && + scene_state.overlays_enabled) + { + overlay_depth_fb_.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx)); overlay_depth_fb_.bind(); manager.submit(overlay_depth_ps_); - }; + } if (!enabled_) { - GPU_texture_copy(color_tx, resources.color_tx); - draw_overlay_depth(depth_tx); return; } + const bool last_sample = scene_state.sample + 1 == scene_state.samples_len; + + if (scene_state.samples_len > 1 && (scene_state.overlays_enabled || DRW_state_is_scene_render())) + { + if (scene_state.sample == 0) { + GPU_texture_copy(sample0_depth_tx_, resources.depth_tx); + if (resources.depth_in_front_tx.is_valid()) { + GPU_texture_copy(sample0_depth_in_front_tx_, resources.depth_in_front_tx); + } + } + else if (!DRW_state_is_scene_render() || last_sample) { + /* Copy back the saved depth buffer for correct overlays. */ + GPU_texture_copy(resources.depth_tx, sample0_depth_tx_); + if (resources.depth_in_front_tx.is_valid()) { + GPU_texture_copy(resources.depth_in_front_tx, sample0_depth_in_front_tx_); + } + } + } + /** * We always do SMAA on top of TAA accumulation, unless the number of samples of TAA is already * high. This ensure a smoother transition. * If TAA accumulation is finished, we only blit the result. */ - const bool last_sample = sample_ + 1 == samples_len_; - const bool taa_finished = sample_ >= samples_len_; - + const bool taa_finished = scene_state.sample >= scene_state.samples_len; if (!taa_finished) { - if (sample_ == 0) { + if (scene_state.sample == 0) { weight_accum_ = 0; } /* Accumulate result to the TAA buffer. */ @@ -288,30 +307,17 @@ void AntiAliasingPass::draw(Manager &manager, weight_accum_ += weights_sum_; } - if (sample_ == 0) { - draw_overlay_depth(sample0_depth_tx_); - GPU_texture_copy(sample0_depth_in_front_tx_, resources.depth_in_front_tx); - } - if (!DRW_state_is_scene_render()) { - /* Copy back the saved depth buffer for correct overlays. */ - GPU_texture_copy(depth_tx, sample0_depth_tx_); - GPU_texture_copy(depth_in_front_tx, sample0_depth_in_front_tx_); - } - else if (last_sample) { - GPU_texture_copy(depth_tx, sample0_depth_tx_); - /* There's no depth_in_front_tx in scene image renders. */ - } + /** Always acquire to avoid constant allocation/deallocation. */ + smaa_weight_tx_.acquire(scene_state.resolution, + GPU_RGBA8, + GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT); + smaa_edge_tx_.acquire(scene_state.resolution, + GPU_RG8, + GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT); if (!DRW_state_is_image_render() || last_sample) { - smaa_weight_tx_.acquire( - resolution, GPU_RGBA8, GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT); - smaa_mix_factor_ = 1.0f - clamp_f(sample_ / 4.0f, 0.0f, 1.0f); - smaa_viewport_metrics_ = float4(float2(1.0f / float2(resolution)), resolution); - /* After a certain point SMAA is no longer necessary. */ if (smaa_mix_factor_ > 0.0f) { - smaa_edge_tx_.acquire( - resolution, GPU_RG8, GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT); smaa_edge_fb_.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(smaa_edge_tx_)); smaa_edge_fb_.bind(); manager.submit(smaa_edge_detect_ps_, view); @@ -319,13 +325,14 @@ void AntiAliasingPass::draw(Manager &manager, smaa_weight_fb_.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(smaa_weight_tx_)); smaa_weight_fb_.bind(); manager.submit(smaa_aa_weight_ps_, view); - smaa_edge_tx_.release(); } - smaa_resolve_fb_.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(color_tx)); + smaa_resolve_fb_.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(resources.color_tx)); smaa_resolve_fb_.bind(); manager.submit(smaa_resolve_ps_, view); - smaa_weight_tx_.release(); } + + smaa_edge_tx_.release(); + smaa_weight_tx_.release(); } } // namespace blender::workbench diff --git a/source/blender/draw/engines/workbench/workbench_engine.cc b/source/blender/draw/engines/workbench/workbench_engine.cc index 81750e75357..b71a23caf0c 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.cc +++ b/source/blender/draw/engines/workbench/workbench_engine.cc @@ -69,12 +69,6 @@ class Instance { void begin_sync() { - const float2 viewport_size = DRW_viewport_size_get(); - const int2 resolution = {int(viewport_size.x), int(viewport_size.y)}; - resources.depth_tx.ensure_2d(GPU_DEPTH24_STENCIL8, - resolution, - GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT | - GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW); resources.material_buf.clear(); opaque_ps.sync(scene_state, resources); @@ -85,7 +79,7 @@ class Instance { volume_ps.sync(resources); outline_ps.sync(resources); dof_ps.sync(resources); - anti_aliasing_ps.sync(resources, scene_state.resolution); + anti_aliasing_ps.sync(scene_state, resources); } void end_sync() @@ -438,38 +432,38 @@ class Instance { if (scene_state.render_finished) { /* Just copy back the already rendered result */ - anti_aliasing_ps.draw( - manager, view, resources, resolution, depth_tx, depth_in_front_tx, color_tx); + anti_aliasing_ps.draw(manager, view, scene_state, resources); return; } - anti_aliasing_ps.setup_view(view, resolution); + anti_aliasing_ps.setup_view(view, scene_state); - resources.color_tx.acquire( - resolution, GPU_RGBA16F, GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT); - resources.color_tx.clear(resources.world_buf.background_color); + resources.depth_tx.wrap(depth_tx); + resources.color_tx.wrap(color_tx); + GPUAttachment id_attachment = GPU_ATTACHMENT_NONE; if (scene_state.draw_object_id) { resources.object_id_tx.acquire( resolution, GPU_R16UI, GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT); - resources.object_id_tx.clear(uint4(0)); + id_attachment = GPU_ATTACHMENT_TEXTURE(resources.object_id_tx); } - - Framebuffer fb = Framebuffer("Workbench.Clear"); - fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx)); - fb.bind(); - GPU_framebuffer_clear_depth_stencil(fb, 1.0f, 0x00); + resources.clear_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx), + GPU_ATTACHMENT_TEXTURE(resources.color_tx), + id_attachment); + resources.clear_fb.bind(); + float4 clear_colors[2] = {scene_state.background_color, float4(0.0f)}; + GPU_framebuffer_multi_clear(resources.clear_fb, reinterpret_cast(clear_colors)); + GPU_framebuffer_clear_depth_stencil(resources.clear_fb, 1.0f, 0x00); bool needs_depth_in_front = !transparent_ps.accumulation_in_front_ps_.is_empty() || - scene_state.sample == 0; - if (needs_depth_in_front) { - resources.depth_in_front_tx.acquire(resolution, - GPU_DEPTH24_STENCIL8, - GPU_TEXTURE_USAGE_SHADER_READ | - GPU_TEXTURE_USAGE_ATTACHMENT); - - fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_in_front_tx)); - fb.bind(); - GPU_framebuffer_clear_depth_stencil(fb, 1.0f, 0x00); + (!opaque_ps.gbuffer_in_front_ps_.is_empty() && + scene_state.overlays_enabled && scene_state.sample == 0); + resources.depth_in_front_tx.wrap(needs_depth_in_front ? depth_in_front_tx : nullptr); + if ((!needs_depth_in_front && scene_state.overlays_enabled) || + (needs_depth_in_front && opaque_ps.gbuffer_in_front_ps_.is_empty())) + { + resources.clear_in_front_fb.ensure(GPU_ATTACHMENT_TEXTURE(depth_in_front_tx)); + resources.clear_in_front_fb.bind(); + GPU_framebuffer_clear_depth_stencil(resources.clear_in_front_fb, 1.0f, 0x00); } opaque_ps.draw( @@ -480,12 +474,9 @@ class Instance { volume_ps.draw(manager, view, resources); outline_ps.draw(manager, resources); dof_ps.draw(manager, view, resources, resolution); - anti_aliasing_ps.draw( - manager, view, resources, resolution, depth_tx, depth_in_front_tx, color_tx); + anti_aliasing_ps.draw(manager, view, scene_state, resources); - resources.color_tx.release(); resources.object_id_tx.release(); - resources.depth_in_front_tx.release(); } void draw_viewport(Manager &manager, @@ -512,8 +503,7 @@ class Instance { /* Re-sync anything dependent on scene_state.sample. */ resources.init(scene_state); dof_ps.init(scene_state); - anti_aliasing_ps.init(scene_state); - anti_aliasing_ps.sync(resources, scene_state.resolution); + anti_aliasing_ps.sync(scene_state, resources); } this->draw(manager, depth_tx, depth_in_front_tx, color_tx); } @@ -622,9 +612,11 @@ static bool workbench_render_framebuffers_init() "txl.color", size.x, size.y, 1, GPU_RGBA16F, usage, nullptr); dtxl->depth = GPU_texture_create_2d( "txl.depth", size.x, size.y, 1, GPU_DEPTH24_STENCIL8, usage, nullptr); + dtxl->depth_in_front = GPU_texture_create_2d( + "txl.depth_in_front", size.x, size.y, 1, GPU_DEPTH24_STENCIL8, usage, nullptr); } - if (!(dtxl->depth && dtxl->color)) { + if (!(dtxl->depth && dtxl->color && dtxl->depth_in_front)) { return false; } diff --git a/source/blender/draw/engines/workbench/workbench_mesh_passes.cc b/source/blender/draw/engines/workbench/workbench_mesh_passes.cc index f2aaee08bf0..55d30921b6b 100644 --- a/source/blender/draw/engines/workbench/workbench_mesh_passes.cc +++ b/source/blender/draw/engines/workbench/workbench_mesh_passes.cc @@ -112,19 +112,20 @@ PassMain::Sub &MeshPass::get_subpass( void OpaquePass::sync(const SceneState &scene_state, SceneResources &resources) { DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | - scene_state.cull_state; + DRW_STATE_WRITE_STENCIL | scene_state.cull_state; bool clip = scene_state.clip_planes.size() > 0; - DRWState in_front_state = state | DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS; + DRWState in_front_state = state | DRW_STATE_STENCIL_ALWAYS; gbuffer_in_front_ps_.init_pass(resources, in_front_state, scene_state.clip_planes.size()); - gbuffer_in_front_ps_.state_stencil(0xFF, 0xFF, 0x00); + gbuffer_in_front_ps_.state_stencil(uint8_t(StencilBits::OBJECT_IN_FRONT), 0xFF, 0x00); gbuffer_in_front_ps_.init_subpasses( ePipelineType::OPAQUE, scene_state.lighting_type, clip, resources.shader_cache); state |= DRW_STATE_STENCIL_NEQUAL; gbuffer_ps_.init_pass(resources, state, scene_state.clip_planes.size()); - gbuffer_ps_.state_stencil(0x00, 0xFF, 0xFF); + gbuffer_ps_.state_stencil( + uint8_t(StencilBits::OBJECT), 0xFF, uint8_t(StencilBits::OBJECT_IN_FRONT)); gbuffer_ps_.init_subpasses( ePipelineType::OPAQUE, scene_state.lighting_type, clip, resources.shader_cache); @@ -133,7 +134,8 @@ void OpaquePass::sync(const SceneState &scene_state, SceneResources &resources) deferred_ps_.shader_set(resources.shader_cache.resolve_shader_get(ePipelineType::OPAQUE, scene_state.lighting_type, scene_state.draw_cavity, - scene_state.draw_curvature)); + scene_state.draw_curvature, + scene_state.draw_shadows)); deferred_ps_.push_constant("forceShadowing", false); deferred_ps_.bind_ubo(WB_WORLD_SLOT, resources.world_buf); deferred_ps_.bind_texture(WB_MATCAP_SLOT, resources.matcap_tx); @@ -165,11 +167,11 @@ void OpaquePass::draw(Manager &manager, } if (!gbuffer_in_front_ps_.is_empty()) { - opaque_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx), - GPU_ATTACHMENT_TEXTURE(gbuffer_material_tx), - GPU_ATTACHMENT_TEXTURE(gbuffer_normal_tx), - object_id_attachment); - opaque_fb.bind(); + gbuffer_in_front_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx), + GPU_ATTACHMENT_TEXTURE(gbuffer_material_tx), + GPU_ATTACHMENT_TEXTURE(gbuffer_normal_tx), + object_id_attachment); + gbuffer_in_front_fb.bind(); manager.submit(gbuffer_in_front_ps_, view); @@ -179,55 +181,40 @@ void OpaquePass::draw(Manager &manager, } if (!gbuffer_ps_.is_empty()) { - opaque_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx), - GPU_ATTACHMENT_TEXTURE(gbuffer_material_tx), - GPU_ATTACHMENT_TEXTURE(gbuffer_normal_tx), - object_id_attachment); - opaque_fb.bind(); + gbuffer_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx), + GPU_ATTACHMENT_TEXTURE(gbuffer_material_tx), + GPU_ATTACHMENT_TEXTURE(gbuffer_normal_tx), + object_id_attachment); + gbuffer_fb.bind(); manager.submit(gbuffer_ps_, view); } - bool needs_stencil_copy = shadow_pass && !gbuffer_in_front_ps_.is_empty(); - - Texture *depth_stencil_tx = nullptr; - - if (needs_stencil_copy) { + if (shadow_pass) { shadow_depth_stencil_tx.ensure_2d(GPU_DEPTH24_STENCIL8, resolution, GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW); + GPU_texture_copy(shadow_depth_stencil_tx, resources.depth_tx); + clear_fb.ensure(GPU_ATTACHMENT_TEXTURE(shadow_depth_stencil_tx)); + clear_fb.bind(); + GPU_framebuffer_clear_stencil(clear_fb, 0); - depth_stencil_tx = shadow_depth_stencil_tx.ptr(); - - opaque_fb.ensure(GPU_ATTACHMENT_TEXTURE(*depth_stencil_tx)); - opaque_fb.bind(); - GPU_framebuffer_clear_stencil(opaque_fb, 0); + shadow_pass->draw( + manager, view, resources, **&shadow_depth_stencil_tx, !gbuffer_in_front_ps_.is_empty()); + deferred_ps_stencil_tx = resources.stencil_view.extract(manager, shadow_depth_stencil_tx); } else { shadow_depth_stencil_tx.free(); - depth_stencil_tx = resources.depth_tx.ptr(); + deferred_ps_stencil_tx = nullptr; } - if (shadow_pass) { - shadow_pass->draw( - manager, view, resources, **depth_stencil_tx, !gbuffer_in_front_ps_.is_empty()); - } - - deferred_ps_stencil_tx = resources.stencil_view.extract(manager, *depth_stencil_tx); - - opaque_fb.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(resources.color_tx)); - opaque_fb.bind(); + deferred_fb.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(resources.color_tx)); + deferred_fb.bind(); manager.submit(deferred_ps_, view); - if (shadow_pass && !needs_stencil_copy) { - opaque_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx)); - opaque_fb.bind(); - GPU_framebuffer_clear_stencil(opaque_fb, 0); - } - gbuffer_normal_tx.release(); gbuffer_material_tx.release(); } @@ -257,7 +244,8 @@ void TransparentPass::sync(const SceneState &scene_state, SceneResources &resour accumulation_ps_.init_pass( resources, state | DRW_STATE_STENCIL_NEQUAL, scene_state.clip_planes.size()); - accumulation_ps_.state_stencil(0x00, 0xFF, 0xFF); + accumulation_ps_.state_stencil( + uint8_t(StencilBits::OBJECT), 0xFF, uint8_t(StencilBits::OBJECT_IN_FRONT)); accumulation_ps_.clear_color(float4(0.0f, 0.0f, 0.0f, 1.0f)); accumulation_ps_.init_subpasses( ePipelineType::TRANSPARENT, scene_state.lighting_type, clip, resources.shader_cache); @@ -335,13 +323,13 @@ TransparentDepthPass::~TransparentDepthPass() void TransparentDepthPass::sync(const SceneState &scene_state, SceneResources &resources) { DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | - scene_state.cull_state; + DRW_STATE_WRITE_STENCIL | scene_state.cull_state; bool clip = scene_state.clip_planes.size() > 0; - DRWState in_front_state = state | DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS; + DRWState in_front_state = state | DRW_STATE_STENCIL_ALWAYS; in_front_ps_.init_pass(resources, in_front_state, scene_state.clip_planes.size()); - in_front_ps_.state_stencil(0xFF, 0xFF, 0x00); + in_front_ps_.state_stencil(uint8_t(StencilBits::OBJECT_IN_FRONT), 0xFF, 0x00); in_front_ps_.init_subpasses( ePipelineType::OPAQUE, eLightingType::FLAT, clip, resources.shader_cache); @@ -350,15 +338,17 @@ void TransparentDepthPass::sync(const SceneState &scene_state, SceneResources &r } merge_ps_.init(); merge_ps_.shader_set(merge_sh_); - merge_ps_.state_set(DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_WRITE_STENCIL | - DRW_STATE_STENCIL_ALWAYS); - merge_ps_.state_stencil(0xFF, 0xFF, 0x00); + merge_ps_.state_set(DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_STENCIL | + DRW_STATE_STENCIL_EQUAL); + merge_ps_.state_stencil( + uint8_t(StencilBits::OBJECT_IN_FRONT), 0xFF, uint8_t(StencilBits::OBJECT_IN_FRONT)); merge_ps_.bind_texture("depth_tx", &resources.depth_in_front_tx); merge_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3); state |= DRW_STATE_STENCIL_NEQUAL; main_ps_.init_pass(resources, state, scene_state.clip_planes.size()); - main_ps_.state_stencil(0x00, 0xFF, 0xFF); + main_ps_.state_stencil( + uint8_t(StencilBits::OBJECT), 0xFF, uint8_t(StencilBits::OBJECT_IN_FRONT)); main_ps_.init_subpasses( ePipelineType::OPAQUE, eLightingType::FLAT, clip, resources.shader_cache); } diff --git a/source/blender/draw/engines/workbench/workbench_private.hh b/source/blender/draw/engines/workbench/workbench_private.hh index d2a1ecb6375..2fc5f0a8146 100644 --- a/source/blender/draw/engines/workbench/workbench_private.hh +++ b/source/blender/draw/engines/workbench/workbench_private.hh @@ -32,14 +32,15 @@ class ShaderCache { GPUShader *resolve_shader_get(ePipelineType pipeline_type, eLightingType lighting_type, bool cavity = false, - bool curvature = false); + bool curvature = false, + bool shadow = false); private: /* TODO(fclem): We might want to change to a Map since most shader will never be compiled. */ GPUShader *prepass_shader_cache_[pipeline_type_len][geometry_type_len][shader_type_len] [lighting_type_len][2 /*clip*/] = {{{{{nullptr}}}}}; GPUShader *resolve_shader_cache_[pipeline_type_len][lighting_type_len][2 /*cavity*/] - [2 /*curvature*/] = {{{{nullptr}}}}; + [2 /*curvature*/][2 /*shadow*/] = {{{{nullptr}}}}; }; struct Material { @@ -96,6 +97,8 @@ struct SceneState { bool reset_taa_next_sample = false; bool render_finished = false; + bool overlays_enabled = false; + /* Used when material_type == eMaterialType::SINGLE */ Material material_override = Material(float3(1.0f)); /* When r == -1.0 the shader uses the vertex color */ @@ -196,10 +199,14 @@ struct SceneResources { StringRefNull current_matcap = {}; Texture matcap_tx = "matcap_tx"; - TextureFromPool color_tx = "wb_color_tx"; TextureFromPool object_id_tx = "wb_object_id_tx"; - Texture depth_tx = "wb_depth_tx"; - TextureFromPool depth_in_front_tx = "wb_depth_in_front_tx"; + + TextureRef color_tx; + TextureRef depth_tx; + TextureRef depth_in_front_tx; + + Framebuffer clear_fb = {"Clear Main"}; + Framebuffer clear_in_front_fb = {"Clear In Front"}; StorageVectorBuffer material_buf = {"material_buf"}; UniformBuffer world_buf = {}; @@ -243,11 +250,16 @@ class MeshPass : public PassMain { ImageUser *iuser = nullptr); }; +enum class StencilBits : uint8_t { + BACKGROUND = 0, + OBJECT = 1u << 0, + OBJECT_IN_FRONT = 1u << 1, +}; + class OpaquePass { public: TextureFromPool gbuffer_normal_tx = {"gbuffer_normal_tx"}; TextureFromPool gbuffer_material_tx = {"gbuffer_material_tx"}; - Framebuffer opaque_fb = {}; Texture shadow_depth_stencil_tx = {"shadow_depth_stencil_tx"}; GPUTexture *deferred_ps_stencil_tx = nullptr; @@ -256,6 +268,11 @@ class OpaquePass { MeshPass gbuffer_in_front_ps_ = {"Opaque.GbufferInFront"}; PassSimple deferred_ps_ = {"Opaque.Deferred"}; + Framebuffer gbuffer_fb = {"Opaque.Gbuffer"}; + Framebuffer gbuffer_in_front_fb = {"Opaque.GbufferInFront"}; + Framebuffer deferred_fb = {"Opaque.Deferred"}; + Framebuffer clear_fb = {"Opaque.Clear"}; + void sync(const SceneState &scene_state, SceneResources &resources); void draw(Manager &manager, View &view, @@ -511,7 +528,6 @@ class AntiAliasingPass { Texture sample0_depth_tx_ = {"sample0_depth_tx"}; Texture sample0_depth_in_front_tx_ = {"sample0_depth_in_front_tx"}; - GPUTexture *stencil_tx_ = nullptr; Texture taa_accumulation_tx_ = {"taa_accumulation_tx"}; Texture smaa_search_tx_ = {"smaa_search_tx"}; @@ -545,15 +561,12 @@ class AntiAliasingPass { ~AntiAliasingPass(); void init(const SceneState &scene_state); - void sync(SceneResources &resources, int2 resolution); - void setup_view(View &view, int2 resolution); + void sync(const SceneState &scene_state, SceneResources &resources); + void setup_view(View &view, const SceneState &scene_state); void draw(Manager &manager, View &view, - SceneResources &resources, - int2 resolution, - GPUTexture *depth_tx, - GPUTexture *depth_in_front_tx, - GPUTexture *color_tx); + const SceneState &scene_state, + SceneResources &resources); }; } // namespace blender::workbench diff --git a/source/blender/draw/engines/workbench/workbench_shader_cache.cc b/source/blender/draw/engines/workbench/workbench_shader_cache.cc index 05b8669fa2c..d814323a2bb 100644 --- a/source/blender/draw/engines/workbench/workbench_shader_cache.cc +++ b/source/blender/draw/engines/workbench/workbench_shader_cache.cc @@ -23,7 +23,9 @@ ShaderCache::~ShaderCache() for (auto j : IndexRange(lighting_type_len)) { for (auto k : IndexRange(2) /*cavity*/) { for (auto l : IndexRange(2) /*curvature*/) { - DRW_SHADER_FREE_SAFE(resolve_shader_cache_[i][j][k][l]); + for (auto m : IndexRange(2) /*shadow*/) { + DRW_SHADER_FREE_SAFE(resolve_shader_cache_[i][j][k][l][m]); + } } } } @@ -92,10 +94,11 @@ GPUShader *ShaderCache::prepass_shader_get(ePipelineType pipeline_type, GPUShader *ShaderCache::resolve_shader_get(ePipelineType pipeline_type, eLightingType lighting_type, bool cavity, - bool curvature) + bool curvature, + bool shadow) { GPUShader *&shader_ptr = - resolve_shader_cache_[int(pipeline_type)][int(lighting_type)][cavity][curvature]; + resolve_shader_cache_[int(pipeline_type)][int(lighting_type)][cavity][curvature][shadow]; if (shader_ptr != nullptr) { return shader_ptr; @@ -125,6 +128,7 @@ GPUShader *ShaderCache::resolve_shader_get(ePipelineType pipeline_type, } info_name += cavity ? "_cavity" : "_no_cavity"; info_name += curvature ? "_curvature" : "_no_curvature"; + info_name += shadow ? "_shadow" : "_no_shadow"; shader_ptr = GPU_shader_create_from_info_name(info_name.c_str()); return shader_ptr; diff --git a/source/blender/draw/engines/workbench/workbench_state.cc b/source/blender/draw/engines/workbench/workbench_state.cc index 0124aeba547..72936304ef8 100644 --- a/source/blender/draw/engines/workbench/workbench_state.cc +++ b/source/blender/draw/engines/workbench/workbench_state.cc @@ -173,6 +173,8 @@ void SceneState::init(Object *camera_ob /*=nullptr*/) shading.flag & V3D_SHADING_DEPTH_OF_FIELD; draw_object_id = draw_outline || draw_curvature; + + overlays_enabled = v3d && !(v3d->flag2 & V3D_HIDE_OVERLAYS); }; static const CustomData *get_loop_custom_data(const Mesh *mesh)