This is the first step of moving the create infos back inside shader sources. All info files are now treated as source files. However, they are not considered in the include tree yet. This will come in another following PR. Each shader source file now generate a `.info` file containing only the create info declarations. This renames all info files so that they do not conflict with their previous versions that were copied (non-generated). Pull Request: https://projects.blender.org/blender/blender/pulls/146676
213 lines
6.2 KiB
GLSL
213 lines
6.2 KiB
GLSL
/* SPDX-FileCopyrightText: 2016-2024 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
#include "infos/gpu_shader_text_infos.hh"
|
|
|
|
#include "gpu_shader_colorspace_lib.glsl"
|
|
|
|
FRAGMENT_SHADER_CREATE_INFO(gpu_shader_text)
|
|
|
|
/* Font texture is conceptually laid out like a big 1D buffer: each glyph
|
|
* rectangle is flattened in row-major order into a "pixel strip". Inside
|
|
* the texture, glyphs strips are put one after another. The texture pixel
|
|
* rows can conceptually be treated as a really wide 1D texture.
|
|
*
|
|
* Because of all this, texture filtering has to be implemented manually,
|
|
* as well as checks for whether filtering samples fall outside of the
|
|
* glyph rectangle. */
|
|
|
|
float texel_fetch(int index)
|
|
{
|
|
int2 texel = int2(index & glyph_tex_width_mask, index >> glyph_tex_width_shift);
|
|
return texelFetch(glyph, texel, 0).r;
|
|
}
|
|
|
|
bool is_inside_box(int2 v)
|
|
{
|
|
return all(greaterThanEqual(v, int2(0))) && all(lessThan(v, glyph_dim));
|
|
}
|
|
|
|
float sample_glyph_bilinear(float2 bilin_f, float2 uv)
|
|
{
|
|
int2 texel = int2(floor(uv)) - 1;
|
|
int index = glyph_offset + texel.y * glyph_dim.x + texel.x;
|
|
|
|
/* Fetch 2x2 texels for filtering. */
|
|
int offset_x = 1;
|
|
int offset_y = glyph_dim.x;
|
|
float tl = texel_fetch(index);
|
|
float tr = texel_fetch(index + offset_x);
|
|
float bl = texel_fetch(index + offset_y);
|
|
float br = texel_fetch(index + offset_x + offset_y);
|
|
|
|
/* Texels outside of glyph box: zero. */
|
|
if (!is_inside_box(texel)) {
|
|
tl = 0.0f;
|
|
}
|
|
if (!is_inside_box(texel + int2(1, 0))) {
|
|
tr = 0.0f;
|
|
}
|
|
if (!is_inside_box(texel + int2(0, 1))) {
|
|
bl = 0.0f;
|
|
}
|
|
if (!is_inside_box(texel + int2(1, 1))) {
|
|
br = 0.0f;
|
|
}
|
|
|
|
/* Bilinear filter. */
|
|
float tA = mix(tl, tr, bilin_f.x);
|
|
float tB = mix(bl, br, bilin_f.x);
|
|
return mix(tA, tB, bilin_f.y);
|
|
}
|
|
|
|
float4 sample_glyph_rgba(float2 uv)
|
|
{
|
|
int2 texel = int2(round(uv)) - 1;
|
|
|
|
float4 col = float4(0.0f);
|
|
if (is_inside_box(texel)) {
|
|
int index = glyph_offset + (texel.y * glyph_dim.x + texel.x) * 4;
|
|
col.r = texel_fetch(index);
|
|
col.g = texel_fetch(index + 1);
|
|
col.b = texel_fetch(index + 2);
|
|
col.a = texel_fetch(index + 3);
|
|
}
|
|
return col;
|
|
}
|
|
|
|
void main()
|
|
{
|
|
float2 uv_base = texCoord_interp;
|
|
uint num_channels = (glyph_flags >> 4) & 0xFu;
|
|
uint shadow_type = glyph_flags & 0xFu;
|
|
|
|
/* Colored glyphs: do not do filtering or blurring. */
|
|
if (num_channels == 4) {
|
|
fragColor.rgba = sample_glyph_rgba(uv_base).rgba;
|
|
fragColor.a *= color_flat.a;
|
|
return;
|
|
}
|
|
|
|
float2 bilin_f = fract(uv_base);
|
|
|
|
fragColor.rgb = color_flat.rgb;
|
|
|
|
if (shadow_type == 0) {
|
|
/* No blurring: just a bilinear sample. */
|
|
fragColor.a = sample_glyph_bilinear(bilin_f, uv_base);
|
|
}
|
|
else {
|
|
|
|
/* Blurring or dilation: will fetch (N+1)x(N+1) are of glyph texels,
|
|
* shifting the filter kernel weights by bilinear fraction. */
|
|
fragColor.a = 0.0f;
|
|
|
|
int2 texel = int2(floor(uv_base)) - 1;
|
|
int frag_offset = glyph_offset + texel.y * glyph_dim.x + texel.x;
|
|
|
|
if (shadow_type == 6) {
|
|
/* 3x3 outline by dilation */
|
|
|
|
float maxval = 0.0f;
|
|
for (int iy = 0; iy < 4; ++iy) {
|
|
int ofsy = iy - 1;
|
|
for (int ix = 0; ix < 4; ++ix) {
|
|
int ofsx = ix - 1;
|
|
float v = texel_fetch(frag_offset + ofsy * glyph_dim.x + ofsx);
|
|
if (!is_inside_box(texel + int2(ofsx, ofsy))) {
|
|
v = 0.0f;
|
|
}
|
|
|
|
/* Bilinearly compute weight for this sample. */
|
|
float w00 = ix < 3 && iy < 3 ? 1.0f : 0.0f;
|
|
float w10 = ix > 0 && iy < 3 ? 1.0f : 0.0f;
|
|
float w01 = ix < 3 && iy > 0 ? 1.0f : 0.0f;
|
|
float w11 = ix > 0 && iy > 0 ? 1.0f : 0.0f;
|
|
float w = mix(mix(w00, w10, bilin_f.x), mix(w01, w11, bilin_f.x), bilin_f.y);
|
|
|
|
maxval = max(maxval, v * w);
|
|
}
|
|
}
|
|
fragColor.a = maxval;
|
|
}
|
|
else if (shadow_type <= 4) {
|
|
/* 3x3 blur */
|
|
|
|
/* clang-format off */
|
|
constexpr float weights3x3[16] = float_array(
|
|
1.0f, 2.0f, 1.0f, 0.0f,
|
|
2.0f, 4.0f, 2.0f, 0.0f,
|
|
1.0f, 2.0f, 1.0f, 0.0f,
|
|
0.0f, 0.0f, 0.0f, 0.0f
|
|
);
|
|
/* clang-format on */
|
|
|
|
float sum = 0.0f;
|
|
int idx = 0;
|
|
for (int iy = 0; iy < 4; ++iy) {
|
|
int ofsy = iy - 1;
|
|
for (int ix = 0; ix < 4; ++ix) {
|
|
int ofsx = ix - 1;
|
|
float v = texel_fetch(frag_offset + ofsy * glyph_dim.x + ofsx);
|
|
if (!is_inside_box(texel + int2(ofsx, ofsy))) {
|
|
v = 0.0f;
|
|
}
|
|
|
|
/* Bilinearly compute filter weight for this sample. */
|
|
float w00 = weights3x3[idx];
|
|
float w10 = ix > 0 ? weights3x3[idx - 1] : 0.0f;
|
|
float w01 = iy > 0 ? weights3x3[idx - 4] : 0.0f;
|
|
float w11 = ix > 0 && iy > 0 ? weights3x3[idx - 5] : 0.0f;
|
|
float w = mix(mix(w00, w10, bilin_f.x), mix(w01, w11, bilin_f.x), bilin_f.y);
|
|
|
|
sum += v * w;
|
|
++idx;
|
|
}
|
|
}
|
|
fragColor.a = sum * (1.0f / 16.0f);
|
|
}
|
|
else {
|
|
/* 5x5 blur */
|
|
|
|
/* clang-format off */
|
|
constexpr float weights5x5[36] = float_array(
|
|
1.0f, 2.0f, 2.0f, 2.0f, 1.0f, 0.0f,
|
|
2.0f, 5.0f, 6.0f, 5.0f, 2.0f, 0.0f,
|
|
2.0f, 6.0f, 8.0f, 6.0f, 2.0f, 0.0f,
|
|
2.0f, 5.0f, 6.0f, 5.0f, 2.0f, 0.0f,
|
|
1.0f, 2.0f, 2.0f, 2.0f, 1.0f, 0.0f,
|
|
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f
|
|
);
|
|
/* clang-format on */
|
|
|
|
float sum = 0.0f;
|
|
int idx = 0;
|
|
for (int iy = 0; iy < 6; ++iy) {
|
|
int ofsy = iy - 2;
|
|
for (int ix = 0; ix < 6; ++ix) {
|
|
int ofsx = ix - 2;
|
|
float v = texel_fetch(frag_offset + ofsy * glyph_dim.x + ofsx);
|
|
if (!is_inside_box(texel + int2(ofsx, ofsy))) {
|
|
v = 0.0f;
|
|
}
|
|
|
|
/* Bilinearly compute filter weight for this sample. */
|
|
float w00 = weights5x5[idx];
|
|
float w10 = ix > 0 ? weights5x5[idx - 1] : 0.0f;
|
|
float w01 = iy > 0 ? weights5x5[idx - 6] : 0.0f;
|
|
float w11 = ix > 0 && iy > 0 ? weights5x5[idx - 7] : 0.0f;
|
|
float w = mix(mix(w00, w10, bilin_f.x), mix(w01, w11, bilin_f.x), bilin_f.y);
|
|
|
|
sum += v * w;
|
|
++idx;
|
|
}
|
|
}
|
|
fragColor.a = sum * (1.0f / 80.0f);
|
|
}
|
|
}
|
|
|
|
fragColor.a *= color_flat.a;
|
|
fragColor = blender_srgb_to_framebuffer_space(fragColor);
|
|
}
|