internal/restorable: use sparate regions instead of a big unified region

This commit is contained in:
Hajime Hoshi 2023-02-24 21:49:33 +09:00
parent 09e0320309
commit aca42e4046
2 changed files with 59 additions and 43 deletions

View File

@ -64,11 +64,11 @@ func (p *Pixels) ReadPixels(pixels []byte, x, y, width, height, imageWidth, imag
p.pixelsRecords.readPixels(pixels, x, y, width, height, imageWidth, imageHeight) p.pixelsRecords.readPixels(pixels, x, y, width, height, imageWidth, imageHeight)
} }
func (p *Pixels) Region() image.Rectangle { func (p *Pixels) AppendRegion(regions []image.Rectangle) []image.Rectangle {
if p.pixelsRecords == nil { if p.pixelsRecords == nil {
return image.Rectangle{} return regions
} }
return p.pixelsRecords.region() return p.pixelsRecords.appendRegions(regions)
} }
// drawTrianglesHistoryItem is an item for history of draw-image commands. // drawTrianglesHistoryItem is an item for history of draw-image commands.
@ -119,9 +119,9 @@ type Image struct {
// stale indicates whether the image needs to be synced with GPU as soon as possible. // stale indicates whether the image needs to be synced with GPU as soon as possible.
stale bool stale bool
// staleRegion indicates the region to restore. // staleRegions indicates the regions to restore.
// staleRegion is valid only when stale is true. // staleRegions is valid only when stale is true.
staleRegion image.Rectangle staleRegions []image.Rectangle
imageType ImageType imageType ImageType
@ -208,7 +208,8 @@ func (i *Image) Extend(width, height int) *Image {
newImg.clearDrawTrianglesHistory() newImg.clearDrawTrianglesHistory()
newImg.basePixels = i.basePixels newImg.basePixels = i.basePixels
newImg.stale = i.stale newImg.stale = i.stale
newImg.staleRegion = i.staleRegion newImg.staleRegions = make([]image.Rectangle, len(i.staleRegions))
copy(newImg.staleRegions, i.staleRegions)
i.Dispose() i.Dispose()
@ -260,13 +261,11 @@ func (i *Image) BasePixelsForTesting() *Pixels {
func (i *Image) makeStale(rect image.Rectangle) { func (i *Image) makeStale(rect image.Rectangle) {
i.stale = true i.stale = true
r := i.staleRegion i.staleRegions = i.basePixels.AppendRegion(i.staleRegions)
r = r.Union(i.basePixels.Region()) i.staleRegions = i.appendRegionsForDrawTriangles(i.staleRegions)
for _, d := range i.drawTrianglesHistory { if !rect.Empty() {
r = r.Union(regionToRectangle(d.dstRegion)) i.staleRegions = append(i.staleRegions, rect)
} }
r = r.Union(rect)
i.staleRegion = r
i.basePixels = Pixels{} i.basePixels = Pixels{}
i.clearDrawTrianglesHistory() i.clearDrawTrianglesHistory()
@ -329,7 +328,7 @@ func (i *Image) WritePixels(pixels []byte, x, y, width, height int) {
} }
i.clearDrawTrianglesHistory() i.clearDrawTrianglesHistory()
i.stale = false i.stale = false
i.staleRegion = image.Rectangle{} i.staleRegions = i.staleRegions[:0]
return return
} }
@ -483,16 +482,19 @@ func (i *Image) makeStaleIfDependingOnShader(shader *Shader) {
// readPixelsFromGPU reads the pixels from GPU and resolves the image's 'stale' state. // readPixelsFromGPU reads the pixels from GPU and resolves the image's 'stale' state.
func (i *Image) readPixelsFromGPU(graphicsDriver graphicsdriver.Graphics) error { func (i *Image) readPixelsFromGPU(graphicsDriver graphicsdriver.Graphics) error {
var r image.Rectangle var rs []image.Rectangle
if i.stale { if i.stale {
i.basePixels = Pixels{} i.basePixels = Pixels{}
r = i.staleRegion rs = append(rs, i.staleRegions...)
} else { } else {
for _, d := range i.drawTrianglesHistory { rs = i.appendRegionsForDrawTriangles(rs)
r = r.Union(regionToRectangle(d.dstRegion))
}
} }
if !r.Empty() {
for _, r := range rs {
if r.Empty() {
continue
}
pix := make([]byte, 4*r.Dx()*r.Dy()) pix := make([]byte, 4*r.Dx()*r.Dy())
if err := i.image.ReadPixels(graphicsDriver, pix, r.Min.X, r.Min.Y, r.Dx(), r.Dy()); err != nil { if err := i.image.ReadPixels(graphicsDriver, pix, r.Min.X, r.Min.Y, r.Dx(), r.Dy()); err != nil {
return err return err
@ -501,7 +503,7 @@ func (i *Image) readPixelsFromGPU(graphicsDriver graphicsdriver.Graphics) error
} }
i.clearDrawTrianglesHistory() i.clearDrawTrianglesHistory()
i.stale = false i.stale = false
i.staleRegion = image.Rectangle{} i.staleRegions = i.staleRegions[:0]
return nil return nil
} }
@ -579,7 +581,7 @@ func (i *Image) restore(graphicsDriver graphicsdriver.Graphics) error {
i.basePixels = Pixels{} i.basePixels = Pixels{}
i.clearDrawTrianglesHistory() i.clearDrawTrianglesHistory()
i.stale = false i.stale = false
i.staleRegion = image.Rectangle{} i.staleRegions = i.staleRegions[:0]
return nil return nil
case ImageTypeVolatile: case ImageTypeVolatile:
i.image = graphicscommand.NewImage(w, h, false) i.image = graphicscommand.NewImage(w, h, false)
@ -617,21 +619,7 @@ func (i *Image) restore(graphicsDriver graphicsdriver.Graphics) error {
// In order to clear the draw-triangles history, read pixels from GPU. // In order to clear the draw-triangles history, read pixels from GPU.
if len(i.drawTrianglesHistory) > 0 { if len(i.drawTrianglesHistory) > 0 {
var rs []image.Rectangle var rs []image.Rectangle
for _, d := range i.drawTrianglesHistory { rs = i.appendRegionsForDrawTriangles(rs)
r := regionToRectangle(d.dstRegion)
if r.Empty() {
continue
}
for i, rr := range rs {
if rr.Empty() {
continue
}
if rr.In(r) {
rs[i] = image.Rectangle{}
}
}
rs = append(rs, r)
}
for _, r := range rs { for _, r := range rs {
if r.Empty() { if r.Empty() {
continue continue
@ -647,7 +635,7 @@ func (i *Image) restore(graphicsDriver graphicsdriver.Graphics) error {
i.image = gimg i.image = gimg
i.clearDrawTrianglesHistory() i.clearDrawTrianglesHistory()
i.stale = false i.stale = false
i.staleRegion = image.Rectangle{} i.staleRegions = i.staleRegions[:0]
return nil return nil
} }
@ -661,7 +649,7 @@ func (i *Image) Dispose() {
i.basePixels = Pixels{} i.basePixels = Pixels{}
i.clearDrawTrianglesHistory() i.clearDrawTrianglesHistory()
i.stale = false i.stale = false
i.staleRegion = image.Rectangle{} i.staleRegions = i.staleRegions[:0]
} }
// isInvalidated returns a boolean value indicating whether the image is invalidated. // isInvalidated returns a boolean value indicating whether the image is invalidated.
@ -688,6 +676,32 @@ func (i *Image) InternalSize() (int, int) {
return i.image.InternalSize() return i.image.InternalSize()
} }
func (i *Image) appendRegionsForDrawTriangles(regions []image.Rectangle) []image.Rectangle {
var rs []image.Rectangle
for _, d := range i.drawTrianglesHistory {
r := regionToRectangle(d.dstRegion)
if r.Empty() {
continue
}
for i, rr := range rs {
if rr.Empty() {
continue
}
if rr.In(r) {
rs[i] = image.Rectangle{}
}
}
rs = append(rs, r)
}
for _, r := range rs {
if r.Empty() {
continue
}
regions = append(regions, r)
}
return regions
}
func regionToRectangle(region graphicsdriver.Region) image.Rectangle { func regionToRectangle(region graphicsdriver.Region) image.Rectangle {
return image.Rect( return image.Rect(
int(math.Floor(float64(region.X))), int(math.Floor(float64(region.X))),

View File

@ -129,10 +129,12 @@ func (pr *pixelsRecords) apply(img *graphicscommand.Image) {
} }
} }
func (pr *pixelsRecords) region() image.Rectangle { func (pr *pixelsRecords) appendRegions(regions []image.Rectangle) []image.Rectangle {
var rect image.Rectangle
for _, r := range pr.records { for _, r := range pr.records {
rect = rect.Union(r.rect) if r.rect.Empty() {
continue
}
regions = append(regions, r.rect)
} }
return rect return regions
} }