Do GeoM projection on CPU (#477)

Handling GeoM projection on CPU may seem like a weird choice, given
how fast GPU is, but it pays off:

* You only have to do a very small subset of the actual matrix
  multiply.
* You don't have to construct a matrix in the vertex shader.
* Six fewer float32 values per vertex.
* You do still have to do the matrix computation for each vertex,
  though.

Signed-off-by: Seebs <seebs@seebs.net>
This commit is contained in:
seebs 2018-01-14 01:01:55 -06:00 committed by Hajime Hoshi
parent 38c72faf95
commit 0b7ba8e573
5 changed files with 43 additions and 79 deletions

View File

@ -45,6 +45,13 @@ func (g *GeoM) Apply(x, y float64) (x2, y2 float64) {
return g.a*x + g.b*y + g.tx, g.c*x + g.d*y + g.ty
}
func (g *GeoM) Apply32(x, y float64) (x2, y2 float32) {
if !g.inited {
return float32(x), float32(y)
}
return float32(g.a*x + g.b*y + g.tx), float32(g.c*x + g.d*y + g.ty)
}
func (g *GeoM) Elements() (a, b, c, d, tx, ty float64) {
if !g.inited {
return 1, 0, 0, 1, 0, 0

View File

@ -92,16 +92,6 @@ var (
dataType: opengl.Float,
num: 4,
},
{
name: "geo_matrix_body",
dataType: opengl.Float,
num: 4,
},
{
name: "geo_matrix_translation",
dataType: opengl.Float,
num: 2,
},
},
}
)

View File

@ -47,8 +47,6 @@ const (
uniform mat4 projection_matrix;
attribute vec2 vertex;
attribute vec4 tex_coord;
attribute vec4 geo_matrix_body;
attribute vec2 geo_matrix_translation;
varying vec2 varying_tex_coord;
varying vec2 varying_tex_coord_min;
varying vec2 varying_tex_coord_max;
@ -59,13 +57,7 @@ void main(void) {
vec2(min(tex_coord[0], tex_coord[2]), min(tex_coord[1], tex_coord[3]));
varying_tex_coord_max =
vec2(max(tex_coord[0], tex_coord[2]), max(tex_coord[1], tex_coord[3]));
mat4 geo_matrix = mat4(
vec4(geo_matrix_body[0], geo_matrix_body[2], 0, 0),
vec4(geo_matrix_body[1], geo_matrix_body[3], 0, 0),
vec4(0, 0, 1, 0),
vec4(geo_matrix_translation, 0, 1)
);
gl_Position = projection_matrix * geo_matrix * vec4(vertex, 0, 1);
gl_Position = projection_matrix * vec4(vertex, 0, 1);
}
`
shaderStrFragment = `

View File

@ -79,10 +79,10 @@ func vertices(sw, sh int, x, y int) []float32 {
// For the rule of values, see vertices.go.
return []float32{
0, 0, 0, 0, 1, 1, a, b, c, d, tx, ty,
0, shf, 0, 1, 1, 0, a, b, c, d, tx, ty,
swf, 0, 1, 0, 0, 1, a, b, c, d, tx, ty,
swf, shf, 1, 1, 0, 0, a, b, c, d, tx, ty,
0 + tx, 0 + ty, 0, 0, 1, 1,
0 + tx, shf + ty, 0, 1, 1, 0,
swf + tx, 0 + ty, 1, 0, 0, 1,
swf + tx, shf + ty, 1, 1, 0, 0,
}
}

View File

@ -70,30 +70,27 @@ func vertices(sx0, sy0, sx1, sy1 int, width, height int, geo *affine.GeoM) []flo
g.Concat(geo)
geo = &g
}
x0, y0 := float64(0), float64(0)
x1, y1 := float64(sx1 - sx0), float64(sy1 - sy0)
a, b, c, d, tx, ty := geo.Elements()
g0 := float32(a)
g1 := float32(b)
g2 := float32(c)
g3 := float32(d)
g4 := float32(tx)
g5 := float32(ty)
// it really feels like we should be able to cache this computation
// but it may not matter.
w := 1
h := 1
for w < width {
w *= 2
w *= 2
}
for h < height {
h *= 2
h *= 2
}
wf := float32(w)
hf := float32(h)
x0, y0, x1, y1 := float32(0), float32(0), float32(sx1-sx0), float32(sy1-sy0)
u0, v0, u1, v1 := float32(sx0)/wf, float32(sy0)/hf, float32(sx1)/wf, float32(sy1)/hf
x, y := geo.Apply32(x0, y0)
// Vertex coordinates
vs[0] = x0
vs[1] = y0
vs[0] = x
vs[1] = y
// Texture coordinates: first 2 values indicates the actual coodinate, and
// the second indicates diagonally opposite coodinates.
@ -103,52 +100,30 @@ func vertices(sx0, sy0, sx1, sy1 int, width, height int, geo *affine.GeoM) []flo
vs[4] = u1
vs[5] = v1
// Geometry matrix
vs[6] = g0
vs[7] = g1
vs[8] = g2
vs[9] = g3
vs[10] = g4
vs[11] = g5
// and the same for the other three coordinates
x, y = geo.Apply32(x1, y0)
vs[6] = x
vs[7] = y
vs[8] = u1
vs[9] = v0
vs[10] = u0
vs[11] = v1
vs[12] = x1
vs[13] = y0
vs[14] = u1
vs[15] = v0
vs[16] = u0
vs[17] = v1
vs[18] = g0
vs[19] = g1
vs[20] = g2
vs[21] = g3
vs[22] = g4
vs[23] = g5
x, y = geo.Apply32(x0, y1)
vs[12] = x
vs[13] = y
vs[14] = u0
vs[15] = v1
vs[16] = u1
vs[17] = v0
vs[24] = x0
vs[25] = y1
vs[26] = u0
vs[27] = v1
vs[28] = u1
vs[29] = v0
vs[30] = g0
vs[31] = g1
vs[32] = g2
vs[33] = g3
vs[34] = g4
vs[35] = g5
vs[36] = x1
vs[37] = y1
vs[38] = u1
vs[39] = v1
vs[40] = u0
vs[41] = v0
vs[42] = g0
vs[43] = g1
vs[44] = g2
vs[45] = g3
vs[46] = g4
vs[47] = g5
x, y = geo.Apply32(x1, y1)
vs[18] = x
vs[19] = y
vs[20] = u1
vs[21] = v1
vs[22] = u0
vs[23] = v0
return vs
}