internal/graphicsdriver: add FillRule and replace boolean values with this

Updates #2782
This commit is contained in:
Hajime Hoshi 2023-11-04 18:09:47 +09:00
parent 0cbcf7e493
commit 38cf964a3b
17 changed files with 161 additions and 140 deletions

View File

@ -262,7 +262,7 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) {
}) })
} }
i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedBounds(), [graphics.ShaderImageCount]image.Rectangle{img.adjustedBounds()}, shader.shader, i.tmpUniforms, false, canSkipMipmap(geoM, filter), false) i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedBounds(), [graphics.ShaderImageCount]image.Rectangle{img.adjustedBounds()}, shader.shader, i.tmpUniforms, graphicsdriver.FillAll, canSkipMipmap(geoM, filter), false)
} }
// Vertex represents a vertex passed to DrawTriangles. // Vertex represents a vertex passed to DrawTriangles.
@ -312,11 +312,11 @@ type FillRule int
const ( const (
// FillAll indicates all the triangles are rendered regardless of overlaps. // FillAll indicates all the triangles are rendered regardless of overlaps.
FillAll FillRule = iota FillAll FillRule = FillRule(graphicsdriver.FillAll)
// EvenOdd means that triangles are rendered based on the even-odd rule. // EvenOdd means that triangles are rendered based on the even-odd rule.
// If and only if the number of overlaps is odd, the region is rendered. // If and only if the number of overlaps is odd, the region is rendered.
EvenOdd EvenOdd FillRule = FillRule(graphicsdriver.EvenOdd)
) )
// ColorScaleMode is the mode of color scales in vertices. // ColorScaleMode is the mode of color scales in vertices.
@ -511,7 +511,7 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o
}) })
} }
i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedBounds(), [graphics.ShaderImageCount]image.Rectangle{img.adjustedBounds()}, shader.shader, i.tmpUniforms, options.FillRule == EvenOdd, filter != builtinshader.FilterLinear, options.AntiAlias) i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedBounds(), [graphics.ShaderImageCount]image.Rectangle{img.adjustedBounds()}, shader.shader, i.tmpUniforms, graphicsdriver.FillRule(options.FillRule), filter != builtinshader.FilterLinear, options.AntiAlias)
} }
// DrawTrianglesShaderOptions represents options for DrawTrianglesShader. // DrawTrianglesShaderOptions represents options for DrawTrianglesShader.
@ -676,7 +676,7 @@ func (i *Image) DrawTrianglesShader(vertices []Vertex, indices []uint16, shader
i.tmpUniforms = i.tmpUniforms[:0] i.tmpUniforms = i.tmpUniforms[:0]
i.tmpUniforms = shader.appendUniforms(i.tmpUniforms, options.Uniforms) i.tmpUniforms = shader.appendUniforms(i.tmpUniforms, options.Uniforms)
i.image.DrawTriangles(imgs, vs, is, blend, i.adjustedBounds(), srcRegions, shader.shader, i.tmpUniforms, options.FillRule == EvenOdd, true, options.AntiAlias) i.image.DrawTriangles(imgs, vs, is, blend, i.adjustedBounds(), srcRegions, shader.shader, i.tmpUniforms, graphicsdriver.FillRule(options.FillRule), true, options.AntiAlias)
} }
// DrawRectShaderOptions represents options for DrawRectShader. // DrawRectShaderOptions represents options for DrawRectShader.
@ -806,7 +806,7 @@ func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawR
i.tmpUniforms = i.tmpUniforms[:0] i.tmpUniforms = i.tmpUniforms[:0]
i.tmpUniforms = shader.appendUniforms(i.tmpUniforms, options.Uniforms) i.tmpUniforms = shader.appendUniforms(i.tmpUniforms, options.Uniforms)
i.image.DrawTriangles(imgs, vs, is, blend, i.adjustedBounds(), srcRegions, shader.shader, i.tmpUniforms, false, true, false) i.image.DrawTriangles(imgs, vs, is, blend, i.adjustedBounds(), srcRegions, shader.shader, i.tmpUniforms, graphicsdriver.FillAll, true, false)
} }
// SubImage returns an image representing the portion of the image p visible through r. // SubImage returns an image representing the portion of the image p visible through r.

View File

