583 lines
20 KiB
C++
583 lines
20 KiB
C++
/*
|
|
* Copyright (C) 2026 Behdad Esfahbod
|
|
*
|
|
* This is part of HarfBuzz, a text shaping library.
|
|
*
|
|
* Permission is hereby granted, without written agreement and without
|
|
* license or royalty fees, to use, copy, modify, and distribute this
|
|
* software and its documentation for any purpose, provided that the
|
|
* above copyright notice and the following two paragraphs appear in
|
|
* all copies of this software.
|
|
*
|
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
|
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
|
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
|
* DAMAGE.
|
|
*
|
|
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
|
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
|
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
|
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
|
*
|
|
* Author(s): Behdad Esfahbod
|
|
*/
|
|
|
|
#include "hb.hh"
|
|
|
|
#include "hb-gpu.h"
|
|
#include "hb-blob.hh"
|
|
|
|
/**
|
|
* SECTION:hb-gpu
|
|
* @title: hb-gpu
|
|
* @short_description: GPU text rendering
|
|
* @include: hb-gpu.h
|
|
*
|
|
* This module provides GPU-side text rendering. Glyph data is
|
|
* encoded on the CPU into compact blobs that the GPU decodes and
|
|
* rasterizes directly in the fragment shader, with no intermediate
|
|
* bitmap atlas.
|
|
*
|
|
* Two renderers share the same atlas, vertex stage, and pipeline:
|
|
*
|
|
* - Draw, an antialiased monochrome coverage mask for outline
|
|
* glyphs.
|
|
* - Paint, a premultiplied-RGBA color accumulator for COLRv0 and
|
|
* COLRv1 glyphs. Paint also renders plain monochrome outlines
|
|
* (as a single foreground-colored layer), at some cost over the
|
|
* Draw path.
|
|
*
|
|
* Applications typically pick one renderer per font, based on
|
|
* whether the font has a color paint table (see
|
|
* hb_ot_color_has_paint()). The Draw path is meaningfully faster
|
|
* than Paint on monochrome fonts, so using Paint unconditionally
|
|
* leaves performance on the table.
|
|
*
|
|
* See the [live web demo](https://harfbuzz.github.io/hb-gpu-demo/).
|
|
*
|
|
* # Draw
|
|
*
|
|
* The draw renderer implements the
|
|
* [Slug](https://github.com/EricLengyel/Slug) algorithm by Eric
|
|
* Lengyel. It produces an antialiased coverage mask in the
|
|
* fragment shader, suitable for compositing over any background
|
|
* or multiplying with any foreground color.
|
|
*
|
|
* ## Encoding
|
|
*
|
|
* Each glyph is encoded independently into an opaque blob of
|
|
* RGBA16I texels (8 bytes each). Typical encoding flow:
|
|
*
|
|
* |[<!-- language="plain" -->
|
|
* hb_gpu_draw_t *draw = hb_gpu_draw_create_or_fail ();
|
|
*
|
|
* hb_gpu_draw_glyph (draw, font, gid);
|
|
* hb_blob_t *blob = hb_gpu_draw_encode (draw);
|
|
*
|
|
* // Upload hb_blob_get_data(blob) to the atlas at some offset.
|
|
* unsigned atlas_offset = upload_to_atlas (blob);
|
|
*
|
|
* hb_gpu_draw_recycle_blob (draw, blob);
|
|
* // repeat for more glyphs...
|
|
*
|
|
* hb_gpu_draw_destroy (draw);
|
|
* ]|
|
|
*
|
|
* Create the encoder once and reuse it across glyphs.
|
|
* hb_gpu_draw_encode() auto-clears the accumulated outlines on
|
|
* return, so the next call to hb_gpu_draw_glyph() starts fresh;
|
|
* user configuration (font scale) is preserved. Pass the
|
|
* encoded blob back via hb_gpu_draw_recycle_blob() after upload
|
|
* to recycle the buffer across encodes.
|
|
*
|
|
* ## Atlas setup
|
|
*
|
|
* All encoded blobs are uploaded into a single GL_TEXTURE_BUFFER
|
|
* backed by a GL_RGBA16I format buffer. Each glyph occupies a
|
|
* contiguous range of texels at a known offset:
|
|
*
|
|
* |[<!-- language="plain" -->
|
|
* GLuint buf, tex;
|
|
* glGenBuffers (1, &buf);
|
|
* glGenTextures (1, &tex);
|
|
*
|
|
* glBindBuffer (GL_TEXTURE_BUFFER, buf);
|
|
* glBufferData (GL_TEXTURE_BUFFER, capacity * 8, NULL, GL_STATIC_DRAW);
|
|
*
|
|
* glBindTexture (GL_TEXTURE_BUFFER, tex);
|
|
* glTexBuffer (GL_TEXTURE_BUFFER, GL_RGBA16I, buf);
|
|
*
|
|
* // Upload a glyph blob at 'offset' texels:
|
|
* glBufferSubData (GL_TEXTURE_BUFFER,
|
|
* offset * 8,
|
|
* hb_blob_get_length (blob),
|
|
* hb_blob_get_data (blob, NULL));
|
|
* ]|
|
|
*
|
|
* ## Shader compilation
|
|
*
|
|
* The library provides GLSL source strings for shared helpers
|
|
* (atlas access, vertex dilation) and for the draw-renderer stage
|
|
* code. Prepend a #version directive, concatenate shared and
|
|
* draw sources in order, and append your own main():
|
|
*
|
|
* |[<!-- language="plain" -->
|
|
* const char *vert_sources[] = {
|
|
* "#version 330\n",
|
|
* hb_gpu_shader_source (HB_GPU_SHADER_STAGE_VERTEX,
|
|
* HB_GPU_SHADER_LANG_GLSL),
|
|
* hb_gpu_draw_shader_source (HB_GPU_SHADER_STAGE_VERTEX,
|
|
* HB_GPU_SHADER_LANG_GLSL),
|
|
* your_vertex_main
|
|
* };
|
|
* glShaderSource (vert_shader, 4, vert_sources, NULL);
|
|
* // Same pattern for the fragment shader.
|
|
* ]|
|
|
*
|
|
* hb_gpu_draw_shader_source() returns an empty string for the
|
|
* vertex stage, so the assembly order above is safe.
|
|
*
|
|
* ## Vertex shader
|
|
*
|
|
* The vertex library provides one function:
|
|
*
|
|
* |[<!-- language="plain" -->
|
|
* void hb_gpu_dilate (inout vec2 position, inout vec2 texcoord,
|
|
* vec2 normal, vec4 jac,
|
|
* mat4 m, vec2 viewport);
|
|
* ]|
|
|
*
|
|
* This expands each glyph quad by approximately half a pixel on
|
|
* screen to ensure proper antialiasing coverage at the edges.
|
|
* It must be called in the vertex shader before computing
|
|
* gl_Position.
|
|
*
|
|
* Per-vertex attributes for each glyph quad (2 triangles, 6
|
|
* vertices, 4 unique corners):
|
|
*
|
|
* - position (vec2): object-space vertex position, computed from
|
|
* the glyph's bounding box. For corner (cx, cy) where cx,cy
|
|
* are 0 or 1:
|
|
* |[<!-- language="plain" -->
|
|
* pos.x = pen_x + scale * lerp(extent_min_x, extent_max_x, cx)
|
|
* pos.y = pen_y - scale * lerp(extent_min_y, extent_max_y, cy)
|
|
* ]|
|
|
* where scale = font_size / upem.
|
|
*
|
|
* - texcoord (vec2): em-space texture coordinates, equal to the
|
|
* raw extent values: `(ex, ey)` where ex/ey are the glyph's
|
|
* bounding box corners in font design units. The fragment shader
|
|
* samples the encoded blob in this coordinate space.
|
|
*
|
|
* - normal (vec2): outward normal at each corner.
|
|
* `(-1, +1)` for (0,0), `(+1, +1)` for (1,0),
|
|
* `(-1, -1)` for (0,1), `(+1, -1)` for (1,1).
|
|
* Note: y is negated relative to cx,cy because the common
|
|
* em-to-object transform flips y.
|
|
*
|
|
* - jac (vec4): maps object-space displacements back to
|
|
* em-space after dilation, stored row-major as
|
|
* (j00, j01, j10, j11). For the common case of uniform
|
|
* scaling with y-flip:
|
|
* |[<!-- language="plain" -->
|
|
* jac = vec4(emPerPos, 0.0, 0.0, -emPerPos)
|
|
* ]|
|
|
* where emPerPos = upem / font_size. For non-trivial
|
|
* transforms, see the hb_gpu_dilate source.
|
|
*
|
|
* - m (mat4): the model-view-projection matrix (uniform).
|
|
*
|
|
* - viewport (vec2): the viewport size in pixels (uniform).
|
|
*
|
|
* A typical vertex main:
|
|
*
|
|
* |[<!-- language="plain" -->
|
|
* uniform mat4 u_matViewProjection;
|
|
* uniform vec2 u_viewport;
|
|
*
|
|
* in vec2 a_position;
|
|
* in vec2 a_texcoord;
|
|
* in vec2 a_normal;
|
|
* in float a_emPerPos;
|
|
* in uint a_glyphLoc;
|
|
*
|
|
* out vec2 v_texcoord;
|
|
* flat out uint v_glyphLoc;
|
|
*
|
|
* void main () {
|
|
* vec2 pos = a_position;
|
|
* vec2 tex = a_texcoord;
|
|
* vec4 jac = vec4 (a_emPerPos, 0.0, 0.0, -a_emPerPos);
|
|
* hb_gpu_dilate (pos, tex, a_normal, jac,
|
|
* u_matViewProjection, u_viewport);
|
|
* gl_Position = u_matViewProjection * vec4 (pos, 0.0, 1.0);
|
|
* v_texcoord = tex;
|
|
* v_glyphLoc = a_glyphLoc;
|
|
* }
|
|
* ]|
|
|
*
|
|
* ## Font scale
|
|
*
|
|
* The encoder works in font design units (upem). For best
|
|
* results, do not set a scale on the #hb_font_t passed to
|
|
* hb_gpu_draw_glyph() — leave it at the default (upem).
|
|
* Scaling is applied later when computing vertex positions:
|
|
*
|
|
* |[<!-- language="plain" -->
|
|
* float scale = font_size / upem;
|
|
* pos.x = pen_x + scale * extent_x;
|
|
* pos.y = pen_y - scale * extent_y;
|
|
* ]|
|
|
*
|
|
* If you do set a font scale (e.g. for hinting), the encoded
|
|
* blob and extents will be in the scaled coordinate space,
|
|
* and you must adjust emPerPos accordingly.
|
|
*
|
|
* ## Dilation
|
|
*
|
|
* Each glyph is rendered on a screen-aligned quad whose
|
|
* corners match the glyph's bounding box. Without dilation,
|
|
* the antialiased edges at the quad boundary get clipped — the
|
|
* fragment shader needs at least half a pixel of padding
|
|
* around the glyph to produce smooth coverage gradients.
|
|
*
|
|
* hb_gpu_dilate computes a perspective-correct half-pixel
|
|
* expansion. It adjusts both the vertex position (expanding
|
|
* the quad) and the texcoord (so the fragment shader samples
|
|
* the right location in em-space after expansion).
|
|
*
|
|
* The `jac` parameter maps object-space displacements back to
|
|
* em-space. For the common case of uniform scaling with
|
|
* y-flip (`pos.y = pen_y - scale * ey`):
|
|
*
|
|
* |[<!-- language="plain" -->
|
|
* float emPerPos = upem / font_size;
|
|
* jac = vec4(emPerPos, 0.0, 0.0, -emPerPos);
|
|
* ]|
|
|
*
|
|
* For non-uniform scaling or shearing transforms, jac is the
|
|
* 2x2 inverse of the em-to-object linear transform, stored
|
|
* row-major.
|
|
*
|
|
* ### Static dilation alternative
|
|
*
|
|
* Applications that do not need perspective correctness (e.g.
|
|
* strictly 2D rendering at known sizes) can skip hb_gpu_dilate
|
|
* and instead expand each quad vertex by a fixed amount along
|
|
* its normal, based on the minimum expected font size:
|
|
*
|
|
* |[<!-- language="plain" -->
|
|
* float min_ppem = 10.0; // smallest expected size in pixels
|
|
* float pad = 0.5 * upem / min_ppem; // half-pixel in em units
|
|
* pos += normal * pad * scale;
|
|
* texcoord += normal * pad;
|
|
* ]|
|
|
*
|
|
* This over-dilates at larger sizes (wasting fill rate on
|
|
* transparent pixels) but is simpler to implement and avoids
|
|
* the need for the MVP matrix and viewport size in the vertex
|
|
* shader.
|
|
*
|
|
* ## Fragment shader
|
|
*
|
|
* The fragment library provides two functions:
|
|
*
|
|
* |[<!-- language="plain" -->
|
|
* float hb_gpu_draw (vec2 renderCoord, uint glyphLoc);
|
|
* ]|
|
|
*
|
|
* It requires the `hb_gpu_atlas` uniform to be bound to the
|
|
* texture containing the encoded glyph data. By default this
|
|
* is an `isamplerBuffer` (GL_TEXTURE_BUFFER). For platforms
|
|
* without texture buffers (e.g. WebGL2), define
|
|
* `HB_GPU_ATLAS_2D` before including the shader source; the
|
|
* atlas then becomes an `isampler2D` and a
|
|
* `uniform int hb_gpu_atlas_width` must also be set to the
|
|
* texture width.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* - renderCoord: the interpolated em-space coordinate from
|
|
* the vertex shader (v_texcoord).
|
|
*
|
|
* - glyphLoc: the texel offset of this glyph's encoded blob
|
|
* in the atlas buffer. Passed as a flat varying from the
|
|
* vertex shader.
|
|
*
|
|
* Returns the coverage in [0, 1]: 1.0 inside the glyph, 0.0
|
|
* outside, with antialiased edges.
|
|
*
|
|
* A typical fragment main:
|
|
*
|
|
* |[<!-- language="plain" -->
|
|
* in vec2 v_texcoord;
|
|
* flat in uint v_glyphLoc;
|
|
* out vec4 fragColor;
|
|
*
|
|
* void main () {
|
|
* float coverage = hb_gpu_draw (v_texcoord, v_glyphLoc);
|
|
* fragColor = vec4 (0.0, 0.0, 0.0, coverage);
|
|
* }
|
|
* ]|
|
|
*
|
|
* The coverage value can be used with alpha blending
|
|
* (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) to composite
|
|
* over a background, or multiplied with any color.
|
|
*
|
|
* ## Stem darkening
|
|
*
|
|
* |[<!-- language="plain" -->
|
|
* float hb_gpu_stem_darken (float coverage, float brightness, float ppem);
|
|
* ]|
|
|
*
|
|
* Optional stem darkening adjusts coverage at small sizes so
|
|
* thin stems are not washed out by gamma correction.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* - coverage: a coverage / alpha value in [0, 1]. For
|
|
* hb_gpu_draw() this is the returned coverage; for
|
|
* hb_gpu_paint() use the edge coverage out parameter.
|
|
*
|
|
* - brightness: brightness of the color that will end up on
|
|
* screen for this fragment, in [0, 1], computed as
|
|
* `dot (straight_color.rgb, vec3 (1.0 / 3.0))`.
|
|
*
|
|
* - ppem: pixels per em at this fragment, computed as
|
|
* `1.0 / max (fwidth (v_texcoord).x, fwidth (v_texcoord).y)`.
|
|
*
|
|
* Example — draw path:
|
|
*
|
|
* |[<!-- language="plain" -->
|
|
* float coverage = hb_gpu_draw (v_texcoord, v_glyphLoc);
|
|
* float brightness = dot (u_foreground.rgb, vec3 (1.0 / 3.0));
|
|
* float ppem = 1.0 / max (fwidth (v_texcoord).x,
|
|
* fwidth (v_texcoord).y);
|
|
* coverage = hb_gpu_stem_darken (coverage, brightness, ppem);
|
|
* ]|
|
|
*
|
|
* Example — paint path: hb_gpu_paint() returns a separate
|
|
* edge coverage value that tracks the maximum antialiasing
|
|
* coverage across paint layers. Apply stem darkening and gamma to this
|
|
* edge coverage, then scale the premultiplied color to match.
|
|
* Interior fragments (coverage == 1) are left untouched.
|
|
*
|
|
* |[<!-- language="plain" -->
|
|
* float cov;
|
|
* vec4 c = hb_gpu_paint (v_texcoord, v_glyphLoc, u_foreground, cov);
|
|
* if (cov > 0.0 && cov < 1.0) {
|
|
* float brightness = c.a > 0.0
|
|
* ? dot (c.rgb, vec3 (1.0 / 3.0)) / c.a : 0.0;
|
|
* float ppem = 1.0 / max (fwidth (v_texcoord).x,
|
|
* fwidth (v_texcoord).y);
|
|
* float adj = hb_gpu_stem_darken (cov, brightness, ppem);
|
|
* c *= adj / cov;
|
|
* }
|
|
* ]|
|
|
*
|
|
* # Paint
|
|
*
|
|
* The paint renderer walks the font's paint tree (COLRv0 layers
|
|
* or COLRv1 paint subtree) and records one layer op per solid or
|
|
* gradient fill, each with its own clip outline encoded as a Slug
|
|
* (so the paint renderer reuses the draw renderer internally for
|
|
* clips). Palette colors and custom overrides are resolved and
|
|
* baked into the blob at encode time, so the shader does not need
|
|
* a separate palette uniform.
|
|
*
|
|
* Monochrome (non-color) glyphs are handled transparently:
|
|
* hb_gpu_paint_glyph() synthesizes a single foreground-colored
|
|
* layer from the glyph's outline, so callers can use the paint
|
|
* renderer uniformly for any font. This costs more per fragment
|
|
* than the Draw path, but the rendered result is the same.
|
|
*
|
|
* ## Encoding
|
|
*
|
|
* |[<!-- language="plain" -->
|
|
* hb_gpu_paint_t *paint = hb_gpu_paint_create_or_fail ();
|
|
*
|
|
* // Optional: select a palette and install any custom-palette
|
|
* // overrides before hb_gpu_paint_glyph — their values are baked
|
|
* // into the encoded blob. (The foreground color is NOT set here:
|
|
* // it stays a shader uniform so dark-mode and color-change
|
|
* // toggles take effect without re-encoding.)
|
|
* hb_gpu_paint_set_palette (paint, 0);
|
|
* hb_gpu_paint_set_custom_palette_color (paint, 2,
|
|
* HB_COLOR (0xff, 0, 0, 0xff));
|
|
*
|
|
* hb_gpu_paint_glyph (paint, font, gid);
|
|
* hb_glyph_extents_t ext;
|
|
* hb_blob_t *blob = hb_gpu_paint_encode (paint, &ext);
|
|
*
|
|
* // Upload hb_blob_get_data(blob) to the same atlas used by draw.
|
|
* unsigned atlas_offset = upload_to_atlas (blob);
|
|
*
|
|
* hb_gpu_paint_recycle_blob (paint, blob);
|
|
* // repeat for more glyphs...
|
|
*
|
|
* hb_gpu_paint_destroy (paint);
|
|
* ]|
|
|
*
|
|
* As with the draw encoder, create the paint encoder once and
|
|
* reuse it. hb_gpu_paint_encode() auto-clears on return; user
|
|
* configuration (palette, custom-palette overrides) is preserved
|
|
* across encodes. Because colors are baked, changing any of that
|
|
* configuration afterwards requires re-encoding the affected
|
|
* glyphs. The encoded blob's texel format is the same RGBA16I
|
|
* as the draw renderer's, so both kinds of blobs can coexist in
|
|
* one atlas at different offsets.
|
|
*
|
|
* ## Shader composition
|
|
*
|
|
* Same pattern as the draw renderer but using
|
|
* hb_gpu_paint_shader_source() for the paint-specific helpers.
|
|
* The vertex stage is identical — hb_gpu_paint_shader_source()
|
|
* returns an empty string for HB_GPU_SHADER_STAGE_VERTEX, so the
|
|
* fixed assembly order still works:
|
|
*
|
|
* |[<!-- language="plain" -->
|
|
* const char *frag_sources[] = {
|
|
* "#version 330\n",
|
|
* hb_gpu_shader_source (HB_GPU_SHADER_STAGE_FRAGMENT,
|
|
* HB_GPU_SHADER_LANG_GLSL),
|
|
* hb_gpu_paint_shader_source (HB_GPU_SHADER_STAGE_FRAGMENT,
|
|
* HB_GPU_SHADER_LANG_GLSL),
|
|
* your_fragment_main
|
|
* };
|
|
* glShaderSource (frag_shader, 4, frag_sources, NULL);
|
|
* ]|
|
|
*
|
|
* The atlas setup, vertex attributes, dilation, and font scaling
|
|
* guidance from the Draw section all apply unchanged.
|
|
*
|
|
* ## Fragment shader
|
|
*
|
|
* The paint library provides one function:
|
|
*
|
|
* |[<!-- language="plain" -->
|
|
* vec4 hb_gpu_paint (vec2 renderCoord, uint glyphLoc, vec4 foreground,
|
|
* out float coverage);
|
|
* ]|
|
|
*
|
|
* Parameters:
|
|
*
|
|
* - renderCoord: the interpolated em-space coordinate from the
|
|
* vertex shader (v_texcoord), as for hb_gpu_draw().
|
|
*
|
|
* - glyphLoc: the texel offset of this glyph's encoded paint blob
|
|
* in the atlas, passed as a flat varying from the vertex shader.
|
|
*
|
|
* - foreground: the foreground color used to resolve palette
|
|
* entries that COLRv1 marks as "foreground color". The encoder
|
|
* only records the is-foreground flag per layer/stop; the actual
|
|
* color is substituted here at render time, so runtime
|
|
* foreground-color changes (e.g. a dark-mode toggle) take effect
|
|
* without re-encoding any glyphs.
|
|
*
|
|
* - coverage (out): the maximum antialiasing coverage across all
|
|
* paint layers. Fractional values (between 0 and 1) indicate
|
|
* antialiased edge pixels; 0 means fully outside, 1 means fully
|
|
* inside. Stem darkening and gamma correction should be applied
|
|
* to this value rather than to the returned color, so that
|
|
* interior paint colors are unaffected. See the stem darkening
|
|
* notes in the Draw section.
|
|
*
|
|
* Returns premultiplied RGBA: fully transparent outside the glyph,
|
|
* composited layers inside. Use (GL_ONE, GL_ONE_MINUS_SRC_ALPHA)
|
|
* blending to composite over a background.
|
|
*
|
|
* A typical fragment main:
|
|
*
|
|
* |[<!-- language="plain" -->
|
|
* uniform vec4 u_foreground;
|
|
* uniform float u_gamma;
|
|
* uniform float u_stem_darkening;
|
|
* in vec2 v_texcoord;
|
|
* flat in uint v_glyphLoc;
|
|
* out vec4 fragColor;
|
|
*
|
|
* void main () {
|
|
* float cov;
|
|
* vec4 c = hb_gpu_paint (v_texcoord, v_glyphLoc, u_foreground, cov);
|
|
* if (cov > 0.0 && cov < 1.0) {
|
|
* float adj = cov;
|
|
* if (u_stem_darkening > 0.0) {
|
|
* float brightness = c.a > 0.0
|
|
* ? dot (c.rgb, vec3 (1.0 / 3.0)) / c.a : 0.0;
|
|
* adj = hb_gpu_stem_darken (adj, brightness,
|
|
* 1.0 / max (fwidth (v_texcoord).x, fwidth (v_texcoord).y));
|
|
* }
|
|
* if (u_gamma != 1.0)
|
|
* adj = pow (adj, u_gamma);
|
|
* c *= adj / cov;
|
|
* }
|
|
* fragColor = c;
|
|
* }
|
|
* ]|
|
|
**/
|
|
|
|
|
|
#include "hb-gpu-fragment-glsl.hh"
|
|
#include "hb-gpu-fragment-msl.hh"
|
|
#include "hb-gpu-fragment-wgsl.hh"
|
|
#include "hb-gpu-fragment-hlsl.hh"
|
|
#include "hb-gpu-vertex-glsl.hh"
|
|
#include "hb-gpu-vertex-msl.hh"
|
|
#include "hb-gpu-vertex-wgsl.hh"
|
|
#include "hb-gpu-vertex-hlsl.hh"
|
|
|
|
/**
|
|
* hb_gpu_shader_source:
|
|
* @stage: pipeline stage (vertex or fragment)
|
|
* @lang: shader language variant
|
|
*
|
|
* Returns the shared helper shader source used by the hb-gpu
|
|
* renderers for the specified stage and language. The returned
|
|
* string is static and must not be freed.
|
|
*
|
|
* The shared source defines utilities such as the atlas sampler
|
|
* and the `hb_gpu_fetch()` accessor for the fragment stage, and
|
|
* the `hb_gpu_dilate()` helper for the vertex stage. Each
|
|
* renderer-specific source (for example,
|
|
* hb_gpu_draw_shader_source()) assumes these helpers are already
|
|
* in scope — callers should concatenate a `#version` directive,
|
|
* then this shared source, then the renderer-specific source,
|
|
* then their own `main()`.
|
|
*
|
|
* Return value: (transfer none):
|
|
* A shader source string, or `NULL` if @stage or @lang is
|
|
* unsupported.
|
|
*
|
|
* Since: 14.2.0
|
|
**/
|
|
const char *
|
|
hb_gpu_shader_source (hb_gpu_shader_stage_t stage,
|
|
hb_gpu_shader_lang_t lang)
|
|
{
|
|
switch (stage) {
|
|
case HB_GPU_SHADER_STAGE_FRAGMENT:
|
|
switch (lang) {
|
|
case HB_GPU_SHADER_LANG_GLSL: return hb_gpu_fragment_glsl;
|
|
case HB_GPU_SHADER_LANG_MSL: return hb_gpu_fragment_msl;
|
|
case HB_GPU_SHADER_LANG_WGSL: return hb_gpu_fragment_wgsl;
|
|
case HB_GPU_SHADER_LANG_HLSL: return hb_gpu_fragment_hlsl;
|
|
case HB_GPU_SHADER_LANG_INVALID:
|
|
default: return nullptr;
|
|
}
|
|
case HB_GPU_SHADER_STAGE_VERTEX:
|
|
switch (lang) {
|
|
case HB_GPU_SHADER_LANG_GLSL: return hb_gpu_vertex_glsl;
|
|
case HB_GPU_SHADER_LANG_MSL: return hb_gpu_vertex_msl;
|
|
case HB_GPU_SHADER_LANG_WGSL: return hb_gpu_vertex_wgsl;
|
|
case HB_GPU_SHADER_LANG_HLSL: return hb_gpu_vertex_hlsl;
|
|
case HB_GPU_SHADER_LANG_INVALID:
|
|
default: return nullptr;
|
|
}
|
|
default:
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
|