mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 04:57:26 +01:00
parent
8a44ef4f6c
commit
c01ceeaa6a
@ -192,7 +192,7 @@ func (g *Game) renderLevel(screen *ebiten.Image) {
|
||||
if scaleLater {
|
||||
if g.offscreen != nil {
|
||||
if g.offscreen.Bounds().Size() != screen.Bounds().Size() {
|
||||
g.offscreen.Dispose()
|
||||
g.offscreen.Deallocate()
|
||||
g.offscreen = nil
|
||||
}
|
||||
}
|
||||
|
@ -342,7 +342,7 @@ func (t *TextBox) Draw(dst *ebiten.Image) {
|
||||
vw, vh := t.viewSize()
|
||||
w, h := t.contentBuf.Bounds().Dx(), t.contentBuf.Bounds().Dy()
|
||||
if vw > w || vh > h {
|
||||
t.contentBuf.Dispose()
|
||||
t.contentBuf.Deallocate()
|
||||
t.contentBuf = nil
|
||||
}
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ func newGameForUI(game Game, transparent bool) *gameForUI {
|
||||
|
||||
func (g *gameForUI) NewOffscreenImage(width, height int) *ui.Image {
|
||||
if g.offscreen != nil {
|
||||
g.offscreen.Dispose()
|
||||
g.offscreen.Deallocate()
|
||||
g.offscreen = nil
|
||||
}
|
||||
|
||||
@ -106,7 +106,7 @@ func (g *gameForUI) NewOffscreenImage(width, height int) *ui.Image {
|
||||
|
||||
func (g *gameForUI) NewScreenImage(width, height int) *ui.Image {
|
||||
if g.screen != nil {
|
||||
g.screen.Dispose()
|
||||
g.screen.Deallocate()
|
||||
g.screen = nil
|
||||
}
|
||||
|
||||
|
29
image.go
29
image.go
@ -963,7 +963,9 @@ func (i *Image) Set(x, y int, clr color.Color) {
|
||||
//
|
||||
// If the image is a sub-image, Dispose does nothing.
|
||||
//
|
||||
// When the image is disposed, Dispose does nothing.
|
||||
// If the image is disposed, Dispose does nothing.
|
||||
//
|
||||
// Deprecated: as of v2.7. Use Deallocate instead.
|
||||
func (i *Image) Dispose() {
|
||||
i.copyCheck()
|
||||
|
||||
@ -973,10 +975,33 @@ func (i *Image) Dispose() {
|
||||
if i.isSubImage() {
|
||||
return
|
||||
}
|
||||
i.image.MarkDisposed()
|
||||
i.image.Deallocate()
|
||||
i.image = nil
|
||||
}
|
||||
|
||||
// Deallocate clears the image and deallocates the internal state of the image.
|
||||
// Even after Deallocate is called, the image is still available.
|
||||
// In this case, the image's internal state is allocated again.
|
||||
//
|
||||
// Usually, you don't have to call Deallocate since the internal state is automatically released by GC.
|
||||
// However, if you are sure that the image is no longer used but not sure how this image object is referred,
|
||||
// you can call Deallocate to make sure that the internal state is deallocated.
|
||||
//
|
||||
// If the image is a sub-image, Deallocate does nothing.
|
||||
//
|
||||
// If the image is disposed, Deallocate does nothing.
|
||||
func (i *Image) Deallocate() {
|
||||
i.copyCheck()
|
||||
|
||||
if i.isDisposed() {
|
||||
return
|
||||
}
|
||||
if i.isSubImage() {
|
||||
return
|
||||
}
|
||||
i.image.Deallocate()
|
||||
}
|
||||
|
||||
// WritePixels replaces the pixels of the image.
|
||||
//
|
||||
// The given pixels are treated as RGBA pre-multiplied alpha values.
|
||||
|
119
image_test.go
119
image_test.go
@ -264,7 +264,7 @@ func TestImageDotByDotInversion(t *testing.T) {
|
||||
func TestImageWritePixels(t *testing.T) {
|
||||
// Create a dummy image so that the shared texture is used and origImg's position is shifted.
|
||||
dummyImg := ebiten.NewImageFromImage(image.NewRGBA(image.Rect(0, 0, 16, 16)))
|
||||
defer dummyImg.Dispose()
|
||||
defer dummyImg.Deallocate()
|
||||
|
||||
_, origImg, err := openEbitenImage()
|
||||
if err != nil {
|
||||
@ -335,6 +335,19 @@ func TestImageDispose(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageDeallocate(t *testing.T) {
|
||||
img := ebiten.NewImage(16, 16)
|
||||
img.Fill(color.White)
|
||||
img.Deallocate()
|
||||
|
||||
// The color is transparent (color.RGBA{}).
|
||||
got := img.At(0, 0)
|
||||
want := color.RGBA{}
|
||||
if got != want {
|
||||
t.Errorf("img.At(0, 0) got: %v, want: %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
type ordered interface {
|
||||
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64 | ~string
|
||||
}
|
||||
@ -1716,6 +1729,37 @@ func TestImageAtAfterDisposingSubImage(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageAtAfterDeallocateSubImage(t *testing.T) {
|
||||
img := ebiten.NewImage(16, 16)
|
||||
img.Set(0, 0, color.White)
|
||||
img.SubImage(image.Rect(0, 0, 16, 16))
|
||||
runtime.GC()
|
||||
|
||||
want := color.RGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff}
|
||||
want64 := color.RGBA64{R: 0xffff, G: 0xffff, B: 0xffff, A: 0xffff}
|
||||
got := img.At(0, 0)
|
||||
if got != want {
|
||||
t.Errorf("At(0,0) got: %v, want: %v", got, want)
|
||||
}
|
||||
got = img.RGBA64At(0, 0)
|
||||
if got != want64 {
|
||||
t.Errorf("RGBA64At(0,0) got: %v, want: %v", got, want)
|
||||
}
|
||||
|
||||
img.Set(0, 1, color.White)
|
||||
sub := img.SubImage(image.Rect(0, 0, 16, 16)).(*ebiten.Image)
|
||||
sub.Deallocate()
|
||||
|
||||
got = img.At(0, 1)
|
||||
if got != want {
|
||||
t.Errorf("At(0,1) got: %v, want: %v", got, want64)
|
||||
}
|
||||
got = img.RGBA64At(0, 1)
|
||||
if got != want64 {
|
||||
t.Errorf("RGBA64At(0,1) got: %v, want: %v", got, want64)
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageSubImageSubImage(t *testing.T) {
|
||||
img := ebiten.NewImage(16, 16)
|
||||
img.Fill(color.White)
|
||||
@ -2263,6 +2307,14 @@ func TestImageDrawDisposedImage(t *testing.T) {
|
||||
dst.DrawImage(src, nil)
|
||||
}
|
||||
|
||||
func TestImageDrawDeallocatedImage(t *testing.T) {
|
||||
dst := ebiten.NewImage(16, 16)
|
||||
src := ebiten.NewImage(16, 16)
|
||||
src.Deallocate()
|
||||
// DrawImage must not panic.
|
||||
dst.DrawImage(src, nil)
|
||||
}
|
||||
|
||||
func TestImageDrawTrianglesDisposedImage(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
@ -2278,6 +2330,16 @@ func TestImageDrawTrianglesDisposedImage(t *testing.T) {
|
||||
dst.DrawTriangles(vs, is, src, nil)
|
||||
}
|
||||
|
||||
func TestImageDrawTrianglesDeallocateImage(t *testing.T) {
|
||||
dst := ebiten.NewImage(16, 16)
|
||||
src := ebiten.NewImage(16, 16)
|
||||
src.Deallocate()
|
||||
vs := make([]ebiten.Vertex, 4)
|
||||
is := []uint16{0, 1, 2, 1, 2, 3}
|
||||
// DrawTriangles must not panic.
|
||||
dst.DrawTriangles(vs, is, src, nil)
|
||||
}
|
||||
|
||||
// #1137
|
||||
func BenchmarkImageDrawOver(b *testing.B) {
|
||||
dst := ebiten.NewImage(16, 16)
|
||||
@ -4344,3 +4406,58 @@ func TestImageWritePixelAndDispose(t *testing.T) {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageWritePixelAndDeallocate(t *testing.T) {
|
||||
const (
|
||||
w = 16
|
||||
h = 16
|
||||
)
|
||||
img := ebiten.NewImage(w, h)
|
||||
pix := make([]byte, 4*w*h)
|
||||
for i := range pix {
|
||||
pix[i] = 0xff
|
||||
}
|
||||
img.WritePixels(pix)
|
||||
img.Deallocate()
|
||||
|
||||
// Confirm that any pixel information is cleared after Dealocate is called.
|
||||
if got, want := img.At(0, 0), (color.RGBA{}); got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageDrawImageAfterDeallocation(t *testing.T) {
|
||||
src, _, err := openEbitenImage()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
return
|
||||
}
|
||||
|
||||
w, h := src.Bounds().Dx(), src.Bounds().Dy()
|
||||
dst := ebiten.NewImage(w, h)
|
||||
|
||||
dst.DrawImage(src, nil)
|
||||
for j := 0; j < h; j++ {
|
||||
for i := 0; i < w; i++ {
|
||||
got := dst.At(i, j)
|
||||
want := src.At(i, j)
|
||||
if got != want {
|
||||
t.Errorf("At(%d, %d): got: %v, want: %v", i, j, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Even after deallocating the image, the image is still available.
|
||||
dst.Deallocate()
|
||||
|
||||
dst.DrawImage(src, nil)
|
||||
for j := 0; j < h; j++ {
|
||||
for i := 0; i < w; i++ {
|
||||
got := dst.At(i, j)
|
||||
want := src.At(i, j)
|
||||
if got != want {
|
||||
t.Errorf("At(%d, %d): got: %v, want: %v", i, j, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -542,8 +542,9 @@ func (i *Image) readPixels(graphicsDriver graphicsdriver.Graphics, pixels []byte
|
||||
return i.backend.restorable.ReadPixels(graphicsDriver, pixels, region.Add(r.Min))
|
||||
}
|
||||
|
||||
// MarkDisposed marks the image as disposed.
|
||||
func (i *Image) MarkDisposed() {
|
||||
// Deallocate deallocates the internal state.
|
||||
// Even after this call, the image is still available as a new cleared image.
|
||||
func (i *Image) Deallocate() {
|
||||
backendsM.Lock()
|
||||
defer backendsM.Unlock()
|
||||
|
||||
|
@ -62,25 +62,25 @@ func TestEnsureIsolatedFromSourceBackend(t *testing.T) {
|
||||
// Create img1 and img2 with this size so that the next images are allocated
|
||||
// with non-upper-left location.
|
||||
img1 := atlas.NewImage(bigSize, 100, atlas.ImageTypeRegular)
|
||||
defer img1.MarkDisposed()
|
||||
defer img1.Deallocate()
|
||||
// Ensure img1's region is allocated.
|
||||
img1.WritePixels(make([]byte, 4*bigSize*100), image.Rect(0, 0, bigSize, 100))
|
||||
|
||||
img2 := atlas.NewImage(100, bigSize, atlas.ImageTypeRegular)
|
||||
defer img2.MarkDisposed()
|
||||
defer img2.Deallocate()
|
||||
img2.WritePixels(make([]byte, 4*100*bigSize), image.Rect(0, 0, 100, bigSize))
|
||||
|
||||
const size = 32
|
||||
|
||||
img3 := atlas.NewImage(size/2, size/2, atlas.ImageTypeRegular)
|
||||
defer img3.MarkDisposed()
|
||||
defer img3.Deallocate()
|
||||
img3.WritePixels(make([]byte, (size/2)*(size/2)*4), image.Rect(0, 0, size/2, size/2))
|
||||
|
||||
img4 := atlas.NewImage(size, size, atlas.ImageTypeRegular)
|
||||
defer img4.MarkDisposed()
|
||||
defer img4.Deallocate()
|
||||
|
||||
img5 := atlas.NewImage(size/2, size/2, atlas.ImageTypeRegular)
|
||||
defer img3.MarkDisposed()
|
||||
defer img3.Deallocate()
|
||||
|
||||
pix := make([]byte, size*size*4)
|
||||
for j := 0; j < size; j++ {
|
||||
@ -148,18 +148,18 @@ func TestReputOnSourceBackend(t *testing.T) {
|
||||
const size = 16
|
||||
|
||||
img0 := atlas.NewImage(size, size, atlas.ImageTypeRegular)
|
||||
defer img0.MarkDisposed()
|
||||
defer img0.Deallocate()
|
||||
img0.WritePixels(make([]byte, 4*size*size), image.Rect(0, 0, size, size))
|
||||
|
||||
img1 := atlas.NewImage(size, size, atlas.ImageTypeRegular)
|
||||
defer img1.MarkDisposed()
|
||||
defer img1.Deallocate()
|
||||
img1.WritePixels(make([]byte, 4*size*size), image.Rect(0, 0, size, size))
|
||||
if got, want := img1.IsOnSourceBackendForTesting(), true; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
|
||||
img2 := atlas.NewImage(size, size, atlas.ImageTypeRegular)
|
||||
defer img2.MarkDisposed()
|
||||
defer img2.Deallocate()
|
||||
pix := make([]byte, 4*size*size)
|
||||
for j := 0; j < size; j++ {
|
||||
for i := 0; i < size; i++ {
|
||||
@ -173,7 +173,7 @@ func TestReputOnSourceBackend(t *testing.T) {
|
||||
|
||||
// Create a volatile image. This should always be on a non-source backend.
|
||||
img3 := atlas.NewImage(size, size, atlas.ImageTypeVolatile)
|
||||
defer img3.MarkDisposed()
|
||||
defer img3.Deallocate()
|
||||
img3.WritePixels(make([]byte, 4*size*size), image.Rect(0, 0, size, size))
|
||||
if got, want := img3.IsOnSourceBackendForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
@ -298,7 +298,7 @@ func TestReputOnSourceBackend(t *testing.T) {
|
||||
func TestExtend(t *testing.T) {
|
||||
const w0, h0 = 100, 100
|
||||
img0 := atlas.NewImage(w0, h0, atlas.ImageTypeRegular)
|
||||
defer img0.MarkDisposed()
|
||||
defer img0.Deallocate()
|
||||
|
||||
p0 := make([]byte, 4*w0*h0)
|
||||
for i := 0; i < w0*h0; i++ {
|
||||
@ -311,7 +311,7 @@ func TestExtend(t *testing.T) {
|
||||
|
||||
const w1, h1 = minSourceImageSizeForTesting + 1, 100
|
||||
img1 := atlas.NewImage(w1, h1, atlas.ImageTypeRegular)
|
||||
defer img1.MarkDisposed()
|
||||
defer img1.Deallocate()
|
||||
|
||||
p1 := make([]byte, 4*w1*h1)
|
||||
for i := 0; i < w1*h1; i++ {
|
||||
@ -365,9 +365,9 @@ func TestExtend(t *testing.T) {
|
||||
func TestWritePixelsAfterDrawTriangles(t *testing.T) {
|
||||
const w, h = 256, 256
|
||||
src := atlas.NewImage(w, h, atlas.ImageTypeRegular)
|
||||
defer src.MarkDisposed()
|
||||
defer src.Deallocate()
|
||||
dst := atlas.NewImage(w, h, atlas.ImageTypeRegular)
|
||||
defer dst.MarkDisposed()
|
||||
defer dst.Deallocate()
|
||||
|
||||
pix := make([]byte, 4*w*h)
|
||||
for i := 0; i < w*h; i++ {
|
||||
@ -408,9 +408,9 @@ func TestWritePixelsAfterDrawTriangles(t *testing.T) {
|
||||
func TestSmallImages(t *testing.T) {
|
||||
const w, h = 4, 8
|
||||
src := atlas.NewImage(w, h, atlas.ImageTypeRegular)
|
||||
defer src.MarkDisposed()
|
||||
defer src.Deallocate()
|
||||
dst := atlas.NewImage(w, h, atlas.ImageTypeRegular)
|
||||
defer dst.MarkDisposed()
|
||||
defer dst.Deallocate()
|
||||
|
||||
pix := make([]byte, 4*w*h)
|
||||
for i := 0; i < w*h; i++ {
|
||||
@ -448,11 +448,11 @@ func TestSmallImages(t *testing.T) {
|
||||
func TestLongImages(t *testing.T) {
|
||||
const w, h = 1, 6
|
||||
src := atlas.NewImage(w, h, atlas.ImageTypeRegular)
|
||||
defer src.MarkDisposed()
|
||||
defer src.Deallocate()
|
||||
|
||||
const dstW, dstH = 256, 256
|
||||
dst := atlas.NewImage(dstW, dstH, atlas.ImageTypeRegular)
|
||||
defer dst.MarkDisposed()
|
||||
defer dst.Deallocate()
|
||||
|
||||
pix := make([]byte, 4*w*h)
|
||||
for i := 0; i < w*h; i++ {
|
||||
@ -487,16 +487,16 @@ func TestLongImages(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDisposeImmediately(t *testing.T) {
|
||||
func TestDeallocateImmediately(t *testing.T) {
|
||||
// This tests restorable.Image.ClearPixels is called but WritePixels is not called.
|
||||
|
||||
img0 := atlas.NewImage(16, 16, atlas.ImageTypeRegular)
|
||||
img0.EnsureIsolatedFromSourceForTesting(nil)
|
||||
defer img0.MarkDisposed()
|
||||
defer img0.Deallocate()
|
||||
|
||||
img1 := atlas.NewImage(16, 16, atlas.ImageTypeRegular)
|
||||
img1.EnsureIsolatedFromSourceForTesting(nil)
|
||||
defer img1.MarkDisposed()
|
||||
defer img1.Deallocate()
|
||||
|
||||
// img0 and img1 should share the same backend in 99.9999% possibility.
|
||||
}
|
||||
@ -504,12 +504,12 @@ func TestDisposeImmediately(t *testing.T) {
|
||||
// Issue #1028
|
||||
func TestExtendWithBigImage(t *testing.T) {
|
||||
img0 := atlas.NewImage(1, 1, atlas.ImageTypeRegular)
|
||||
defer img0.MarkDisposed()
|
||||
defer img0.Deallocate()
|
||||
|
||||
img0.WritePixels(make([]byte, 4*1*1), image.Rect(0, 0, 1, 1))
|
||||
|
||||
img1 := atlas.NewImage(minSourceImageSizeForTesting+1, minSourceImageSizeForTesting+1, atlas.ImageTypeRegular)
|
||||
defer img1.MarkDisposed()
|
||||
defer img1.Deallocate()
|
||||
|
||||
img1.WritePixels(make([]byte, 4*(minSourceImageSizeForTesting+1)*(minSourceImageSizeForTesting+1)), image.Rect(0, 0, minSourceImageSizeForTesting+1, minSourceImageSizeForTesting+1))
|
||||
}
|
||||
@ -517,13 +517,13 @@ func TestExtendWithBigImage(t *testing.T) {
|
||||
// Issue #1217
|
||||
func TestMaxImageSize(t *testing.T) {
|
||||
img0 := atlas.NewImage(1, 1, atlas.ImageTypeRegular)
|
||||
defer img0.MarkDisposed()
|
||||
defer img0.Deallocate()
|
||||
paddingSize := img0.PaddingSizeForTesting()
|
||||
|
||||
// This tests that a too-big image is allocated correctly.
|
||||
s := maxImageSizeForTesting - 2*paddingSize
|
||||
img1 := atlas.NewImage(s, s, atlas.ImageTypeRegular)
|
||||
defer img1.MarkDisposed()
|
||||
defer img1.Deallocate()
|
||||
img1.WritePixels(make([]byte, 4*s*s), image.Rect(0, 0, s, s))
|
||||
}
|
||||
|
||||
@ -536,7 +536,7 @@ func Disable_TestMinImageSize(t *testing.T) {
|
||||
// Though the image size is minimum size of the backend, extending the backend happens due to the paddings.
|
||||
s := minSourceImageSizeForTesting
|
||||
img := atlas.NewImage(s, s, atlas.ImageTypeRegular)
|
||||
defer img.MarkDisposed()
|
||||
defer img.Deallocate()
|
||||
img.WritePixels(make([]byte, 4*s*s), image.Rect(0, 0, s, s))
|
||||
}
|
||||
|
||||
@ -545,7 +545,7 @@ func TestMaxImageSizeJust(t *testing.T) {
|
||||
// An unmanaged image never belongs to an atlas and doesn't have its paddings.
|
||||
// TODO: Should we allow such this size for ImageTypeRegular?
|
||||
img := atlas.NewImage(s, s, atlas.ImageTypeUnmanaged)
|
||||
defer img.MarkDisposed()
|
||||
defer img.Deallocate()
|
||||
img.WritePixels(make([]byte, 4*s*s), image.Rect(0, 0, s, s))
|
||||
}
|
||||
|
||||
@ -553,7 +553,7 @@ func TestMaxImageSizeExceeded(t *testing.T) {
|
||||
// This tests that a too-big image is allocated correctly.
|
||||
s := maxImageSizeForTesting
|
||||
img := atlas.NewImage(s+1, s, atlas.ImageTypeRegular)
|
||||
defer img.MarkDisposed()
|
||||
defer img.Deallocate()
|
||||
|
||||
defer func() {
|
||||
if err := recover(); err == nil {
|
||||
@ -565,15 +565,15 @@ func TestMaxImageSizeExceeded(t *testing.T) {
|
||||
}
|
||||
|
||||
// Issue #1421
|
||||
func TestDisposedAndReputOnSourceBackend(t *testing.T) {
|
||||
func TestDeallocatedAndReputOnSourceBackend(t *testing.T) {
|
||||
const size = 16
|
||||
|
||||
src := atlas.NewImage(size, size, atlas.ImageTypeRegular)
|
||||
defer src.MarkDisposed()
|
||||
defer src.Deallocate()
|
||||
src2 := atlas.NewImage(size, size, atlas.ImageTypeRegular)
|
||||
defer src2.MarkDisposed()
|
||||
defer src2.Deallocate()
|
||||
dst := atlas.NewImage(size, size, atlas.ImageTypeRegular)
|
||||
defer dst.MarkDisposed()
|
||||
defer dst.Deallocate()
|
||||
|
||||
// Use src as a render target so that src is not on an atlas.
|
||||
vs := quadVertices(size, size, 0, 0, 1)
|
||||
@ -594,11 +594,8 @@ func TestDisposedAndReputOnSourceBackend(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Before PutImagesOnSourceBackendForTesting, dispose the image.
|
||||
src.MarkDisposed()
|
||||
|
||||
// Force to dispose the image.
|
||||
atlas.FlushDeferredForTesting()
|
||||
// Before PutImagesOnSourceBackendForTesting, deallocate the image.
|
||||
src.Deallocate()
|
||||
|
||||
// Confirm that PutImagesOnSourceBackendForTesting doesn't panic.
|
||||
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
|
||||
@ -609,11 +606,11 @@ func TestImageIsNotReputOnSourceBackendWithoutUsingAsSource(t *testing.T) {
|
||||
const size = 16
|
||||
|
||||
src := atlas.NewImage(size, size, atlas.ImageTypeRegular)
|
||||
defer src.MarkDisposed()
|
||||
defer src.Deallocate()
|
||||
src2 := atlas.NewImage(size, size, atlas.ImageTypeRegular)
|
||||
defer src2.MarkDisposed()
|
||||
defer src2.Deallocate()
|
||||
dst := atlas.NewImage(size, size, atlas.ImageTypeRegular)
|
||||
defer dst.MarkDisposed()
|
||||
defer dst.Deallocate()
|
||||
|
||||
// Use src as a render target so that src is not on an atlas.
|
||||
vs := quadVertices(size, size, 0, 0, 1)
|
||||
@ -660,7 +657,7 @@ func TestImageWritePixelsModify(t *testing.T) {
|
||||
for _, typ := range []atlas.ImageType{atlas.ImageTypeRegular, atlas.ImageTypeVolatile, atlas.ImageTypeUnmanaged} {
|
||||
const size = 16
|
||||
img := atlas.NewImage(size, size, typ)
|
||||
defer img.MarkDisposed()
|
||||
defer img.Deallocate()
|
||||
pix := make([]byte, 4*size*size)
|
||||
for j := 0; j < size; j++ {
|
||||
for i := 0; i < size; i++ {
|
||||
@ -754,11 +751,11 @@ func TestPowerOf2(t *testing.T) {
|
||||
func TestDestinationCountOverflow(t *testing.T) {
|
||||
const w, h = 256, 256
|
||||
src := atlas.NewImage(w, h, atlas.ImageTypeRegular)
|
||||
defer src.MarkDisposed()
|
||||
defer src.Deallocate()
|
||||
dst0 := atlas.NewImage(w, h, atlas.ImageTypeRegular)
|
||||
defer dst0.MarkDisposed()
|
||||
defer dst0.Deallocate()
|
||||
dst1 := atlas.NewImage(w, h, atlas.ImageTypeRegular)
|
||||
defer dst1.MarkDisposed()
|
||||
defer dst1.Deallocate()
|
||||
|
||||
vs := quadVertices(w, h, 0, 0, 1)
|
||||
is := graphics.QuadIndices()
|
||||
@ -785,14 +782,14 @@ func TestDestinationCountOverflow(t *testing.T) {
|
||||
func TestIteratingImagesToPutOnSourceBackend(t *testing.T) {
|
||||
const w, h = 16, 16
|
||||
src := atlas.NewImage(w, h, atlas.ImageTypeRegular)
|
||||
defer src.MarkDisposed()
|
||||
defer src.Deallocate()
|
||||
srcs := make([]*atlas.Image, 10)
|
||||
for i := range srcs {
|
||||
srcs[i] = atlas.NewImage(w, h, atlas.ImageTypeRegular)
|
||||
defer srcs[i].MarkDisposed()
|
||||
defer srcs[i].Deallocate()
|
||||
}
|
||||
dst := atlas.NewImage(w, h, atlas.ImageTypeRegular)
|
||||
defer dst.MarkDisposed()
|
||||
defer dst.Deallocate()
|
||||
|
||||
// Use srcs as detinations once.
|
||||
vs := quadVertices(w, h, 0, 0, 1)
|
||||
|
@ -45,8 +45,8 @@ func (i *Image) invalidatePixels() {
|
||||
i.pixels = nil
|
||||
}
|
||||
|
||||
func (i *Image) MarkDisposed() {
|
||||
i.img.MarkDisposed()
|
||||
func (i *Image) Deallocate() {
|
||||
i.img.Deallocate()
|
||||
}
|
||||
|
||||
func (i *Image) ReadPixels(graphicsDriver graphicsdriver.Graphics, pixels []byte, region image.Rectangle) error {
|
||||
|
@ -58,7 +58,7 @@ func (m *Mipmap) DumpScreenshot(graphicsDriver graphicsdriver.Graphics, name str
|
||||
|
||||
func (m *Mipmap) WritePixels(pix []byte, region image.Rectangle) {
|
||||
m.orig.WritePixels(pix, region)
|
||||
m.disposeMipmaps()
|
||||
m.deallocateMipmaps()
|
||||
}
|
||||
|
||||
func (m *Mipmap) ReadPixels(graphicsDriver graphicsdriver.Graphics, pixels []byte, region image.Rectangle) error {
|
||||
@ -124,7 +124,7 @@ func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderImageCount]*Mipmap, vertices
|
||||
}
|
||||
|
||||
m.orig.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, evenOdd)
|
||||
m.disposeMipmaps()
|
||||
m.deallocateMipmaps()
|
||||
}
|
||||
|
||||
func (m *Mipmap) setImg(level int, img *buffered.Image) {
|
||||
@ -203,16 +203,15 @@ func sizeForLevel(x int, level int) int {
|
||||
return x
|
||||
}
|
||||
|
||||
func (m *Mipmap) MarkDisposed() {
|
||||
m.disposeMipmaps()
|
||||
m.orig.MarkDisposed()
|
||||
m.orig = nil
|
||||
func (m *Mipmap) Deallocate() {
|
||||
m.deallocateMipmaps()
|
||||
m.orig.Deallocate()
|
||||
}
|
||||
|
||||
func (m *Mipmap) disposeMipmaps() {
|
||||
func (m *Mipmap) deallocateMipmaps() {
|
||||
for _, img := range m.imgs {
|
||||
if img != nil {
|
||||
img.MarkDisposed()
|
||||
img.Deallocate()
|
||||
}
|
||||
}
|
||||
for k := range m.imgs {
|
||||
|
2
internal/processtest/testdata/issue2079.go
vendored
2
internal/processtest/testdata/issue2079.go
vendored
@ -45,7 +45,7 @@ func (g *Game) Layout(width, height int) (int, int) {
|
||||
go func() {
|
||||
i := ebiten.NewImage(width, height)
|
||||
i.Fill(color.White)
|
||||
i.Dispose()
|
||||
i.Deallocate()
|
||||
close(done)
|
||||
}()
|
||||
|
||||
|
4
internal/processtest/testdata/issue2154_1.go
vendored
4
internal/processtest/testdata/issue2154_1.go
vendored
@ -84,14 +84,14 @@ func (g *Game) Draw(screen *ebiten.Image) {
|
||||
)
|
||||
|
||||
src0 := ebiten.NewImage(w, h)
|
||||
defer src0.Dispose()
|
||||
defer src0.Deallocate()
|
||||
src0.Fill(color.RGBA{0xff, 0xff, 0xff, 0xff})
|
||||
src0.Set(0, 0, color.RGBA{0, 0, 0, 0xff})
|
||||
src0.Set(0, 1, color.RGBA{0, 0, 0, 0xff})
|
||||
src0.Set(1, 0, color.RGBA{0, 0, 0, 0xff})
|
||||
|
||||
src1 := ebiten.NewImage(w, h)
|
||||
defer src1.Dispose()
|
||||
defer src1.Deallocate()
|
||||
src1.DrawImage(src0, nil)
|
||||
|
||||
screen.Fill(color.RGBA{0xff, 0xff, 0xff, 0xff})
|
||||
|
@ -170,7 +170,7 @@ func (c *context) newOffscreenImage(w, h int) *Image {
|
||||
func (c *context) drawGame(graphicsDriver graphicsdriver.Graphics, ui *UserInterface, forceDraw bool) error {
|
||||
if (c.offscreen.imageType == atlas.ImageTypeVolatile) != ui.IsScreenClearedEveryFrame() {
|
||||
w, h := c.offscreen.width, c.offscreen.height
|
||||
c.offscreen.MarkDisposed()
|
||||
c.offscreen.Deallocate()
|
||||
c.offscreen = c.newOffscreenImage(w, h)
|
||||
}
|
||||
|
||||
@ -230,21 +230,17 @@ func (c *context) layoutGame(outsideWidth, outsideHeight float64, deviceScaleFac
|
||||
ow := int(math.Ceil(c.offscreenWidth))
|
||||
oh := int(math.Ceil(c.offscreenHeight))
|
||||
|
||||
if c.screen != nil {
|
||||
if c.screen.width != sw || c.screen.height != sh {
|
||||
c.screen.MarkDisposed()
|
||||
c.screen = nil
|
||||
}
|
||||
if c.screen != nil && (c.screen.width != sw || c.screen.height != sh) {
|
||||
c.screen.Deallocate()
|
||||
c.screen = nil
|
||||
}
|
||||
if c.screen == nil {
|
||||
c.screen = c.game.NewScreenImage(sw, sh)
|
||||
}
|
||||
|
||||
if c.offscreen != nil {
|
||||
if c.offscreen.width != ow || c.offscreen.height != oh {
|
||||
c.offscreen.MarkDisposed()
|
||||
c.offscreen = nil
|
||||
}
|
||||
if c.offscreen != nil && (c.offscreen.width != ow || c.offscreen.height != oh) {
|
||||
c.offscreen.Deallocate()
|
||||
c.offscreen = nil
|
||||
}
|
||||
if c.offscreen == nil {
|
||||
c.offscreen = c.newOffscreenImage(ow, oh)
|
||||
|
@ -69,18 +69,15 @@ func (u *UserInterface) NewImage(width, height int, imageType atlas.ImageType) *
|
||||
}
|
||||
}
|
||||
|
||||
func (i *Image) MarkDisposed() {
|
||||
func (i *Image) Deallocate() {
|
||||
if i.mipmap == nil {
|
||||
return
|
||||
}
|
||||
if i.bigOffscreenBuffer != nil {
|
||||
i.bigOffscreenBuffer.markDisposed()
|
||||
i.bigOffscreenBuffer = nil
|
||||
i.bigOffscreenBuffer.deallocate()
|
||||
}
|
||||
i.mipmap.MarkDisposed()
|
||||
i.mipmap = nil
|
||||
i.mipmap.Deallocate()
|
||||
i.dotsBuffer = nil
|
||||
i.modifyCallback = nil
|
||||
}
|
||||
|
||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, evenOdd bool, canSkipMipmap bool, antialias bool) {
|
||||
@ -321,10 +318,9 @@ func (u *UserInterface) newBigOffscreenImage(orig *Image, imageType atlas.ImageT
|
||||
}
|
||||
}
|
||||
|
||||
func (i *bigOffscreenImage) markDisposed() {
|
||||
func (i *bigOffscreenImage) deallocate() {
|
||||
if i.image != nil {
|
||||
i.image.MarkDisposed()
|
||||
i.image = nil
|
||||
i.image.Deallocate()
|
||||
}
|
||||
i.dirty = false
|
||||
}
|
||||
|
@ -57,14 +57,19 @@ func (s *Shader) Dispose() {
|
||||
s.shader = nil
|
||||
}
|
||||
|
||||
// Deallocate deallocates the internal state of shader.
|
||||
// Deallocate deallocates the internal state of the shader.
|
||||
// Even after Deallocate is called, the shader is still available.
|
||||
// In this case, the shader's internal state is allocated again.
|
||||
//
|
||||
// Usually, you don't have to call Deallocate since the internal state is automatically released by GC.
|
||||
// However, if you are sure that the shader is no longer used but not sure how this shader object is referred,
|
||||
// you can call Deallocate to make sure that the internal state is deallocated.
|
||||
//
|
||||
// If the shader is disposed, Deallocate does nothing.
|
||||
func (s *Shader) Deallocate() {
|
||||
if s.shader == nil {
|
||||
return
|
||||
}
|
||||
s.shader.Deallocate()
|
||||
}
|
||||
|
||||
|
@ -649,13 +649,13 @@ func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {
|
||||
const w, h = 1, 1
|
||||
|
||||
dst := ebiten.NewImage(w, h)
|
||||
defer dst.Dispose()
|
||||
defer dst.Deallocate()
|
||||
|
||||
s, err := ebiten.NewShader([]byte(shader.Shader))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer s.Dispose()
|
||||
defer s.Deallocate()
|
||||
|
||||
op := &ebiten.DrawRectShaderOptions{}
|
||||
op.Uniforms = shader.Uniforms
|
||||
@ -1588,13 +1588,13 @@ func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {
|
||||
const w, h = 1, 1
|
||||
|
||||
dst := ebiten.NewImage(w, h)
|
||||
defer dst.Dispose()
|
||||
defer dst.Deallocate()
|
||||
|
||||
s, err := ebiten.NewShader([]byte(tc.Shader))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer s.Dispose()
|
||||
defer s.Deallocate()
|
||||
|
||||
op := &ebiten.DrawRectShaderOptions{}
|
||||
op.Uniforms = tc.Uniforms
|
||||
@ -1621,13 +1621,13 @@ func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {
|
||||
const w, h = 1, 1
|
||||
|
||||
dst := ebiten.NewImage(w, h)
|
||||
defer dst.Dispose()
|
||||
defer dst.Deallocate()
|
||||
|
||||
s, err := ebiten.NewShader([]byte(shader))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer s.Dispose()
|
||||
defer s.Deallocate()
|
||||
|
||||
op := &ebiten.DrawRectShaderOptions{}
|
||||
op.Uniforms = map[string]any{
|
||||
@ -1692,13 +1692,13 @@ func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {
|
||||
const w, h = 1, 1
|
||||
|
||||
dst := ebiten.NewImage(w, h)
|
||||
defer dst.Dispose()
|
||||
defer dst.Deallocate()
|
||||
|
||||
s, err := ebiten.NewShader([]byte(shader))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer s.Dispose()
|
||||
defer s.Deallocate()
|
||||
|
||||
op := &ebiten.DrawRectShaderOptions{}
|
||||
dst.DrawRectShader(w, h, s, op)
|
||||
@ -1763,12 +1763,12 @@ func TestShaderDifferentTextureSizes(t *testing.T) {
|
||||
src0 := ebiten.NewImageWithOptions(image.Rect(0, 0, 20, 4000), &ebiten.NewImageOptions{
|
||||
Unmanaged: true,
|
||||
}).SubImage(image.Rect(4, 1025, 6, 1028)).(*ebiten.Image)
|
||||
defer src0.Dispose()
|
||||
defer src0.Deallocate()
|
||||
|
||||
src1 := ebiten.NewImageWithOptions(image.Rect(0, 0, 4000, 20), &ebiten.NewImageOptions{
|
||||
Unmanaged: true,
|
||||
}).SubImage(image.Rect(2047, 7, 2049, 10)).(*ebiten.Image)
|
||||
defer src1.Dispose()
|
||||
defer src1.Deallocate()
|
||||
|
||||
src0.Fill(color.RGBA{0x10, 0x20, 0x30, 0xff})
|
||||
src1.Fill(color.RGBA{0x30, 0x20, 0x10, 0xff})
|
||||
@ -1787,10 +1787,10 @@ func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer shader.Dispose()
|
||||
defer shader.Deallocate()
|
||||
|
||||
dst := ebiten.NewImage(2, 3)
|
||||
defer dst.Dispose()
|
||||
defer dst.Deallocate()
|
||||
|
||||
op := &ebiten.DrawRectShaderOptions{}
|
||||
op.Images[0] = src0
|
||||
@ -2137,12 +2137,12 @@ func TestShaderDifferentSourceSizes(t *testing.T) {
|
||||
src0 := ebiten.NewImageWithOptions(image.Rect(0, 0, 20, 4000), &ebiten.NewImageOptions{
|
||||
Unmanaged: true,
|
||||
}).SubImage(image.Rect(4, 1025, 7, 1029)).(*ebiten.Image) // 3x4
|
||||
defer src0.Dispose()
|
||||
defer src0.Deallocate()
|
||||
|
||||
src1 := ebiten.NewImageWithOptions(image.Rect(0, 0, 4000, 20), &ebiten.NewImageOptions{
|
||||
Unmanaged: true,
|
||||
}).SubImage(image.Rect(2047, 7, 2049, 10)).(*ebiten.Image) // 2x3
|
||||
defer src1.Dispose()
|
||||
defer src1.Deallocate()
|
||||
|
||||
src0.Fill(color.RGBA{0x10, 0x20, 0x30, 0xff})
|
||||
src1.Fill(color.RGBA{0x30, 0x20, 0x10, 0xff})
|
||||
@ -2168,10 +2168,10 @@ func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer shader.Dispose()
|
||||
defer shader.Deallocate()
|
||||
|
||||
dst := ebiten.NewImage(3, 4)
|
||||
defer dst.Dispose()
|
||||
defer dst.Deallocate()
|
||||
|
||||
op := &ebiten.DrawTrianglesShaderOptions{}
|
||||
op.Images[0] = src0
|
||||
|
Loading…
Reference in New Issue
Block a user