Fix #103398: Fix Icon sampler initialization in Metal backend.

Resolves issue with nearest filtering on UI Icons. Note that as
Metal does not support LOD bias as a parameter on a sampler
object, the original code has been modified to perform LOD
biasing at the shader level.

As GPU_SAMPLER_ICON is not  widely used, it is more
efficient to apply directly to the  affected shaders, rather
than workaround passing in the sampler LOD bias as a
separate value e.g. uniform or push constant.

Original PR feedback addressed to also refactor ICON
shaders to use consistent style for single and multi
Icon rendering.

Authored by Apple: Michael Parkin-White

Ref #96261
Pull Request #105145
This commit is contained in:
Jason Fielder
2023-02-26 13:23:40 +01:00
committed by Clément Foucault
parent f9bcd8c7e8
commit fb63e484b9
14 changed files with 53 additions and 42 deletions

View File

@@ -1617,12 +1617,12 @@ static void icon_draw_cache_texture_flush_ex(GPUTexture *texture,
return;
}
GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR);
GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_ICON_MULTI);
GPU_shader_bind(shader);
const int data_binding = GPU_shader_get_ubo_binding(shader, "multi_rect_data");
const int data_binding = GPU_shader_get_ubo_binding(shader, "multi_icon_data");
GPUUniformBuf *ubo = GPU_uniformbuf_create_ex(
sizeof(MultiRectCallData), texture_draw_calls->drawcall_cache, __func__);
sizeof(MultiIconCallData), texture_draw_calls->drawcall_cache, __func__);
GPU_uniformbuf_bind(ubo, data_binding);
const int img_binding = GPU_shader_get_sampler_binding(shader, "image");
@@ -1798,7 +1798,7 @@ static void icon_draw_texture(float x,
GPU_shader_bind(shader);
const int img_binding = GPU_shader_get_sampler_binding(shader, "image");
const int color_loc = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_COLOR);
const int color_loc = GPU_shader_get_uniform(shader, "finalColor");
const int rect_tex_loc = GPU_shader_get_uniform(shader, "rect_icon");
const int rect_geom_loc = GPU_shader_get_uniform(shader, "rect_geom");

View File

