From 3c0cd47b1f4b792277f14f3ea79c38a5518194bd Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sun, 26 May 2019 21:10:25 +0900 Subject: [PATCH] restorable: Refactoring --- internal/restorable/image.go | 16 ++++++---------- internal/restorable/images.go | 29 +++++++++++++++++++++++------ internal/restorable/images_test.go | 22 +++++++++++----------- internal/shareable/shareable.go | 16 ++-------------- uicontext.go | 16 +--------------- 5 files changed, 43 insertions(+), 56 deletions(-) diff --git a/internal/restorable/image.go b/internal/restorable/image.go index ee2ce2705..7b9e10057 100644 --- a/internal/restorable/image.go +++ b/internal/restorable/image.go @@ -301,7 +301,7 @@ func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) { } i.image.ReplacePixels(pixels, x, y, width, height) - if !NeedsRestoring() { + if !needsRestoring() { i.makeStale() return } @@ -362,7 +362,7 @@ func (i *Image) DrawTriangles(img *Image, vertices []float32, indices []uint16, } theImages.makeStaleIfDependingOn(i) - if img.stale || img.volatile || i.screen || !NeedsRestoring() || i.volatile { + if img.stale || img.volatile || i.screen || !needsRestoring() || i.volatile { i.makeStale() } else { i.appendDrawTrianglesHistory(img, vertices, indices, colorm, mode, filter, address) @@ -447,7 +447,7 @@ func (i *Image) readPixelsFromGPU() { // resolveStale resolves the image's 'stale' state. func (i *Image) resolveStale() { - if !NeedsRestoring() { + if !needsRestoring() { return } @@ -551,15 +551,11 @@ func (i *Image) Dispose() { i.stale = false } -// IsInvalidated returns a boolean value indicating whether the image is invalidated. +// isInvalidated returns a boolean value indicating whether the image is invalidated. // // If an image is invalidated, GL context is lost and all the images should be restored asap. -func (i *Image) IsInvalidated() (bool, error) { +func (i *Image) isInvalidated() bool { // FlushCommands is required because c.offscreen.impl might not have an actual texture. graphicscommand.FlushCommands() - if !NeedsRestoring() { - return false, nil - } - - return i.image.IsInvalidated(), nil + return i.image.IsInvalidated() } diff --git a/internal/restorable/images.go b/internal/restorable/images.go index 44f04f83a..09e191a20 100644 --- a/internal/restorable/images.go +++ b/internal/restorable/images.go @@ -23,8 +23,8 @@ import ( // forceRestoring reports whether restoring forcely happens or not. var forceRestoring = true -// NeedsRestoring reports whether restoring process works or not. -func NeedsRestoring() bool { +// needsRestoring reports whether restoring process works or not. +func needsRestoring() bool { if forceRestoring { return true } @@ -53,16 +53,33 @@ var theImages = &images{ // ResolveStaleImages is intended to be called at the end of a frame. func ResolveStaleImages() { graphicscommand.FlushCommands() - if !NeedsRestoring() { + if !needsRestoring() { return } theImages.resolveStaleImages() } -// Restore restores the images. +// RestoreIfNeeded restores the images. // // Restoring means to make all *graphicscommand.Image objects have their textures and framebuffers. -func Restore() error { +func RestoreIfNeeded() error { + if !needsRestoring() { + return nil + } + + if !forceRestoring { + r := false + // As isInvalidated() is expensive, call this only for one image. + // This assumes that if there is one image that is invalidated, all images are invalidated. + for img := range theImages.images { + r = img.isInvalidated() + break + } + if !r { + return nil + } + } + if err := graphicscommand.ResetGraphicsDriverState(); err != nil { return err } @@ -144,7 +161,7 @@ func (i *images) makeStaleIfDependingOnImpl(target *Image) { // // Restoring means to make all *graphicscommand.Image objects have their textures and framebuffers. func (i *images) restore() error { - if !NeedsRestoring() { + if !needsRestoring() { panic("restorable: restore cannot be called when restoring is disabled") } diff --git a/internal/restorable/images_test.go b/internal/restorable/images_test.go index d59a647a9..772b412cf 100644 --- a/internal/restorable/images_test.go +++ b/internal/restorable/images_test.go @@ -75,7 +75,7 @@ func TestRestore(t *testing.T) { clr0 := color.RGBA{0x00, 0x00, 0x00, 0xff} img0.Fill(clr0.R, clr0.G, clr0.B, clr0.A) ResolveStaleImages() - if err := Restore(); err != nil { + if err := RestoreIfNeeded(); err != nil { t.Fatal(err) } want := clr0 @@ -92,7 +92,7 @@ func TestRestoreWithoutDraw(t *testing.T) { // If there is no drawing command on img0, img0 is cleared when restored. ResolveStaleImages() - if err := Restore(); err != nil { + if err := RestoreIfNeeded(); err != nil { t.Fatal(err) } @@ -131,7 +131,7 @@ func TestRestoreChain(t *testing.T) { imgs[i+1].DrawTriangles(imgs[i], vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest, graphics.AddressClampToZero) } ResolveStaleImages() - if err := Restore(); err != nil { + if err := RestoreIfNeeded(); err != nil { t.Fatal(err) } want := clr @@ -175,7 +175,7 @@ func TestRestoreChain2(t *testing.T) { } ResolveStaleImages() - if err := Restore(); err != nil { + if err := RestoreIfNeeded(); err != nil { t.Fatal(err) } for i, img := range imgs { @@ -214,7 +214,7 @@ func TestRestoreOverrideSource(t *testing.T) { img0.Fill(clr1.R, clr1.G, clr1.B, clr1.A) img1.DrawTriangles(img0, quadVertices(img0, w, h, 0, 0), is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest, graphics.AddressClampToZero) ResolveStaleImages() - if err := Restore(); err != nil { + if err := RestoreIfNeeded(); err != nil { t.Fatal(err) } testCases := []struct { @@ -307,7 +307,7 @@ func TestRestoreComplexGraph(t *testing.T) { vs = quadVertices(img3, w, h, 2, 0) img7.DrawTriangles(img3, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest, graphics.AddressClampToZero) ResolveStaleImages() - if err := Restore(); err != nil { + if err := RestoreIfNeeded(); err != nil { t.Fatal(err) } testCases := []struct { @@ -398,7 +398,7 @@ func TestRestoreRecursive(t *testing.T) { img1.DrawTriangles(img0, quadVertices(img0, w, h, 1, 0), is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest, graphics.AddressClampToZero) img0.DrawTriangles(img1, quadVertices(img1, w, h, 1, 0), is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest, graphics.AddressClampToZero) ResolveStaleImages() - if err := Restore(); err != nil { + if err := RestoreIfNeeded(); err != nil { t.Fatal(err) } testCases := []struct { @@ -452,7 +452,7 @@ func TestReplacePixels(t *testing.T) { } } ResolveStaleImages() - if err := Restore(); err != nil { + if err := RestoreIfNeeded(); err != nil { t.Fatal(err) } for j := 7; j < 11; j++ { @@ -484,7 +484,7 @@ func TestDrawTrianglesAndReplacePixels(t *testing.T) { img1.ReplacePixels([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 0, 0, 2, 1) ResolveStaleImages() - if err := Restore(); err != nil { + if err := RestoreIfNeeded(); err != nil { t.Fatal(err) } r, g, b, a := img1.At(0, 0) @@ -517,7 +517,7 @@ func TestDispose(t *testing.T) { img1.Dispose() ResolveStaleImages() - if err := Restore(); err != nil { + if err := RestoreIfNeeded(); err != nil { t.Fatal(err) } r, g, b, a := img0.At(0, 0) @@ -625,7 +625,7 @@ func TestReplacePixelsOnly(t *testing.T) { } ResolveStaleImages() - if err := Restore(); err != nil { + if err := RestoreIfNeeded(); err != nil { t.Fatal(err) } want := color.RGBA{1, 2, 3, 4} diff --git a/internal/shareable/shareable.go b/internal/shareable/shareable.go index 5a9b01040..e951399bf 100644 --- a/internal/shareable/shareable.go +++ b/internal/shareable/shareable.go @@ -404,13 +404,6 @@ func (i *Image) IsVolatile() bool { return i.backend.restorable.IsVolatile() } -func (i *Image) IsInvalidated() (bool, error) { - backendsM.Lock() - defer backendsM.Unlock() - v, err := i.backend.restorable.IsInvalidated() - return v, err -} - func NewImage(width, height int) *Image { // Actual allocation is done lazily. return &Image{ @@ -508,15 +501,10 @@ func ResolveStaleImages() { restorable.ResolveStaleImages() } -func NeedsRestoring() bool { - // As NeedsRestoring is an immutable state, no need to lock here. - return restorable.NeedsRestoring() -} - -func Restore() error { +func RestoreIfNeeded() error { backendsM.Lock() defer backendsM.Unlock() - return restorable.Restore() + return restorable.RestoreIfNeeded() } func Images() []image.Image { diff --git a/uicontext.go b/uicontext.go index e5e37a943..3d03c2802 100644 --- a/uicontext.go +++ b/uicontext.go @@ -146,22 +146,8 @@ func (c *uiContext) Update(afterFrameUpdate func()) error { return nil } -func (c *uiContext) needsRestoring() (bool, error) { - return c.offscreen.mipmap.original().IsInvalidated() -} - func (c *uiContext) restoreIfNeeded() error { - if !shareable.NeedsRestoring() { - return nil - } - r, err := c.needsRestoring() - if err != nil { - return err - } - if !r { - return nil - } - if err := shareable.Restore(); err != nil { + if err := shareable.RestoreIfNeeded(); err != nil { return err } return nil