mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 13:07:26 +01:00
restorable: Bug fix: Image must be protected with locks (#567)
This commit is contained in:
parent
e2632e358e
commit
125e5c4f32
@ -23,6 +23,7 @@ import (
|
|||||||
"github.com/hajimehoshi/ebiten/internal/affine"
|
"github.com/hajimehoshi/ebiten/internal/affine"
|
||||||
"github.com/hajimehoshi/ebiten/internal/graphics"
|
"github.com/hajimehoshi/ebiten/internal/graphics"
|
||||||
"github.com/hajimehoshi/ebiten/internal/opengl"
|
"github.com/hajimehoshi/ebiten/internal/opengl"
|
||||||
|
"github.com/hajimehoshi/ebiten/internal/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// drawImageHistoryItem is an item for history of draw-image commands.
|
// drawImageHistoryItem is an item for history of draw-image commands.
|
||||||
@ -70,6 +71,8 @@ type Image struct {
|
|||||||
|
|
||||||
// screen indicates whether the image is used as an actual screen.
|
// screen indicates whether the image is used as an actual screen.
|
||||||
screen bool
|
screen bool
|
||||||
|
|
||||||
|
m sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewImage creates an empty image with the given size.
|
// NewImage creates an empty image with the given size.
|
||||||
@ -131,6 +134,9 @@ func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) {
|
|||||||
// For this purpuse, images should remember which part of that is used for DrawImage.
|
// For this purpuse, images should remember which part of that is used for DrawImage.
|
||||||
theImages.makeStaleIfDependingOn(i)
|
theImages.makeStaleIfDependingOn(i)
|
||||||
|
|
||||||
|
i.m.Lock()
|
||||||
|
defer i.m.Unlock()
|
||||||
|
|
||||||
i.image.ReplacePixels(pixels, x, y, width, height)
|
i.image.ReplacePixels(pixels, x, y, width, height)
|
||||||
|
|
||||||
if x == 0 && y == 0 && width == w && height == h {
|
if x == 0 && y == 0 && width == w && height == h {
|
||||||
@ -160,11 +166,16 @@ func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) {
|
|||||||
|
|
||||||
// DrawImage draws a given image img to the image.
|
// DrawImage draws a given image img to the image.
|
||||||
func (i *Image) DrawImage(img *Image, sx0, sy0, sx1, sy1 int, geom *affine.GeoM, colorm *affine.ColorM, mode opengl.CompositeMode, filter graphics.Filter) {
|
func (i *Image) DrawImage(img *Image, sx0, sy0, sx1, sy1 int, geom *affine.GeoM, colorm *affine.ColorM, mode opengl.CompositeMode, filter graphics.Filter) {
|
||||||
vs := img.vertices(sx0, sy0, sx1, sy1, geom)
|
w, h := img.Size()
|
||||||
|
vs := vertices(w, h, sx0, sy0, sx1, sy1, geom)
|
||||||
if vs == nil {
|
if vs == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
theImages.makeStaleIfDependingOn(i)
|
theImages.makeStaleIfDependingOn(i)
|
||||||
|
|
||||||
|
i.m.Lock()
|
||||||
|
defer i.m.Unlock()
|
||||||
|
|
||||||
if img.stale || img.volatile || i.screen || !IsRestoringEnabled() {
|
if img.stale || img.volatile || i.screen || !IsRestoringEnabled() {
|
||||||
i.makeStale()
|
i.makeStale()
|
||||||
} else {
|
} else {
|
||||||
@ -210,6 +221,10 @@ func (i *Image) At(x, y int) (color.RGBA, error) {
|
|||||||
if x < 0 || y < 0 || w <= x || h <= y {
|
if x < 0 || y < 0 || w <= x || h <= y {
|
||||||
return color.RGBA{}, nil
|
return color.RGBA{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i.m.Lock()
|
||||||
|
defer i.m.Unlock()
|
||||||
|
|
||||||
if err := graphics.FlushCommands(); err != nil {
|
if err := graphics.FlushCommands(); err != nil {
|
||||||
return color.RGBA{}, err
|
return color.RGBA{}, err
|
||||||
}
|
}
|
||||||
@ -225,6 +240,9 @@ func (i *Image) At(x, y int) (color.RGBA, error) {
|
|||||||
|
|
||||||
// makeStaleIfDependingOn makes the image stale if the image depends on target.
|
// makeStaleIfDependingOn makes the image stale if the image depends on target.
|
||||||
func (i *Image) makeStaleIfDependingOn(target *Image) {
|
func (i *Image) makeStaleIfDependingOn(target *Image) {
|
||||||
|
i.m.Lock()
|
||||||
|
defer i.m.Unlock()
|
||||||
|
|
||||||
if i.stale {
|
if i.stale {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -250,6 +268,10 @@ func (i *Image) resolveStale() error {
|
|||||||
if !IsRestoringEnabled() {
|
if !IsRestoringEnabled() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i.m.Lock()
|
||||||
|
defer i.m.Unlock()
|
||||||
|
|
||||||
if i.volatile {
|
if i.volatile {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -274,6 +296,9 @@ func (i *Image) dependsOn(target *Image) bool {
|
|||||||
|
|
||||||
// dependingImages returns all images that is depended by the image.
|
// dependingImages returns all images that is depended by the image.
|
||||||
func (i *Image) dependingImages() map[*Image]struct{} {
|
func (i *Image) dependingImages() map[*Image]struct{} {
|
||||||
|
i.m.Lock()
|
||||||
|
defer i.m.Unlock()
|
||||||
|
|
||||||
r := map[*Image]struct{}{}
|
r := map[*Image]struct{}{}
|
||||||
for _, c := range i.drawImageHistory {
|
for _, c := range i.drawImageHistory {
|
||||||
r[c.image] = struct{}{}
|
r[c.image] = struct{}{}
|
||||||
@ -283,6 +308,9 @@ func (i *Image) dependingImages() map[*Image]struct{} {
|
|||||||
|
|
||||||
// hasDependency returns a boolean value indicating whether the image depends on another image.
|
// hasDependency returns a boolean value indicating whether the image depends on another image.
|
||||||
func (i *Image) hasDependency() bool {
|
func (i *Image) hasDependency() bool {
|
||||||
|
i.m.Lock()
|
||||||
|
defer i.m.Unlock()
|
||||||
|
|
||||||
if i.stale {
|
if i.stale {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -291,6 +319,9 @@ func (i *Image) hasDependency() bool {
|
|||||||
|
|
||||||
// Restore restores *graphics.Image from the pixels using its state.
|
// Restore restores *graphics.Image from the pixels using its state.
|
||||||
func (i *Image) restore() error {
|
func (i *Image) restore() error {
|
||||||
|
i.m.Lock()
|
||||||
|
defer i.m.Unlock()
|
||||||
|
|
||||||
w, h := i.image.Size()
|
w, h := i.image.Size()
|
||||||
if i.screen {
|
if i.screen {
|
||||||
// The screen image should also be recreated because framebuffer might
|
// The screen image should also be recreated because framebuffer might
|
||||||
@ -348,6 +379,10 @@ func (i *Image) restore() error {
|
|||||||
// After disposing, calling the function of the image causes unexpected results.
|
// After disposing, calling the function of the image causes unexpected results.
|
||||||
func (i *Image) Dispose() {
|
func (i *Image) Dispose() {
|
||||||
theImages.remove(i)
|
theImages.remove(i)
|
||||||
|
|
||||||
|
i.m.Lock()
|
||||||
|
defer i.m.Unlock()
|
||||||
|
|
||||||
i.image.Dispose()
|
i.image.Dispose()
|
||||||
i.image = nil
|
i.image = nil
|
||||||
i.basePixels = nil
|
i.basePixels = nil
|
||||||
@ -364,9 +399,12 @@ func (i *Image) IsInvalidated() (bool, error) {
|
|||||||
if err := graphics.FlushCommands(); err != nil {
|
if err := graphics.FlushCommands(); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !IsRestoringEnabled() {
|
if !IsRestoringEnabled() {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i.m.Lock()
|
||||||
|
defer i.m.Unlock()
|
||||||
|
|
||||||
return i.image.IsInvalidated(), nil
|
return i.image.IsInvalidated(), nil
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ func (v *verticesBackend) get() []float32 {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) vertices(sx0, sy0, sx1, sy1 int, geo *affine.GeoM) []float32 {
|
func vertices(width, height int, sx0, sy0, sx1, sy1 int, geo *affine.GeoM) []float32 {
|
||||||
if sx0 >= sx1 || sy0 >= sy1 {
|
if sx0 >= sx1 || sy0 >= sy1 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -58,7 +58,6 @@ func (i *Image) vertices(sx0, sy0, sx1, sy1 int, geo *affine.GeoM) []float32 {
|
|||||||
|
|
||||||
// it really feels like we should be able to cache this computation
|
// it really feels like we should be able to cache this computation
|
||||||
// but it may not matter.
|
// but it may not matter.
|
||||||
width, height := i.Size()
|
|
||||||
w := 1
|
w := 1
|
||||||
h := 1
|
h := 1
|
||||||
for w < width {
|
for w < width {
|
||||||
|
Loading…
Reference in New Issue
Block a user