@@ -348,7 +348,7 @@ set(GLSL_SRC
shaders/gpu_shader_2D_line_dashed_frag.glsl
shaders/gpu_shader_2D_image_vert.glsl
shaders/gpu_shader_2D_image_rect_vert.glsl
shaders/gpu_shader_2D_image_multi_rect_vert.glsl
shaders/gpu_shader_icon_multi_vert.glsl
shaders/gpu_shader_icon_frag.glsl
shaders/gpu_shader_icon_vert.glsl
shaders/gpu_shader_image_frag.glsl
@@ -357,7 +357,6 @@ set(GLSL_SRC
shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl
shaders/gpu_shader_image_shuffle_color_frag.glsl
shaders/gpu_shader_image_color_frag.glsl
shaders/gpu_shader_image_varying_color_frag.glsl
shaders/gpu_shader_3D_image_vert.glsl
shaders/gpu_shader_3D_vert.glsl
shaders/gpu_shader_3D_normal_vert.glsl
@@ -639,7 +638,6 @@ set(SRC_SHADER_CREATE_INFOS
shaders/infos/gpu_shader_2D_diag_stripes_info.hh
shaders/infos/gpu_shader_2D_image_desaturate_color_info.hh
shaders/infos/gpu_shader_2D_image_info.hh
shaders/infos/gpu_shader_2D_image_multi_rect_color_info.hh
shaders/infos/gpu_shader_2D_image_overlays_merge_info.hh
shaders/infos/gpu_shader_2D_image_overlays_stereo_merge_info.hh
shaders/infos/gpu_shader_2D_image_rect_color_info.hh

View File

@@ -39,7 +39,7 @@ typedef enum eGPUBuiltinShader {
/** Draw a texture with a desaturation factor. */
GPU_SHADER_2D_IMAGE_DESATURATE_COLOR,
/** Draw a group of texture rectangle with an associated color multiplied. */
GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR,
GPU_SHADER_ICON_MULTI,
/** Draw a two color checker based on screen position (not UV coordinates). */
GPU_SHADER_2D_CHECKER,
/** Draw diagonal stripes with two alternating colors. */

View File

@@ -82,10 +82,10 @@ BLI_STATIC_ASSERT_ALIGN(struct SimpleLightingData, 16)
#define MAX_CALLS 16
struct MultiRectCallData {
struct MultiIconCallData {
float4 calls_data[MAX_CALLS * 3];
};
BLI_STATIC_ASSERT_ALIGN(struct MultiRectCallData, 16)
BLI_STATIC_ASSERT_ALIGN(struct MultiIconCallData, 16)
enum TestStatus {
TEST_STATUS_NONE = 0,

View File

@@ -42,8 +42,8 @@ static const char *builtin_shader_create_info_name(eGPUBuiltinShader shader)
return "gpu_shader_2D_image_shuffle_color";
case GPU_SHADER_2D_IMAGE_RECT_COLOR:
return "gpu_shader_2D_image_rect_color";
case GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR:
return "gpu_shader_2D_image_multi_rect_color";
case GPU_SHADER_ICON_MULTI:
return "gpu_shader_icon_multi";
case GPU_SHADER_3D_UNIFORM_COLOR:
return "gpu_shader_3D_uniform_color";
case GPU_SHADER_3D_FLAT_COLOR:

View File

@@ -768,6 +768,7 @@ class MTLContext : public Context {
void texture_unbind_all();
id<MTLSamplerState> get_sampler_from_state(MTLSamplerState state);
id<MTLSamplerState> generate_sampler_from_state(MTLSamplerState state);
id<MTLSamplerState> generate_icon_sampler();
id<MTLSamplerState> get_default_sampler_state();
/* Metal Context pipeline state. */

View File

@@ -223,11 +223,13 @@ MTLContext::MTLContext(void *ghost_window, void *ghost_context)
}
/* Initialize samplers. */
for (uint i = 0; i < GPU_SAMPLER_MAX; i++) {
for (uint i = 0; i < GPU_SAMPLER_ICON; i++) {
MTLSamplerState state;
state.state = static_cast<eGPUSamplerState>(i);
sampler_state_cache_[i] = this->generate_sampler_from_state(state);
}
/* Special sampler for icons. */
sampler_state_cache_[GPU_SAMPLER_ICON] = this->generate_icon_sampler();
}
MTLContext::~MTLContext()
@@ -2024,7 +2026,6 @@ id<MTLSamplerState> MTLContext::get_sampler_from_state(MTLSamplerState sampler_s
id<MTLSamplerState> MTLContext::generate_sampler_from_state(MTLSamplerState sampler_state)
{
/* Check if sampler already exists for given state. */
MTLSamplerDescriptor *descriptor = [[MTLSamplerDescriptor alloc] init];
descriptor.normalizedCoordinates = true;
@@ -2067,6 +2068,21 @@ id<MTLSamplerState> MTLContext::generate_sampler_from_state(MTLSamplerState samp
return state;
}
id<MTLSamplerState> MTLContext::generate_icon_sampler()
{
MTLSamplerDescriptor *descriptor = [[MTLSamplerDescriptor alloc] init];
descriptor.minFilter = MTLSamplerMinMagFilterLinear;
descriptor.magFilter = MTLSamplerMinMagFilterLinear;
descriptor.mipFilter = MTLSamplerMipFilterNearest;
descriptor.lodMinClamp = 0;
descriptor.lodMaxClamp = 1;
id<MTLSamplerState> icon_state = [this->device newSamplerStateWithDescriptor:descriptor];
BLI_assert(icon_state != nil);
[descriptor autorelease];
return icon_state;
}
id<MTLSamplerState> MTLContext::get_default_sampler_state()
{
if (default_sampler_state_ == nil) {

View File

@@ -594,11 +594,11 @@ void GLTexture::samplers_init()
}
samplers_update();
/* Custom sampler for icons. */
/* Custom sampler for icons.
* NOTE: The icon texture is sampled within the shader using a -0.5f lod bias. */
GLuint icon_sampler = samplers_[GPU_SAMPLER_ICON];
glSamplerParameteri(icon_sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glSamplerParameteri(icon_sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glSamplerParameterf(icon_sampler, GL_TEXTURE_LOD_BIAS, -0.5f);
debug::object_label(GL_SAMPLER, icon_sampler, "icons");
}

View File

@@ -8,6 +8,10 @@
void main()
{
/* Sample texture with LOD BIAS. Used instead of custom lod bias in GPU_SAMPLER_ICON. */
fragColor = texture(image, texCoord_interp, -0.5) * finalColor;
#ifdef DO_CORNER_MASKING
/* Top-left rounded corner parameters. */
const float circle_radius_outer = 0.1;
const float circle_radius_inner = 0.075;
@@ -18,7 +22,6 @@ void main()
const float mask_transparency = 0.25;
vec2 circle_center = vec2(circle_radius_outer - text_width, 0.5);
fragColor = texture(image, texCoord_interp) * color;
/* radius in icon space (1 is the icon width). */
float radius = length(mask_coord_interp - circle_center);
@@ -39,4 +42,5 @@ void main()
}
fragColor = mix(vec4(0.0), fragColor, max(mask_transparency, mask));
#endif
}

View File

@@ -5,9 +5,9 @@
void main()
{
vec4 rect = multi_rect_data.calls_data[gl_InstanceID * 3];
vec4 tex = multi_rect_data.calls_data[gl_InstanceID * 3 + 1];
finalColor = multi_rect_data.calls_data[gl_InstanceID * 3 + 2];
vec4 rect = multi_icon_data.calls_data[gl_InstanceID * 3];
vec4 tex = multi_icon_data.calls_data[gl_InstanceID * 3 + 1];
finalColor = multi_icon_data.calls_data[gl_InstanceID * 3 + 2];
/* Use pos to select the right swizzle (instead of gl_VertexID)
* in order to workaround an OSX driver bug. */

View File

@@ -1,5 +0,0 @@
void main()
{
fragColor = texture(image, texCoord_interp) * finalColor;
}

View File

@@ -1,15 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_interface_info.hh"
#include "gpu_shader_create_info.hh"
GPU_SHADER_CREATE_INFO(gpu_shader_2D_image_multi_rect_color)
.vertex_in(0, Type::VEC2, "pos")
.vertex_out(flat_color_smooth_tex_coord_interp_iface)
.fragment_out(0, Type::VEC4, "fragColor")
.uniform_buf(0, "MultiRectCallData", "multi_rect_data")
.sampler(0, ImageType::FLOAT_2D, "image")
.typedef_source("GPU_shader_shared.h")
.vertex_source("gpu_shader_2D_image_multi_rect_vert.glsl")
.fragment_source("gpu_shader_image_varying_color_frag.glsl")
.do_static_compilation(true);

View File

@@ -9,10 +9,11 @@
#include "gpu_shader_create_info.hh"
GPU_SHADER_CREATE_INFO(gpu_shader_icon)
.define("DO_CORNER_MASKING")
.vertex_out(smooth_icon_interp_iface)
.fragment_out(0, Type::VEC4, "fragColor")
.push_constant(Type::MAT4, "ModelViewProjectionMatrix")
.push_constant(Type::VEC4, "color")
.push_constant(Type::VEC4, "finalColor")
.push_constant(Type::VEC4, "rect_icon")
.push_constant(Type::VEC4, "rect_geom")
.push_constant(Type::FLOAT, "text_width")
@@ -20,3 +21,14 @@ GPU_SHADER_CREATE_INFO(gpu_shader_icon)
.vertex_source("gpu_shader_icon_vert.glsl")
.fragment_source("gpu_shader_icon_frag.glsl")
.do_static_compilation(true);
GPU_SHADER_CREATE_INFO(gpu_shader_icon_multi)
.vertex_in(0, Type::VEC2, "pos")
.vertex_out(flat_color_smooth_tex_coord_interp_iface)
.fragment_out(0, Type::VEC4, "fragColor")
.uniform_buf(0, "MultiIconCallData", "multi_icon_data")
.sampler(0, ImageType::FLOAT_2D, "image")
.typedef_source("GPU_shader_shared.h")
.vertex_source("gpu_shader_icon_multi_vert.glsl")
.fragment_source("gpu_shader_icon_frag.glsl")
.do_static_compilation(true);

View File

@@ -36,7 +36,7 @@ static void test_shader_builtin()
test_compile_builtin_shader(GPU_SHADER_3D_IMAGE_COLOR, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_DESATURATE_COLOR, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_RECT_COLOR, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_ICON_MULTI, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_CHECKER, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_DIAG_STRIPES, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR, GPU_SHADER_CFG_DEFAULT);