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
This commit is contained in:
Miguel Pozo
2023-08-24 15:10:33 +02:00
parent 45d8a8b0c3
commit f63a0e670a
11 changed files with 87 additions and 7 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -0,0 +1,5 @@
void main()
{
out_stencil_value = 0xFF;
}

View File

@@ -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_);

View File

@@ -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);

View File

@@ -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);
};

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);