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:
Elias Naur
2020-02-16 21:53:19 +01:00
parent 1f43bfa0e4
commit ac7029fa24
15 changed files with 1263 additions and 301 deletions
+27 -1
View File
@@ -23,7 +23,7 @@ type Backend interface {
NilTexture() Texture
NewFramebuffer() Framebuffer
NewBuffer(typ BufferType, data []byte) Buffer
NewProgram(vertexShader, fragmentShader string, attribMap []string) (Program, error)
NewProgram(vertexShader, fragmentShader ShaderSources, attribMap []string) (Program, error)
SetupVertexArray(slot int, size int, dataType DataType, stride, offset int)
DepthFunc(f DepthFunc)
@@ -39,6 +39,32 @@ type Backend interface {
BlendFunc(sfactor, dfactor BlendFactor)
}
type ShaderSources struct {
GLES2 string
HLSL []byte
Uniforms []UniformLocation
Inputs []InputLocation
}
type UniformLocation struct {
Name string
Type DataType
Size int
Offset int
}
type InputLocation struct {
// For GLSL.
Name string
Location int
// For HLSL.
Semantic string
SemanticIndex int
Type DataType
Size int
}
type BlendFactor uint8
type DrawMode uint8
+361
View File
@@ -0,0 +1,361 @@
// SPDX-License-Identifier: Unlicense OR MIT
// +build ignore
package main
import (
"bytes"
"encoding/json"
"fmt"
"go/format"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"sort"
"strings"
"text/template"
)
// This program generates shader variants for
// multiple GPU backends (OpenGL ES, Direct3D 11...)
// from a single source.
type shaderArgs struct {
FetchColorExpr string
Header string
}
// InputLocation matches gpu.InputLocation.
type InputLocation struct {
Name string
Location int
Semantic string
SemanticIndex int
Type DataType
Size int
}
type DataType uint8
// UniformLocation matches gpu.UniformLocation.
type UniformLocation struct {
Name string
Type DataType
Size int
Offset int
}
const (
DataTypeFloat DataType = iota
DataTypeShort
)
func main() {
if err := generate(); err != nil {
fmt.Fprintf(os.Stderr, "gpu generate: %v\n", err)
os.Exit(1)
}
}
func generate() error {
tmp, err := ioutil.TempDir("", "gpu-generate")
if err != nil {
return err
}
defer os.RemoveAll(tmp)
glslcc, err := exec.LookPath("glslcc")
if err != nil {
return err
}
fxc, err := exec.LookPath("fxc")
fxcFound := err == nil
shaders, err := filepath.Glob("shaders/*")
if err != nil {
return err
}
var out bytes.Buffer
out.WriteString("// Code generated by build.go. DO NOT EDIT.\n\n")
out.WriteString("package gpu\n\n")
out.WriteString("var (\n")
for _, shader := range shaders {
const nvariants = 2
var variants [nvariants]struct {
gles2 string
hlslSrc string
hlsl []byte
inputs []InputLocation
uniforms []UniformLocation
}
args := [nvariants]shaderArgs{
{
FetchColorExpr: `color.color`,
Header: `layout(binding=0) uniform Color { vec4 color; } color;`,
},
{
FetchColorExpr: `texture(tex, vUV)`,
Header: `layout(binding=0) uniform sampler2D tex;`,
},
}
for i := range args {
gles2, reflect, err := convertShader(tmp, glslcc, shader, "gles", "100", &args[i], false)
if err != nil {
return err
}
// Make the GL ES 2 source compatible with desktop GL 3.
gles2 = "#version 100\n" + gles2
inputs, uniforms, err := parseReflection(reflect)
if err != nil {
return err
}
hlsl, _, err := convertShader(tmp, glslcc, shader, "hlsl", "40", &args[i], false)
if err != nil {
return err
}
var hlslProf string
switch filepath.Ext(shader) {
case ".frag":
hlslProf = "ps"
case ".vert":
hlslProf = "vs"
default:
return fmt.Errorf("unrecognized shader type %s", shader)
}
var hlslc []byte
if fxcFound {
hlslc, err = compileHLSL(tmp, fxc, hlsl, "main", hlslProf+"_4_0")
if err != nil {
return err
}
}
variants[i].gles2 = gles2
variants[i].hlslSrc = hlsl
variants[i].hlsl = hlslc
variants[i].inputs = inputs
variants[i].uniforms = uniforms
}
name := filepath.Base(shader)
name = strings.ReplaceAll(name, ".", "_")
fmt.Fprintf(&out, "\tshader_%s = ", name)
// If the shader don't use the variant arguments, output
// only a single version.
multiVariant := variants[0].gles2 != variants[1].gles2
if multiVariant {
fmt.Fprintf(&out, "[...]ShaderSources{\n")
}
for _, src := range variants {
fmt.Fprintf(&out, "ShaderSources{\n")
if len(src.inputs) > 0 {
fmt.Fprintf(&out, "Inputs: []InputLocation{\n")
for _, inp := range src.inputs {
fmt.Fprintf(&out, "{Name: %q, Location: %d, Semantic: %q, ", inp.Name, inp.Location, inp.Semantic)
fmt.Fprintf(&out, "SemanticIndex: %d, Type: %d, Size: %d},\n", inp.SemanticIndex, inp.Type, inp.Size)
}
fmt.Fprintf(&out, "},\n")
}
if len(src.uniforms) > 0 {
fmt.Fprintf(&out, "Uniforms: []UniformLocation{\n")
for _, u := range src.uniforms {
fmt.Fprintf(&out, "{Name: %q, Type: %d, Size: %d, Offset: %d},\n", u.Name, u.Type, u.Size, u.Offset)
}
fmt.Fprintf(&out, "},\n")
}
fmt.Fprintf(&out, "GLES2: %#v,\n", src.gles2)
fmt.Fprintf(&out, "/*\n%s\n*/\n", src.hlslSrc)
fmt.Fprintf(&out, "HLSL: %#v,\n", src.hlsl)
fmt.Fprintf(&out, "}")
if multiVariant {
fmt.Fprintf(&out, ",")
}
fmt.Fprintf(&out, "\n")
if !multiVariant {
break
}
}
if multiVariant {
fmt.Fprintf(&out, "}\n")
}
}
out.WriteString(")")
gosrc, err := format.Source(out.Bytes())
if err != nil {
return fmt.Errorf("shader.go: %v", err)
}
return ioutil.WriteFile("shaders.go", gosrc, 0644)
}
func parseReflection(jsonData []byte) ([]InputLocation, []UniformLocation, error) {
type InputReflection struct {
ID int `json:"id"`
Name string `json:"name"`
Location int `json:"location"`
Semantic string `json:"semantic"`
SemanticIndex int `json:"semantic_index"`
Type string `json:"type"`
}
type UniformMemberReflection struct {
Name string `json:"name"`
Type string `json:"type"`
Offset int `json:"offset"`
Size int `json:"size"`
}
type UniformBufferReflection struct {
ID int `json:"id"`
Name string `json:"name"`
Set int `json:"set"`
Binding int `json:"binding"`
Size int `json:"block_size"`
Members []UniformMemberReflection `json:"members"`
}
type shaderReflection struct {
Inputs []InputReflection `json:"inputs"`
UniformBuffers []UniformBufferReflection `json:"uniform_buffers"`
}
type shaderMetadata struct {
VS shaderReflection `json:"vs"`
FS shaderReflection `json:"fs"`
}
var reflect shaderMetadata
if err := json.Unmarshal(jsonData, &reflect); err != nil {
return nil, nil, fmt.Errorf("parseReflection: %v", err)
}
var inputs []InputLocation
inputRef := reflect.VS.Inputs
for _, input := range inputRef {
dataType, dataSize, err := parseDataType(input.Type)
if err != nil {
return nil, nil, err
}
inputs = append(inputs, InputLocation{
Name: input.Name,
Location: input.Location,
Semantic: input.Semantic,
SemanticIndex: input.SemanticIndex,
Type: dataType,
Size: dataSize,
})
}
sort.Slice(inputs, func(i, j int) bool {
return inputs[i].Location < inputs[j].Location
})
var ublocks []UniformLocation
shaderBlocks := reflect.VS.UniformBuffers
if len(shaderBlocks) == 0 {
shaderBlocks = reflect.FS.UniformBuffers
}
for _, block := range shaderBlocks {
for _, member := range block.Members {
dataType, size, err := parseDataType(member.Type)
if err != nil {
return nil, nil, err
}
ublocks = append(ublocks, UniformLocation{
// Synthetic name generated by glslcc.
Name: fmt.Sprintf("_%d.%s", block.ID, member.Name),
Type: dataType,
Size: size,
Offset: member.Offset,
})
}
}
return inputs, ublocks, nil
}
func parseDataType(t string) (DataType, int, error) {
switch t {
case "float":
return DataTypeFloat, 1, nil
case "float2":
return DataTypeFloat, 2, nil
case "float3":
return DataTypeFloat, 3, nil
case "float4":
return DataTypeFloat, 4, nil
default:
return 0, 0, fmt.Errorf("unsupported input data type: %s", t)
}
}
func compileHLSL(tmp, fxc, src, entry, profile string) ([]byte, error) {
tmpfile := filepath.Join(tmp, "shader.hlsl")
if err := ioutil.WriteFile(tmpfile, []byte(src), 0644); err != nil {
return nil, err
}
outFile := filepath.Join(tmp, "shader.bin")
cmd := exec.Command(fxc,
"/T", profile,
"/E", entry,
"/nologo",
"/Fo", outFile,
tmpfile,
)
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return nil, err
}
return ioutil.ReadFile(outFile)
}
func convertShader(tmp, glslcc, path, lang, profile string, args *shaderArgs, flattenUBOs bool) (string, []byte, error) {
shaderTmpl, err := template.ParseFiles(path)
if err != nil {
return "", nil, err
}
var buf bytes.Buffer
if err := shaderTmpl.Execute(&buf, args); err != nil {
return "", nil, err
}
tmppath := filepath.Join(tmp, filepath.Base(path))
if err := ioutil.WriteFile(tmppath, buf.Bytes(), 0644); err != nil {
return "", nil, err
}
defer os.Remove(tmppath)
var progFlag string
var progSuffix string
switch filepath.Ext(path) {
case ".vert":
progFlag = "--vert"
progSuffix = "vs"
case ".frag":
progFlag = "--frag"
progSuffix = "fs"
default:
return "", nil, fmt.Errorf("unrecognized shader type: %s", path)
}
cmd := exec.Command(glslcc,
"--silent",
"--optimize",
"--reflect",
"--output", filepath.Join(tmp, "shader"),
"--lang", lang,
"--profile", profile,
progFlag, tmppath,
)
if flattenUBOs {
cmd.Args = append(cmd.Args, "--flatten-ubos")
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return "", nil, fmt.Errorf("%s: %v", path, err)
}
f, err := os.Open(filepath.Join(tmp, "shader_"+progSuffix))
if err != nil {
return "", nil, err
}
defer f.Close()
defer os.Remove(f.Name())
src, err := ioutil.ReadAll(f)
if err != nil {
return "", nil, err
}
reflect, err := ioutil.ReadFile(filepath.Join(tmp, "shader_"+progSuffix+".json"))
if err != nil {
return "", nil, err
}
return string(src), reflect, nil
}
+5
View File
@@ -0,0 +1,5 @@
// SPDX-License-Identifier: Unlicense OR MIT
package gpu
//go:generate go run build.go
+2 -2
View File
@@ -284,8 +284,8 @@ func (b *Backend) DepthFunc(f gpu.DepthFunc) {
b.funcs.DepthFunc(glfunc)
}
func (b *Backend) NewProgram(vssrc, fssrc string, attr []string) (gpu.Program, error) {
p, err := CreateProgram(b.funcs, vssrc, fssrc, attr)
func (b *Backend) NewProgram(vssrc, fssrc gpu.ShaderSources, attr []string) (gpu.Program, error) {
p, err := CreateProgram(b.funcs, vssrc.GLES2, fssrc.GLES2, attr)
if err != nil {
return nil, err
}
+10 -65
View File
@@ -13,7 +13,6 @@ import (
"image"
"image/color"
"math"
"strings"
"time"
"unsafe"
@@ -376,7 +375,7 @@ func (r *renderer) release() {
}
func newBlitter(ctx Backend) *blitter {
prog, err := createColorPrograms(ctx, blitVSrc, blitFSrc)
prog, err := createColorPrograms(ctx, shader_blit_vert, shader_blit_frag)
if err != nil {
panic(err)
}
@@ -398,14 +397,14 @@ func newBlitter(ctx Backend) *blitter {
case materialTexture:
uTex := prog.UniformFor("tex")
prog.Uniform1i(uTex, 0)
b.vars[i].uUVScale = prog.UniformFor("uvScale")
b.vars[i].uUVOffset = prog.UniformFor("uvOffset")
b.vars[i].uUVScale = prog.UniformFor("uniforms.uvScale")
b.vars[i].uUVOffset = prog.UniformFor("uniforms.uvOffset")
case materialColor:
b.vars[i].uColor = prog.UniformFor("color")
b.vars[i].uColor = prog.UniformFor("color.color")
}
b.vars[i].z = prog.UniformFor("z")
b.vars[i].uScale = prog.UniformFor("scale")
b.vars[i].uOffset = prog.UniformFor("offset")
b.vars[i].z = prog.UniformFor("uniforms.z")
b.vars[i].uScale = prog.UniformFor("uniforms.scale")
b.vars[i].uOffset = prog.UniformFor("uniforms.offset")
}
return b
}
@@ -417,28 +416,14 @@ func (b *blitter) release() {
}
}
func createColorPrograms(ctx Backend, vsSrc, fsSrc string) ([2]Program, error) {
func createColorPrograms(ctx Backend, vsSrc ShaderSources, fsSrc [2]ShaderSources) ([2]Program, error) {
var prog [2]Program
frep := strings.NewReplacer(
"HEADER", `
uniform sampler2D tex;
`,
"GET_COLOR", `texture2D(tex, vUV)`,
)
fsSrcTex := frep.Replace(fsSrc)
var err error
prog[materialTexture], err = ctx.NewProgram(vsSrc, fsSrcTex, blitAttribs)
prog[materialTexture], err = ctx.NewProgram(vsSrc, fsSrc[materialTexture], blitAttribs)
if err != nil {
return prog, err
}
frep = strings.NewReplacer(
"HEADER", `
uniform vec4 color;
`,
"GET_COLOR", `color`,
)
fsSrcCol := frep.Replace(fsSrc)
prog[materialColor], err = ctx.NewProgram(vsSrc, fsSrcCol, blitAttribs)
prog[materialColor], err = ctx.NewProgram(vsSrc, fsSrc[materialColor], blitAttribs)
if err != nil {
prog[materialTexture].Release()
return prog, err
@@ -949,43 +934,3 @@ func fillContourMaxY(maxy float32, verts []byte) {
bo.PutUint32(verts[i+off:], math.Float32bits(maxy))
}
}
const blitVSrc = `
#version 100
precision highp float;
uniform float z;
uniform vec2 scale;
uniform vec2 offset;
attribute vec2 pos;
attribute vec2 uv;
uniform vec2 uvScale;
uniform vec2 uvOffset;
varying vec2 vUV;
void main() {
vec2 p = pos;
p *= scale;
p += offset;
gl_Position = vec4(p, z, 1);
vUV = uv*uvScale + uvOffset;
}
`
const blitFSrc = `
#version 100
precision mediump float;
varying vec2 vUV;
HEADER
void main() {
gl_FragColor = GET_COLOR;
}
`
+16 -233
View File
@@ -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;
}
`
+574
View File
@@ -0,0 +1,574 @@
// Code generated by build.go. DO NOT EDIT.
package gpu
var (
shader_blit_frag = [...]ShaderSources{
ShaderSources{
Uniforms: []UniformLocation{
{Name: "_12.color", Type: 0, Size: 4, Offset: 0},
},
GLES2: "#version 100\nprecision mediump float;\nprecision highp int;\n\nstruct Color\n{\n vec4 color;\n};\n\nuniform Color color;\n\nvarying vec2 vUV;\n\nvoid main()\n{\n gl_FragData[0] = color.color;\n}\n\n",
/*
cbuffer Color : register(b0)
{
float4 color_color : packoffset(c0);
};
static float4 fragColor;
static float2 vUV;
struct SPIRV_Cross_Input
{
float2 vUV : TEXCOORD0;
};
struct SPIRV_Cross_Output
{
float4 fragColor : SV_Target0;
};
void frag_main()
{
fragColor = color_color;
}
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
{
vUV = stage_input.vUV;
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.fragColor = fragColor;
return stage_output;
}
*/
HLSL: []byte(nil),
},
ShaderSources{
GLES2: "#version 100\nprecision mediump float;\nprecision highp int;\n\nuniform mediump sampler2D tex;\n\nvarying vec2 vUV;\n\nvoid main()\n{\n gl_FragData[0] = texture2D(tex, vUV);\n}\n\n",
/*
Texture2D<float4> tex : register(t0);
SamplerState _tex_sampler : register(s0);
static float4 fragColor;
static float2 vUV;
struct SPIRV_Cross_Input
{
float2 vUV : TEXCOORD0;
};
struct SPIRV_Cross_Output
{
float4 fragColor : SV_Target0;
};
void frag_main()
{
fragColor = tex.Sample(_tex_sampler, vUV);
}
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
{
vUV = stage_input.vUV;
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.fragColor = fragColor;
return stage_output;
}
*/
HLSL: []byte(nil),
},
}
shader_blit_vert = ShaderSources{
Inputs: []InputLocation{
{Name: "pos", Location: 0, Semantic: "POSITION", SemanticIndex: 0, Type: 0, Size: 2},
{Name: "uv", Location: 1, Semantic: "NORMAL", SemanticIndex: 0, Type: 0, Size: 2},
},
Uniforms: []UniformLocation{
{Name: "_15.z", Type: 0, Size: 1, Offset: 0},
{Name: "_15.scale", Type: 0, Size: 2, Offset: 8},
{Name: "_15.offset", Type: 0, Size: 2, Offset: 16},
{Name: "_15.uvScale", Type: 0, Size: 2, Offset: 24},
{Name: "_15.uvOffset", Type: 0, Size: 2, Offset: 32},
},
GLES2: "#version 100\n\nstruct Block\n{\n float z;\n vec2 scale;\n vec2 offset;\n vec2 uvScale;\n vec2 uvOffset;\n};\n\nuniform Block uniforms;\n\nattribute vec2 pos;\nvarying vec2 vUV;\nattribute vec2 uv;\n\nvoid main()\n{\n vec2 p = pos;\n p *= uniforms.scale;\n p += uniforms.offset;\n gl_Position = vec4(p, uniforms.z, 1.0);\n vUV = (uv * uniforms.uvScale) + uniforms.uvOffset;\n}\n\n",
/*
cbuffer Block : register(b0)
{
float uniforms_z : packoffset(c0);
float2 uniforms_scale : packoffset(c0.z);
float2 uniforms_offset : packoffset(c1);
float2 uniforms_uvScale : packoffset(c1.z);
float2 uniforms_uvOffset : packoffset(c2);
};
static float4 gl_Position;
static float2 pos;
static float2 vUV;
static float2 uv;
struct SPIRV_Cross_Input
{
float2 pos : POSITION;
float2 uv : NORMAL;
};
struct SPIRV_Cross_Output
{
float2 vUV : TEXCOORD0;
float4 gl_Position : SV_Position;
};
void vert_main()
{
float2 p = pos;
p *= uniforms_scale;
p += uniforms_offset;
gl_Position = float4(p, uniforms_z, 1.0f);
vUV = (uv * uniforms_uvScale) + uniforms_uvOffset;
}
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
{
pos = stage_input.pos;
uv = stage_input.uv;
vert_main();
SPIRV_Cross_Output stage_output;
stage_output.gl_Position = gl_Position;
stage_output.vUV = vUV;
return stage_output;
}
*/
HLSL: []byte(nil),
}
shader_cover_frag = [...]ShaderSources{
ShaderSources{
Uniforms: []UniformLocation{
{Name: "_12.color", Type: 0, Size: 4, Offset: 0},
},
GLES2: "#version 100\nprecision mediump float;\nprecision highp int;\n\nstruct Color\n{\n vec4 color;\n};\n\nuniform Color color;\n\nuniform mediump sampler2D cover;\n\nvarying highp vec2 vCoverUV;\nvarying vec2 vUV;\n\nvoid main()\n{\n gl_FragData[0] = color.color;\n float cover_1 = abs(texture2D(cover, vCoverUV).x);\n gl_FragData[0] *= cover_1;\n}\n\n",
/*
cbuffer Color : register(b0)
{
float4 color_color : packoffset(c0);
};
Texture2D<float4> cover : register(t1);
SamplerState _cover_sampler : register(s1);
static float4 fragColor;
static float2 vCoverUV;
static float2 vUV;
struct SPIRV_Cross_Input
{
float2 vCoverUV : TEXCOORD0;
float2 vUV : TEXCOORD1;
};
struct SPIRV_Cross_Output
{
float4 fragColor : SV_Target0;
};
void frag_main()
{
fragColor = color_color;
float cover_1 = abs(cover.Sample(_cover_sampler, vCoverUV).x);
fragColor *= cover_1;
}
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
{
vCoverUV = stage_input.vCoverUV;
vUV = stage_input.vUV;
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.fragColor = fragColor;
return stage_output;
}
*/
HLSL: []byte(nil),
},
ShaderSources{
GLES2: "#version 100\nprecision mediump float;\nprecision highp int;\n\nuniform mediump sampler2D tex;\nuniform mediump sampler2D cover;\n\nvarying vec2 vUV;\nvarying highp vec2 vCoverUV;\n\nvoid main()\n{\n gl_FragData[0] = texture2D(tex, vUV);\n float cover_1 = abs(texture2D(cover, vCoverUV).x);\n gl_FragData[0] *= cover_1;\n}\n\n",
/*
Texture2D<float4> tex : register(t0);
SamplerState _tex_sampler : register(s0);
Texture2D<float4> cover : register(t1);
SamplerState _cover_sampler : register(s1);
static float4 fragColor;
static float2 vUV;
static float2 vCoverUV;
struct SPIRV_Cross_Input
{
float2 vCoverUV : TEXCOORD0;
float2 vUV : TEXCOORD1;
};
struct SPIRV_Cross_Output
{
float4 fragColor : SV_Target0;
};
void frag_main()
{
fragColor = tex.Sample(_tex_sampler, vUV);
float cover_1 = abs(cover.Sample(_cover_sampler, vCoverUV).x);
fragColor *= cover_1;
}
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
{
vUV = stage_input.vUV;
vCoverUV = stage_input.vCoverUV;
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.fragColor = fragColor;
return stage_output;
}
*/
HLSL: []byte(nil),
},
}
shader_cover_vert = ShaderSources{
Inputs: []InputLocation{
{Name: "pos", Location: 0, Semantic: "POSITION", SemanticIndex: 0, Type: 0, Size: 2},
{Name: "uv", Location: 1, Semantic: "NORMAL", SemanticIndex: 0, Type: 0, Size: 2},
},
Uniforms: []UniformLocation{
{Name: "_19.z", Type: 0, Size: 1, Offset: 0},
{Name: "_19.scale", Type: 0, Size: 2, Offset: 8},
{Name: "_19.offset", Type: 0, Size: 2, Offset: 16},
{Name: "_19.uvScale", Type: 0, Size: 2, Offset: 24},
{Name: "_19.uvOffset", Type: 0, Size: 2, Offset: 32},
{Name: "_19.uvCoverScale", Type: 0, Size: 2, Offset: 40},
{Name: "_19.uvCoverOffset", Type: 0, Size: 2, Offset: 48},
},
GLES2: "#version 100\n\nstruct Block\n{\n float z;\n vec2 scale;\n vec2 offset;\n vec2 uvScale;\n vec2 uvOffset;\n vec2 uvCoverScale;\n vec2 uvCoverOffset;\n};\n\nuniform Block uniforms;\n\nattribute vec2 pos;\nvarying vec2 vUV;\nattribute vec2 uv;\nvarying vec2 vCoverUV;\n\nvoid main()\n{\n gl_Position = vec4((pos * uniforms.scale) + uniforms.offset, uniforms.z, 1.0);\n vUV = (uv * uniforms.uvScale) + uniforms.uvOffset;\n vCoverUV = (uv * uniforms.uvCoverScale) + uniforms.uvCoverOffset;\n}\n\n",
/*
cbuffer Block : register(b0)
{
float uniforms_z : packoffset(c0);
float2 uniforms_scale : packoffset(c0.z);
float2 uniforms_offset : packoffset(c1);
float2 uniforms_uvScale : packoffset(c1.z);
float2 uniforms_uvOffset : packoffset(c2);
float2 uniforms_uvCoverScale : packoffset(c2.z);
float2 uniforms_uvCoverOffset : packoffset(c3);
};
static float4 gl_Position;
static float2 pos;
static float2 vUV;
static float2 uv;
static float2 vCoverUV;
struct SPIRV_Cross_Input
{
float2 pos : POSITION;
float2 uv : NORMAL;
};
struct SPIRV_Cross_Output
{
float2 vCoverUV : TEXCOORD0;
float2 vUV : TEXCOORD1;
float4 gl_Position : SV_Position;
};
void vert_main()
{
gl_Position = float4((pos * uniforms_scale) + uniforms_offset, uniforms_z, 1.0f);
vUV = (uv * uniforms_uvScale) + uniforms_uvOffset;
vCoverUV = (uv * uniforms_uvCoverScale) + uniforms_uvCoverOffset;
}
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
{
pos = stage_input.pos;
uv = stage_input.uv;
vert_main();
SPIRV_Cross_Output stage_output;
stage_output.gl_Position = gl_Position;
stage_output.vUV = vUV;
stage_output.vCoverUV = vCoverUV;
return stage_output;
}
*/
HLSL: []byte(nil),
}
shader_intersect_frag = ShaderSources{
GLES2: "#version 100\nprecision mediump float;\nprecision highp int;\n\nuniform mediump sampler2D cover;\n\nvarying highp vec2 vUV;\n\nvoid main()\n{\n float cover_1 = abs(texture2D(cover, vUV).x);\n gl_FragData[0].x = cover_1;\n}\n\n",
/*
Texture2D<float4> cover : register(t0);
SamplerState _cover_sampler : register(s0);
static float2 vUV;
static float4 fragColor;
struct SPIRV_Cross_Input
{
float2 vUV : TEXCOORD0;
};
struct SPIRV_Cross_Output
{
float4 fragColor : SV_Target0;
};
void frag_main()
{
float cover_1 = abs(cover.Sample(_cover_sampler, vUV).x);
fragColor.x = cover_1;
}
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
{
vUV = stage_input.vUV;
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.fragColor = fragColor;
return stage_output;
}
*/
HLSL: []byte(nil),
}
shader_intersect_vert = ShaderSources{
Inputs: []InputLocation{
{Name: "pos", Location: 0, Semantic: "POSITION", SemanticIndex: 0, Type: 0, Size: 2},
{Name: "uv", Location: 1, Semantic: "NORMAL", SemanticIndex: 0, Type: 0, Size: 2},
},
Uniforms: []UniformLocation{
{Name: "_40.scale", Type: 0, Size: 2, Offset: 0},
{Name: "_40.offset", Type: 0, Size: 2, Offset: 8},
},
GLES2: "#version 100\n\nstruct Block\n{\n vec2 scale;\n vec2 offset;\n};\n\nuniform Block uvparams;\n\nattribute vec2 pos;\nvarying vec2 vUV;\nattribute vec2 uv;\n\nvoid main()\n{\n vec2 p = pos;\n p.y = -p.y;\n gl_Position = vec4(p, 0.0, 1.0);\n vUV = (uv * uvparams.scale) + uvparams.offset;\n}\n\n",
/*
cbuffer Block : register(b0)
{
float2 uvparams_scale : packoffset(c0);
float2 uvparams_offset : packoffset(c0.z);
};
static float4 gl_Position;
static float2 pos;
static float2 vUV;
static float2 uv;
struct SPIRV_Cross_Input
{
float2 pos : POSITION;
float2 uv : NORMAL;
};
struct SPIRV_Cross_Output
{
float2 vUV : TEXCOORD0;
float4 gl_Position : SV_Position;
};
void vert_main()
{
float2 p = pos;
p.y = -p.y;
gl_Position = float4(p, 0.0f, 1.0f);
vUV = (uv * uvparams_scale) + uvparams_offset;
}
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
{
pos = stage_input.pos;
uv = stage_input.uv;
vert_main();
SPIRV_Cross_Output stage_output;
stage_output.gl_Position = gl_Position;
stage_output.vUV = vUV;
return stage_output;
}
*/
HLSL: []byte(nil),
}
shader_stencil_frag = ShaderSources{
GLES2: "#version 100\nprecision mediump float;\nprecision highp int;\n\nuniform mediump sampler2D areaLUT;\n\nvarying vec2 vTo;\nvarying vec2 vFrom;\nvarying vec2 vCtrl;\n\nvoid main()\n{\n float dx = vTo.x - vFrom.x;\n bool increasing = vTo.x >= vFrom.x;\n bvec2 _35 = bvec2(increasing);\n vec2 left = vec2(_35.x ? vFrom.x : vTo.x, _35.y ? vFrom.y : vTo.y);\n bvec2 _41 = bvec2(increasing);\n vec2 right = vec2(_41.x ? vTo.x : vFrom.x, _41.y ? vTo.y : vFrom.y);\n vec2 extent = clamp(vec2(vFrom.x, vTo.x), vec2(-0.5), vec2(0.5));\n float midx = mix(extent.x, extent.y, 0.5);\n float x0 = midx - left.x;\n vec2 p1 = vCtrl - left;\n vec2 v = right - vCtrl;\n float t = x0 / (p1.x + sqrt((p1.x * p1.x) + ((v.x - p1.x) * x0)));\n float y = mix(mix(left.y, vCtrl.y, t), mix(vCtrl.y, right.y, t), t);\n vec2 d_half = mix(p1, v, vec2(t));\n float dy = d_half.y / d_half.x;\n float width = extent.y - extent.x;\n dy = abs(dy * width);\n vec4 sides = vec4((dy * 0.5) + y, (dy * (-0.5)) + y, (0.5 - y) / dy, ((-0.5) - y) / dy);\n sides = clamp(sides + vec4(0.5), vec4(0.0), vec4(1.0));\n float area = 0.5 * ((((sides.z - (sides.z * sides.y)) + 1.0) - sides.x) + (sides.x * sides.w));\n area *= width;\n if (width == 0.0)\n {\n area = 0.0;\n }\n gl_FragData[0].x = area;\n}\n\n",
/*
Texture2D<float4> areaLUT : register(t0);
SamplerState _areaLUT_sampler : register(s0);
static float2 vTo;
static float2 vFrom;
static float2 vCtrl;
static float4 fragCover;
struct SPIRV_Cross_Input
{
float2 vFrom : TEXCOORD0;
float2 vCtrl : TEXCOORD1;
float2 vTo : TEXCOORD2;
};
struct SPIRV_Cross_Output
{
float4 fragCover : SV_Target0;
};
void frag_main()
{
float dx = vTo.x - vFrom.x;
bool increasing = vTo.x >= vFrom.x;
bool2 _35 = increasing.xx;
float2 left = float2(_35.x ? vFrom.x : vTo.x, _35.y ? vFrom.y : vTo.y);
bool2 _41 = increasing.xx;
float2 right = float2(_41.x ? vTo.x : vFrom.x, _41.y ? vTo.y : vFrom.y);
float2 extent = clamp(float2(vFrom.x, vTo.x), (-0.5f).xx, 0.5f.xx);
float midx = lerp(extent.x, extent.y, 0.5f);
float x0 = midx - left.x;
float2 p1 = vCtrl - left;
float2 v = right - vCtrl;
float t = x0 / (p1.x + sqrt((p1.x * p1.x) + ((v.x - p1.x) * x0)));
float y = lerp(lerp(left.y, vCtrl.y, t), lerp(vCtrl.y, right.y, t), t);
float2 d_half = lerp(p1, v, t.xx);
float dy = d_half.y / d_half.x;
float width = extent.y - extent.x;
dy = abs(dy * width);
float4 sides = float4((dy * 0.5f) + y, (dy * (-0.5f)) + y, (0.5f - y) / dy, ((-0.5f) - y) / dy);
sides = clamp(sides + 0.5f.xxxx, 0.0f.xxxx, 1.0f.xxxx);
float area = 0.5f * ((((sides.z - (sides.z * sides.y)) + 1.0f) - sides.x) + (sides.x * sides.w));
area *= width;
if (width == 0.0f)
{
area = 0.0f;
}
fragCover.x = area;
}
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
{
vTo = stage_input.vTo;
vFrom = stage_input.vFrom;
vCtrl = stage_input.vCtrl;
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.fragCover = fragCover;
return stage_output;
}
*/
HLSL: []byte(nil),
}
shader_stencil_vert = ShaderSources{
Inputs: []InputLocation{
{Name: "corner", Location: 0, Semantic: "POSITION", SemanticIndex: 0, Type: 0, Size: 2},
{Name: "maxy", Location: 1, Semantic: "NORMAL", SemanticIndex: 0, Type: 0, Size: 1},
{Name: "from", Location: 2, Semantic: "TEXCOORD", SemanticIndex: 0, Type: 0, Size: 2},
{Name: "ctrl", Location: 3, Semantic: "TEXCOORD", SemanticIndex: 1, Type: 0, Size: 2},
{Name: "to", Location: 4, Semantic: "TEXCOORD", SemanticIndex: 2, Type: 0, Size: 2},
},
Uniforms: []UniformLocation{
{Name: "_15.scale", Type: 0, Size: 2, Offset: 0},
{Name: "_15.offset", Type: 0, Size: 2, Offset: 8},
{Name: "_15.pathOffset", Type: 0, Size: 2, Offset: 16},
},
GLES2: "#version 100\n\nstruct Block\n{\n vec2 scale;\n vec2 offset;\n vec2 pathOffset;\n};\n\nuniform Block uniforms;\n\nattribute vec2 from;\nattribute vec2 ctrl;\nattribute vec2 to;\nattribute float maxy;\nattribute vec2 corner;\nvarying vec2 vFrom;\nvarying vec2 vCtrl;\nvarying vec2 vTo;\n\nvoid main()\n{\n vec2 from_1 = from + uniforms.pathOffset;\n vec2 ctrl_1 = ctrl + uniforms.pathOffset;\n vec2 to_1 = to + uniforms.pathOffset;\n float maxy_1 = maxy + uniforms.pathOffset.y;\n vec2 pos;\n if (corner.x > 0.0)\n {\n pos.x = max(max(from_1.x, ctrl_1.x), to_1.x) + 1.0;\n }\n else\n {\n pos.x = min(min(from_1.x, ctrl_1.x), to_1.x) - 1.0;\n }\n if (corner.y > 0.0)\n {\n pos.y = maxy_1 + 1.0;\n }\n else\n {\n pos.y = min(min(from_1.y, ctrl_1.y), to_1.y) - 1.0;\n }\n vFrom = from_1 - pos;\n vCtrl = ctrl_1 - pos;\n vTo = to_1 - pos;\n pos *= uniforms.scale;\n pos += uniforms.offset;\n gl_Position = vec4(pos, 1.0, 1.0);\n}\n\n",
/*
cbuffer Block : register(b0)
{
float2 uniforms_scale : packoffset(c0);
float2 uniforms_offset : packoffset(c0.z);
float2 uniforms_pathOffset : packoffset(c1);
};
static float4 gl_Position;
static float2 from;
static float2 ctrl;
static float2 to;
static float maxy;
static float2 corner;
static float2 vFrom;
static float2 vCtrl;
static float2 vTo;
struct SPIRV_Cross_Input
{
float2 corner : POSITION;
float maxy : NORMAL;
float2 from : TEXCOORD0;
float2 ctrl : TEXCOORD1;
float2 to : TEXCOORD2;
};
struct SPIRV_Cross_Output
{
float2 vFrom : TEXCOORD0;
float2 vCtrl : TEXCOORD1;
float2 vTo : TEXCOORD2;
float4 gl_Position : SV_Position;
};
void vert_main()
{
float2 from_1 = from + uniforms_pathOffset;
float2 ctrl_1 = ctrl + uniforms_pathOffset;
float2 to_1 = to + uniforms_pathOffset;
float maxy_1 = maxy + uniforms_pathOffset.y;
float2 pos;
if (corner.x > 0.0f)
{
pos.x = max(max(from_1.x, ctrl_1.x), to_1.x) + 1.0f;
}
else
{
pos.x = min(min(from_1.x, ctrl_1.x), to_1.x) - 1.0f;
}
if (corner.y > 0.0f)
{
pos.y = maxy_1 + 1.0f;
}
else
{
pos.y = min(min(from_1.y, ctrl_1.y), to_1.y) - 1.0f;
}
vFrom = from_1 - pos;
vCtrl = ctrl_1 - pos;
vTo = to_1 - pos;
pos *= uniforms_scale;
pos += uniforms_offset;
gl_Position = float4(pos, 1.0f, 1.0f);
}
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
{
from = stage_input.from;
ctrl = stage_input.ctrl;
to = stage_input.to;
maxy = stage_input.maxy;
corner = stage_input.corner;
vert_main();
SPIRV_Cross_Output stage_output;
stage_output.gl_Position = gl_Position;
stage_output.vFrom = vFrom;
stage_output.vCtrl = vCtrl;
stage_output.vTo = vTo;
return stage_output;
}
*/
HLSL: []byte(nil),
}
)
+15
View File
@@ -0,0 +1,15 @@
#version 310 es
// SPDX-License-Identifier: Unlicense OR MIT
precision mediump float;
layout(location=0) in vec2 vUV;
{{.Header}}
layout(location = 0) out vec4 fragColor;
void main() {
fragColor = {{.FetchColorExpr}};
}
+27
View File
@@ -0,0 +1,27 @@
#version 310 es
// SPDX-License-Identifier: Unlicense OR MIT
precision highp float;
layout(binding = 0) uniform Block {
float z;
vec2 scale;
vec2 offset;
vec2 uvScale;
vec2 uvOffset;
} uniforms;
layout(location = 0) in vec2 pos;
layout(location = 1) in vec2 uv;
layout(location = 0) out vec2 vUV;
void main() {
vec2 p = pos;
p *= uniforms.scale;
p += uniforms.offset;
gl_Position = vec4(p, uniforms.z, 1);
vUV = uv*uniforms.uvScale + uniforms.uvOffset;
}
+22
View File
@@ -0,0 +1,22 @@
#version 310 es
// SPDX-License-Identifier: Unlicense OR MIT
precision mediump float;
{{.Header}}
// Use high precision to be pixel accurate for
// large cover atlases.
layout(location = 0) in highp vec2 vCoverUV;
layout(location = 1) in vec2 vUV;
layout(binding = 1) uniform sampler2D cover;
layout(location = 0) out vec4 fragColor;
void main() {
fragColor = {{.FetchColorExpr}};
float cover = abs(texture(cover, vCoverUV).r);
fragColor *= cover;
}
+28
View File
@@ -0,0 +1,28 @@
#version 310 es
// SPDX-License-Identifier: Unlicense OR MIT
precision highp float;
layout(binding = 0) uniform Block {
float z;
vec2 scale;
vec2 offset;
vec2 uvScale;
vec2 uvOffset;
vec2 uvCoverScale;
vec2 uvCoverOffset;
} uniforms;
layout(location = 0) in vec2 pos;
layout(location = 0) out vec2 vCoverUV;
layout(location = 1) in vec2 uv;
layout(location = 1) out vec2 vUV;
void main() {
gl_Position = vec4(pos*uniforms.scale + uniforms.offset, uniforms.z, 1);
vUV = uv*uniforms.uvScale + uniforms.uvOffset;
vCoverUV = uv*uniforms.uvCoverScale+uniforms.uvCoverOffset;
}
+18
View File
@@ -0,0 +1,18 @@
#version 310 es
// SPDX-License-Identifier: Unlicense OR MIT
precision mediump float;
// Use high precision to be pixel accurate for
// large cover atlases.
layout(location = 0) in highp vec2 vUV;
layout(binding = 0) uniform sampler2D cover;
layout(location = 0) out vec4 fragColor;
void main() {
float cover = abs(texture(cover, vUV).r);
fragColor.r = cover;
}
+22
View File
@@ -0,0 +1,22 @@
#version 310 es
// SPDX-License-Identifier: Unlicense OR MIT
precision highp float;
layout(location = 0) in vec2 pos;
layout(location = 1) in vec2 uv;
layout(binding = 0) uniform Block {
vec2 scale;
vec2 offset;
} uvparams;
layout(location = 0) out vec2 vUV;
void main() {
vec2 p = pos;
p.y = -p.y;
gl_Position = vec4(p, 0, 1);
vUV = uv*uvparams.scale + uvparams.offset;
}
+83
View File
@@ -0,0 +1,83 @@
#version 310 es
// SPDX-License-Identifier: Unlicense OR MIT
precision mediump float;
layout(location=0) in vec2 vFrom;
layout(location=1) in vec2 vCtrl;
layout(location=2) in vec2 vTo;
layout(binding=0) uniform sampler2D areaLUT;
layout(location = 0) out vec4 fragCover;
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;
fragCover.r = area;
}
+53
View File
@@ -0,0 +1,53 @@
#version 310 es
// SPDX-License-Identifier: Unlicense OR MIT
precision highp float;
layout(binding = 0) uniform Block {
vec2 scale;
vec2 offset;
vec2 pathOffset;
} uniforms;
layout(location=0) in vec2 corner;
layout(location=1) in float maxy;
layout(location=2) in vec2 from;
layout(location=3) in vec2 ctrl;
layout(location=4) in vec2 to;
layout(location=0) out vec2 vFrom;
layout(location=1) out vec2 vCtrl;
layout(location=2) out 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 + uniforms.pathOffset;
vec2 ctrl = ctrl + uniforms.pathOffset;
vec2 to = to + uniforms.pathOffset;
float maxy = maxy + uniforms.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 *= uniforms.scale;
pos += uniforms.offset;
gl_Position = vec4(pos, 1, 1);
}