graphics: Remove delayedImageTasks

This commit is contained in:
Hajime Hoshi 2016-06-12 00:32:35 +09:00
parent 32c2cb3ead
commit fabed66b4a
2 changed files with 64 additions and 144 deletions

View File

@ -30,7 +30,7 @@ type graphicsContext struct {
screen *Image screen *Image
defaultRenderTarget *Image defaultRenderTarget *Image
screenScale int screenScale int
imageTasksDone bool initialized bool
} }
func (c *graphicsContext) SetSize(screenWidth, screenHeight, screenScale int) error { func (c *graphicsContext) SetSize(screenWidth, screenHeight, screenScale int) error {
@ -55,16 +55,11 @@ func (c *graphicsContext) SetSize(screenWidth, screenHeight, screenScale int) er
} }
func (c *graphicsContext) Update() error { func (c *graphicsContext) Update() error {
if !c.imageTasksDone { if !c.initialized {
if err := graphics.Initialize(ui.GLContext()); err != nil { if err := graphics.Initialize(ui.GLContext()); err != nil {
return err return err
} }
// This execution is called here because we can say actual GL function calls c.initialized = true
// should be done here (especailly on mobiles).
if err := theDelayedImageTasks.exec(); err != nil {
return err
}
c.imageTasksDone = true
} }
if err := c.screen.Clear(); err != nil { if err := c.screen.Clear(); err != nil {
return err return err
@ -104,7 +99,7 @@ func (c *graphicsContext) flush() error {
func (c *graphicsContext) Resume() error { func (c *graphicsContext) Resume() error {
ui.GLContext().Resume() ui.GLContext().Resume()
if !c.imageTasksDone { if !c.initialized {
return nil return nil
} }
if err := graphics.Initialize(ui.GLContext()); err != nil { if err := graphics.Initialize(ui.GLContext()); err != nil {

195
image.go
View File

@ -33,38 +33,6 @@ var (
imageM sync.Mutex imageM sync.Mutex
) )
type delayedImageTasks struct {
tasks []func() error
m sync.Mutex
execCalled bool
}
var theDelayedImageTasks = &delayedImageTasks{
tasks: []func() error{},
}
func (t *delayedImageTasks) add(f func() error) bool {
t.m.Lock()
defer t.m.Unlock()
if t.execCalled {
return false
}
t.tasks = append(t.tasks, f)
return true
}
func (t *delayedImageTasks) exec() error {
t.m.Lock()
defer t.m.Unlock()
t.execCalled = true
for _, f := range t.tasks {
if err := f(); err != nil {
return err
}
}
return nil
}
type images struct { type images struct {
images map[*imageImpl]struct{} images map[*imageImpl]struct{}
m sync.Mutex m sync.Mutex
@ -206,19 +174,13 @@ type imageImpl struct {
} }
func (i *imageImpl) Fill(clr color.Color) error { func (i *imageImpl) Fill(clr color.Color) error {
f := func() error { imageM.Lock()
imageM.Lock() defer imageM.Unlock()
defer imageM.Unlock() if i.isDisposed() {
if i.isDisposed() { return errors.New("ebiten: image is already disposed")
return errors.New("ebiten: image is already disposed")
}
i.pixels = nil
return i.framebuffer.Fill(clr)
} }
if theDelayedImageTasks.add(f) { i.pixels = nil
return nil return i.framebuffer.Fill(clr)
}
return f()
} }
func isWholeNumber(x float64) bool { func isWholeNumber(x float64) bool {
@ -251,25 +213,19 @@ func (i *imageImpl) DrawImage(image *Image, options *DrawImageOptions) error {
if i == image.impl { if i == image.impl {
return errors.New("ebiten: Image.DrawImage: image should be different from the receiver") return errors.New("ebiten: Image.DrawImage: image should be different from the receiver")
} }
f := func() error { imageM.Lock()
imageM.Lock() defer imageM.Unlock()
defer imageM.Unlock() if i.isDisposed() {
if i.isDisposed() { return errors.New("ebiten: image is already disposed")
return errors.New("ebiten: image is already disposed")
}
i.pixels = nil
geom := &options.GeoM
colorm := &options.ColorM
mode := opengl.CompositeMode(options.CompositeMode)
if err := i.framebuffer.DrawTexture(image.impl.texture, vertices[:16*n], geom, colorm, mode); err != nil {
return err
}
return nil
} }
if theDelayedImageTasks.add(f) { i.pixels = nil
return nil geom := &options.GeoM
colorm := &options.ColorM
mode := opengl.CompositeMode(options.CompositeMode)
if err := i.framebuffer.DrawTexture(image.impl.texture, vertices[:16*n], geom, colorm, mode); err != nil {
return err
} }
return f() return nil
} }
func (i *imageImpl) At(x, y int) color.Color { func (i *imageImpl) At(x, y int) color.Color {
@ -321,27 +277,20 @@ func (i *imageImpl) restorePixels(context *opengl.Context) error {
} }
func (i *imageImpl) Dispose() error { func (i *imageImpl) Dispose() error {
f := func() error { imageM.Lock()
imageM.Lock() defer imageM.Unlock()
defer imageM.Unlock() if i.isDisposed() {
if i.isDisposed() { return errors.New("ebiten: image is already disposed")
return errors.New("ebiten: image is already disposed")
}
if err := graphics.Dispose(i.texture, i.framebuffer); err != nil {
return err
}
i.framebuffer = nil
i.texture = nil
i.disposed = true
i.pixels = nil
runtime.SetFinalizer(i, nil)
return nil
} }
if err := graphics.Dispose(i.texture, i.framebuffer); err != nil {
if theDelayedImageTasks.add(f) { return err
return nil
} }
return f() i.framebuffer = nil
i.texture = nil
i.disposed = true
i.pixels = nil
runtime.SetFinalizer(i, nil)
return nil
} }
func (i *imageImpl) isDisposed() bool { func (i *imageImpl) isDisposed() bool {
@ -352,20 +301,14 @@ func (i *imageImpl) ReplacePixels(p []uint8) error {
if l := 4 * i.width * i.height; len(p) != l { if l := 4 * i.width * i.height; len(p) != l {
return fmt.Errorf("ebiten: p's length must be %d", l) return fmt.Errorf("ebiten: p's length must be %d", l)
} }
f := func() error { imageM.Lock()
imageM.Lock() defer imageM.Unlock()
defer imageM.Unlock() // TODO: Copy p?
// TODO: Copy p? i.pixels = nil
i.pixels = nil if i.isDisposed() {
if i.isDisposed() { return errors.New("ebiten: image is already disposed")
return errors.New("ebiten: image is already disposed")
}
return i.framebuffer.ReplacePixels(i.texture, p)
} }
if theDelayedImageTasks.add(f) { return i.framebuffer.ReplacePixels(i.texture, p)
return nil
}
return f()
} }
// A DrawImageOptions represents options to render an image on an image. // A DrawImageOptions represents options to render an image on an image.
@ -394,25 +337,16 @@ func NewImage(width, height int, filter Filter) (*Image, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
f := func() error { imageM.Lock()
imageM.Lock() defer imageM.Unlock()
defer imageM.Unlock() texture, framebuffer, err := graphics.NewImage(width, height, glFilter(ui.GLContext(), filter))
texture, framebuffer, err := graphics.NewImage(width, height, glFilter(ui.GLContext(), filter)) if err != nil {
if err != nil { return nil, err
return err
}
image.framebuffer = framebuffer
image.texture = texture
runtime.SetFinalizer(image, (*imageImpl).Dispose)
if err := image.framebuffer.Fill(color.Transparent); err != nil {
return err
}
return nil
} }
if theDelayedImageTasks.add(f) { image.framebuffer = framebuffer
return eimg, nil image.texture = texture
} runtime.SetFinalizer(image, (*imageImpl).Dispose)
if err := f(); err != nil { if err := image.framebuffer.Fill(color.Transparent); err != nil {
return nil, err return nil, err
} }
return eimg, nil return eimg, nil
@ -436,33 +370,24 @@ func NewImageFromImage(source image.Image, filter Filter) (*Image, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
f := func() error { // Don't lock while manipulating an image.Image interface.
// Don't lock while manipulating an image.Image interface. rgbaImg, ok := source.(*image.RGBA)
rgbaImg, ok := source.(*image.RGBA) if !ok {
if !ok { origImg := source
origImg := source newImg := image.NewRGBA(origImg.Bounds())
newImg := image.NewRGBA(origImg.Bounds()) draw.Draw(newImg, newImg.Bounds(), origImg, origImg.Bounds().Min, draw.Src)
draw.Draw(newImg, newImg.Bounds(), origImg, origImg.Bounds().Min, draw.Src) rgbaImg = newImg
rgbaImg = newImg
}
imageM.Lock()
defer imageM.Unlock()
texture, framebuffer, err := graphics.NewImageFromImage(rgbaImg, glFilter(ui.GLContext(), filter))
if err != nil {
// TODO: texture should be removed here?
return err
}
img.framebuffer = framebuffer
img.texture = texture
runtime.SetFinalizer(img, (*imageImpl).Dispose)
return nil
} }
if theDelayedImageTasks.add(f) { imageM.Lock()
return eimg, nil defer imageM.Unlock()
} texture, framebuffer, err := graphics.NewImageFromImage(rgbaImg, glFilter(ui.GLContext(), filter))
if err := f(); err != nil { if err != nil {
// TODO: texture should be removed here?
return nil, err return nil, err
} }
img.framebuffer = framebuffer
img.texture = texture
runtime.SetFinalizer(img, (*imageImpl).Dispose)
return eimg, nil return eimg, nil
} }