From f63a0e670acdf9738f669eecf86e87ded2b4e680 Mon Sep 17 00:00:00 2001 From: Miguel Pozo Date: Thu, 24 Aug 2023 15:10:33 +0200 Subject: [PATCH] Workbench-Next: Workaround lack of texture views support Extract a mask from the stencil buffer and use that texture instead when texture views are not available. Needed for supporting the Windows ARM software driver. The workaround is isolated on its own class so it's easy to remove once it's no longer needed. Note that while this adds a function to check if texture views are available (`GPU_texture_view_support`), at the moment this always returns true in practice, since OpenGL 4.3 is the minimum supported version. A separate patch will be needed to allow Blender to run using OpenGL 4.2 + extensions. Pull Request: https://projects.blender.org/blender/blender/pulls/111402 --- source/blender/draw/CMakeLists.txt | 1 + .../infos/workbench_merge_infront_info.hh | 6 +++ .../shaders/workbench_extract_stencil.glsl | 5 ++ .../workbench_effect_antialiasing.cc | 2 +- .../workbench/workbench_mesh_passes.cc | 12 +++-- .../engines/workbench/workbench_private.hh | 54 +++++++++++++++++++ .../workbench/workbench_volume_next.cc | 5 +- source/blender/gpu/GPU_capabilities.h | 1 + source/blender/gpu/intern/gpu_capabilities.cc | 5 ++ .../gpu/intern/gpu_capabilities_private.hh | 1 + source/blender/gpu/opengl/gl_backend.cc | 2 + 11 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 source/blender/draw/engines/workbench/shaders/workbench_extract_stencil.glsl diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index e090a9de537..1b721f0cdd4 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -603,6 +603,7 @@ set(GLSL_SRC engines/workbench/shaders/workbench_effect_smaa_frag.glsl engines/workbench/shaders/workbench_effect_smaa_vert.glsl engines/workbench/shaders/workbench_effect_taa_frag.glsl + engines/workbench/shaders/workbench_extract_stencil.glsl engines/workbench/shaders/workbench_image_lib.glsl engines/workbench/shaders/workbench_matcap_lib.glsl engines/workbench/shaders/workbench_material_lib.glsl diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_merge_infront_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_merge_infront_info.hh index 5f7402b68b7..b17edba19fb 100644 --- a/source/blender/draw/engines/workbench/shaders/infos/workbench_merge_infront_info.hh +++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_merge_infront_info.hh @@ -18,3 +18,9 @@ GPU_SHADER_CREATE_INFO(workbench_next_merge_depth) .additional_info("draw_fullscreen") .depth_write(DepthWrite::ANY) .do_static_compilation(true); + +GPU_SHADER_CREATE_INFO(workbench_extract_stencil) + .fragment_out(0, Type::UINT, "out_stencil_value") + .fragment_source("workbench_extract_stencil.glsl") + .additional_info("draw_fullscreen") + .do_static_compilation(true); diff --git a/source/blender/draw/engines/workbench/shaders/workbench_extract_stencil.glsl b/source/blender/draw/engines/workbench/shaders/workbench_extract_stencil.glsl new file mode 100644 index 00000000000..a6fb3b568c5 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_extract_stencil.glsl @@ -0,0 +1,5 @@ + +void main() +{ + out_stencil_value = 0xFF; +} diff --git a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.cc b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.cc index 671710998a6..5a0c6886a6e 100644 --- a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.cc +++ b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.cc @@ -254,7 +254,7 @@ void AntiAliasingPass::draw(Manager &manager, GPUTexture *color_tx) { auto draw_overlay_depth = [&](GPUTexture *target) { - stencil_tx_ = resources.depth_tx.stencil_view(); + stencil_tx_ = resources.stencil_view.extract(manager, resources.depth_tx); overlay_depth_fb_.ensure(GPU_ATTACHMENT_TEXTURE(target)); overlay_depth_fb_.bind(); manager.submit(overlay_depth_ps_); diff --git a/source/blender/draw/engines/workbench/workbench_mesh_passes.cc b/source/blender/draw/engines/workbench/workbench_mesh_passes.cc index 426d9408cef..a68a97293fc 100644 --- a/source/blender/draw/engines/workbench/workbench_mesh_passes.cc +++ b/source/blender/draw/engines/workbench/workbench_mesh_passes.cc @@ -190,6 +190,8 @@ void OpaquePass::draw(Manager &manager, bool needs_stencil_copy = shadow_pass && !gbuffer_in_front_ps_.is_empty(); + Texture *depth_stencil_tx = nullptr; + if (needs_stencil_copy) { shadow_depth_stencil_tx.ensure_2d(GPU_DEPTH24_STENCIL8, resolution, @@ -198,22 +200,24 @@ void OpaquePass::draw(Manager &manager, GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW); GPU_texture_copy(shadow_depth_stencil_tx, resources.depth_tx); - deferred_ps_stencil_tx = shadow_depth_stencil_tx.stencil_view(); + depth_stencil_tx = shadow_depth_stencil_tx.ptr(); - opaque_fb.ensure(GPU_ATTACHMENT_TEXTURE(deferred_ps_stencil_tx)); + opaque_fb.ensure(GPU_ATTACHMENT_TEXTURE(*depth_stencil_tx)); opaque_fb.bind(); GPU_framebuffer_clear_stencil(opaque_fb, 0); } else { shadow_depth_stencil_tx.free(); - deferred_ps_stencil_tx = resources.depth_tx.stencil_view(); + depth_stencil_tx = resources.depth_tx.ptr(); } if (shadow_pass) { shadow_pass->draw( - manager, view, resources, *deferred_ps_stencil_tx, !gbuffer_in_front_ps_.is_empty()); + 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(); manager.submit(deferred_ps_, view); diff --git a/source/blender/draw/engines/workbench/workbench_private.hh b/source/blender/draw/engines/workbench/workbench_private.hh index 03c806a5a1b..c5b86d1e74c 100644 --- a/source/blender/draw/engines/workbench/workbench_private.hh +++ b/source/blender/draw/engines/workbench/workbench_private.hh @@ -11,6 +11,8 @@ #include "workbench_enums.hh" #include "workbench_shader_shared.h" +#include "GPU_capabilities.h" + extern "C" DrawEngineType draw_engine_workbench_next; namespace blender::workbench { @@ -137,6 +139,56 @@ class CavityEffect { void load_samples_buf(int ssao_samples); }; +/* Used as a temporary workaround for the lack of texture views support on Windows ARM. */ +class StencilViewWorkaround { + private: + Texture stencil_copy_tx_ = "stencil_copy_tx"; + GPUShader *stencil_copy_sh_ = nullptr; + + public: + StencilViewWorkaround() + { + stencil_copy_sh_ = GPU_shader_create_from_info_name("workbench_extract_stencil"); + } + ~StencilViewWorkaround() + { + DRW_SHADER_FREE_SAFE(stencil_copy_sh_); + } + + /** WARNING: Should only be called at render time. + * When the workaround path is active, + * the returned texture won't stay in sync with the stencil_src, + * and will only be valid until the next time this function is called. + * Note that the output is a binary mask, + * any stencil value that is not 0x00 will be rendered as 0xFF. */ + GPUTexture *extract(Manager &manager, Texture &stencil_src) + { + if (GPU_texture_view_support()) { + return stencil_src.stencil_view(); + } + + int2 extent = int2(stencil_src.width(), stencil_src.height()); + stencil_copy_tx_.ensure_2d( + GPU_R8UI, extent, GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_SHADER_READ); + + PassSimple ps("Stencil View Workaround"); + ps.init(); + ps.clear_color(float4(0)); + ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_NEQUAL); + ps.state_stencil(0x00, 0x00, 0xFF); + ps.shader_set(stencil_copy_sh_); + ps.draw_procedural(GPU_PRIM_TRIS, 1, 3); + + Framebuffer fb; + fb.ensure(GPU_ATTACHMENT_TEXTURE(stencil_src), GPU_ATTACHMENT_TEXTURE(stencil_copy_tx_)); + fb.bind(); + + manager.submit(ps); + + return stencil_copy_tx_; + } +}; + struct SceneResources { static const int jitter_tx_size = 64; @@ -158,6 +210,8 @@ struct SceneResources { CavityEffect cavity = {}; + StencilViewWorkaround stencil_view; + void init(const SceneState &scene_state); void load_jitter_tx(int total_samples); }; diff --git a/source/blender/draw/engines/workbench/workbench_volume_next.cc b/source/blender/draw/engines/workbench/workbench_volume_next.cc index d8c45e1203c..87b19b27b51 100644 --- a/source/blender/draw/engines/workbench/workbench_volume_next.cc +++ b/source/blender/draw/engines/workbench/workbench_volume_next.cc @@ -21,8 +21,6 @@ void VolumePass::sync(SceneResources &resources) dummy_shadow_tx_.ensure_3d(GPU_RGBA8, int3(1), GPU_TEXTURE_USAGE_SHADER_READ, float4(1)); dummy_volume_tx_.ensure_3d(GPU_RGBA8, int3(1), GPU_TEXTURE_USAGE_SHADER_READ, float4(0)); dummy_coba_tx_.ensure_1d(GPU_RGBA8, 1, GPU_TEXTURE_USAGE_SHADER_READ, float4(0)); - - stencil_tx_ = resources.depth_tx.stencil_view(); } void VolumePass::object_sync_volume(Manager &manager, @@ -182,6 +180,9 @@ void VolumePass::draw(Manager &manager, View &view, SceneResources &resources) if (!active_) { return; } + + stencil_tx_ = resources.stencil_view.extract(manager, resources.depth_tx); + fb_.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(resources.color_tx)); fb_.bind(); manager.submit(ps_, view); diff --git a/source/blender/gpu/GPU_capabilities.h b/source/blender/gpu/GPU_capabilities.h index 3273626e603..fbf5fd8f20a 100644 --- a/source/blender/gpu/GPU_capabilities.h +++ b/source/blender/gpu/GPU_capabilities.h @@ -53,6 +53,7 @@ bool GPU_shader_storage_buffer_objects_support(void); bool GPU_shader_image_load_store_support(void); bool GPU_shader_draw_parameters_support(void); bool GPU_hdr_support(void); +bool GPU_texture_view_support(); bool GPU_mem_stats_supported(void); void GPU_mem_stats_get(int *totalmem, int *freemem); diff --git a/source/blender/gpu/intern/gpu_capabilities.cc b/source/blender/gpu/intern/gpu_capabilities.cc index b3556e4dbe2..2597e022f9c 100644 --- a/source/blender/gpu/intern/gpu_capabilities.cc +++ b/source/blender/gpu/intern/gpu_capabilities.cc @@ -187,6 +187,11 @@ bool GPU_hdr_support() return GCaps.hdr_viewport_support; } +bool GPU_texture_view_support() +{ + return GCaps.texture_view_support; +} + int GPU_max_shader_storage_buffer_bindings() { return GCaps.max_shader_storage_buffer_bindings; diff --git a/source/blender/gpu/intern/gpu_capabilities_private.hh b/source/blender/gpu/intern/gpu_capabilities_private.hh index cfad99b0a5a..79f4c8b5225 100644 --- a/source/blender/gpu/intern/gpu_capabilities_private.hh +++ b/source/blender/gpu/intern/gpu_capabilities_private.hh @@ -49,6 +49,7 @@ struct GPUCapabilities { bool shader_draw_parameters_support = false; bool transform_feedback_support = false; bool hdr_viewport_support = false; + bool texture_view_support = true; /* OpenGL related workarounds. */ bool mip_render_workaround = false; diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc index b1c90c6023f..9ff7220b42f 100644 --- a/source/blender/gpu/opengl/gl_backend.cc +++ b/source/blender/gpu/opengl/gl_backend.cc @@ -563,6 +563,8 @@ void GLBackend::capabilities_init() GCaps.shader_storage_buffer_objects_support = epoxy_has_gl_extension( "GL_ARB_shader_storage_buffer_object"); GCaps.transform_feedback_support = true; + GCaps.texture_view_support = epoxy_gl_version() >= 43 || + epoxy_has_gl_extension("GL_ARB_texture_view"); /* GL specific capabilities. */ glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &GCaps.max_texture_3d_size);