@ -251,7 +251,7 @@ func (i *Image) ensureIsolatedFromSource(backends []*backend) {
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.ShaderImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, NearestFilterShader, nil, false) newI.drawTriangles([graphics.ShaderImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, NearestFilterShader, nil, graphicsdriver.FillAll)
newI.moveTo(i) newI.moveTo(i)
} }
@ -281,7 +281,7 @@ func (i *Image) putOnSourceBackend(graphicsDriver graphicsdriver.Graphics) {
graphics.QuadVertices(vs, 0, 0, w, h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1) graphics.QuadVertices(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.ShaderImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, NearestFilterShader, nil, false) newI.drawTriangles([graphics.ShaderImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, NearestFilterShader, nil, graphicsdriver.FillAll)
newI.moveTo(i) newI.moveTo(i)
i.usedAsSourceCount = 0 i.usedAsSourceCount = 0
@ -313,7 +313,7 @@ func (i *Image) regionWithPadding() image.Rectangle {
// 5: Color G // 5: Color G
// 6: Color B // 6: Color B
// 7: Color Y // 7: Color Y
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, evenOdd bool) { func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
backendsM.Lock() backendsM.Lock()
defer backendsM.Unlock() defer backendsM.Unlock()
@ -326,15 +326,15 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [
copy(us, uniforms) copy(us, uniforms)
appendDeferred(func() { appendDeferred(func() {
i.drawTriangles(srcs, vs, is, blend, dstRegion, srcRegions, shader, us, evenOdd) i.drawTriangles(srcs, vs, is, blend, dstRegion, srcRegions, shader, us, fillRule)
}) })
return return
} }
i.drawTriangles(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, evenOdd) i.drawTriangles(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule)
} }
func (i *Image) drawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, evenOdd bool) { func (i *Image) drawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
backends := make([]*backend, 0, len(srcs)) backends := make([]*backend, 0, len(srcs))
for _, src := range srcs { for _, src := range srcs {
if src == nil { if src == nil {
@ -415,7 +415,7 @@ func (i *Image) drawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [
imgs[i] = src.backend.restorable imgs[i] = src.backend.restorable
} }
i.backend.restorable.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegions, shader.ensureShader(), uniforms, evenOdd) i.backend.restorable.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegions, shader.ensureShader(), uniforms, fillRule)
for _, src := range srcs { for _, src := range srcs {
if src == nil { if src == nil {

View File

@ -103,7 +103,7 @@ func TestEnsureIsolatedFromSourceBackend(t *testing.T) {
vs := quadVertices(size/2, size/2, size/4, size/4, 1) vs := quadVertices(size/2, size/2, size/4, size/4, 1)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, size, size) dr := image.Rect(0, 0, size, size)
img4.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) img4.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
if got, want := img4.IsOnSourceBackendForTesting(), false; got != want { if got, want := img4.IsOnSourceBackendForTesting(), false; got != want {
t.Errorf("got: %v, want: %v", got, want) t.Errorf("got: %v, want: %v", got, want)
} }
@ -111,7 +111,7 @@ func TestEnsureIsolatedFromSourceBackend(t *testing.T) {
// img5 is not allocated now, but is allocated at DrawTriangles. // img5 is not allocated now, but is allocated at DrawTriangles.
vs = quadVertices(0, 0, size/2, size/2, 1) vs = quadVertices(0, 0, size/2, size/2, 1)
dr = image.Rect(0, 0, size/2, size/2) dr = image.Rect(0, 0, size/2, size/2)
img3.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img5}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) img3.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img5}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
if got, want := img3.IsOnSourceBackendForTesting(), false; got != want { if got, want := img3.IsOnSourceBackendForTesting(), false; got != want {
t.Errorf("got: %v, want: %v", got, want) t.Errorf("got: %v, want: %v", got, want)
} }
@ -141,7 +141,7 @@ func TestEnsureIsolatedFromSourceBackend(t *testing.T) {
// Check further drawing doesn't cause panic. // Check further drawing doesn't cause panic.
// This bug was fixed by 03dcd948. // This bug was fixed by 03dcd948.
vs = quadVertices(0, 0, size/2, size/2, 1) vs = quadVertices(0, 0, size/2, size/2, 1)
img4.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) img4.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
} }
func TestReputOnSourceBackend(t *testing.T) { func TestReputOnSourceBackend(t *testing.T) {
@ -185,7 +185,7 @@ func TestReputOnSourceBackend(t *testing.T) {
// Render onto img1. The count should not matter. // Render onto img1. The count should not matter.
for i := 0; i < 5; i++ { for i := 0; i < 5; i++ {
vs := quadVertices(size, size, 0, 0, 1) vs := quadVertices(size, size, 0, 0, 1)
img1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) img1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
if got, want := img1.IsOnSourceBackendForTesting(), false; got != want { if got, want := img1.IsOnSourceBackendForTesting(), false; got != want {
t.Errorf("got: %v, want: %v", got, want) t.Errorf("got: %v, want: %v", got, want)
} }
@ -197,7 +197,7 @@ func TestReputOnSourceBackend(t *testing.T) {
for i := 0; i < atlas.BaseCountToPutOnSourceBackend*2; i++ { for i := 0; i < atlas.BaseCountToPutOnSourceBackend*2; i++ {
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting()) atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
vs := quadVertices(size, size, 0, 0, 1) vs := quadVertices(size, size, 0, 0, 1)
img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
if got, want := img1.IsOnSourceBackendForTesting(), false; got != want { if got, want := img1.IsOnSourceBackendForTesting(), false; got != want {
t.Errorf("got: %v, want: %v", got, want) t.Errorf("got: %v, want: %v", got, want)
} }
@ -205,7 +205,7 @@ func TestReputOnSourceBackend(t *testing.T) {
// Finally, img1 is on a source backend. // Finally, img1 is on a source backend.
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting()) atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
vs := quadVertices(size, size, 0, 0, 1) vs := quadVertices(size, size, 0, 0, 1)
img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
if got, want := img1.IsOnSourceBackendForTesting(), true; got != want { if got, want := img1.IsOnSourceBackendForTesting(), true; got != want {
t.Errorf("got: %v, want: %v", got, want) t.Errorf("got: %v, want: %v", got, want)
} }
@ -230,7 +230,7 @@ func TestReputOnSourceBackend(t *testing.T) {
} }
vs = quadVertices(size, size, 0, 0, 1) vs = quadVertices(size, size, 0, 0, 1)
img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
if got, want := img1.IsOnSourceBackendForTesting(), true; got != want { if got, want := img1.IsOnSourceBackendForTesting(), true; got != want {
t.Errorf("got: %v, want: %v", got, want) t.Errorf("got: %v, want: %v", got, want)
} }
@ -256,7 +256,7 @@ func TestReputOnSourceBackend(t *testing.T) {
// Use img1 as a render target again. The count should not matter. // Use img1 as a render target again. The count should not matter.
for i := 0; i < 5; i++ { for i := 0; i < 5; i++ {
vs := quadVertices(size, size, 0, 0, 1) vs := quadVertices(size, size, 0, 0, 1)
img1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) img1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
if got, want := img1.IsOnSourceBackendForTesting(), false; got != want { if got, want := img1.IsOnSourceBackendForTesting(), false; got != want {
t.Errorf("got: %v, want: %v", got, want) t.Errorf("got: %v, want: %v", got, want)
} }
@ -268,7 +268,7 @@ func TestReputOnSourceBackend(t *testing.T) {
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting()) atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
img1.WritePixels(make([]byte, 4*size*size), image.Rect(0, 0, size, size)) img1.WritePixels(make([]byte, 4*size*size), image.Rect(0, 0, size, size))
vs := quadVertices(size, size, 0, 0, 1) vs := quadVertices(size, size, 0, 0, 1)
img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
if got, want := img1.IsOnSourceBackendForTesting(), false; got != want { if got, want := img1.IsOnSourceBackendForTesting(), false; got != want {
t.Errorf("got: %v, want: %v", got, want) t.Errorf("got: %v, want: %v", got, want)
} }
@ -277,7 +277,7 @@ func TestReputOnSourceBackend(t *testing.T) {
// img1 is not on an atlas due to WritePixels. // img1 is not on an atlas due to WritePixels.
vs = quadVertices(size, size, 0, 0, 1) vs = quadVertices(size, size, 0, 0, 1)
img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
if got, want := img1.IsOnSourceBackendForTesting(), false; got != want { if got, want := img1.IsOnSourceBackendForTesting(), false; got != want {
t.Errorf("got: %v, want: %v", got, want) t.Errorf("got: %v, want: %v", got, want)
} }
@ -286,7 +286,7 @@ func TestReputOnSourceBackend(t *testing.T) {
for i := 0; i < atlas.BaseCountToPutOnSourceBackend*2; i++ { for i := 0; i < atlas.BaseCountToPutOnSourceBackend*2; i++ {
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting()) atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
vs := quadVertices(size, size, 0, 0, 1) vs := quadVertices(size, size, 0, 0, 1)
img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
if got, want := img3.IsOnSourceBackendForTesting(), false; got != want { if got, want := img3.IsOnSourceBackendForTesting(), false; got != want {
t.Errorf("got: %v, want: %v", got, want) t.Errorf("got: %v, want: %v", got, want)
} }
@ -381,7 +381,7 @@ func TestWritePixelsAfterDrawTriangles(t *testing.T) {
vs := quadVertices(w, h, 0, 0, 1) vs := quadVertices(w, h, 0, 0, 1)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, w, h) dr := image.Rect(0, 0, w, h)
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
dst.WritePixels(pix, image.Rect(0, 0, w, h)) dst.WritePixels(pix, image.Rect(0, 0, w, h))
pix = make([]byte, 4*w*h) pix = make([]byte, 4*w*h)
@ -424,7 +424,7 @@ func TestSmallImages(t *testing.T) {
vs := quadVertices(w, h, 0, 0, 1) vs := quadVertices(w, h, 0, 0, 1)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, w, h) dr := image.Rect(0, 0, w, h)
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
pix = make([]byte, 4*w*h) pix = make([]byte, 4*w*h)
if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h)); err != nil { if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h)); err != nil {
@ -467,7 +467,7 @@ func TestLongImages(t *testing.T) {
vs := quadVertices(w, h, 0, 0, scale) vs := quadVertices(w, h, 0, 0, scale)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, dstW, dstH) dr := image.Rect(0, 0, dstW, dstH)
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
pix = make([]byte, 4*dstW*dstH) pix = make([]byte, 4*dstW*dstH)
if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, dstW, dstH)); err != nil { if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, dstW, dstH)); err != nil {
@ -579,7 +579,7 @@ func TestDeallocatedAndReputOnSourceBackend(t *testing.T) {
vs := quadVertices(size, size, 0, 0, 1) vs := quadVertices(size, size, 0, 0, 1)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, size, size) dr := image.Rect(0, 0, size, size)
src.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) src.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
if got, want := src.IsOnSourceBackendForTesting(), false; got != want { if got, want := src.IsOnSourceBackendForTesting(), false; got != want {
t.Errorf("got: %v, want: %v", got, want) t.Errorf("got: %v, want: %v", got, want)
} }
@ -588,7 +588,7 @@ func TestDeallocatedAndReputOnSourceBackend(t *testing.T) {
for i := 0; i < atlas.BaseCountToPutOnSourceBackend/2; i++ { for i := 0; i < atlas.BaseCountToPutOnSourceBackend/2; i++ {
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting()) atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
vs := quadVertices(size, size, 0, 0, 1) vs := quadVertices(size, size, 0, 0, 1)
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
if got, want := src.IsOnSourceBackendForTesting(), false; got != want { if got, want := src.IsOnSourceBackendForTesting(), false; got != want {
t.Errorf("got: %v, want: %v", got, want) t.Errorf("got: %v, want: %v", got, want)
} }
@ -622,7 +622,7 @@ func TestImageIsNotReputOnSourceBackendWithoutUsingAsSource(t *testing.T) {
// Call DrawTriangles multiple times. // Call DrawTriangles multiple times.
// The number of DrawTriangles doesn't matter as long as these are called in one frame. // The number of DrawTriangles doesn't matter as long as these are called in one frame.
for i := 0; i < 2; i++ { for i := 0; i < 2; i++ {
src2.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) src2.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
} }
if got, want := src2.IsOnSourceBackendForTesting(), false; got != want { if got, want := src2.IsOnSourceBackendForTesting(), false; got != want {
t.Errorf("got: %v, want: %v", got, want) t.Errorf("got: %v, want: %v", got, want)
@ -641,7 +641,7 @@ func TestImageIsNotReputOnSourceBackendWithoutUsingAsSource(t *testing.T) {
for i := 0; i < atlas.BaseCountToPutOnSourceBackend; i++ { for i := 0; i < atlas.BaseCountToPutOnSourceBackend; i++ {
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting()) atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
vs := quadVertices(size, size, 0, 0, 1) vs := quadVertices(size, size, 0, 0, 1)
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
if got, want := src2.IsOnSourceBackendForTesting(), false; got != want { if got, want := src2.IsOnSourceBackendForTesting(), false; got != want {
t.Errorf("got: %v, want: %v", got, want) t.Errorf("got: %v, want: %v", got, want)
} }
@ -763,14 +763,14 @@ func TestDestinationCountOverflow(t *testing.T) {
// Use dst0 as a destination for a while. // Use dst0 as a destination for a while.
for i := 0; i < 31; i++ { for i := 0; i < 31; i++ {
dst0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) dst0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting()) atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
} }
// Use dst0 as a source for a while. // Use dst0 as a source for a while.
// As dst0 is used as a destination too many times (31 is a maximum), dst0's backend should never be a source backend. // As dst0 is used as a destination too many times (31 is a maximum), dst0's backend should never be a source backend.
for i := 0; i < 100; i++ { for i := 0; i < 100; i++ {
dst1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{dst0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) dst1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{dst0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting()) atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
if dst0.IsOnSourceBackendForTesting() { if dst0.IsOnSourceBackendForTesting() {
t.Errorf("dst0 cannot be on a source backend: %d", i) t.Errorf("dst0 cannot be on a source backend: %d", i)
@ -796,7 +796,7 @@ func TestIteratingImagesToPutOnSourceBackend(t *testing.T) {
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, w, h) dr := image.Rect(0, 0, w, h)
for _, img := range srcs { for _, img := range srcs {
img.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) img.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
} }
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting()) atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
@ -804,7 +804,7 @@ func TestIteratingImagesToPutOnSourceBackend(t *testing.T) {
// Check iterating the registered image works correctly. // Check iterating the registered image works correctly.
for i := 0; i < 100; i++ { for i := 0; i < 100; i++ {
for _, src := range srcs { for _, src := range srcs {
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
} }
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting()) atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
} }

View File

@ -36,12 +36,12 @@ func TestShaderFillTwice(t *testing.T) {
dr := image.Rect(0, 0, w, h) dr := image.Rect(0, 0, w, h)
g := ui.Get().GraphicsDriverForTesting() g := ui.Get().GraphicsDriverForTesting()
s0 := atlas.NewShader(etesting.ShaderProgramFill(0xff, 0xff, 0xff, 0xff)) s0 := atlas.NewShader(etesting.ShaderProgramFill(0xff, 0xff, 0xff, 0xff))
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, s0, nil, false) dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, s0, nil, graphicsdriver.FillAll)
// Vertices must be recreated (#1755) // Vertices must be recreated (#1755)
vs = quadVertices(w, h, 0, 0, 1) vs = quadVertices(w, h, 0, 0, 1)
s1 := atlas.NewShader(etesting.ShaderProgramFill(0x80, 0x80, 0x80, 0xff)) s1 := atlas.NewShader(etesting.ShaderProgramFill(0x80, 0x80, 0x80, 0xff))
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, s1, nil, false) dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, s1, nil, graphicsdriver.FillAll)
pix := make([]byte, 4*w*h) pix := make([]byte, 4*w*h)
if err := dst.ReadPixels(g, pix, image.Rect(0, 0, w, h)); err != nil { if err := dst.ReadPixels(g, pix, image.Rect(0, 0, w, h)); err != nil {
@ -64,11 +64,11 @@ func TestImageDrawTwice(t *testing.T) {
vs := quadVertices(w, h, 0, 0, 1) vs := quadVertices(w, h, 0, 0, 1)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, w, h) dr := image.Rect(0, 0, w, h)
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
// Vertices must be recreated (#1755) // Vertices must be recreated (#1755)
vs = quadVertices(w, h, 0, 0, 1) vs = quadVertices(w, h, 0, 0, 1)
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
pix := make([]byte, 4*w*h) pix := make([]byte, 4*w*h)
if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h)); err != nil { if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h)); err != nil {

View File

@ -92,7 +92,7 @@ func (i *Image) WritePixels(pix []byte, region image.Rectangle) {
// DrawTriangles draws the src image with the given vertices. // DrawTriangles draws the src image with the given vertices.
// //
// Copying vertices and indices is the caller's responsibility. // Copying vertices and indices is the caller's responsibility.
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *atlas.Shader, uniforms []uint32, evenOdd bool) { func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *atlas.Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
for _, src := range srcs { for _, src := range srcs {
if i == src { if i == src {
panic("buffered: Image.DrawTriangles: source images must be different from the receiver") panic("buffered: Image.DrawTriangles: source images must be different from the receiver")
@ -108,5 +108,5 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [
imgs[i] = img.img imgs[i] = img.img
} }
i.img.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, evenOdd) i.img.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule)
} }

View File

@ -68,7 +68,7 @@ type drawTrianglesCommand struct {
dstRegions []graphicsdriver.DstRegion dstRegions []graphicsdriver.DstRegion
shader *Shader shader *Shader
uniforms []uint32 uniforms []uint32
evenOdd bool fillRule graphicsdriver.FillRule
} }
func (c *drawTrianglesCommand) String() string { func (c *drawTrianglesCommand) String() string {
@ -98,7 +98,7 @@ func (c *drawTrianglesCommand) String() string {
} }
} }
return fmt.Sprintf("draw-triangles: dst: %s <- src: [%s], num of dst regions: %d, num of indices: %d, blend: %s, even-odd: %t", dst, strings.Join(srcstrs[:], ", "), len(c.dstRegions), c.numIndices(), blend, c.evenOdd) return fmt.Sprintf("draw-triangles: dst: %s <- src: [%s], num of dst regions: %d, num of indices: %d, blend: %s, fill rule: %s", dst, strings.Join(srcstrs[:], ", "), len(c.dstRegions), c.numIndices(), blend, c.fillRule)
} }
// Exec executes the drawTrianglesCommand. // Exec executes the drawTrianglesCommand.
@ -117,7 +117,7 @@ func (c *drawTrianglesCommand) Exec(commandQueue *commandQueue, graphicsDriver g
imgs[i] = src.image.ID() imgs[i] = src.image.ID()
} }
return graphicsDriver.DrawTriangles(c.dst.image.ID(), imgs, c.shader.shader.ID(), c.dstRegions, indexOffset, c.blend, c.uniforms, c.evenOdd) return graphicsDriver.DrawTriangles(c.dst.image.ID(), imgs, c.shader.shader.ID(), c.dstRegions, indexOffset, c.blend, c.uniforms, c.fillRule)
} }
func (c *drawTrianglesCommand) NeedsSync() bool { func (c *drawTrianglesCommand) NeedsSync() bool {
@ -142,7 +142,7 @@ func (c *drawTrianglesCommand) setVertices(vertices []float32) {
// CanMergeWithDrawTrianglesCommand returns a boolean value indicating whether the other drawTrianglesCommand can be merged // CanMergeWithDrawTrianglesCommand returns a boolean value indicating whether the other drawTrianglesCommand can be merged
// with the drawTrianglesCommand c. // with the drawTrianglesCommand c.
func (c *drawTrianglesCommand) CanMergeWithDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderImageCount]*Image, vertices []float32, blend graphicsdriver.Blend, shader *Shader, uniforms []uint32, evenOdd bool) bool { func (c *drawTrianglesCommand) CanMergeWithDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderImageCount]*Image, vertices []float32, blend graphicsdriver.Blend, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) bool {
if c.shader != shader { if c.shader != shader {
return false return false
} }
@ -163,10 +163,10 @@ func (c *drawTrianglesCommand) CanMergeWithDrawTrianglesCommand(dst *Image, srcs
if c.blend != blend { if c.blend != blend {
return false return false
} }
if c.evenOdd != evenOdd { if c.fillRule != fillRule {
return false return false
} }
if c.evenOdd && mightOverlapDstRegions(c.vertices, vertices) { if c.fillRule == graphicsdriver.EvenOdd && mightOverlapDstRegions(c.vertices, vertices) {
return false return false
} }
return true return true

View File

@ -101,7 +101,7 @@ func mustUseDifferentVertexBuffer(nextNumVertexFloats int) bool {
} }
// EnqueueDrawTrianglesCommand enqueues a drawing-image command. // EnqueueDrawTrianglesCommand enqueues a drawing-image command.
func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, evenOdd bool) { func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
if len(vertices) > maxVertexFloatCount { if len(vertices) > maxVertexFloatCount {
panic(fmt.Sprintf("graphicscommand: len(vertices) must equal to or less than %d but was %d", maxVertexFloatCount, len(vertices))) panic(fmt.Sprintf("graphicscommand: len(vertices) must equal to or less than %d but was %d", maxVertexFloatCount, len(vertices)))
} }
@ -129,7 +129,7 @@ func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.Sh
// TODO: If dst is the screen, reorder the command to be the last. // TODO: If dst is the screen, reorder the command to be the last.
if !split && 0 < len(q.commands) { if !split && 0 < len(q.commands) {
if last, ok := q.commands[len(q.commands)-1].(*drawTrianglesCommand); ok { if last, ok := q.commands[len(q.commands)-1].(*drawTrianglesCommand); ok {
if last.CanMergeWithDrawTrianglesCommand(dst, srcs, vertices, blend, shader, uniforms, evenOdd) { if last.CanMergeWithDrawTrianglesCommand(dst, srcs, vertices, blend, shader, uniforms, fillRule) {
last.setVertices(q.lastVertices(len(vertices) + last.numVertices())) last.setVertices(q.lastVertices(len(vertices) + last.numVertices()))
if last.dstRegions[len(last.dstRegions)-1].Region == dstRegion { if last.dstRegions[len(last.dstRegions)-1].Region == dstRegion {
last.dstRegions[len(last.dstRegions)-1].IndexCount += len(indices) last.dstRegions[len(last.dstRegions)-1].IndexCount += len(indices)
@ -157,7 +157,7 @@ func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.Sh
} }
c.shader = shader c.shader = shader
c.uniforms = uniforms c.uniforms = uniforms
c.evenOdd = evenOdd c.fillRule = fillRule
q.commands = append(q.commands, c) q.commands = append(q.commands, c)
} }
@ -493,11 +493,11 @@ func (c *commandQueueManager) putCommandQueue(commandQueue *commandQueue) {
c.pool.put(commandQueue) c.pool.put(commandQueue)
} }
func (c *commandQueueManager) enqueueDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, evenOdd bool) { func (c *commandQueueManager) enqueueDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
if c.current == nil { if c.current == nil {
c.current, _ = c.pool.get() c.current, _ = c.pool.get()
} }
c.current.EnqueueDrawTrianglesCommand(dst, srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, evenOdd) c.current.EnqueueDrawTrianglesCommand(dst, srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule)
} }
func (c *commandQueueManager) flush(graphicsDriver graphicsdriver.Graphics, endFrame bool, swapBuffersForGL func()) error { func (c *commandQueueManager) flush(graphicsDriver graphicsdriver.Graphics, endFrame bool, swapBuffersForGL func()) error {

View File

@ -130,7 +130,7 @@ func (i *Image) InternalSize() (int, int) {
// //
// If the source image is not specified, i.e., src is nil and there is no image in the uniform variables, the // If the source image is not specified, i.e., src is nil and there is no image in the uniform variables, the
// elements for the source image are not used. // elements for the source image are not used.
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, evenOdd bool) { func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
for _, src := range srcs { for _, src := range srcs {
if src == nil { if src == nil {
continue continue
@ -142,7 +142,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [
} }
i.flushBufferedWritePixels() i.flushBufferedWritePixels()
theCommandQueueManager.enqueueDrawTrianglesCommand(i, srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, evenOdd) theCommandQueueManager.enqueueDrawTrianglesCommand(i, srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule)
} }
// ReadPixels reads the image's pixels. // ReadPixels reads the image's pixels.

View File

@ -59,7 +59,7 @@ func TestClear(t *testing.T) {
vs := quadVertices(w/2, h/2) vs := quadVertices(w/2, h/2)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, w, h) dr := image.Rect(0, 0, w, h)
dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderImageCount]image.Rectangle{}, nearestFilterShader, nil, false) dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderImageCount]image.Rectangle{}, nearestFilterShader, nil, graphicsdriver.FillAll)
pix := make([]byte, 4*w*h) pix := make([]byte, 4*w*h)
if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), []graphicsdriver.PixelsArgs{ if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), []graphicsdriver.PixelsArgs{
@ -90,8 +90,8 @@ func TestWritePixelsPartAfterDrawTriangles(t *testing.T) {
vs := quadVertices(w/2, h/2) vs := quadVertices(w/2, h/2)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, w, h) dr := image.Rect(0, 0, w, h)
dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{clr}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderImageCount]image.Rectangle{}, nearestFilterShader, nil, false) dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{clr}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderImageCount]image.Rectangle{}, nearestFilterShader, nil, graphicsdriver.FillAll)
dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, nearestFilterShader, nil, false) dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, nearestFilterShader, nil, graphicsdriver.FillAll)
bs := graphics.NewManagedBytes(4, func(bs []byte) { bs := graphics.NewManagedBytes(4, func(bs []byte) {
for i := range bs { for i := range bs {
bs[i] = 0 bs[i] = 0
@ -109,11 +109,11 @@ func TestShader(t *testing.T) {
vs := quadVertices(w, h) vs := quadVertices(w, h)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, w, h) dr := image.Rect(0, 0, w, h)
dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{clr}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderImageCount]image.Rectangle{}, nearestFilterShader, nil, false) dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{clr}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderImageCount]image.Rectangle{}, nearestFilterShader, nil, graphicsdriver.FillAll)
g := ui.Get().GraphicsDriverForTesting() g := ui.Get().GraphicsDriverForTesting()
s := graphicscommand.NewShader(etesting.ShaderProgramFill(0xff, 0, 0, 0xff)) s := graphicscommand.NewShader(etesting.ShaderProgramFill(0xff, 0, 0, 0xff))
dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, s, nil, false) dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, s, nil, graphicsdriver.FillAll)
pix := make([]byte, 4*w*h) pix := make([]byte, 4*w*h)
if err := dst.ReadPixels(g, []graphicsdriver.PixelsArgs{ if err := dst.ReadPixels(g, []graphicsdriver.PixelsArgs{

View File

@ -15,6 +15,7 @@
package graphicsdriver package graphicsdriver
import ( import (
"fmt"
"image" "image"
"github.com/hajimehoshi/ebiten/v2/internal/graphics" "github.com/hajimehoshi/ebiten/v2/internal/graphics"
@ -26,6 +27,24 @@ type DstRegion struct {
IndexCount int IndexCount int
} }
type FillRule int
const (
FillAll FillRule = iota
EvenOdd
)
func (f FillRule) String() string {
switch f {
case FillAll:
return "FillAll"
case EvenOdd:
return "EvenOdd"
default:
return fmt.Sprintf("FillRule(%d)", f)
}
}
const ( const (
InvalidImageID = 0 InvalidImageID = 0
InvalidShaderID = 0 InvalidShaderID = 0
@ -47,7 +66,7 @@ type Graphics interface {
NewShader(program *shaderir.Program) (Shader, error) NewShader(program *shaderir.Program) (Shader, error)
// DrawTriangles draws an image onto another image with the given parameters. // DrawTriangles draws an image onto another image with the given parameters.
DrawTriangles(dst ImageID, srcs [graphics.ShaderImageCount]ImageID, shader ShaderID, dstRegions []DstRegion, indexOffset int, blend Blend, uniforms []uint32, evenOdd bool) error DrawTriangles(dst ImageID, srcs [graphics.ShaderImageCount]ImageID, shader ShaderID, dstRegions []DstRegion, indexOffset int, blend Blend, uniforms []uint32, fillRule FillRule) error
} }
type Resetter interface { type Resetter interface {

View File

@ -46,8 +46,8 @@ type Graphics struct {
buffers map[mtl.CommandBuffer][]mtl.Buffer buffers map[mtl.CommandBuffer][]mtl.Buffer
unusedBuffers map[mtl.Buffer]struct{} unusedBuffers map[mtl.Buffer]struct{}
lastDst *Image lastDst *Image
lastEvenOdd bool lastFillRule graphicsdriver.FillRule
vb mtl.Buffer vb mtl.Buffer
ib mtl.Buffer ib mtl.Buffer
@ -468,15 +468,15 @@ func (g *Graphics) flushRenderCommandEncoderIfNeeded() {
g.lastDst = nil g.lastDst = nil
} }
func (g *Graphics) draw(dst *Image, dstRegions []graphicsdriver.DstRegion, srcs [graphics.ShaderImageCount]*Image, indexOffset int, shader *Shader, uniforms [][]uint32, blend graphicsdriver.Blend, evenOdd bool) error { func (g *Graphics) draw(dst *Image, dstRegions []graphicsdriver.DstRegion, srcs [graphics.ShaderImageCount]*Image, indexOffset int, shader *Shader, uniforms [][]uint32, blend graphicsdriver.Blend, fillRule graphicsdriver.FillRule) error {
// When preparing a stencil buffer, flush the current render command encoder // When preparing a stencil buffer, flush the current render command encoder
// to make sure the stencil buffer is cleared when loading. // to make sure the stencil buffer is cleared when loading.
// TODO: What about clearing the stencil buffer by vertices? // TODO: What about clearing the stencil buffer by vertices?
if g.lastDst != dst || g.lastEvenOdd != evenOdd || evenOdd { if g.lastDst != dst || g.lastFillRule != fillRule || fillRule == graphicsdriver.EvenOdd {
g.flushRenderCommandEncoderIfNeeded() g.flushRenderCommandEncoderIfNeeded()
} }
g.lastDst = dst g.lastDst = dst
g.lastEvenOdd = evenOdd g.lastFillRule = fillRule
if g.rce == (mtl.RenderCommandEncoder{}) { if g.rce == (mtl.RenderCommandEncoder{}) {
rpd := mtl.RenderPassDescriptor{} rpd := mtl.RenderPassDescriptor{}
@ -498,7 +498,7 @@ func (g *Graphics) draw(dst *Image, dstRegions []graphicsdriver.DstRegion, srcs
rpd.ColorAttachments[0].Texture = t rpd.ColorAttachments[0].Texture = t
rpd.ColorAttachments[0].ClearColor = mtl.ClearColor{} rpd.ColorAttachments[0].ClearColor = mtl.ClearColor{}
if evenOdd { if fillRule == graphicsdriver.EvenOdd {
dst.ensureStencil() dst.ensureStencil()
rpd.StencilAttachment.LoadAction = mtl.LoadActionClear rpd.StencilAttachment.LoadAction = mtl.LoadActionClear
rpd.StencilAttachment.StoreAction = mtl.StoreActionDontCare rpd.StencilAttachment.StoreAction = mtl.StoreActionDontCare
@ -543,7 +543,14 @@ func (g *Graphics) draw(dst *Image, dstRegions []graphicsdriver.DstRegion, srcs
drawWithStencilRpss mtl.RenderPipelineState drawWithStencilRpss mtl.RenderPipelineState
noStencilRpss mtl.RenderPipelineState noStencilRpss mtl.RenderPipelineState
) )
if evenOdd { switch fillRule {
case graphicsdriver.FillAll:
s, err := shader.RenderPipelineState(&g.view, blend, noStencil, dst.screen)
if err != nil {
return err
}
noStencilRpss = s
case graphicsdriver.EvenOdd:
s, err := shader.RenderPipelineState(&g.view, blend, prepareStencil, dst.screen) s, err := shader.RenderPipelineState(&g.view, blend, prepareStencil, dst.screen)
if err != nil { if err != nil {
return err return err
@ -555,12 +562,6 @@ func (g *Graphics) draw(dst *Image, dstRegions []graphicsdriver.DstRegion, srcs
return err return err
} }
drawWithStencilRpss = s drawWithStencilRpss = s
} else {
s, err := shader.RenderPipelineState(&g.view, blend, noStencil, dst.screen)
if err != nil {
return err
}
noStencilRpss = s
} }
for _, dstRegion := range dstRegions { for _, dstRegion := range dstRegions {
@ -571,7 +572,12 @@ func (g *Graphics) draw(dst *Image, dstRegions []graphicsdriver.DstRegion, srcs
Height: dstRegion.Region.Dy(), Height: dstRegion.Region.Dy(),
}) })
if evenOdd { switch fillRule {
case graphicsdriver.FillAll:
g.rce.SetDepthStencilState(g.dsss[noStencil])
g.rce.SetRenderPipelineState(noStencilRpss)
g.rce.DrawIndexedPrimitives(mtl.PrimitiveTypeTriangle, dstRegion.IndexCount, mtl.IndexTypeUInt32, g.ib, indexOffset*int(unsafe.Sizeof(uint32(0))))
case graphicsdriver.EvenOdd:
g.rce.SetDepthStencilState(g.dsss[prepareStencil]) g.rce.SetDepthStencilState(g.dsss[prepareStencil])
g.rce.SetRenderPipelineState(prepareStencilRpss) g.rce.SetRenderPipelineState(prepareStencilRpss)
g.rce.DrawIndexedPrimitives(mtl.PrimitiveTypeTriangle, dstRegion.IndexCount, mtl.IndexTypeUInt32, g.ib, indexOffset*int(unsafe.Sizeof(uint32(0)))) g.rce.DrawIndexedPrimitives(mtl.PrimitiveTypeTriangle, dstRegion.IndexCount, mtl.IndexTypeUInt32, g.ib, indexOffset*int(unsafe.Sizeof(uint32(0))))
@ -579,10 +585,6 @@ func (g *Graphics) draw(dst *Image, dstRegions []graphicsdriver.DstRegion, srcs
g.rce.SetDepthStencilState(g.dsss[drawWithStencil]) g.rce.SetDepthStencilState(g.dsss[drawWithStencil])
g.rce.SetRenderPipelineState(drawWithStencilRpss) g.rce.SetRenderPipelineState(drawWithStencilRpss)
g.rce.DrawIndexedPrimitives(mtl.PrimitiveTypeTriangle, dstRegion.IndexCount, mtl.IndexTypeUInt32, g.ib, indexOffset*int(unsafe.Sizeof(uint32(0)))) g.rce.DrawIndexedPrimitives(mtl.PrimitiveTypeTriangle, dstRegion.IndexCount, mtl.IndexTypeUInt32, g.ib, indexOffset*int(unsafe.Sizeof(uint32(0))))
} else {
g.rce.SetDepthStencilState(g.dsss[noStencil])
g.rce.SetRenderPipelineState(noStencilRpss)
g.rce.DrawIndexedPrimitives(mtl.PrimitiveTypeTriangle, dstRegion.IndexCount, mtl.IndexTypeUInt32, g.ib, indexOffset*int(unsafe.Sizeof(uint32(0))))
} }
indexOffset += dstRegion.IndexCount indexOffset += dstRegion.IndexCount
@ -591,7 +593,7 @@ func (g *Graphics) draw(dst *Image, dstRegions []graphicsdriver.DstRegion, srcs
return nil return nil
} }
func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.ShaderImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, evenOdd bool) error { func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.ShaderImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error {
if shaderID == graphicsdriver.InvalidShaderID { if shaderID == graphicsdriver.InvalidShaderID {
return fmt.Errorf("metal: shader ID is invalid") return fmt.Errorf("metal: shader ID is invalid")
} }
@ -667,7 +669,7 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.
idx += n idx += n
} }
if err := g.draw(dst, dstRegions, srcs, indexOffset, g.shaders[shaderID], uniformVars, blend, evenOdd); err != nil { if err := g.draw(dst, dstRegions, srcs, indexOffset, g.shaders[shaderID], uniformVars, blend, fillRule); err != nil {
return err return err
} }

View File

@ -182,7 +182,7 @@ func (g *Graphics) uniformVariableName(idx int) string {
return name return name
} }
func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.ShaderImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, evenOdd bool) error { func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.ShaderImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error {
if shaderID == graphicsdriver.InvalidShaderID { if shaderID == graphicsdriver.InvalidShaderID {
return fmt.Errorf("opengl: shader ID is invalid") return fmt.Errorf("opengl: shader ID is invalid")
} }
@ -243,7 +243,7 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.
} }
g.uniformVars = g.uniformVars[:0] g.uniformVars = g.uniformVars[:0]
if evenOdd { if fillRule == graphicsdriver.EvenOdd {
if err := destination.ensureStencilBuffer(); err != nil { if err := destination.ensureStencilBuffer(); err != nil {
return err return err
} }
@ -257,7 +257,7 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.
int32(dstRegion.Region.Dx()), int32(dstRegion.Region.Dx()),
int32(dstRegion.Region.Dy()), int32(dstRegion.Region.Dy()),
) )
if evenOdd { if fillRule == graphicsdriver.EvenOdd {
g.context.ctx.Clear(gl.STENCIL_BUFFER_BIT) g.context.ctx.Clear(gl.STENCIL_BUFFER_BIT)
g.context.ctx.StencilFunc(gl.ALWAYS, 0x00, 0xff) g.context.ctx.StencilFunc(gl.ALWAYS, 0x00, 0xff)
g.context.ctx.StencilOp(gl.KEEP, gl.KEEP, gl.INVERT) g.context.ctx.StencilOp(gl.KEEP, gl.KEEP, gl.INVERT)
@ -273,7 +273,7 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.
indexOffset += dstRegion.IndexCount indexOffset += dstRegion.IndexCount
} }
if evenOdd { if fillRule == graphicsdriver.EvenOdd {
g.context.ctx.Disable(gl.STENCIL_TEST) g.context.ctx.Disable(gl.STENCIL_TEST)
} }

View File

@ -65,7 +65,7 @@ func (m *Mipmap) ReadPixels(graphicsDriver graphicsdriver.Graphics, pixels []byt
return m.orig.ReadPixels(graphicsDriver, pixels, region) return m.orig.ReadPixels(graphicsDriver, pixels, region)
} }
func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderImageCount]*Mipmap, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *atlas.Shader, uniforms []uint32, evenOdd bool, canSkipMipmap bool) { func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderImageCount]*Mipmap, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *atlas.Shader, uniforms []uint32, fillRule graphicsdriver.FillRule, canSkipMipmap bool) {
if len(indices) == 0 { if len(indices) == 0 {
return return
} }
@ -123,7 +123,7 @@ func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderImageCount]*Mipmap, vertices
imgs[i] = src.orig imgs[i] = src.orig
} }
m.orig.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, evenOdd) m.orig.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule)
m.deallocateMipmaps() m.deallocateMipmaps()
} }
@ -187,7 +187,7 @@ func (m *Mipmap) level(level int) *buffered.Image {
s := buffered.NewImage(w2, h2, m.imageType) s := buffered.NewImage(w2, h2, m.imageType)
dstRegion := image.Rect(0, 0, w2, h2) dstRegion := image.Rect(0, 0, w2, h2)
s.DrawTriangles([graphics.ShaderImageCount]*buffered.Image{src}, vs, is, graphicsdriver.BlendCopy, dstRegion, [graphics.ShaderImageCount]image.Rectangle{}, shader, nil, false) s.DrawTriangles([graphics.ShaderImageCount]*buffered.Image{src}, vs, is, graphicsdriver.BlendCopy, dstRegion, [graphics.ShaderImageCount]image.Rectangle{}, shader, nil, graphicsdriver.FillAll)
m.setImg(level, s) m.setImg(level, s)
return m.imgs[level] return m.imgs[level]

View File

@ -87,7 +87,7 @@ type drawTrianglesHistoryItem struct {
srcRegions [graphics.ShaderImageCount]image.Rectangle srcRegions [graphics.ShaderImageCount]image.Rectangle
shader *Shader shader *Shader
uniforms []uint32 uniforms []uint32
evenOdd bool fillRule graphicsdriver.FillRule
} }
type ImageType int type ImageType int
@ -187,7 +187,7 @@ func (i *Image) Extend(width, height int) *Image {
vs := quadVertices(0, 0, float32(sw), float32(sh), 0, 0, float32(sw), float32(sh), 1, 1, 1, 1) vs := quadVertices(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.ShaderImageCount]image.Rectangle{}, NearestFilterShader, nil, false) newImg.DrawTriangles(srcs, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, NearestFilterShader, nil, graphicsdriver.FillAll)
i.Dispose() i.Dispose()
return newImg return newImg
@ -206,7 +206,7 @@ func quadVertices(dx0, dy0, dx1, dy1, sx0, sy0, sx1, sy1, cr, cg, cb, ca float32
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 := 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)
is := graphics.QuadIndices() is := graphics.QuadIndices()
i.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{}, vs, is, graphicsdriver.BlendClear, region, [graphics.ShaderImageCount]image.Rectangle{}, clearShader.shader, nil, false) i.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{}, vs, is, graphicsdriver.BlendClear, region, [graphics.ShaderImageCount]image.Rectangle{}, clearShader.shader, nil, graphicsdriver.FillAll)
} }
// BasePixelsForTesting returns the image's basePixels for testing. // BasePixelsForTesting returns the image's basePixels for testing.
@ -322,7 +322,7 @@ func (i *Image) WritePixels(pixels *graphics.ManagedBytes, region image.Rectangl
// 5: Color G // 5: Color G
// 6: Color B // 6: Color B
// 7: Color Y // 7: Color Y
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, evenOdd bool) { func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
if len(vertices) == 0 { if len(vertices) == 0 {
return return
} }
@ -344,7 +344,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [
if srcstale || !needsRestoring() || !i.needsRestoring() || i.stale { if srcstale || !needsRestoring() || !i.needsRestoring() || i.stale {
i.makeStale(dstRegion) i.makeStale(dstRegion)
} else { } else {
i.appendDrawTrianglesHistory(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, evenOdd) i.appendDrawTrianglesHistory(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule)
} }
var imgs [graphics.ShaderImageCount]*graphicscommand.Image var imgs [graphics.ShaderImageCount]*graphicscommand.Image
@ -354,11 +354,11 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [
} }
imgs[i] = src.image imgs[i] = src.image
} }
i.image.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegions, shader.shader, uniforms, evenOdd) i.image.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegions, shader.shader, uniforms, fillRule)
} }
// appendDrawTrianglesHistory appends a draw-image history item to the image. // appendDrawTrianglesHistory appends a draw-image history item to the image.
func (i *Image) appendDrawTrianglesHistory(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, evenOdd bool) { func (i *Image) appendDrawTrianglesHistory(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
if i.stale || !i.needsRestoring() { if i.stale || !i.needsRestoring() {
panic("restorable: an image must not be stale or need restoring at appendDrawTrianglesHistory") panic("restorable: an image must not be stale or need restoring at appendDrawTrianglesHistory")
} }
@ -393,7 +393,7 @@ func (i *Image) appendDrawTrianglesHistory(srcs [graphics.ShaderImageCount]*Imag
srcRegions: srcRegions, srcRegions: srcRegions,
shader: shader, shader: shader,
uniforms: us, uniforms: us,
evenOdd: evenOdd, fillRule: fillRule,
} }
i.drawTrianglesHistory = append(i.drawTrianglesHistory, item) i.drawTrianglesHistory = append(i.drawTrianglesHistory, item)
} }
@ -610,7 +610,7 @@ func (i *Image) restore(graphicsDriver graphicsdriver.Graphics) error {
} }
imgs[i] = img.image imgs[i] = img.image
} }
gimg.DrawTriangles(imgs, c.vertices, c.indices, c.blend, c.dstRegion, c.srcRegions, c.shader.shader, c.uniforms, c.evenOdd) gimg.DrawTriangles(imgs, c.vertices, c.indices, c.blend, c.dstRegion, c.srcRegions, c.shader.shader, c.uniforms, c.fillRule)
} }
// In order to clear the draw-triangles history, read pixels from GPU. // In order to clear the draw-triangles history, read pixels from GPU.

