Skip to content

Commit

Permalink
internal/restorable: optimize WritePixels
Browse files Browse the repository at this point in the history
This adds (*Image).makeStaleIfDependingOnWithRegion to reduce the
possibility of making an image stale.
  • Loading branch information
hajimehoshi committed Sep 8, 2024
1 parent af9bd6a commit 6a51e5b
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 3 deletions.
33 changes: 30 additions & 3 deletions internal/restorable/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,9 +277,7 @@ func (i *Image) WritePixels(pixels *graphics.ManagedBytes, region image.Rectangl
panic(fmt.Sprintf("restorable: out of range %v", region))
}

// TODO: Avoid making other images stale if possible. (#514)
// For this purpose, images should remember which part of that is used for DrawTriangles.
theImages.makeStaleIfDependingOn(i)
theImages.makeStaleIfDependingOnAtRegion(i, region)

if pixels != nil {
i.image.WritePixels(pixels, region)
Expand Down Expand Up @@ -343,6 +341,9 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertice
if len(vertices) == 0 {
return
}

// makeStaleIfDependingOnAtRegion is not available here.
// This might create cyclic dependency.
theImages.makeStaleIfDependingOn(i)

// TODO: Add tests to confirm this logic.
Expand Down Expand Up @@ -510,6 +511,17 @@ func (i *Image) makeStaleIfDependingOn(src *Image) {
}
}

// makeStaleIfDependingOnAtRegion makes the image stale if the image depends on src at srcRegion.
func (i *Image) makeStaleIfDependingOnAtRegion(src *Image, srcRegion image.Rectangle) {
if i.stale {
return
}
if i.dependsOnAtRegion(src, srcRegion) {
// There is no new region to make stale.
i.makeStale(image.Rectangle{})
}
}

// makeStaleIfDependingOnShader makes the image stale if the image depends on shader.
func (i *Image) makeStaleIfDependingOnShader(shader *Shader) {
if i.stale {
Expand Down Expand Up @@ -603,6 +615,21 @@ func (i *Image) dependsOn(src *Image) bool {
return false
}

// dependsOnAtRegion reports whether the image depends on src at srcRegion.
func (i *Image) dependsOnAtRegion(src *Image, srcRegion image.Rectangle) bool {
for _, c := range i.drawTrianglesHistory {
for i, img := range c.srcImages {
if img != src {
continue
}
if c.srcRegions[i].Overlaps(srcRegion) {
return true
}
}
}
return false
}

// dependsOnShader reports whether the image depends on shader.
func (i *Image) dependsOnShader(shader *Shader) bool {
for _, c := range i.drawTrianglesHistory {
Expand Down
13 changes: 13 additions & 0 deletions internal/restorable/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,19 @@ func (i *images) makeStaleIfDependingOn(src *Image) {
}
}

// makeStaleIfDependingOnAtRegion makes all the images stale that depend on src at srcRegion.
//
// When src is modified, all images depending on src can't be restored with src at srcRegion.
// makeStaleIfDependingOnAtRegion is called in such situation.
func (i *images) makeStaleIfDependingOnAtRegion(src *Image, srcRegion image.Rectangle) {
if src == nil {
panic("restorable: src must not be nil at makeStaleIfDependingOnAtRegion")
}
for img := range i.images {
img.makeStaleIfDependingOnAtRegion(src, srcRegion)
}
}

// makeStaleIfDependingOn makes all the images stale that depend on shader.
func (i *images) makeStaleIfDependingOnShader(shader *Shader) {
if shader == nil {
Expand Down

0 comments on commit 6a51e5b

Please sign in to comment.