internal/graphics: unify QuadVertices

This is a preparation for adding members to Vertex.

Updates #2640
This commit is contained in:
Hajime Hoshi 2024-08-12 00:27:28 +09:00
parent 6cd00f3b88
commit b6ab7a10c1
8 changed files with 71 additions and 38 deletions

View File

@ -247,7 +247,7 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) {
colorm, cr, cg, cb, ca := colorMToScale(options.ColorM.affineColorM()) colorm, cr, cg, cb, ca := colorMToScale(options.ColorM.affineColorM())
cr, cg, cb, ca = options.ColorScale.apply(cr, cg, cb, ca) cr, cg, cb, ca = options.ColorScale.apply(cr, cg, cb, ca)
vs := i.ensureTmpVertices(4 * graphics.VertexFloatCount) vs := i.ensureTmpVertices(4 * graphics.VertexFloatCount)
graphics.QuadVertices(vs, float32(sx0), float32(sy0), float32(sx1), float32(sy1), a, b, c, d, tx, ty, cr, cg, cb, ca) graphics.QuadVerticesFromSrcAndMatrix(vs, float32(sx0), float32(sy0), float32(sx1), float32(sy1), a, b, c, d, tx, ty, cr, cg, cb, ca)
is := graphics.QuadIndices() is := graphics.QuadIndices()
srcs := [graphics.ShaderSrcImageCount]*ui.Image{img.image} srcs := [graphics.ShaderSrcImageCount]*ui.Image{img.image}
@ -829,7 +829,7 @@ func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawR
vs := i.ensureTmpVertices(4 * graphics.VertexFloatCount) vs := i.ensureTmpVertices(4 * graphics.VertexFloatCount)
// Do not use srcRegions[0].Dx() and srcRegions[0].Dy() as these might be empty. // Do not use srcRegions[0].Dx() and srcRegions[0].Dy() as these might be empty.
graphics.QuadVertices(vs, graphics.QuadVerticesFromSrcAndMatrix(vs,
float32(srcRegions[0].Min.X), float32(srcRegions[0].Min.Y), float32(srcRegions[0].Min.X), float32(srcRegions[0].Min.Y),
float32(srcRegions[0].Min.X+width), float32(srcRegions[0].Min.Y+height), float32(srcRegions[0].Min.X+width), float32(srcRegions[0].Min.Y+height),
a, b, c, d, tx, ty, cr, cg, cb, ca) a, b, c, d, tx, ty, cr, cg, cb, ca)

View File

@ -43,16 +43,6 @@ func min(a, b int) int {
return b return b
} }
// quadVertices returns vertices to render a quad. These values are passed to graphicscommand.Image.
func quadVertices(dx0, dy0, dx1, dy1, sx0, sy0, sx1, sy1, cr, cg, cb, ca float32) []float32 {
return []float32{
dx0, dy0, sx0, sy0, cr, cg, cb, ca,
dx1, dy0, sx1, sy0, cr, cg, cb, ca,
dx0, dy1, sx0, sy1, cr, cg, cb, ca,
dx1, dy1, sx1, sy1, cr, cg, cb, ca,
}
}
func appendDeferred(f func()) { func appendDeferred(f func()) {
deferredM.Lock() deferredM.Lock()
defer deferredM.Unlock() defer deferredM.Unlock()
@ -149,7 +139,8 @@ func (b *backend) extendIfNeeded(width, height int) {
srcs := [graphics.ShaderSrcImageCount]*graphicscommand.Image{b.image} srcs := [graphics.ShaderSrcImageCount]*graphicscommand.Image{b.image}
sw, sh := b.image.InternalSize() sw, sh := b.image.InternalSize()
vs := quadVertices(0, 0, float32(sw), float32(sh), 0, 0, float32(sw), float32(sh), 1, 1, 1, 1) vs := make([]float32, 4*graphics.VertexFloatCount)
graphics.QuadVerticesFromDstAndSrc(vs, 0, 0, float32(sw), float32(sh), 0, 0, float32(sw), float32(sh), 1, 1, 1, 1)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, sw, sh) dr := image.Rect(0, 0, sw, sh)
newImg.DrawTriangles(srcs, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, NearestFilterShader.ensureShader(), nil, graphicsdriver.FillRuleFillAll) newImg.DrawTriangles(srcs, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, NearestFilterShader.ensureShader(), nil, graphicsdriver.FillRuleFillAll)
@ -174,7 +165,8 @@ func newClearedImage(width, height int, screen bool) *graphicscommand.Image {
} }
func clearImage(i *graphicscommand.Image, region image.Rectangle) { func clearImage(i *graphicscommand.Image, region image.Rectangle) {
vs := quadVertices(float32(region.Min.X), float32(region.Min.Y), float32(region.Max.X), float32(region.Max.Y), 0, 0, 0, 0, 0, 0, 0, 0) vs := make([]float32, 4*graphics.VertexFloatCount)
graphics.QuadVerticesFromDstAndSrc(vs, float32(region.Min.X), float32(region.Min.Y), float32(region.Max.X), float32(region.Max.Y), 0, 0, 0, 0, 0, 0, 0, 0)
is := graphics.QuadIndices() is := graphics.QuadIndices()
i.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{}, vs, is, graphicsdriver.BlendClear, region, [graphics.ShaderSrcImageCount]image.Rectangle{}, clearShader.ensureShader(), nil, graphicsdriver.FillRuleFillAll) i.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{}, vs, is, graphicsdriver.BlendClear, region, [graphics.ShaderSrcImageCount]image.Rectangle{}, clearShader.ensureShader(), nil, graphicsdriver.FillRuleFillAll)
} }
@ -353,7 +345,7 @@ func (i *Image) ensureIsolatedFromSource(backends []*backend) {
w, h := float32(i.width), float32(i.height) w, h := float32(i.width), float32(i.height)
vs := make([]float32, 4*graphics.VertexFloatCount) vs := make([]float32, 4*graphics.VertexFloatCount)
graphics.QuadVertices(vs, 0, 0, w, h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1) graphics.QuadVerticesFromSrcAndMatrix(vs, 0, 0, w, h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, i.width, i.height) dr := image.Rect(0, 0, i.width, i.height)
@ -384,7 +376,7 @@ func (i *Image) putOnSourceBackend() {
w, h := float32(i.width), float32(i.height) w, h := float32(i.width), float32(i.height)
vs := make([]float32, 4*graphics.VertexFloatCount) vs := make([]float32, 4*graphics.VertexFloatCount)
graphics.QuadVertices(vs, 0, 0, w, h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1) graphics.QuadVerticesFromSrcAndMatrix(vs, 0, 0, w, h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, i.width, i.height) dr := image.Rect(0, 0, i.width, i.height)
newI.drawTriangles([graphics.ShaderSrcImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, NearestFilterShader, nil, graphicsdriver.FillRuleFillAll) newI.drawTriangles([graphics.ShaderSrcImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)

View File

@ -50,12 +50,9 @@ func quadVertices(sw, sh, x, y int, scalex float32) []float32 {
sy0 := float32(0) sy0 := float32(0)
sx1 := float32(sw) sx1 := float32(sw)
sy1 := float32(sh) sy1 := float32(sh)
return []float32{ vs := make([]float32, 4*graphics.VertexFloatCount)
dx0, dy0, sx0, sy0, 1, 1, 1, 1, graphics.QuadVerticesFromDstAndSrc(vs, dx0, dy0, dx1, dy1, sx0, sy0, sx1, sy1, 1, 1, 1, 1)
dx1, dy0, sx1, sy0, 1, 1, 1, 1, return vs
dx0, dy1, sx0, sy1, 1, 1, 1, 1,
dx1, dy1, sx1, sy1, 1, 1, 1, 1,
}
} }
const bigSize = 2049 const bigSize = 2049

View File

@ -52,7 +52,7 @@ func TestUnsyncedPixels(t *testing.T) {
// Flush unsynced pixel cache. // Flush unsynced pixel cache.
src := buffered.NewImage(16, 16, atlas.ImageTypeRegular) src := buffered.NewImage(16, 16, atlas.ImageTypeRegular)
vs := make([]float32, 4*graphics.VertexFloatCount) vs := make([]float32, 4*graphics.VertexFloatCount)
graphics.QuadVertices(vs, 0, 0, 16, 16, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1) graphics.QuadVerticesFromSrcAndMatrix(vs, 0, 0, 16, 16, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, 16, 16) dr := image.Rect(0, 0, 16, 16)
sr := [graphics.ShaderSrcImageCount]image.Rectangle{image.Rect(0, 0, 16, 16)} sr := [graphics.ShaderSrcImageCount]image.Rectangle{image.Rect(0, 0, 16, 16)}

View File

@ -50,16 +50,16 @@ func QuadIndices() []uint32 {
return quadIndices return quadIndices
} }
// QuadVertices sets a float32 slice for a quadrangle. // QuadVerticesFromSrcAndMatrix sets a float32 slice for a quadrangle.
// QuadVertices sets a slice that never overlaps with other slices returned this function, func QuadVerticesFromSrcAndMatrix(dst []float32, sx0, sy0, sx1, sy1 float32, a, b, c, d, tx, ty float32, cr, cg, cb, ca float32) {
// and users can do optimization based on this fact.
func QuadVertices(dst []float32, sx0, sy0, sx1, sy1 float32, a, b, c, d, tx, ty float32, cr, cg, cb, ca float32) {
x := sx1 - sx0 x := sx1 - sx0
y := sy1 - sy0 y := sy1 - sy0
ax, by, cx, dy := a*x, b*y, c*x, d*y ax, by, cx, dy := a*x, b*y, c*x, d*y
u0, v0, u1, v1 := sx0, sy0, sx1, sy1 u0, v0, u1, v1 := sx0, sy0, sx1, sy1
// This function is very performance-sensitive and implement in a very dumb way. // This function is very performance-sensitive and implement in a very dumb way.
// Remove the boundary check.
dst = dst[:4*VertexFloatCount] dst = dst[:4*VertexFloatCount]
dst[0] = adjustDestinationPixel(tx) dst[0] = adjustDestinationPixel(tx)
@ -99,6 +99,53 @@ func QuadVertices(dst []float32, sx0, sy0, sx1, sy1 float32, a, b, c, d, tx, ty
dst[3*VertexFloatCount+7] = ca dst[3*VertexFloatCount+7] = ca
} }
// QuadVerticesFromDstAndSrc sets a float32 slice for a quadrangle.
func QuadVerticesFromDstAndSrc(dst []float32, dx0, dy0, dx1, dy1, sx0, sy0, sx1, sy1, cr, cg, cb, ca float32) {
dx0 = adjustDestinationPixel(dx0)
dy0 = adjustDestinationPixel(dy0)
dx1 = adjustDestinationPixel(dx1)
dy1 = adjustDestinationPixel(dy1)
// Remove the boundary check.
dst = dst[:4*VertexFloatCount]
dst[0] = dx0
dst[1] = dy0
dst[2] = sx0
dst[3] = sy0
dst[4] = cr
dst[5] = cg
dst[6] = cb
dst[7] = ca
dst[VertexFloatCount] = dx1
dst[VertexFloatCount+1] = dy0
dst[VertexFloatCount+2] = sx1
dst[VertexFloatCount+3] = sy0
dst[VertexFloatCount+4] = cr
dst[VertexFloatCount+5] = cg
dst[VertexFloatCount+6] = cb
dst[VertexFloatCount+7] = ca
dst[2*VertexFloatCount] = dx0
dst[2*VertexFloatCount+1] = dy1
dst[2*VertexFloatCount+2] = sx0
dst[2*VertexFloatCount+3] = sy1
dst[2*VertexFloatCount+4] = cr
dst[2*VertexFloatCount+5] = cg
dst[2*VertexFloatCount+6] = cb
dst[2*VertexFloatCount+7] = ca
dst[3*VertexFloatCount] = dx1
dst[3*VertexFloatCount+1] = dy1
dst[3*VertexFloatCount+2] = sx1
dst[3*VertexFloatCount+3] = sy1
dst[3*VertexFloatCount+4] = cr
dst[3*VertexFloatCount+5] = cg
dst[3*VertexFloatCount+6] = cb
dst[3*VertexFloatCount+7] = ca
}
func adjustDestinationPixel(x float32) float32 { func adjustDestinationPixel(x float32) float32 {
// Avoid the center of the pixel, which is problematic (#929, #1171). // Avoid the center of the pixel, which is problematic (#929, #1171).
// Instead, align the vertices with about 1/3 pixels. // Instead, align the vertices with about 1/3 pixels.

View File

@ -43,12 +43,9 @@ func TestMain(m *testing.M) {
} }
func quadVertices(w, h float32) []float32 { func quadVertices(w, h float32) []float32 {
return []float32{ vs := make([]float32, 8*graphics.VertexFloatCount)
0, 0, 0, 0, 1, 1, 1, 1, graphics.QuadVerticesFromDstAndSrc(vs, 0, 0, w, h, 0, 0, w, h, 1, 1, 1, 1)
w, 0, w, 0, 1, 1, 1, 1, return vs
0, w, 0, h, 1, 1, 1, 1,
w, h, w, h, 1, 1, 1, 1,
}
} }
func TestClear(t *testing.T) { func TestClear(t *testing.T) {

View File

@ -152,7 +152,7 @@ func (m *Mipmap) level(level int) *buffered.Image {
switch { switch {
case level == 1: case level == 1:
src = m.orig src = m.orig
graphics.QuadVertices(vs, 0, 0, float32(m.width), float32(m.height), 0.5, 0, 0, 0.5, 0, 0, 1, 1, 1, 1) graphics.QuadVerticesFromSrcAndMatrix(vs, 0, 0, float32(m.width), float32(m.height), 0.5, 0, 0, 0.5, 0, 0, 1, 1, 1, 1)
case level > 1: case level > 1:
src = m.level(level - 1) src = m.level(level - 1)
if src == nil { if src == nil {
@ -161,7 +161,7 @@ func (m *Mipmap) level(level int) *buffered.Image {
} }
w := sizeForLevel(m.width, level-1) w := sizeForLevel(m.width, level-1)
h := sizeForLevel(m.height, level-1) h := sizeForLevel(m.height, level-1)
graphics.QuadVertices(vs, 0, 0, float32(w), float32(h), 0.5, 0, 0, 0.5, 0, 0, 1, 1, 1, 1) graphics.QuadVerticesFromSrcAndMatrix(vs, 0, 0, float32(w), float32(h), 0.5, 0, 0, 0.5, 0, 0, 1, 1, 1, 1)
default: default:
panic(fmt.Sprintf("mipmap: invalid level: %d", level)) panic(fmt.Sprintf("mipmap: invalid level: %d", level))
} }

View File

@ -158,7 +158,7 @@ func (i *Image) Fill(r, g, b, a float32, region image.Rectangle) {
i.tmpVerticesForFill = make([]float32, 4*graphics.VertexFloatCount) i.tmpVerticesForFill = make([]float32, 4*graphics.VertexFloatCount)
} }
// i.tmpVerticesForFill can be reused as this is sent to DrawTriangles immediately. // i.tmpVerticesForFill can be reused as this is sent to DrawTriangles immediately.
graphics.QuadVertices( graphics.QuadVerticesFromSrcAndMatrix(
i.tmpVerticesForFill, i.tmpVerticesForFill,
1, 1, float32(i.ui.whiteImage.width-1), float32(i.ui.whiteImage.height-1), 1, 1, float32(i.ui.whiteImage.width-1), float32(i.ui.whiteImage.height-1),
float32(i.width), 0, 0, float32(i.height), 0, 0, float32(i.width), 0, 0, float32(i.height), 0, 0,
@ -235,7 +235,7 @@ func (i *bigOffscreenImage) drawTriangles(srcs [graphics.ShaderSrcImageCount]*Im
i.tmpVerticesForCopying = make([]float32, 4*graphics.VertexFloatCount) i.tmpVerticesForCopying = make([]float32, 4*graphics.VertexFloatCount)
} }
// i.tmpVerticesForCopying can be reused as this is sent to DrawTriangles immediately. // i.tmpVerticesForCopying can be reused as this is sent to DrawTriangles immediately.
graphics.QuadVertices( graphics.QuadVerticesFromSrcAndMatrix(
i.tmpVerticesForCopying, i.tmpVerticesForCopying,
float32(i.region.Min.X), float32(i.region.Min.Y), float32(i.region.Max.X), float32(i.region.Max.Y), float32(i.region.Min.X), float32(i.region.Min.Y), float32(i.region.Max.X), float32(i.region.Max.Y),
bigOffscreenScale, 0, 0, bigOffscreenScale, 0, 0, bigOffscreenScale, 0, 0, bigOffscreenScale, 0, 0,
@ -279,7 +279,7 @@ func (i *bigOffscreenImage) flush() {
i.tmpVerticesForFlushing = make([]float32, 4*graphics.VertexFloatCount) i.tmpVerticesForFlushing = make([]float32, 4*graphics.VertexFloatCount)
} }
// i.tmpVerticesForFlushing can be reused as this is sent to DrawTriangles in this function. // i.tmpVerticesForFlushing can be reused as this is sent to DrawTriangles in this function.
graphics.QuadVertices( graphics.QuadVerticesFromSrcAndMatrix(
i.tmpVerticesForFlushing, i.tmpVerticesForFlushing,
0, 0, float32(i.region.Dx()*bigOffscreenScale), float32(i.region.Dy()*bigOffscreenScale), 0, 0, float32(i.region.Dx()*bigOffscreenScale), float32(i.region.Dy()*bigOffscreenScale),
1.0/bigOffscreenScale, 0, 0, 1.0/bigOffscreenScale, float32(i.region.Min.X), float32(i.region.Min.Y), 1.0/bigOffscreenScale, 0, 0, 1.0/bigOffscreenScale, float32(i.region.Min.X), float32(i.region.Min.Y),