mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-07 18:35:34 +00:00
ui/app/internal/gpu: replace look up texture with calculation
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
@@ -1,76 +0,0 @@
|
|||||||
// SPDX-License-Identifier: Unlicense OR MIT
|
|
||||||
|
|
||||||
package gpu
|
|
||||||
|
|
||||||
import (
|
|
||||||
"image"
|
|
||||||
)
|
|
||||||
|
|
||||||
// genAreaLUT generates the lookup table conpatible with the stencilFSrc
|
|
||||||
// fragment shaders. The table contains the area of a pixel square above
|
|
||||||
// a line. The square has area 1 and is centered in (0, 0).
|
|
||||||
// The y-axis intersection of the line in [-8;+8] is specified by the
|
|
||||||
// first coordinate.
|
|
||||||
// The slope of the line [0;16] is specified by the second coordinate.
|
|
||||||
func genAreaLUT(width, height int) *image.Gray {
|
|
||||||
lut := image.NewGray(image.Rectangle{Max: image.Point{X: width, Y: height}})
|
|
||||||
for v := 0; v < height; v++ {
|
|
||||||
a := float32(v) * 16 / float32(height)
|
|
||||||
for u := 0; u < width; u++ {
|
|
||||||
var area float32
|
|
||||||
switch u {
|
|
||||||
case 0:
|
|
||||||
area = 1.0
|
|
||||||
case width - 1:
|
|
||||||
area = 0.0
|
|
||||||
default:
|
|
||||||
b := (float32(u) - float32(width)/2) / 16
|
|
||||||
// f(x) = ax+b.
|
|
||||||
area = computeLineArea(a, b)
|
|
||||||
}
|
|
||||||
lut.Pix[v*height+u] = uint8(area*255 + 0.5)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return lut
|
|
||||||
}
|
|
||||||
|
|
||||||
func computeLineArea(a, b float32) float32 {
|
|
||||||
// Compute intersections with the square edges.
|
|
||||||
// Right and left.
|
|
||||||
ry := a*+0.5 + b
|
|
||||||
ly := a*-0.5 + b
|
|
||||||
// Top and bottom.
|
|
||||||
tx := (+0.5 - b) / a
|
|
||||||
bx := (-0.5 - b) / a
|
|
||||||
// The line will intersect zero or two edges.
|
|
||||||
if ry <= -0.5 {
|
|
||||||
// Line is below the square.
|
|
||||||
return 1.0
|
|
||||||
}
|
|
||||||
if ly >= 0.5 {
|
|
||||||
// Line is above the square.
|
|
||||||
return 0.0
|
|
||||||
}
|
|
||||||
// The slope is positive, so there are only 4 possible
|
|
||||||
// pairs of edges: (bottom, right), (left, right),
|
|
||||||
// (bottom, top), (left, top).
|
|
||||||
if ry <= 0.5 {
|
|
||||||
// Intersection with right edge.
|
|
||||||
if ly <= -0.5 {
|
|
||||||
// (bottom, right).
|
|
||||||
return 1.0 - (0.5-bx)*(ry-(-0.5))/2
|
|
||||||
} else {
|
|
||||||
// (left, right).
|
|
||||||
return 1.0*(0.5-ry) + 1.0*(ry-ly)/2
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Intersection with top edge.
|
|
||||||
if ly <= -0.5 {
|
|
||||||
// (bottom, top).
|
|
||||||
return (bx-(-0.5))*1.0 + (tx-bx)*1.0/2
|
|
||||||
} else {
|
|
||||||
// (left, top).
|
|
||||||
return (tx - (-0.5)) * (0.5 - ly) / 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+13
-39
@@ -48,7 +48,6 @@ type stenciler struct {
|
|||||||
uIntersectUVOffset gl.Uniform
|
uIntersectUVOffset gl.Uniform
|
||||||
uIntersectUVScale gl.Uniform
|
uIntersectUVScale gl.Uniform
|
||||||
indexBuf gl.Buffer
|
indexBuf gl.Buffer
|
||||||
areaLUT gl.Texture
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type fboSet struct {
|
type fboSet struct {
|
||||||
@@ -122,13 +121,7 @@ func newStenciler(ctx *context) *stenciler {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
uAreaLUT := gl.GetUniformLocation(ctx.Functions, prog, "areaLUT")
|
|
||||||
ctx.UseProgram(prog)
|
ctx.UseProgram(prog)
|
||||||
ctx.Uniform1i(uAreaLUT, 0)
|
|
||||||
areaLUT, err := loadLUT(ctx, genAreaLUT(256, 256))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
iprog, err := gl.CreateProgram(ctx.Functions, intersectVSrc, intersectFSrc, intersectAttribs)
|
iprog, err := gl.CreateProgram(ctx.Functions, intersectVSrc, intersectFSrc, intersectAttribs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -141,7 +134,6 @@ func newStenciler(ctx *context) *stenciler {
|
|||||||
defFBO: defFBO,
|
defFBO: defFBO,
|
||||||
prog: prog,
|
prog: prog,
|
||||||
iprog: iprog,
|
iprog: iprog,
|
||||||
areaLUT: areaLUT,
|
|
||||||
uScale: gl.GetUniformLocation(ctx.Functions, prog, "scale"),
|
uScale: gl.GetUniformLocation(ctx.Functions, prog, "scale"),
|
||||||
uOffset: gl.GetUniformLocation(ctx.Functions, prog, "offset"),
|
uOffset: gl.GetUniformLocation(ctx.Functions, prog, "offset"),
|
||||||
uPathOffset: gl.GetUniformLocation(ctx.Functions, prog, "pathOffset"),
|
uPathOffset: gl.GetUniformLocation(ctx.Functions, prog, "pathOffset"),
|
||||||
@@ -205,7 +197,6 @@ func (s *fboSet) delete(ctx *context, idx int) {
|
|||||||
|
|
||||||
func (s *stenciler) release() {
|
func (s *stenciler) release() {
|
||||||
s.fbos.delete(s.ctx, 0)
|
s.fbos.delete(s.ctx, 0)
|
||||||
s.ctx.DeleteTexture(s.areaLUT)
|
|
||||||
s.ctx.DeleteProgram(s.prog)
|
s.ctx.DeleteProgram(s.prog)
|
||||||
s.ctx.DeleteBuffer(s.indexBuf)
|
s.ctx.DeleteBuffer(s.indexBuf)
|
||||||
}
|
}
|
||||||
@@ -281,7 +272,6 @@ func (s *stenciler) begin(sizes []image.Point) {
|
|||||||
s.ctx.BlendFunc(gl.ONE, gl.ONE)
|
s.ctx.BlendFunc(gl.ONE, gl.ONE)
|
||||||
s.fbos.resize(s.ctx, sizes)
|
s.fbos.resize(s.ctx, sizes)
|
||||||
s.ctx.ClearColor(0.0, 0.0, 0.0, 0.0)
|
s.ctx.ClearColor(0.0, 0.0, 0.0, 0.0)
|
||||||
s.ctx.BindTexture(gl.TEXTURE_2D, s.areaLUT)
|
|
||||||
s.ctx.UseProgram(s.prog)
|
s.ctx.UseProgram(s.prog)
|
||||||
s.ctx.EnableVertexAttribArray(attribPathCorner)
|
s.ctx.EnableVertexAttribArray(attribPathCorner)
|
||||||
s.ctx.EnableVertexAttribArray(attribPathMaxY)
|
s.ctx.EnableVertexAttribArray(attribPathMaxY)
|
||||||
@@ -365,23 +355,6 @@ func (c *coverer) cover(z float32, mat materialType, col [4]float32, scale, off,
|
|||||||
c.ctx.DrawArrays(gl.TRIANGLE_STRIP, 0, 4)
|
c.ctx.DrawArrays(gl.TRIANGLE_STRIP, 0, 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadLUT(ctx *context, lut *image.Gray) (gl.Texture, error) {
|
|
||||||
tex := ctx.CreateTexture()
|
|
||||||
ctx.BindTexture(gl.TEXTURE_2D, tex)
|
|
||||||
ctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
|
|
||||||
ctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
|
|
||||||
ctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
|
|
||||||
ctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
|
|
||||||
ctx.PixelStorei(gl.UNPACK_ALIGNMENT, 1)
|
|
||||||
if lut.Stride != lut.Bounds().Dx() {
|
|
||||||
panic("unsupported LUT stride")
|
|
||||||
}
|
|
||||||
tt := ctx.caps.alphaTriple
|
|
||||||
ctx.TexImage2D(gl.TEXTURE_2D, 0, tt.internalFormat, lut.Bounds().Dx(), lut.Bounds().Dy(), tt.format, tt.typ, lut.Pix)
|
|
||||||
ctx.PixelStorei(gl.UNPACK_ALIGNMENT, 4)
|
|
||||||
return tex, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
const stencilVSrc = `
|
const stencilVSrc = `
|
||||||
#version 100
|
#version 100
|
||||||
|
|
||||||
@@ -494,19 +467,20 @@ void main() {
|
|||||||
// And the slope.
|
// And the slope.
|
||||||
vec2 d_half = mix(p1, v, t);
|
vec2 d_half = mix(p1, v, t);
|
||||||
float dy = d_half.y/d_half.x;
|
float dy = d_half.y/d_half.x;
|
||||||
// Together, y and dy form a line approximation. The areaLUT table
|
// Together, y and dy form a line approximation.
|
||||||
// maps the line to a pixel coverage.
|
|
||||||
|
// 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;
|
float width = extent.y - extent.x;
|
||||||
// The first axis maps y in [-8;+8] to [0;1].
|
dy = abs(dy*width);
|
||||||
float areau = y/16.0 + 0.5;
|
|
||||||
// The second axis maps slopes in [0;16] to [0;1]. The area is symmetric
|
vec4 sides = vec4(dy*+0.5 + y, dy*-0.5 + y, (+0.5-y)/dy, (-0.5-y)/dy);
|
||||||
// around dy = 0. Scale slope with extent width.
|
sides = clamp(sides+0.5, 0.0, 1.0);
|
||||||
float areav = abs(dy*width)/16.0;
|
|
||||||
// Look up coverage from y and slope and scale to extent.
|
float area = 0.5*(sides.z - sides.z*sides.y + 1.0 - sides.x+sides.x*sides.w);
|
||||||
float cover = texture2D(areaLUT, vec2(areau, areav)).r*width;
|
area *= width;
|
||||||
if (width == 0.0)
|
|
||||||
cover = 0.0; // Needed on the iOS simulator.
|
gl_FragColor.r = area;
|
||||||
gl_FragColor.r = cover;
|
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user