mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 04:57:26 +01:00
Compare commits
16 Commits
59e45a523d
...
971c30f170
Author | SHA1 | Date | |
---|---|---|---|
|
971c30f170 | ||
|
6a51e5b003 | ||
|
af9bd6a282 | ||
|
73565034a9 | ||
|
bbe3cba110 | ||
|
f32648b144 | ||
|
aa8e112414 | ||
|
26f0479f16 | ||
|
9ef9ea0469 | ||
|
b36160d9e7 | ||
|
20f8df7fc1 | ||
|
167c3435f7 | ||
|
d84b030300 | ||
|
4824dc0360 | ||
|
30a2817ab5 | ||
|
29ef2c84ef |
41
image.go
41
image.go
@ -26,6 +26,7 @@ import (
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicscommand"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/restorable"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/ui"
|
||||
)
|
||||
@ -266,7 +267,32 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) {
|
||||
})
|
||||
}
|
||||
|
||||
i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedBounds(), [graphics.ShaderSrcImageCount]image.Rectangle{img.adjustedBounds()}, shader.shader, i.tmpUniforms, graphicsdriver.FillRuleFillAll, canSkipMipmap(geoM, filter), false)
|
||||
dr := i.adjustedBounds()
|
||||
hint := restorable.HintNone
|
||||
if overwritesDstRegion(options.Blend, dr, geoM, sx0, sy0, sx1, sy1) {
|
||||
hint = restorable.HintOverwriteDstRegion
|
||||
}
|
||||
|
||||
i.image.DrawTriangles(srcs, vs, is, blend, dr, [graphics.ShaderSrcImageCount]image.Rectangle{img.adjustedBounds()}, shader.shader, i.tmpUniforms, graphicsdriver.FillRuleFillAll, canSkipMipmap(geoM, filter), false, hint)
|
||||
}
|
||||
|
||||
// overwritesDstRegion reports whether the given parameters overwrite the destination region completely.
|
||||
func overwritesDstRegion(blend Blend, dstRegion image.Rectangle, geoM GeoM, sx0, sy0, sx1, sy1 int) bool {
|
||||
// TODO: More precisely, BlendFactorDestinationRGB, BlendFactorDestinationAlpha, and operations should be checked.
|
||||
if blend != BlendCopy && blend != BlendClear {
|
||||
return false
|
||||
}
|
||||
// Check the result vertices is not a rotated rectangle.
|
||||
if geoM.b != 0 || geoM.c != 0 {
|
||||
return false
|
||||
}
|
||||
// Check the result vertices completely covers dstRegion.
|
||||
x0, y0 := geoM.Apply(float64(sx0), float64(sy0))
|
||||
x1, y1 := geoM.Apply(float64(sx1), float64(sy1))
|
||||
if float64(dstRegion.Min.X) < x0 || float64(dstRegion.Min.Y) < y0 || float64(dstRegion.Max.X) > x1 || float64(dstRegion.Max.Y) > y1 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Vertex represents a vertex passed to DrawTriangles.
|
||||
@ -550,7 +576,7 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o
|
||||
})
|
||||
}
|
||||
|
||||
i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedBounds(), [graphics.ShaderSrcImageCount]image.Rectangle{img.adjustedBounds()}, shader.shader, i.tmpUniforms, graphicsdriver.FillRule(options.FillRule), filter != builtinshader.FilterLinear, options.AntiAlias)
|
||||
i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedBounds(), [graphics.ShaderSrcImageCount]image.Rectangle{img.adjustedBounds()}, shader.shader, i.tmpUniforms, graphicsdriver.FillRule(options.FillRule), filter != builtinshader.FilterLinear, options.AntiAlias, restorable.HintNone)
|
||||
}
|
||||
|
||||
// DrawTrianglesShaderOptions represents options for DrawTrianglesShader.
|
||||
@ -722,7 +748,7 @@ func (i *Image) DrawTrianglesShader(vertices []Vertex, indices []uint16, shader
|
||||
i.tmpUniforms = i.tmpUniforms[:0]
|
||||
i.tmpUniforms = shader.appendUniforms(i.tmpUniforms, options.Uniforms)
|
||||
|
||||
i.image.DrawTriangles(imgs, vs, is, blend, i.adjustedBounds(), srcRegions, shader.shader, i.tmpUniforms, graphicsdriver.FillRule(options.FillRule), true, options.AntiAlias)
|
||||
i.image.DrawTriangles(imgs, vs, is, blend, i.adjustedBounds(), srcRegions, shader.shader, i.tmpUniforms, graphicsdriver.FillRule(options.FillRule), true, options.AntiAlias, restorable.HintNone)
|
||||
}
|
||||
|
||||
// DrawRectShaderOptions represents options for DrawRectShader.
|
||||
@ -855,7 +881,14 @@ func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawR
|
||||
i.tmpUniforms = i.tmpUniforms[:0]
|
||||
i.tmpUniforms = shader.appendUniforms(i.tmpUniforms, options.Uniforms)
|
||||
|
||||
i.image.DrawTriangles(imgs, vs, is, blend, i.adjustedBounds(), srcRegions, shader.shader, i.tmpUniforms, graphicsdriver.FillRuleFillAll, true, false)
|
||||
dr := i.adjustedBounds()
|
||||
hint := restorable.HintNone
|
||||
// Do not use srcRegions[0].Dx() and srcRegions[0].Dy() as these might be empty.
|
||||
if overwritesDstRegion(options.Blend, dr, geoM, srcRegions[0].Min.X, srcRegions[0].Min.Y, srcRegions[0].Min.X+width, srcRegions[0].Min.Y+height) {
|
||||
hint = restorable.HintOverwriteDstRegion
|
||||
}
|
||||
|
||||
i.image.DrawTriangles(imgs, vs, is, blend, i.adjustedBounds(), srcRegions, shader.shader, i.tmpUniforms, graphicsdriver.FillRuleFillAll, true, false, hint)
|
||||
}
|
||||
|
||||
// SubImage returns an image representing the portion of the image p visible through r.
|
||||
|
@ -157,6 +157,7 @@ const (
|
||||
ImageTypeScreen
|
||||
|
||||
// ImageTypeVolatile is a volatile image that is cleared every frame.
|
||||
// A volatile image is also unmanaged.
|
||||
ImageTypeVolatile
|
||||
|
||||
// ImageTypeUnmanaged is an unmanaged image that is not on an atlas.
|
||||
@ -283,8 +284,9 @@ func (i *Image) ensureIsolatedFromSource(backends []*backend) {
|
||||
graphics.QuadVerticesFromDstAndSrc(vs, 0, 0, w, h, 0, 0, w, h, 1, 1, 1, 1)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, i.width, i.height)
|
||||
sr := image.Rect(0, 0, i.width, i.height)
|
||||
|
||||
newI.drawTriangles([graphics.ShaderSrcImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
newI.drawTriangles([graphics.ShaderSrcImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintOverwriteDstRegion)
|
||||
newI.moveTo(i)
|
||||
}
|
||||
|
||||
@ -314,7 +316,8 @@ func (i *Image) putOnSourceBackend() {
|
||||
graphics.QuadVerticesFromDstAndSrc(vs, 0, 0, w, h, 0, 0, w, h, 1, 1, 1, 1)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, i.width, i.height)
|
||||
newI.drawTriangles([graphics.ShaderSrcImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr := image.Rect(0, 0, i.width, i.height)
|
||||
newI.drawTriangles([graphics.ShaderSrcImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintOverwriteDstRegion)
|
||||
|
||||
newI.moveTo(i)
|
||||
i.usedAsSourceCount = 0
|
||||
@ -346,7 +349,7 @@ func (i *Image) regionWithPadding() image.Rectangle {
|
||||
// 5: Color G
|
||||
// 6: Color B
|
||||
// 7: Color Y
|
||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
|
||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule, hint restorable.Hint) {
|
||||
backendsM.Lock()
|
||||
defer backendsM.Unlock()
|
||||
|
||||
@ -359,15 +362,15 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertice
|
||||
copy(us, uniforms)
|
||||
|
||||
appendDeferred(func() {
|
||||
i.drawTriangles(srcs, vs, is, blend, dstRegion, srcRegions, shader, us, fillRule)
|
||||
i.drawTriangles(srcs, vs, is, blend, dstRegion, srcRegions, shader, us, fillRule, hint)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
i.drawTriangles(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule)
|
||||
i.drawTriangles(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule, hint)
|
||||
}
|
||||
|
||||
func (i *Image) drawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
|
||||
func (i *Image) drawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule, hint restorable.Hint) {
|
||||
backends := make([]*backend, 0, len(srcs))
|
||||
for _, src := range srcs {
|
||||
if src == nil {
|
||||
@ -432,6 +435,7 @@ func (i *Image) drawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertice
|
||||
|
||||
// A source region can be deliberately empty when this is not needed in order to avoid unexpected
|
||||
// performance issue (#1293).
|
||||
// TODO: This should no longer be needed but is kept just in case. Remove this later.
|
||||
if srcRegions[i].Empty() {
|
||||
continue
|
||||
}
|
||||
@ -448,7 +452,7 @@ func (i *Image) drawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertice
|
||||
imgs[i] = src.backend.restorable
|
||||
}
|
||||
|
||||
i.backend.restorable.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegions, shader.ensureShader(), uniforms, fillRule)
|
||||
i.backend.restorable.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegions, shader.ensureShader(), uniforms, fillRule, hint)
|
||||
|
||||
for _, src := range srcs {
|
||||
if src == nil {
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/atlas"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/restorable"
|
||||
t "github.com/hajimehoshi/ebiten/v2/internal/testing"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/ui"
|
||||
)
|
||||
@ -102,7 +103,8 @@ func TestEnsureIsolatedFromSourceBackend(t *testing.T) {
|
||||
vs := quadVertices(size/2, size/2, size/4, size/4, 1)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, size, size)
|
||||
img4.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr := image.Rect(0, 0, size/2, size/2)
|
||||
img4.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
if got, want := img4.IsOnSourceBackendForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -110,7 +112,8 @@ func TestEnsureIsolatedFromSourceBackend(t *testing.T) {
|
||||
// img5 is not allocated now, but is allocated at DrawTriangles.
|
||||
vs = quadVertices(0, 0, size/2, size/2, 1)
|
||||
dr = image.Rect(0, 0, size/2, size/2)
|
||||
img3.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img5}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr = image.Rect(0, 0, size/2, size/2)
|
||||
img3.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img5}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
if got, want := img3.IsOnSourceBackendForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -144,7 +147,9 @@ func TestEnsureIsolatedFromSourceBackend(t *testing.T) {
|
||||
// Check further drawing doesn't cause panic.
|
||||
// This bug was fixed by 03dcd948.
|
||||
vs = quadVertices(0, 0, size/2, size/2, 1)
|
||||
img4.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
dr = image.Rect(0, 0, size, size)
|
||||
sr = image.Rect(0, 0, size/2, size/2)
|
||||
img4.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
}
|
||||
|
||||
func TestReputOnSourceBackend(t *testing.T) {
|
||||
@ -185,10 +190,11 @@ func TestReputOnSourceBackend(t *testing.T) {
|
||||
// Use img1 as a render target.
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, size, size)
|
||||
sr := image.Rect(0, 0, size, size)
|
||||
// Render onto img1. The count should not matter.
|
||||
for i := 0; i < 5; i++ {
|
||||
vs := quadVertices(size, size, 0, 0, 1)
|
||||
img1.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
img1.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
if got, want := img1.IsOnSourceBackendForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -200,7 +206,7 @@ func TestReputOnSourceBackend(t *testing.T) {
|
||||
for i := 0; i < atlas.BaseCountToPutOnSourceBackend*2; i++ {
|
||||
atlas.PutImagesOnSourceBackendForTesting()
|
||||
vs := quadVertices(size, size, 0, 0, 1)
|
||||
img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
if got, want := img1.IsOnSourceBackendForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -208,7 +214,7 @@ func TestReputOnSourceBackend(t *testing.T) {
|
||||
// Finally, img1 is on a source backend.
|
||||
atlas.PutImagesOnSourceBackendForTesting()
|
||||
vs := quadVertices(size, size, 0, 0, 1)
|
||||
img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
if got, want := img1.IsOnSourceBackendForTesting(), true; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -237,7 +243,7 @@ func TestReputOnSourceBackend(t *testing.T) {
|
||||
}
|
||||
|
||||
vs = quadVertices(size, size, 0, 0, 1)
|
||||
img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
if got, want := img1.IsOnSourceBackendForTesting(), true; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -267,7 +273,7 @@ func TestReputOnSourceBackend(t *testing.T) {
|
||||
// Use img1 as a render target again. The count should not matter.
|
||||
for i := 0; i < 5; i++ {
|
||||
vs := quadVertices(size, size, 0, 0, 1)
|
||||
img1.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
img1.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
if got, want := img1.IsOnSourceBackendForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -279,7 +285,7 @@ func TestReputOnSourceBackend(t *testing.T) {
|
||||
atlas.PutImagesOnSourceBackendForTesting()
|
||||
img1.WritePixels(make([]byte, 4*size*size), image.Rect(0, 0, size, size))
|
||||
vs := quadVertices(size, size, 0, 0, 1)
|
||||
img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
if got, want := img1.IsOnSourceBackendForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -288,7 +294,7 @@ func TestReputOnSourceBackend(t *testing.T) {
|
||||
|
||||
// img1 is not on an atlas due to WritePixels.
|
||||
vs = quadVertices(size, size, 0, 0, 1)
|
||||
img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
if got, want := img1.IsOnSourceBackendForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -297,7 +303,7 @@ func TestReputOnSourceBackend(t *testing.T) {
|
||||
for i := 0; i < atlas.BaseCountToPutOnSourceBackend*2; i++ {
|
||||
atlas.PutImagesOnSourceBackendForTesting()
|
||||
vs := quadVertices(size, size, 0, 0, 1)
|
||||
img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
if got, want := img3.IsOnSourceBackendForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -400,7 +406,8 @@ func TestWritePixelsAfterDrawTriangles(t *testing.T) {
|
||||
vs := quadVertices(w, h, 0, 0, 1)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, w, h)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr := image.Rect(0, 0, w, h)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
dst.WritePixels(pix, image.Rect(0, 0, w, h))
|
||||
|
||||
pix = make([]byte, 4*w*h)
|
||||
@ -447,7 +454,8 @@ func TestSmallImages(t *testing.T) {
|
||||
vs := quadVertices(w, h, 0, 0, 1)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, w, h)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr := image.Rect(0, 0, w, h)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
|
||||
pix = make([]byte, 4*w*h)
|
||||
ok, err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h))
|
||||
@ -494,7 +502,8 @@ func TestLongImages(t *testing.T) {
|
||||
vs := quadVertices(w, h, 0, 0, scale)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, dstW, dstH)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr := image.Rect(0, 0, w, h)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
|
||||
pix = make([]byte, 4*dstW*dstH)
|
||||
ok, err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, dstW, dstH))
|
||||
@ -610,7 +619,8 @@ func TestDeallocatedAndReputOnSourceBackend(t *testing.T) {
|
||||
vs := quadVertices(size, size, 0, 0, 1)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, size, size)
|
||||
src.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr := image.Rect(0, 0, size, size)
|
||||
src.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
if got, want := src.IsOnSourceBackendForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -619,7 +629,7 @@ func TestDeallocatedAndReputOnSourceBackend(t *testing.T) {
|
||||
for i := 0; i < atlas.BaseCountToPutOnSourceBackend/2; i++ {
|
||||
atlas.PutImagesOnSourceBackendForTesting()
|
||||
vs := quadVertices(size, size, 0, 0, 1)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
if got, want := src.IsOnSourceBackendForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -647,13 +657,14 @@ func TestImageIsNotReputOnSourceBackendWithoutUsingAsSource(t *testing.T) {
|
||||
vs := quadVertices(size, size, 0, 0, 1)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, size, size)
|
||||
sr := image.Rect(0, 0, size, size)
|
||||
|
||||
// Use src2 as a rendering target, and make src2 on a destination backend.
|
||||
//
|
||||
// Call DrawTriangles multiple times.
|
||||
// The number of DrawTriangles doesn't matter as long as these are called in one frame.
|
||||
for i := 0; i < 2; i++ {
|
||||
src2.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
src2.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
}
|
||||
if got, want := src2.IsOnSourceBackendForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
@ -672,7 +683,7 @@ func TestImageIsNotReputOnSourceBackendWithoutUsingAsSource(t *testing.T) {
|
||||
for i := 0; i < atlas.BaseCountToPutOnSourceBackend; i++ {
|
||||
atlas.PutImagesOnSourceBackendForTesting()
|
||||
vs := quadVertices(size, size, 0, 0, 1)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
if got, want := src2.IsOnSourceBackendForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -795,17 +806,18 @@ func TestDestinationCountOverflow(t *testing.T) {
|
||||
vs := quadVertices(w, h, 0, 0, 1)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, w, h)
|
||||
sr := image.Rect(0, 0, w, h)
|
||||
|
||||
// Use dst0 as a destination for a while.
|
||||
for i := 0; i < 31; i++ {
|
||||
dst0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
dst0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
atlas.PutImagesOnSourceBackendForTesting()
|
||||
}
|
||||
|
||||
// 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.
|
||||
for i := 0; i < 100; i++ {
|
||||
dst1.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{dst0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
dst1.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{dst0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
atlas.PutImagesOnSourceBackendForTesting()
|
||||
if dst0.IsOnSourceBackendForTesting() {
|
||||
t.Errorf("dst0 cannot be on a source backend: %d", i)
|
||||
@ -830,8 +842,9 @@ func TestIteratingImagesToPutOnSourceBackend(t *testing.T) {
|
||||
vs := quadVertices(w, h, 0, 0, 1)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, w, h)
|
||||
sr := image.Rect(0, 0, w, h)
|
||||
for _, img := range srcs {
|
||||
img.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
img.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
}
|
||||
atlas.PutImagesOnSourceBackendForTesting()
|
||||
|
||||
@ -839,7 +852,7 @@ func TestIteratingImagesToPutOnSourceBackend(t *testing.T) {
|
||||
// Check iterating the registered image works correctly.
|
||||
for i := 0; i < 100; i++ {
|
||||
for _, src := range srcs {
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
}
|
||||
atlas.PutImagesOnSourceBackendForTesting()
|
||||
}
|
||||
@ -887,7 +900,8 @@ func TestDallocateUnmanagedImageBackends(t *testing.T) {
|
||||
vs := quadVertices(w, h, 0, 0, 1)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, w, h)
|
||||
img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr := image.Rect(0, 0, w, h)
|
||||
img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
|
||||
// Get the difference of the number of backends before and after the images are deallocated.
|
||||
c := atlas.BackendCountForTesting()
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/atlas"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/restorable"
|
||||
etesting "github.com/hajimehoshi/ebiten/v2/internal/testing"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/ui"
|
||||
)
|
||||
@ -37,12 +38,12 @@ func TestShaderFillTwice(t *testing.T) {
|
||||
dr := image.Rect(0, 0, w, h)
|
||||
g := ui.Get().GraphicsDriverForTesting()
|
||||
s0 := atlas.NewShader(etesting.ShaderProgramFill(0xff, 0xff, 0xff, 0xff), "")
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, s0, nil, graphicsdriver.FillRuleFillAll)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, s0, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
|
||||
// Vertices must be recreated (#1755)
|
||||
vs = quadVertices(w, h, 0, 0, 1)
|
||||
s1 := atlas.NewShader(etesting.ShaderProgramFill(0x80, 0x80, 0x80, 0xff), "")
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, s1, nil, graphicsdriver.FillRuleFillAll)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, s1, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
|
||||
pix := make([]byte, 4*w*h)
|
||||
ok, err := dst.ReadPixels(g, pix, image.Rect(0, 0, w, h))
|
||||
@ -69,11 +70,12 @@ func TestImageDrawTwice(t *testing.T) {
|
||||
vs := quadVertices(w, h, 0, 0, 1)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, w, h)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr := image.Rect(0, 0, w, h)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
|
||||
// Vertices must be recreated (#1755)
|
||||
vs = quadVertices(w, h, 0, 0, 1)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
|
||||
pix := make([]byte, 4*w*h)
|
||||
ok, err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h))
|
||||
@ -97,7 +99,7 @@ func TestGCShader(t *testing.T) {
|
||||
vs := quadVertices(w, h, 0, 0, 1)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, w, h)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, s, nil, graphicsdriver.FillRuleFillAll)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, s, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
|
||||
// Ensure other objects are GCed, as GC appends deferred functions for collected objects.
|
||||
ensureGC()
|
||||
|
@ -196,7 +196,7 @@ func (i *Image) WritePixels(pix []byte, region image.Rectangle) {
|
||||
// DrawTriangles draws the src image with the given vertices.
|
||||
//
|
||||
// Copying vertices and indices is the caller's responsibility.
|
||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *atlas.Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
|
||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *atlas.Shader, uniforms []uint32, fillRule graphicsdriver.FillRule, hint restorable.Hint) {
|
||||
for _, src := range srcs {
|
||||
if i == src {
|
||||
panic("buffered: Image.DrawTriangles: source images must be different from the receiver")
|
||||
@ -218,7 +218,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertice
|
||||
imgs[i] = img.img
|
||||
}
|
||||
|
||||
i.img.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule)
|
||||
i.img.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule, hint)
|
||||
|
||||
// After rendering, the pixel cache is no longer valid.
|
||||
i.pixels = nil
|
||||
@ -310,8 +310,9 @@ func (i *Image) syncPixelsIfNeeded() {
|
||||
|
||||
srcs := [graphics.ShaderSrcImageCount]*atlas.Image{whiteImage.img}
|
||||
dr := image.Rect(0, 0, i.width, i.height)
|
||||
sr := image.Rect(0, 0, whiteImage.width, whiteImage.height)
|
||||
blend := graphicsdriver.BlendCopy
|
||||
i.img.DrawTriangles(srcs, vs, is, blend, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
i.img.DrawTriangles(srcs, vs, is, blend, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
|
||||
// TODO: Use clear if Go 1.21 is available.
|
||||
for pos := range i.dotsBuffer {
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/buffered"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/restorable"
|
||||
t "github.com/hajimehoshi/ebiten/v2/internal/testing"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/ui"
|
||||
)
|
||||
@ -56,7 +57,7 @@ func TestUnsyncedPixels(t *testing.T) {
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, 16, 16)
|
||||
sr := [graphics.ShaderSrcImageCount]image.Rectangle{image.Rect(0, 0, 16, 16)}
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*buffered.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, sr, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*buffered.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, sr, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
|
||||
// Check the result is correct.
|
||||
var got [4]byte
|
||||
|
@ -56,7 +56,8 @@ func TestClear(t *testing.T) {
|
||||
vs := quadVertices(w/2, h/2)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, w, h)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{src}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, nearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr := image.Rect(0, 0, w/2, h/2)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{src}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, nearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
|
||||
pix := make([]byte, 4*w*h)
|
||||
if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), []graphicsdriver.PixelsArgs{
|
||||
@ -87,8 +88,10 @@ func TestWritePixelsPartAfterDrawTriangles(t *testing.T) {
|
||||
vs := quadVertices(w/2, h/2)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, w, h)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{clr}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, nearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, nearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr0 := image.Rect(0, 0, w, h)
|
||||
sr1 := image.Rect(0, 0, w/2, h/2)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{clr}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr0}, nearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr1}, nearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
bs := graphics.NewManagedBytes(4, func(bs []byte) {
|
||||
for i := range bs {
|
||||
bs[i] = 0
|
||||
@ -106,7 +109,8 @@ func TestShader(t *testing.T) {
|
||||
vs := quadVertices(w, h)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, w, h)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{clr}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, nearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr := image.Rect(0, 0, w, h)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{clr}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, nearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
|
||||
g := ui.Get().GraphicsDriverForTesting()
|
||||
s := graphicscommand.NewShader(etesting.ShaderProgramFill(0xff, 0, 0, 0xff), "")
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/buffered"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/restorable"
|
||||
)
|
||||
|
||||
func canUseMipmap(imageType atlas.ImageType) bool {
|
||||
@ -65,7 +66,7 @@ func (m *Mipmap) ReadPixels(graphicsDriver graphicsdriver.Graphics, pixels []byt
|
||||
return m.orig.ReadPixels(graphicsDriver, pixels, region)
|
||||
}
|
||||
|
||||
func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderSrcImageCount]*Mipmap, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *atlas.Shader, uniforms []uint32, fillRule graphicsdriver.FillRule, canSkipMipmap bool) {
|
||||
func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderSrcImageCount]*Mipmap, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *atlas.Shader, uniforms []uint32, fillRule graphicsdriver.FillRule, canSkipMipmap bool, hint restorable.Hint) {
|
||||
if len(indices) == 0 {
|
||||
return
|
||||
}
|
||||
@ -123,7 +124,7 @@ func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderSrcImageCount]*Mipmap, verti
|
||||
imgs[i] = src.orig
|
||||
}
|
||||
|
||||
m.orig.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule)
|
||||
m.orig.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule, hint)
|
||||
m.deallocateMipmaps()
|
||||
}
|
||||
|
||||
@ -184,7 +185,10 @@ func (m *Mipmap) level(level int) *buffered.Image {
|
||||
s := buffered.NewImage(w2, h2, m.imageType)
|
||||
|
||||
dstRegion := image.Rect(0, 0, w2, h2)
|
||||
s.DrawTriangles([graphics.ShaderSrcImageCount]*buffered.Image{src}, vs, is, graphicsdriver.BlendCopy, dstRegion, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.LinearFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
w := sizeForLevel(m.width, level-1)
|
||||
h := sizeForLevel(m.height, level-1)
|
||||
srcRegion := image.Rect(0, 0, w, h)
|
||||
s.DrawTriangles([graphics.ShaderSrcImageCount]*buffered.Image{src}, vs, is, graphicsdriver.BlendCopy, dstRegion, [graphics.ShaderSrcImageCount]image.Rectangle{srcRegion}, atlas.LinearFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintOverwriteDstRegion)
|
||||
m.setImg(level, s)
|
||||
|
||||
return m.imgs[level]
|
||||
|
@ -80,7 +80,7 @@ func (p *Pixels) Dispose() {
|
||||
|
||||
// drawTrianglesHistoryItem is an item for history of draw-image commands.
|
||||
type drawTrianglesHistoryItem struct {
|
||||
images [graphics.ShaderSrcImageCount]*Image
|
||||
srcImages [graphics.ShaderSrcImageCount]*Image
|
||||
vertices []float32
|
||||
indices []uint32
|
||||
blend graphicsdriver.Blend
|
||||
@ -109,6 +109,18 @@ const (
|
||||
ImageTypeVolatile
|
||||
)
|
||||
|
||||
// Hint is a hint to optimize the info to restore the image.
|
||||
type Hint int
|
||||
|
||||
const (
|
||||
// HintNone indicates that there is no hint.
|
||||
HintNone Hint = iota
|
||||
|
||||
// HintOverwriteDstRegion indicates that the destination region is overwritten.
|
||||
// HintOverwriteDstRegion helps to reduce the size of the draw-image history.
|
||||
HintOverwriteDstRegion
|
||||
)
|
||||
|
||||
// Image represents an image that can be restored when GL context is lost.
|
||||
type Image struct {
|
||||
image *graphicscommand.Image
|
||||
@ -194,7 +206,7 @@ func (i *Image) Extend(width, height int) *Image {
|
||||
graphics.QuadVerticesFromDstAndSrc(vs, 0, 0, float32(sw), float32(sh), 0, 0, float32(sw), float32(sh), 1, 1, 1, 1)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, sw, sh)
|
||||
newImg.DrawTriangles(srcs, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
newImg.DrawTriangles(srcs, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, HintOverwriteDstRegion)
|
||||
i.Dispose()
|
||||
|
||||
return newImg
|
||||
@ -221,6 +233,10 @@ func (i *Image) makeStale(rect image.Rectangle) {
|
||||
return
|
||||
}
|
||||
|
||||
if !i.needsRestoration() {
|
||||
return
|
||||
}
|
||||
|
||||
origSize := len(i.staleRegions)
|
||||
i.staleRegions = i.appendRegionsForDrawTriangles(i.staleRegions)
|
||||
if !rect.Empty() {
|
||||
@ -261,9 +277,7 @@ func (i *Image) WritePixels(pixels *graphics.ManagedBytes, region image.Rectangl
|
||||
panic(fmt.Sprintf("restorable: out of range %v", region))
|
||||
}
|
||||
|
||||
// TODO: Avoid making other images stale if possible. (#514)
|
||||
// For this purpose, images should remember which part of that is used for DrawTriangles.
|
||||
theImages.makeStaleIfDependingOn(i)
|
||||
theImages.makeStaleIfDependingOnAtRegion(i, region)
|
||||
|
||||
if pixels != nil {
|
||||
i.image.WritePixels(pixels, region)
|
||||
@ -271,8 +285,7 @@ func (i *Image) WritePixels(pixels *graphics.ManagedBytes, region image.Rectangl
|
||||
clearImage(i.image, region)
|
||||
}
|
||||
|
||||
// Even if the image is already stale, call makeStale to extend the stale region.
|
||||
if !needsRestoration() || !i.needsRestoration() || i.stale {
|
||||
if !needsRestoration() || !i.needsRestoration() {
|
||||
i.makeStale(region)
|
||||
return
|
||||
}
|
||||
@ -280,9 +293,9 @@ func (i *Image) WritePixels(pixels *graphics.ManagedBytes, region image.Rectangl
|
||||
if region.Eq(image.Rect(0, 0, w, h)) {
|
||||
if pixels != nil {
|
||||
// Clone a ManagedBytes as the package graphicscommand has a different lifetime management.
|
||||
i.basePixels.AddOrReplace(pixels.Clone(), image.Rect(0, 0, w, h))
|
||||
i.basePixels.AddOrReplace(pixels.Clone(), region)
|
||||
} else {
|
||||
i.basePixels.Clear(image.Rect(0, 0, w, h))
|
||||
i.basePixels.Clear(region)
|
||||
}
|
||||
i.clearDrawTrianglesHistory()
|
||||
i.stale = false
|
||||
@ -290,6 +303,14 @@ func (i *Image) WritePixels(pixels *graphics.ManagedBytes, region image.Rectangl
|
||||
return
|
||||
}
|
||||
|
||||
if i.stale {
|
||||
// Even if the image is already stale, call makeStale to extend the stale region.
|
||||
i.makeStale(region)
|
||||
return
|
||||
}
|
||||
|
||||
i.removeDrawTrianglesHistoryItems(region)
|
||||
|
||||
// Records for DrawTriangles cannot come before records for WritePixels.
|
||||
if len(i.drawTrianglesHistory) > 0 {
|
||||
i.makeStale(region)
|
||||
@ -316,10 +337,13 @@ func (i *Image) WritePixels(pixels *graphics.ManagedBytes, region image.Rectangl
|
||||
// 5: Color G
|
||||
// 6: Color B
|
||||
// 7: Color Y
|
||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
|
||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule, hint Hint) {
|
||||
if len(vertices) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// makeStaleIfDependingOnAtRegion is not available here.
|
||||
// This might create cyclic dependency.
|
||||
theImages.makeStaleIfDependingOn(i)
|
||||
|
||||
// TODO: Add tests to confirm this logic.
|
||||
@ -335,10 +359,26 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertice
|
||||
}
|
||||
|
||||
// Even if the image is already stale, call makeStale to extend the stale region.
|
||||
if srcstale || !needsRestoration() || !i.needsRestoration() || i.stale {
|
||||
if srcstale || !needsRestoration() || !i.needsRestoration() {
|
||||
i.makeStale(dstRegion)
|
||||
} else {
|
||||
i.appendDrawTrianglesHistory(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule)
|
||||
} else if i.stale {
|
||||
var overwrite bool
|
||||
if hint == HintOverwriteDstRegion {
|
||||
overwrite = i.areStaleRegionsIncludedIn(dstRegion)
|
||||
}
|
||||
if overwrite {
|
||||
i.basePixels.Clear(dstRegion)
|
||||
i.clearDrawTrianglesHistory()
|
||||
i.stale = false
|
||||
i.staleRegions = i.staleRegions[:0]
|
||||
} else {
|
||||
// Even if the image is already stale, call makeStale to extend the stale region.
|
||||
i.makeStale(dstRegion)
|
||||
}
|
||||
}
|
||||
|
||||
if !i.stale {
|
||||
i.appendDrawTrianglesHistory(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule, hint)
|
||||
}
|
||||
|
||||
var imgs [graphics.ShaderSrcImageCount]*graphicscommand.Image
|
||||
@ -351,8 +391,39 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertice
|
||||
i.image.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegions, shader.shader, uniforms, fillRule)
|
||||
}
|
||||
|
||||
func (i *Image) areStaleRegionsIncludedIn(r image.Rectangle) bool {
|
||||
if !i.stale {
|
||||
return false
|
||||
}
|
||||
for _, sr := range i.staleRegions {
|
||||
if !sr.In(r) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// removeDrawTrianglesHistoryItems removes draw-image history items whose destination regions are in the given region.
|
||||
// This is useful when the destination region is overwritten soon later.
|
||||
func (i *Image) removeDrawTrianglesHistoryItems(region image.Rectangle) {
|
||||
for idx, c := range i.drawTrianglesHistory {
|
||||
if c.dstRegion.In(region) {
|
||||
i.drawTrianglesHistory[idx] = nil
|
||||
}
|
||||
}
|
||||
var n int
|
||||
for _, c := range i.drawTrianglesHistory {
|
||||
if c == nil {
|
||||
continue
|
||||
}
|
||||
i.drawTrianglesHistory[n] = c
|
||||
n++
|
||||
}
|
||||
i.drawTrianglesHistory = i.drawTrianglesHistory[:n]
|
||||
}
|
||||
|
||||
// appendDrawTrianglesHistory appends a draw-image history item to the image.
|
||||
func (i *Image) appendDrawTrianglesHistory(srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
|
||||
func (i *Image) appendDrawTrianglesHistory(srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule, hint Hint) {
|
||||
if i.stale || !i.needsRestoration() {
|
||||
panic("restorable: an image must not be stale or need restoration at appendDrawTrianglesHistory")
|
||||
}
|
||||
@ -360,6 +431,11 @@ func (i *Image) appendDrawTrianglesHistory(srcs [graphics.ShaderSrcImageCount]*I
|
||||
panic("restorable: appendDrawTrianglesHistory must not be called when AlwaysReadPixelsFromGPU() returns true")
|
||||
}
|
||||
|
||||
// If the command overwrites the destination region, remove the history items that are in the region.
|
||||
if hint == HintOverwriteDstRegion {
|
||||
i.removeDrawTrianglesHistoryItems(dstRegion)
|
||||
}
|
||||
|
||||
// TODO: Would it be possible to merge draw image history items?
|
||||
const maxDrawTrianglesHistoryCount = 1024
|
||||
if len(i.drawTrianglesHistory)+1 > maxDrawTrianglesHistoryCount {
|
||||
@ -379,7 +455,7 @@ func (i *Image) appendDrawTrianglesHistory(srcs [graphics.ShaderSrcImageCount]*I
|
||||
copy(us, uniforms)
|
||||
|
||||
item := &drawTrianglesHistoryItem{
|
||||
images: srcs,
|
||||
srcImages: srcs,
|
||||
vertices: vs,
|
||||
indices: is,
|
||||
blend: blend,
|
||||
@ -402,7 +478,7 @@ func (i *Image) readPixelsFromGPUIfNeeded(graphicsDriver graphicsdriver.Graphics
|
||||
}
|
||||
|
||||
func (i *Image) ReadPixels(graphicsDriver graphicsdriver.Graphics, pixels []byte, region image.Rectangle) error {
|
||||
if AlwaysReadPixelsFromGPU() {
|
||||
if AlwaysReadPixelsFromGPU() || !i.needsRestoration() {
|
||||
if err := i.image.ReadPixels(graphicsDriver, []graphicsdriver.PixelsArgs{
|
||||
{
|
||||
Pixels: pixels,
|
||||
@ -424,12 +500,23 @@ func (i *Image) ReadPixels(graphicsDriver graphicsdriver.Graphics, pixels []byte
|
||||
return nil
|
||||
}
|
||||
|
||||
// makeStaleIfDependingOn makes the image stale if the image depends on target.
|
||||
func (i *Image) makeStaleIfDependingOn(target *Image) {
|
||||
// makeStaleIfDependingOn makes the image stale if the image depends on src.
|
||||
func (i *Image) makeStaleIfDependingOn(src *Image) {
|
||||
if i.stale {
|
||||
return
|
||||
}
|
||||
if i.dependsOn(target) {
|
||||
if i.dependsOn(src) {
|
||||
// There is no new region to make stale.
|
||||
i.makeStale(image.Rectangle{})
|
||||
}
|
||||
}
|
||||
|
||||
// makeStaleIfDependingOnAtRegion makes the image stale if the image depends on src at srcRegion.
|
||||
func (i *Image) makeStaleIfDependingOnAtRegion(src *Image, srcRegion image.Rectangle) {
|
||||
if i.stale {
|
||||
return
|
||||
}
|
||||
if i.dependsOnAtRegion(src, srcRegion) {
|
||||
// There is no new region to make stale.
|
||||
i.makeStale(image.Rectangle{})
|
||||
}
|
||||
@ -515,14 +602,27 @@ func (i *Image) resolveStale(graphicsDriver graphicsdriver.Graphics) error {
|
||||
return i.readPixelsFromGPU(graphicsDriver)
|
||||
}
|
||||
|
||||
// dependsOn reports whether the image depends on target.
|
||||
func (i *Image) dependsOn(target *Image) bool {
|
||||
// dependsOn reports whether the image depends on src.
|
||||
func (i *Image) dependsOn(src *Image) bool {
|
||||
for _, c := range i.drawTrianglesHistory {
|
||||
for _, img := range c.images {
|
||||
if img == nil {
|
||||
for _, img := range c.srcImages {
|
||||
if img != src {
|
||||
continue
|
||||
}
|
||||
if img == target {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// dependsOnAtRegion reports whether the image depends on src at srcRegion.
|
||||
func (i *Image) dependsOnAtRegion(src *Image, srcRegion image.Rectangle) bool {
|
||||
for _, c := range i.drawTrianglesHistory {
|
||||
for i, img := range c.srcImages {
|
||||
if img != src {
|
||||
continue
|
||||
}
|
||||
if c.srcRegions[i].Overlaps(srcRegion) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -544,7 +644,7 @@ func (i *Image) dependsOnShader(shader *Shader) bool {
|
||||
func (i *Image) dependingImages() map[*Image]struct{} {
|
||||
r := map[*Image]struct{}{}
|
||||
for _, c := range i.drawTrianglesHistory {
|
||||
for _, img := range c.images {
|
||||
for _, img := range c.srcImages {
|
||||
if img == nil {
|
||||
continue
|
||||
}
|
||||
@ -598,7 +698,7 @@ func (i *Image) restore(graphicsDriver graphicsdriver.Graphics) error {
|
||||
|
||||
for _, c := range i.drawTrianglesHistory {
|
||||
var imgs [graphics.ShaderSrcImageCount]*graphicscommand.Image
|
||||
for i, img := range c.images {
|
||||
for i, img := range c.srcImages {
|
||||
if img == nil {
|
||||
continue
|
||||
}
|
||||
|
@ -62,7 +62,6 @@ func AlwaysReadPixelsFromGPU() bool {
|
||||
type images struct {
|
||||
images map[*Image]struct{}
|
||||
shaders map[*Shader]struct{}
|
||||
lastTarget *Image
|
||||
contextLost atomic.Bool
|
||||
}
|
||||
|
||||
@ -91,7 +90,7 @@ func resolveStaleImages(graphicsDriver graphicsdriver.Graphics, endFrame bool) e
|
||||
if disabled.Load() {
|
||||
disabledOnce.Do(func() {
|
||||
for img := range theImages.images {
|
||||
img.makeStale(image.Rectangle{})
|
||||
img.makeStale(image.Rect(0, 0, img.width, img.height))
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -157,7 +156,6 @@ func (i *images) removeShader(shader *Shader) {
|
||||
|
||||
// resolveStaleImages resolves stale images.
|
||||
func (i *images) resolveStaleImages(graphicsDriver graphicsdriver.Graphics) error {
|
||||
i.lastTarget = nil
|
||||
for img := range i.images {
|
||||
if err := img.resolveStale(graphicsDriver); err != nil {
|
||||
return err
|
||||
@ -166,20 +164,29 @@ func (i *images) resolveStaleImages(graphicsDriver graphicsdriver.Graphics) erro
|
||||
return nil
|
||||
}
|
||||
|
||||
// makeStaleIfDependingOn makes all the images stale that depend on target.
|
||||
// makeStaleIfDependingOn makes all the images stale that depend on src.
|
||||
//
|
||||
// When target is modified, all images depending on target can't be restored with target.
|
||||
// When src is modified, all images depending on src can't be restored with src.
|
||||
// makeStaleIfDependingOn is called in such situation.
|
||||
func (i *images) makeStaleIfDependingOn(target *Image) {
|
||||
if target == nil {
|
||||
panic("restorable: target must not be nil at makeStaleIfDependingOn")
|
||||
func (i *images) makeStaleIfDependingOn(src *Image) {
|
||||
if src == nil {
|
||||
panic("restorable: src must not be nil at makeStaleIfDependingOn")
|
||||
}
|
||||
if i.lastTarget == target {
|
||||
return
|
||||
}
|
||||
i.lastTarget = target
|
||||
for img := range i.images {
|
||||
img.makeStaleIfDependingOn(target)
|
||||
img.makeStaleIfDependingOn(src)
|
||||
}
|
||||
}
|
||||
|
||||
// makeStaleIfDependingOnAtRegion makes all the images stale that depend on src at srcRegion.
|
||||
//
|
||||
// When src is modified, all images depending on src can't be restored with src at srcRegion.
|
||||
// makeStaleIfDependingOnAtRegion is called in such situation.
|
||||
func (i *images) makeStaleIfDependingOnAtRegion(src *Image, srcRegion image.Rectangle) {
|
||||
if src == nil {
|
||||
panic("restorable: src must not be nil at makeStaleIfDependingOnAtRegion")
|
||||
}
|
||||
for img := range i.images {
|
||||
img.makeStaleIfDependingOnAtRegion(src, srcRegion)
|
||||
}
|
||||
}
|
||||
|
||||
@ -242,9 +249,7 @@ func (i *images) restore(graphicsDriver graphicsdriver.Graphics) error {
|
||||
current[i] = struct{}{}
|
||||
}
|
||||
for e := range edges {
|
||||
if _, ok := current[e.target]; ok {
|
||||
delete(current, e.target)
|
||||
}
|
||||
delete(current, e.target)
|
||||
}
|
||||
for i := range current {
|
||||
delete(images, i)
|
||||
|
@ -140,7 +140,8 @@ func TestRestoreChain(t *testing.T) {
|
||||
vs := quadVertices(1, 1, 0, 0)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, 1, 1)
|
||||
imgs[i+1].DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{imgs[i]}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr := image.Rect(0, 0, 1, 1)
|
||||
imgs[i+1].DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{imgs[i]}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
}
|
||||
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
|
||||
t.Fatal(err)
|
||||
@ -183,10 +184,11 @@ func TestRestoreChain2(t *testing.T) {
|
||||
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, w, h)
|
||||
imgs[8].DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{imgs[7]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
imgs[9].DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{imgs[8]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr := image.Rect(0, 0, w, h)
|
||||
imgs[8].DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{imgs[7]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
imgs[9].DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{imgs[8]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
for i := 0; i < 7; i++ {
|
||||
imgs[i+1].DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{imgs[i]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
imgs[i+1].DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{imgs[i]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
}
|
||||
|
||||
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
|
||||
@ -227,10 +229,11 @@ func TestRestoreOverrideSource(t *testing.T) {
|
||||
img1.WritePixels(bytesToManagedBytes([]byte{clr0.R, clr0.G, clr0.B, clr0.A}), image.Rect(0, 0, w, h))
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, w, h)
|
||||
img2.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img1}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
img3.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img2}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr := image.Rect(0, 0, w, h)
|
||||
img2.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img1}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
img3.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img2}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
img0.WritePixels(bytesToManagedBytes([]byte{clr1.R, clr1.G, clr1.B, clr1.A}), image.Rect(0, 0, w, h))
|
||||
img1.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img0}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
img1.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img0}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -309,24 +312,25 @@ func TestRestoreComplexGraph(t *testing.T) {
|
||||
}()
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, w, h)
|
||||
sr := image.Rect(0, 0, w, h)
|
||||
vs := quadVertices(w, h, 0, 0)
|
||||
img3.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
img3.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
vs = quadVertices(w, h, 1, 0)
|
||||
img3.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img1}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
img3.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img1}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
vs = quadVertices(w, h, 1, 0)
|
||||
img4.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img1}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
img4.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img1}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
vs = quadVertices(w, h, 2, 0)
|
||||
img4.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img2}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
img4.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img2}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
vs = quadVertices(w, h, 0, 0)
|
||||
img5.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
img5.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
vs = quadVertices(w, h, 0, 0)
|
||||
img6.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
img6.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
vs = quadVertices(w, h, 1, 0)
|
||||
img6.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img4}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
img6.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img4}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
vs = quadVertices(w, h, 0, 0)
|
||||
img7.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img2}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
img7.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img2}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
vs = quadVertices(w, h, 2, 0)
|
||||
img7.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
img7.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -419,8 +423,9 @@ func TestRestoreRecursive(t *testing.T) {
|
||||
}()
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, w, h)
|
||||
img1.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img0}, quadVertices(w, h, 1, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
img0.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img1}, quadVertices(w, h, 1, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr := image.Rect(0, 0, w, h)
|
||||
img1.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img0}, quadVertices(w, h, 1, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
img0.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img1}, quadVertices(w, h, 1, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -519,7 +524,8 @@ func TestDrawTrianglesAndWritePixels(t *testing.T) {
|
||||
vs := quadVertices(1, 1, 0, 0)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, 2, 1)
|
||||
img1.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr := image.Rect(0, 0, 1, 1)
|
||||
img1.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
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 {
|
||||
@ -557,8 +563,9 @@ func TestDispose(t *testing.T) {
|
||||
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, 1, 1)
|
||||
img1.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img2}, quadVertices(1, 1, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
img0.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img1}, quadVertices(1, 1, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr := image.Rect(0, 0, 1, 1)
|
||||
img1.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img2}, quadVertices(1, 1, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
img0.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img1}, quadVertices(1, 1, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
img1.Dispose()
|
||||
|
||||
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
|
||||
@ -667,7 +674,8 @@ func TestWritePixelsOnly(t *testing.T) {
|
||||
vs := quadVertices(1, 1, 0, 0)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, 1, 1)
|
||||
img1.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr := image.Rect(0, 0, w, h)
|
||||
img1.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
img0.WritePixels(bytesToManagedBytes([]byte{5, 6, 7, 8}), image.Rect(0, 0, 1, 1))
|
||||
|
||||
// BasePixelsForTesting is available without GPU accessing.
|
||||
@ -721,7 +729,8 @@ func TestReadPixelsFromVolatileImage(t *testing.T) {
|
||||
vs := quadVertices(1, 1, 0, 0)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, w, h)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr := image.Rect(0, 0, w, h)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
|
||||
// Read the pixels. If the implementation is correct, dst tries to read its pixels from GPU due to being
|
||||
// stale.
|
||||
@ -745,7 +754,8 @@ func TestAllowWritePixelsAfterDrawTriangles(t *testing.T) {
|
||||
vs := quadVertices(w, h, 0, 0)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, w, h)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr := image.Rect(0, 0, w, h)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
dst.WritePixels(bytesToManagedBytes(make([]byte, 4*w*h)), image.Rect(0, 0, w, h))
|
||||
// WritePixels for a whole image doesn't panic.
|
||||
}
|
||||
@ -764,7 +774,8 @@ func TestAllowWritePixelsForPartAfterDrawTriangles(t *testing.T) {
|
||||
vs := quadVertices(w, h, 0, 0)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, w, h)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr := image.Rect(0, 0, w, h)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
dst.WritePixels(bytesToManagedBytes(make([]byte, 4*2*2)), image.Rect(0, 0, 2, 2))
|
||||
// WritePixels for a part of image doesn't panic.
|
||||
|
||||
@ -858,7 +869,8 @@ func TestDrawTrianglesAndExtend(t *testing.T) {
|
||||
vs := quadVertices(w, h, 0, 0)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, w, h)
|
||||
orig.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr := image.Rect(0, 0, w, h)
|
||||
orig.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
extended := orig.Extend(w*2, h*2) // After this, orig is already disposed.
|
||||
|
||||
result := make([]byte, 4*(w*2)*(h*2))
|
||||
@ -908,7 +920,8 @@ func TestMutateSlices(t *testing.T) {
|
||||
is := make([]uint32, len(graphics.QuadIndices()))
|
||||
copy(is, graphics.QuadIndices())
|
||||
dr := image.Rect(0, 0, w, h)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr := image.Rect(0, 0, w, h)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
for i := range vs {
|
||||
vs[i] = 0
|
||||
}
|
||||
@ -1100,7 +1113,8 @@ func TestDrawTrianglesAndReadPixels(t *testing.T) {
|
||||
vs := quadVertices(w, h, 0, 0)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, w, h)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr := image.Rect(0, 0, w, h)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
|
||||
pix := make([]byte, 4*w*h)
|
||||
if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h)); err != nil {
|
||||
@ -1124,7 +1138,8 @@ func TestWritePixelsAndDrawTriangles(t *testing.T) {
|
||||
vs := quadVertices(1, 1, 1, 0)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(1, 0, 2, 1)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr := image.Rect(0, 0, 1, 1)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
|
||||
// Get the pixels.
|
||||
pix := make([]byte, 4*2*1)
|
||||
@ -1138,3 +1153,37 @@ func TestWritePixelsAndDrawTriangles(t *testing.T) {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOverwriteDstRegion(t *testing.T) {
|
||||
const w, h = 1, 1
|
||||
src0 := restorable.NewImage(w, h, restorable.ImageTypeRegular)
|
||||
src1 := restorable.NewImage(w, h, restorable.ImageTypeRegular)
|
||||
dst := restorable.NewImage(w, h, restorable.ImageTypeRegular)
|
||||
|
||||
src0.WritePixels(bytesToManagedBytes([]byte{0x40, 0x40, 0x40, 0x40}), image.Rect(0, 0, 1, 1))
|
||||
src1.WritePixels(bytesToManagedBytes([]byte{0x80, 0x80, 0x80, 0x80}), image.Rect(0, 0, 1, 1))
|
||||
|
||||
vs := quadVertices(w, h, 0, 0)
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, w, h)
|
||||
sr := image.Rect(0, 0, w, h)
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src0}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
// This tests that HintOverwriteDstRegion removes the previous DrawTriangles.
|
||||
// In practice, BlendCopy should be used instead of BlendSourceOver in this case.
|
||||
dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src1}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintOverwriteDstRegion)
|
||||
|
||||
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pix := make([]byte, 4*w*h)
|
||||
if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got, want := (color.RGBA{R: pix[0], G: pix[1], B: pix[2], A: pix[3]}), (color.RGBA{R: 0x80, G: 0x80, B: 0x80, A: 0x80}); !sameColors(got, want, 1) {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,8 @@ func clearImage(img *restorable.Image, w, h int) {
|
||||
}
|
||||
is := graphics.QuadIndices()
|
||||
dr := image.Rect(0, 0, w, h)
|
||||
img.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{emptyImage}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr := image.Rect(0, 0, 3, 3)
|
||||
img.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{emptyImage}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
}
|
||||
|
||||
func TestShader(t *testing.T) {
|
||||
@ -55,7 +56,7 @@ func TestShader(t *testing.T) {
|
||||
|
||||
s := restorable.NewShader(etesting.ShaderProgramFill(0xff, 0, 0, 0xff), "")
|
||||
dr := image.Rect(0, 0, 1, 1)
|
||||
img.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, s, nil, graphicsdriver.FillRuleFillAll)
|
||||
img.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, s, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
|
||||
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
|
||||
t.Fatal(err)
|
||||
@ -85,7 +86,8 @@ func TestShaderChain(t *testing.T) {
|
||||
s := restorable.NewShader(etesting.ShaderProgramImages(1), "")
|
||||
for i := 0; i < num-1; i++ {
|
||||
dr := image.Rect(0, 0, 1, 1)
|
||||
imgs[i+1].DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{imgs[i]}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, s, nil, graphicsdriver.FillRuleFillAll)
|
||||
sr := image.Rect(0, 0, 1, 1)
|
||||
imgs[i+1].DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{imgs[i]}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, s, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
}
|
||||
|
||||
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
|
||||
@ -117,7 +119,12 @@ func TestShaderMultipleSources(t *testing.T) {
|
||||
|
||||
s := restorable.NewShader(etesting.ShaderProgramImages(3), "")
|
||||
dr := image.Rect(0, 0, 1, 1)
|
||||
dst.DrawTriangles(srcs, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, s, nil, graphicsdriver.FillRuleFillAll)
|
||||
srs := [graphics.ShaderSrcImageCount]image.Rectangle{
|
||||
image.Rect(0, 0, 1, 1),
|
||||
image.Rect(0, 0, 1, 1),
|
||||
image.Rect(0, 0, 1, 1),
|
||||
}
|
||||
dst.DrawTriangles(srcs, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, srs, s, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
|
||||
// Clear one of the sources after DrawTriangles. dst should not be affected.
|
||||
clearImage(srcs[0], 1, 1)
|
||||
@ -154,7 +161,7 @@ func TestShaderMultipleSourcesOnOneTexture(t *testing.T) {
|
||||
image.Rect(1, 0, 2, 1),
|
||||
image.Rect(2, 0, 3, 1),
|
||||
}
|
||||
dst.DrawTriangles(srcs, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, srcRegions, s, nil, graphicsdriver.FillRuleFillAll)
|
||||
dst.DrawTriangles(srcs, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, srcRegions, s, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
|
||||
// Clear one of the sources after DrawTriangles. dst should not be affected.
|
||||
clearImage(srcs[0], 3, 1)
|
||||
@ -179,7 +186,7 @@ func TestShaderDispose(t *testing.T) {
|
||||
|
||||
s := restorable.NewShader(etesting.ShaderProgramFill(0xff, 0, 0, 0xff), "")
|
||||
dr := image.Rect(0, 0, 1, 1)
|
||||
img.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, s, nil, graphicsdriver.FillRuleFillAll)
|
||||
img.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, s, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
|
||||
|
||||
// Dispose the shader. This should invalidate all the images using this shader i.e., all the images become
|
||||
// stale.
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/mipmap"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/restorable"
|
||||
)
|
||||
|
||||
// panicOnErrorOnReadingPixels indicates whether reading pixels panics on an error or not.
|
||||
@ -77,7 +78,7 @@ func (i *Image) Deallocate() {
|
||||
i.mipmap.Deallocate()
|
||||
}
|
||||
|
||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule, canSkipMipmap bool, antialias bool) {
|
||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule, canSkipMipmap bool, antialias bool, hint restorable.Hint) {
|
||||
if i.modifyCallback != nil {
|
||||
i.modifyCallback()
|
||||
}
|
||||
@ -113,7 +114,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertice
|
||||
srcMipmaps[i] = src.mipmap
|
||||
}
|
||||
|
||||
i.mipmap.DrawTriangles(srcMipmaps, vertices, indices, blend, dstRegion, srcRegions, shader.shader, uniforms, fillRule, canSkipMipmap)
|
||||
i.mipmap.DrawTriangles(srcMipmaps, vertices, indices, blend, dstRegion, srcRegions, shader.shader, uniforms, fillRule, canSkipMipmap, hint)
|
||||
}
|
||||
|
||||
func (i *Image) WritePixels(pix []byte, region image.Rectangle) {
|
||||
@ -182,8 +183,9 @@ func (i *Image) Fill(r, g, b, a float32, region image.Rectangle) {
|
||||
if a == 1 && i.lastBlend == graphicsdriver.BlendSourceOver {
|
||||
blend = graphicsdriver.BlendSourceOver
|
||||
}
|
||||
sr := image.Rect(0, 0, i.ui.whiteImage.width, i.ui.whiteImage.height)
|
||||
// i.lastBlend is updated in DrawTriangles.
|
||||
i.DrawTriangles(srcs, i.tmpVerticesForFill, is, blend, region, [graphics.ShaderSrcImageCount]image.Rectangle{}, NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, true, false)
|
||||
i.DrawTriangles(srcs, i.tmpVerticesForFill, is, blend, region, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, true, false, restorable.HintOverwriteDstRegion)
|
||||
}
|
||||
|
||||
type bigOffscreenImage struct {
|
||||
@ -252,7 +254,8 @@ func (i *bigOffscreenImage) drawTriangles(srcs [graphics.ShaderSrcImageCount]*Im
|
||||
1, 1, 1, 1)
|
||||
is := graphics.QuadIndices()
|
||||
dstRegion := image.Rect(0, 0, i.region.Dx()*bigOffscreenScale, i.region.Dy()*bigOffscreenScale)
|
||||
i.image.DrawTriangles(srcs, i.tmpVerticesForCopying, is, graphicsdriver.BlendCopy, dstRegion, [graphics.ShaderSrcImageCount]image.Rectangle{}, NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, true, false)
|
||||
srcRegion := i.region
|
||||
i.image.DrawTriangles(srcs, i.tmpVerticesForCopying, is, graphicsdriver.BlendCopy, dstRegion, [graphics.ShaderSrcImageCount]image.Rectangle{srcRegion}, NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, true, false, restorable.HintOverwriteDstRegion)
|
||||
}
|
||||
|
||||
for idx := 0; idx < len(vertices); idx += graphics.VertexFloatCount {
|
||||
@ -268,7 +271,7 @@ func (i *bigOffscreenImage) drawTriangles(srcs [graphics.ShaderSrcImageCount]*Im
|
||||
dstRegion.Max.X *= bigOffscreenScale
|
||||
dstRegion.Max.Y *= bigOffscreenScale
|
||||
|
||||
i.image.DrawTriangles(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule, canSkipMipmap, false)
|
||||
i.image.DrawTriangles(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule, canSkipMipmap, false, restorable.HintNone)
|
||||
i.dirty = true
|
||||
}
|
||||
|
||||
@ -296,11 +299,14 @@ func (i *bigOffscreenImage) flush() {
|
||||
1, 1, 1, 1)
|
||||
is := graphics.QuadIndices()
|
||||
dstRegion := i.region
|
||||
srcRegion := image.Rect(0, 0, i.region.Dx()*bigOffscreenScale, i.region.Dy()*bigOffscreenScale)
|
||||
blend := graphicsdriver.BlendSourceOver
|
||||
hint := restorable.HintNone
|
||||
if i.blend != graphicsdriver.BlendSourceOver {
|
||||
blend = graphicsdriver.BlendCopy
|
||||
hint = restorable.HintOverwriteDstRegion
|
||||
}
|
||||
i.orig.DrawTriangles(srcs, i.tmpVerticesForFlushing, is, blend, dstRegion, [graphics.ShaderSrcImageCount]image.Rectangle{}, LinearFilterShader, nil, graphicsdriver.FillRuleFillAll, true, false)
|
||||
i.orig.DrawTriangles(srcs, i.tmpVerticesForFlushing, is, blend, dstRegion, [graphics.ShaderSrcImageCount]image.Rectangle{srcRegion}, LinearFilterShader, nil, graphicsdriver.FillRuleFillAll, true, false, hint)
|
||||
|
||||
i.image.clear()
|
||||
i.dirty = false
|
||||
|
Loading…
Reference in New Issue
Block a user