View File

@ -143,7 +143,7 @@ func TestRestoreChain(t *testing.T) {
vs := quadVertices(1, 1, 0, 0) vs := quadVertices(1, 1, 0, 0)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, 1, 1) dr := image.Rect(0, 0, 1, 1)
imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
} }
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil { if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) t.Fatal(err)
@ -186,10 +186,10 @@ func TestRestoreChain2(t *testing.T) {
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, w, h) dr := image.Rect(0, 0, w, h)
imgs[8].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[7]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) imgs[8].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[7]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
imgs[9].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[8]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) imgs[9].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[8]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
for i := 0; i < 7; i++ { for i := 0; i < 7; i++ {
imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
} }
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil { if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
@ -230,10 +230,10 @@ func TestRestoreOverrideSource(t *testing.T) {
img1.WritePixels(bytesToManagedBytes([]byte{clr0.R, clr0.G, clr0.B, clr0.A}), image.Rect(0, 0, w, h)) img1.WritePixels(bytesToManagedBytes([]byte{clr0.R, clr0.G, clr0.B, clr0.A}), image.Rect(0, 0, w, h))
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, w, h) dr := image.Rect(0, 0, w, h)
img2.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) img2.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
img0.WritePixels(bytesToManagedBytes([]byte{clr1.R, clr1.G, clr1.B, clr1.A}), image.Rect(0, 0, w, h)) img0.WritePixels(bytesToManagedBytes([]byte{clr1.R, clr1.G, clr1.B, clr1.A}), image.Rect(0, 0, w, h))
img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil { if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -313,23 +313,23 @@ func TestRestoreComplexGraph(t *testing.T) {
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, w, h) dr := image.Rect(0, 0, w, h)
vs := quadVertices(w, h, 0, 0) vs := quadVertices(w, h, 0, 0)
img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
vs = quadVertices(w, h, 1, 0) vs = quadVertices(w, h, 1, 0)
img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
vs = quadVertices(w, h, 1, 0) vs = quadVertices(w, h, 1, 0)
img4.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) img4.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
vs = quadVertices(w, h, 2, 0) vs = quadVertices(w, h, 2, 0)
img4.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) img4.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
vs = quadVertices(w, h, 0, 0) vs = quadVertices(w, h, 0, 0)
img5.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) img5.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
vs = quadVertices(w, h, 0, 0) vs = quadVertices(w, h, 0, 0)
img6.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) img6.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
vs = quadVertices(w, h, 1, 0) vs = quadVertices(w, h, 1, 0)
img6.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img4}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) img6.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img4}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
vs = quadVertices(w, h, 0, 0) vs = quadVertices(w, h, 0, 0)
img7.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) img7.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
vs = quadVertices(w, h, 2, 0) vs = quadVertices(w, h, 2, 0)
img7.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) img7.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil { if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -422,8 +422,8 @@ func TestRestoreRecursive(t *testing.T) {
}() }()
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, w, h) dr := image.Rect(0, 0, w, h)
img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, quadVertices(w, h, 1, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, quadVertices(w, h, 1, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
img0.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, quadVertices(w, h, 1, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) img0.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, quadVertices(w, h, 1, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil { if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -522,7 +522,7 @@ func TestDrawTrianglesAndWritePixels(t *testing.T) {
vs := quadVertices(1, 1, 0, 0) vs := quadVertices(1, 1, 0, 0)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, 2, 1) dr := image.Rect(0, 0, 2, 1)
img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
img1.WritePixels(bytesToManagedBytes([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), image.Rect(0, 0, 2, 1)) img1.WritePixels(bytesToManagedBytes([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), image.Rect(0, 0, 2, 1))
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil { if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
@ -560,8 +560,8 @@ func TestDispose(t *testing.T) {
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, 1, 1) dr := image.Rect(0, 0, 1, 1)
img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, quadVertices(1, 1, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, quadVertices(1, 1, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
img0.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, quadVertices(1, 1, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) img0.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, quadVertices(1, 1, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
img1.Dispose() img1.Dispose()
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil { if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
@ -670,7 +670,7 @@ func TestWritePixelsOnly(t *testing.T) {
vs := quadVertices(1, 1, 0, 0) vs := quadVertices(1, 1, 0, 0)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, 1, 1) dr := image.Rect(0, 0, 1, 1)
img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
img0.WritePixels(bytesToManagedBytes([]byte{5, 6, 7, 8}), image.Rect(0, 0, 1, 1)) img0.WritePixels(bytesToManagedBytes([]byte{5, 6, 7, 8}), image.Rect(0, 0, 1, 1))
// BasePixelsForTesting is available without GPU accessing. // BasePixelsForTesting is available without GPU accessing.
@ -724,7 +724,7 @@ func TestReadPixelsFromVolatileImage(t *testing.T) {
vs := quadVertices(1, 1, 0, 0) vs := quadVertices(1, 1, 0, 0)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, w, h) dr := image.Rect(0, 0, w, h)
dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
// Read the pixels. If the implementation is correct, dst tries to read its pixels from GPU due to being // Read the pixels. If the implementation is correct, dst tries to read its pixels from GPU due to being
// stale. // stale.
@ -748,7 +748,7 @@ func TestAllowWritePixelsAfterDrawTriangles(t *testing.T) {
vs := quadVertices(w, h, 0, 0) vs := quadVertices(w, h, 0, 0)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, w, h) dr := image.Rect(0, 0, w, h)
dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
dst.WritePixels(bytesToManagedBytes(make([]byte, 4*w*h)), image.Rect(0, 0, w, h)) dst.WritePixels(bytesToManagedBytes(make([]byte, 4*w*h)), image.Rect(0, 0, w, h))
// WritePixels for a whole image doesn't panic. // WritePixels for a whole image doesn't panic.
} }
@ -767,7 +767,7 @@ func TestAllowWritePixelsForPartAfterDrawTriangles(t *testing.T) {
vs := quadVertices(w, h, 0, 0) vs := quadVertices(w, h, 0, 0)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, w, h) dr := image.Rect(0, 0, w, h)
dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
dst.WritePixels(bytesToManagedBytes(make([]byte, 4*2*2)), image.Rect(0, 0, 2, 2)) dst.WritePixels(bytesToManagedBytes(make([]byte, 4*2*2)), image.Rect(0, 0, 2, 2))
// WritePixels for a part of image doesn't panic. // WritePixels for a part of image doesn't panic.
@ -861,7 +861,7 @@ func TestDrawTrianglesAndExtend(t *testing.T) {
vs := quadVertices(w, h, 0, 0) vs := quadVertices(w, h, 0, 0)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, w, h) dr := image.Rect(0, 0, w, h)
orig.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) orig.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
extended := orig.Extend(w*2, h*2) // After this, orig is already disposed. extended := orig.Extend(w*2, h*2) // After this, orig is already disposed.
result := make([]byte, 4*(w*2)*(h*2)) result := make([]byte, 4*(w*2)*(h*2))
@ -911,7 +911,7 @@ func TestMutateSlices(t *testing.T) {
is := make([]uint32, len(graphics.QuadIndices())) is := make([]uint32, len(graphics.QuadIndices()))
copy(is, graphics.QuadIndices()) copy(is, graphics.QuadIndices())
dr := image.Rect(0, 0, w, h) dr := image.Rect(0, 0, w, h)
dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
for i := range vs { for i := range vs {
vs[i] = 0 vs[i] = 0
} }
@ -1103,7 +1103,7 @@ func TestDrawTrianglesAndReadPixels(t *testing.T) {
vs := quadVertices(w, h, 0, 0) vs := quadVertices(w, h, 0, 0)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, w, h) dr := image.Rect(0, 0, w, h)
dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
pix := make([]byte, 4*w*h) pix := make([]byte, 4*w*h)
if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h)); err != nil { if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h)); err != nil {
@ -1127,7 +1127,7 @@ func TestWritePixelsAndDrawTriangles(t *testing.T) {
vs := quadVertices(1, 1, 1, 0) vs := quadVertices(1, 1, 1, 0)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(1, 0, 2, 1) dr := image.Rect(1, 0, 2, 1)
dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
// Get the pixels. // Get the pixels.
pix := make([]byte, 4*2*1) pix := make([]byte, 4*2*1)

View File

@ -46,7 +46,7 @@ func clearImage(img *restorable.Image, w, h int) {
} }
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, w, h) dr := image.Rect(0, 0, w, h)
img.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{emptyImage}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) img.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{emptyImage}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillAll)
} }
func TestShader(t *testing.T) { func TestShader(t *testing.T) {
@ -55,7 +55,7 @@ func TestShader(t *testing.T) {
s := restorable.NewShader(etesting.ShaderProgramFill(0xff, 0, 0, 0xff)) s := restorable.NewShader(etesting.ShaderProgramFill(0xff, 0, 0, 0xff))
dr := image.Rect(0, 0, 1, 1) dr := image.Rect(0, 0, 1, 1)
img.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, s, nil, false) img.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, s, nil, graphicsdriver.FillAll)
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil { if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) t.Fatal(err)
@ -85,7 +85,7 @@ func TestShaderChain(t *testing.T) {
s := restorable.NewShader(etesting.ShaderProgramImages(1)) s := restorable.NewShader(etesting.ShaderProgramImages(1))
for i := 0; i < num-1; i++ { for i := 0; i < num-1; i++ {
dr := image.Rect(0, 0, 1, 1) dr := image.Rect(0, 0, 1, 1)
imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, s, nil, false) imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, s, nil, graphicsdriver.FillAll)
} }
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil { if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
@ -117,7 +117,7 @@ func TestShaderMultipleSources(t *testing.T) {
s := restorable.NewShader(etesting.ShaderProgramImages(3)) s := restorable.NewShader(etesting.ShaderProgramImages(3))
dr := image.Rect(0, 0, 1, 1) dr := image.Rect(0, 0, 1, 1)
dst.DrawTriangles(srcs, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, s, nil, false) dst.DrawTriangles(srcs, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, s, nil, graphicsdriver.FillAll)
// Clear one of the sources after DrawTriangles. dst should not be affected. // Clear one of the sources after DrawTriangles. dst should not be affected.
clearImage(srcs[0], 1, 1) clearImage(srcs[0], 1, 1)
@ -154,7 +154,7 @@ func TestShaderMultipleSourcesOnOneTexture(t *testing.T) {
image.Rect(1, 0, 2, 1), image.Rect(1, 0, 2, 1),
image.Rect(2, 0, 3, 1), image.Rect(2, 0, 3, 1),
} }
dst.DrawTriangles(srcs, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, srcRegions, s, nil, false) dst.DrawTriangles(srcs, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, srcRegions, s, nil, graphicsdriver.FillAll)
// Clear one of the sources after DrawTriangles. dst should not be affected. // Clear one of the sources after DrawTriangles. dst should not be affected.
clearImage(srcs[0], 3, 1) clearImage(srcs[0], 3, 1)
@ -179,7 +179,7 @@ func TestShaderDispose(t *testing.T) {
s := restorable.NewShader(etesting.ShaderProgramFill(0xff, 0, 0, 0xff)) s := restorable.NewShader(etesting.ShaderProgramFill(0xff, 0, 0, 0xff))
dr := image.Rect(0, 0, 1, 1) dr := image.Rect(0, 0, 1, 1)
img.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, s, nil, false) img.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, s, nil, graphicsdriver.FillAll)
// Dispose the shader. This should invalidate all the images using this shader i.e., all the images become // Dispose the shader. This should invalidate all the images using this shader i.e., all the images become
// stale. // stale.

View File

@ -80,7 +80,7 @@ func (i *Image) Deallocate() {
i.dotsBuffer = nil i.dotsBuffer = nil
} }
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, evenOdd bool, canSkipMipmap bool, antialias bool) { func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule, canSkipMipmap bool, antialias bool) {
if i.modifyCallback != nil { if i.modifyCallback != nil {
i.modifyCallback() i.modifyCallback()
} }
@ -104,7 +104,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [
i.bigOffscreenBuffer = i.ui.newBigOffscreenImage(i, imageType) i.bigOffscreenBuffer = i.ui.newBigOffscreenImage(i, imageType)
} }
i.bigOffscreenBuffer.drawTriangles(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, evenOdd, canSkipMipmap, false) i.bigOffscreenBuffer.drawTriangles(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule, canSkipMipmap, false)
return return
} }
@ -119,7 +119,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [
srcMipmaps[i] = src.mipmap srcMipmaps[i] = src.mipmap
} }
i.mipmap.DrawTriangles(srcMipmaps, vertices, indices, blend, dstRegion, srcRegions, shader.shader, uniforms, evenOdd, canSkipMipmap) i.mipmap.DrawTriangles(srcMipmaps, vertices, indices, blend, dstRegion, srcRegions, shader.shader, uniforms, fillRule, canSkipMipmap)
} }
func (i *Image) WritePixels(pix []byte, region image.Rectangle) { func (i *Image) WritePixels(pix []byte, region image.Rectangle) {
@ -253,7 +253,7 @@ func (i *Image) flushDotsBufferIfNeeded() {
dr := image.Rect(0, 0, i.width, i.height) dr := image.Rect(0, 0, i.width, i.height)
blend := graphicsdriver.BlendCopy blend := graphicsdriver.BlendCopy
i.lastBlend = blend i.lastBlend = blend
i.mipmap.DrawTriangles(srcs, vs, is, blend, dr, [graphics.ShaderImageCount]image.Rectangle{}, NearestFilterShader.shader, nil, false, true) i.mipmap.DrawTriangles(srcs, vs, is, blend, dr, [graphics.ShaderImageCount]image.Rectangle{}, NearestFilterShader.shader, nil, graphicsdriver.FillAll, true)
} }
func (i *Image) flushBigOffscreenBufferIfNeeded() { func (i *Image) flushBigOffscreenBufferIfNeeded() {
@ -290,7 +290,7 @@ func (i *Image) Fill(r, g, b, a float32, region image.Rectangle) {
blend = graphicsdriver.BlendSourceOver blend = graphicsdriver.BlendSourceOver
} }
// i.lastBlend is updated in DrawTriangles. // i.lastBlend is updated in DrawTriangles.
i.DrawTriangles(srcs, i.tmpVerticesForFill, is, blend, region, [graphics.ShaderImageCount]image.Rectangle{}, NearestFilterShader, nil, false, true, false) i.DrawTriangles(srcs, i.tmpVerticesForFill, is, blend, region, [graphics.ShaderImageCount]image.Rectangle{}, NearestFilterShader, nil, graphicsdriver.FillAll, true, false)
} }
type bigOffscreenImage struct { type bigOffscreenImage struct {
@ -324,7 +324,7 @@ func (i *bigOffscreenImage) deallocate() {
i.dirty = false i.dirty = false
} }
func (i *bigOffscreenImage) drawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, evenOdd bool, canSkipMipmap bool, antialias bool) { func (i *bigOffscreenImage) drawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule, canSkipMipmap bool, antialias bool) {
if i.blend != blend { if i.blend != blend {
i.flush() i.flush()
} }
@ -359,7 +359,7 @@ func (i *bigOffscreenImage) drawTriangles(srcs [graphics.ShaderImageCount]*Image
1, 1, 1, 1) 1, 1, 1, 1)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dstRegion := image.Rect(0, 0, i.region.Dx()*bigOffscreenScale, i.region.Dy()*bigOffscreenScale) dstRegion := image.Rect(0, 0, i.region.Dx()*bigOffscreenScale, i.region.Dy()*bigOffscreenScale)
i.image.DrawTriangles(srcs, i.tmpVerticesForCopying, is, graphicsdriver.BlendCopy, dstRegion, [graphics.ShaderImageCount]image.Rectangle{}, NearestFilterShader, nil, false, true, false) i.image.DrawTriangles(srcs, i.tmpVerticesForCopying, is, graphicsdriver.BlendCopy, dstRegion, [graphics.ShaderImageCount]image.Rectangle{}, NearestFilterShader, nil, graphicsdriver.FillAll, true, false)
} }
for idx := 0; idx < len(vertices); idx += graphics.VertexFloatCount { for idx := 0; idx < len(vertices); idx += graphics.VertexFloatCount {
@ -375,7 +375,7 @@ func (i *bigOffscreenImage) drawTriangles(srcs [graphics.ShaderImageCount]*Image
dstRegion.Max.X *= bigOffscreenScale dstRegion.Max.X *= bigOffscreenScale
dstRegion.Max.Y *= bigOffscreenScale dstRegion.Max.Y *= bigOffscreenScale
i.image.DrawTriangles(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, evenOdd, canSkipMipmap, false) i.image.DrawTriangles(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule, canSkipMipmap, false)
i.dirty = true i.dirty = true
} }
@ -407,7 +407,7 @@ func (i *bigOffscreenImage) flush() {
if i.blend != graphicsdriver.BlendSourceOver { if i.blend != graphicsdriver.BlendSourceOver {
blend = graphicsdriver.BlendCopy blend = graphicsdriver.BlendCopy
} }
i.orig.DrawTriangles(srcs, i.tmpVerticesForFlushing, is, blend, dstRegion, [graphics.ShaderImageCount]image.Rectangle{}, LinearFilterShader, nil, false, true, false) i.orig.DrawTriangles(srcs, i.tmpVerticesForFlushing, is, blend, dstRegion, [graphics.ShaderImageCount]image.Rectangle{}, LinearFilterShader, nil, graphicsdriver.FillAll, true, false)
i.image.clear() i.image.clear()
i.dirty = false i.dirty = false