mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-05 01:15:35 +00:00
gpu/internal/shaders: generate shader variants
We're about to add Direct3D support, where shaders are written in HLSL. Rather than write shaders twice (or more), convert them to a GLSL variant understood by the glslcc cross-compiler and generate the OpenGL ES 2.0 and HLSL variants. The HLSL is used by a future change. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+16
-233
@@ -91,7 +91,7 @@ func newPather(ctx Backend) *pather {
|
||||
}
|
||||
|
||||
func newCoverer(ctx Backend) *coverer {
|
||||
prog, err := createColorPrograms(ctx, coverVSrc, coverFSrc)
|
||||
prog, err := createColorPrograms(ctx, shader_cover_vert, shader_cover_frag)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -104,29 +104,29 @@ func newCoverer(ctx Backend) *coverer {
|
||||
case materialTexture:
|
||||
uTex := prog.UniformFor("tex")
|
||||
prog.Uniform1i(uTex, 0)
|
||||
c.vars[i].uUVScale = prog.UniformFor("uvScale")
|
||||
c.vars[i].uUVOffset = prog.UniformFor("uvOffset")
|
||||
c.vars[i].uUVScale = prog.UniformFor("uniforms.uvScale")
|
||||
c.vars[i].uUVOffset = prog.UniformFor("uniforms.uvOffset")
|
||||
case materialColor:
|
||||
c.vars[i].uColor = prog.UniformFor("color")
|
||||
c.vars[i].uColor = prog.UniformFor("color.color")
|
||||
}
|
||||
uCover := prog.UniformFor("cover")
|
||||
prog.Uniform1i(uCover, 1)
|
||||
c.vars[i].z = prog.UniformFor("z")
|
||||
c.vars[i].uScale = prog.UniformFor("scale")
|
||||
c.vars[i].uOffset = prog.UniformFor("offset")
|
||||
c.vars[i].uCoverUVScale = prog.UniformFor("uvCoverScale")
|
||||
c.vars[i].uCoverUVOffset = prog.UniformFor("uvCoverOffset")
|
||||
c.vars[i].z = prog.UniformFor("uniforms.z")
|
||||
c.vars[i].uScale = prog.UniformFor("uniforms.scale")
|
||||
c.vars[i].uOffset = prog.UniformFor("uniforms.offset")
|
||||
c.vars[i].uCoverUVScale = prog.UniformFor("uniforms.uvCoverScale")
|
||||
c.vars[i].uCoverUVOffset = prog.UniformFor("uniforms.uvCoverOffset")
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func newStenciler(ctx Backend) *stenciler {
|
||||
defFBO := ctx.DefaultFramebuffer()
|
||||
prog, err := ctx.NewProgram(stencilVSrc, stencilFSrc, pathAttribs)
|
||||
prog, err := ctx.NewProgram(shader_stencil_vert, shader_stencil_frag, pathAttribs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
iprog, err := ctx.NewProgram(intersectVSrc, intersectFSrc, intersectAttribs)
|
||||
iprog, err := ctx.NewProgram(shader_intersect_vert, shader_intersect_frag, intersectAttribs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -149,11 +149,11 @@ func newStenciler(ctx Backend) *stenciler {
|
||||
defFBO: defFBO,
|
||||
prog: prog,
|
||||
iprog: iprog,
|
||||
uScale: prog.UniformFor("scale"),
|
||||
uOffset: prog.UniformFor("offset"),
|
||||
uPathOffset: prog.UniformFor("pathOffset"),
|
||||
uIntersectUVScale: iprog.UniformFor("uvScale"),
|
||||
uIntersectUVOffset: iprog.UniformFor("uvOffset"),
|
||||
uScale: prog.UniformFor("uniforms.scale"),
|
||||
uOffset: prog.UniformFor("uniforms.offset"),
|
||||
uPathOffset: prog.UniformFor("uniforms.pathOffset"),
|
||||
uIntersectUVScale: iprog.UniformFor("uvparams.scale"),
|
||||
uIntersectUVOffset: iprog.UniformFor("uvparams.offset"),
|
||||
indexBuf: indexBuf,
|
||||
}
|
||||
}
|
||||
@@ -328,220 +328,3 @@ func (c *coverer) cover(z float32, mat materialType, col [4]float32, scale, off,
|
||||
p.Uniform2f(c.vars[mat].uCoverUVOffset, coverOff.X, coverOff.Y)
|
||||
c.ctx.DrawArrays(DrawModeTriangleStrip, 0, 4)
|
||||
}
|
||||
|
||||
const stencilVSrc = `
|
||||
#version 100
|
||||
|
||||
precision highp float;
|
||||
|
||||
uniform vec2 scale;
|
||||
uniform vec2 offset;
|
||||
uniform vec2 pathOffset;
|
||||
|
||||
attribute vec2 corner;
|
||||
attribute float maxy;
|
||||
attribute vec2 from;
|
||||
attribute vec2 ctrl;
|
||||
attribute vec2 to;
|
||||
|
||||
varying vec2 vFrom;
|
||||
varying vec2 vCtrl;
|
||||
varying vec2 vTo;
|
||||
|
||||
void main() {
|
||||
// Add a one pixel overlap so curve quads cover their
|
||||
// entire curves. Could use conservative rasterization
|
||||
// if available.
|
||||
vec2 from = from + pathOffset;
|
||||
vec2 ctrl = ctrl + pathOffset;
|
||||
vec2 to = to + pathOffset;
|
||||
float maxy = maxy + pathOffset.y;
|
||||
vec2 pos;
|
||||
if (corner.x > 0.0) {
|
||||
// East.
|
||||
pos.x = max(max(from.x, ctrl.x), to.x)+1.0;
|
||||
} else {
|
||||
// West.
|
||||
pos.x = min(min(from.x, ctrl.x), to.x)-1.0;
|
||||
}
|
||||
if (corner.y > 0.0) {
|
||||
// North.
|
||||
pos.y = maxy + 1.0;
|
||||
} else {
|
||||
// South.
|
||||
pos.y = min(min(from.y, ctrl.y), to.y) - 1.0;
|
||||
}
|
||||
vFrom = from-pos;
|
||||
vCtrl = ctrl-pos;
|
||||
vTo = to-pos;
|
||||
pos *= scale;
|
||||
pos += offset;
|
||||
gl_Position = vec4(pos, 1, 1);
|
||||
}
|
||||
`
|
||||
|
||||
const stencilFSrc = `
|
||||
#version 100
|
||||
|
||||
precision mediump float;
|
||||
|
||||
varying vec2 vFrom;
|
||||
varying vec2 vCtrl;
|
||||
varying vec2 vTo;
|
||||
|
||||
uniform sampler2D areaLUT;
|
||||
|
||||
void main() {
|
||||
float dx = vTo.x - vFrom.x;
|
||||
// Sort from and to in increasing order so the root below
|
||||
// is always the positive square root, if any.
|
||||
// We need the direction of the curve below, so this can't be
|
||||
// done from the vertex shader.
|
||||
bool increasing = vTo.x >= vFrom.x;
|
||||
vec2 left = increasing ? vFrom : vTo;
|
||||
vec2 right = increasing ? vTo : vFrom;
|
||||
|
||||
// The signed horizontal extent of the fragment.
|
||||
vec2 extent = clamp(vec2(vFrom.x, vTo.x), -0.5, 0.5);
|
||||
// Find the t where the curve crosses the middle of the
|
||||
// extent, x₀.
|
||||
// Given the Bézier curve with x coordinates P₀, P₁, P₂
|
||||
// where P₀ is at the origin, its x coordinate in t
|
||||
// is given by:
|
||||
//
|
||||
// x(t) = 2(1-t)tP₁ + t²P₂
|
||||
//
|
||||
// Rearranging:
|
||||
//
|
||||
// x(t) = (P₂ - 2P₁)t² + 2P₁t
|
||||
//
|
||||
// Setting x(t) = x₀ and using Muller's quadratic formula ("Citardauq")
|
||||
// for robustnesss,
|
||||
//
|
||||
// t = 2x₀/(2P₁±√(4P₁²+4(P₂-2P₁)x₀))
|
||||
//
|
||||
// which simplifies to
|
||||
//
|
||||
// t = x₀/(P₁±√(P₁²+(P₂-2P₁)x₀))
|
||||
//
|
||||
// Setting v = P₂-P₁,
|
||||
//
|
||||
// t = x₀/(P₁±√(P₁²+(v-P₁)x₀))
|
||||
//
|
||||
// t lie in [0; 1]; P₂ ≥ P₁ and P₁ ≥ 0 since we split curves where
|
||||
// the control point lies before the start point or after the end point.
|
||||
// It can then be shown that only the positive square root is valid.
|
||||
float midx = mix(extent.x, extent.y, 0.5);
|
||||
float x0 = midx - left.x;
|
||||
vec2 p1 = vCtrl - left;
|
||||
vec2 v = right - vCtrl;
|
||||
float t = x0/(p1.x+sqrt(p1.x*p1.x+(v.x-p1.x)*x0));
|
||||
// Find y(t) on the curve.
|
||||
float y = mix(mix(left.y, vCtrl.y, t), mix(vCtrl.y, right.y, t), t);
|
||||
// And the slope.
|
||||
vec2 d_half = mix(p1, v, t);
|
||||
float dy = d_half.y/d_half.x;
|
||||
// Together, y and dy form a line approximation.
|
||||
|
||||
// Compute the fragment area above the line.
|
||||
// The area is symmetric around dy = 0. Scale slope with extent width.
|
||||
float width = extent.y - extent.x;
|
||||
dy = abs(dy*width);
|
||||
|
||||
vec4 sides = vec4(dy*+0.5 + y, dy*-0.5 + y, (+0.5-y)/dy, (-0.5-y)/dy);
|
||||
sides = clamp(sides+0.5, 0.0, 1.0);
|
||||
|
||||
float area = 0.5*(sides.z - sides.z*sides.y + 1.0 - sides.x+sides.x*sides.w);
|
||||
area *= width;
|
||||
|
||||
// Work around issue #13.
|
||||
if (width == 0.0)
|
||||
area = 0.0;
|
||||
|
||||
gl_FragColor.r = area;
|
||||
}
|
||||
`
|
||||
|
||||
const coverVSrc = `
|
||||
#version 100
|
||||
|
||||
precision highp float;
|
||||
|
||||
uniform float z;
|
||||
uniform vec2 scale;
|
||||
uniform vec2 offset;
|
||||
uniform vec2 uvScale;
|
||||
uniform vec2 uvOffset;
|
||||
uniform vec2 uvCoverScale;
|
||||
uniform vec2 uvCoverOffset;
|
||||
|
||||
attribute vec2 pos;
|
||||
|
||||
varying vec2 vCoverUV;
|
||||
|
||||
attribute vec2 uv;
|
||||
varying vec2 vUV;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(pos*scale + offset, z, 1);
|
||||
vUV = uv*uvScale + uvOffset;
|
||||
vCoverUV = uv*uvCoverScale+uvCoverOffset;
|
||||
}
|
||||
`
|
||||
|
||||
const coverFSrc = `
|
||||
#version 100
|
||||
|
||||
precision mediump float;
|
||||
|
||||
// Use high precision to be pixel accurate for
|
||||
// large cover atlases.
|
||||
varying highp vec2 vCoverUV;
|
||||
uniform sampler2D cover;
|
||||
varying vec2 vUV;
|
||||
|
||||
HEADER
|
||||
|
||||
void main() {
|
||||
gl_FragColor = GET_COLOR;
|
||||
float cover = abs(texture2D(cover, vCoverUV).r);
|
||||
gl_FragColor *= cover;
|
||||
}
|
||||
`
|
||||
|
||||
const intersectVSrc = `
|
||||
#version 100
|
||||
|
||||
precision highp float;
|
||||
|
||||
attribute vec2 pos;
|
||||
attribute vec2 uv;
|
||||
|
||||
uniform vec2 uvScale;
|
||||
uniform vec2 uvOffset;
|
||||
|
||||
varying vec2 vUV;
|
||||
|
||||
void main() {
|
||||
vec2 p = pos;
|
||||
p.y = -p.y;
|
||||
gl_Position = vec4(p, 0, 1);
|
||||
vUV = uv*uvScale + uvOffset;
|
||||
}
|
||||
`
|
||||
|
||||
const intersectFSrc = `
|
||||
#version 100
|
||||
|
||||
precision mediump float;
|
||||
|
||||
// Use high precision to be pixel accurate for
|
||||
// large cover atlases.
|
||||
varying highp vec2 vUV;
|
||||
uniform sampler2D cover;
|
||||
|
||||
void main() {
|
||||
float cover = abs(texture2D(cover, vUV).r);
|
||||
gl_FragColor.r = cover;
|
||||
}
|
||||
`
|
||||
|
||||
Reference in New Issue
Block a user