restorable: Refactoring

This commit is contained in:
Hajime Hoshi 2019-05-26 21:10:25 +09:00
parent 0f611b49ac
commit 3c0cd47b1f
5 changed files with 43 additions and 56 deletions

View File

@ -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()
}

View File

@ -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")
}

View File

@ -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}

View File

@ -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 {

View File

@ -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