mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 03:08:54 +01:00
restorable: Merge Clear to ReplacePixels
This can avoid unnecessary stale images that requires loading pixels from GPU.
This commit is contained in:
parent
4900d74a4d
commit
fb641d88cd
@ -89,18 +89,10 @@ func newImageWithoutInit(width, height int, volatile bool) *Image {
|
||||
// The returned image is cleared.
|
||||
func NewImage(width, height int, volatile bool) *Image {
|
||||
i := newImageWithoutInit(width, height, volatile)
|
||||
i.Clear(0, 0, width, height)
|
||||
i.ReplacePixels(nil, 0, 0, width, height)
|
||||
return i
|
||||
}
|
||||
|
||||
func (i *Image) Clear(x, y, width, height int) {
|
||||
w, h := dummyImage.Size()
|
||||
geom := (*affine.GeoM)(nil).Scale(float64(width)/float64(w), float64(height)/float64(h))
|
||||
geom = geom.Translate(float64(x), float64(y))
|
||||
colorm := (*affine.ColorM)(nil).Scale(0, 0, 0, 0)
|
||||
i.DrawImage(dummyImage, 0, 0, w, h, geom, colorm, opengl.CompositeModeCopy, graphics.FilterNearest)
|
||||
}
|
||||
|
||||
// NewScreenFramebufferImage creates a special image that framebuffer is one for the screen.
|
||||
//
|
||||
// The returned image is cleared.
|
||||
@ -112,7 +104,7 @@ func NewScreenFramebufferImage(width, height int) *Image {
|
||||
}
|
||||
theImages.add(i)
|
||||
runtime.SetFinalizer(i, (*Image).Dispose)
|
||||
i.Clear(0, 0, width, height)
|
||||
i.ReplacePixels(nil, 0, 0, width, height)
|
||||
return i
|
||||
}
|
||||
|
||||
@ -139,6 +131,8 @@ func (i *Image) makeStale() {
|
||||
}
|
||||
|
||||
// ReplacePixels replaces the image pixels with the given pixels slice.
|
||||
//
|
||||
// If pixels is nil, ReplacePixels clears the specified reagion.
|
||||
func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) {
|
||||
w, h := i.image.Size()
|
||||
if width <= 0 || height <= 0 {
|
||||
@ -152,7 +146,16 @@ func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) {
|
||||
// For this purpuse, images should remember which part of that is used for DrawImage.
|
||||
theImages.makeStaleIfDependingOn(i)
|
||||
|
||||
i.image.ReplacePixels(pixels, x, y, width, height)
|
||||
if pixels != nil {
|
||||
i.image.ReplacePixels(pixels, x, y, width, height)
|
||||
} else {
|
||||
w, h := dummyImage.Size()
|
||||
geom := (*affine.GeoM)(nil).Scale(float64(width)/float64(w), float64(height)/float64(h))
|
||||
geom = geom.Translate(float64(x), float64(y))
|
||||
colorm := (*affine.ColorM)(nil).Scale(0, 0, 0, 0)
|
||||
vs := vertices(w, h, 0, 0, w, h, geom)
|
||||
i.image.DrawImage(dummyImage.image, vs, colorm, opengl.CompositeModeCopy, graphics.FilterNearest)
|
||||
}
|
||||
|
||||
if x == 0 && y == 0 && width == w && height == h {
|
||||
if i.basePixels == nil {
|
||||
@ -172,9 +175,17 @@ func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) {
|
||||
return
|
||||
}
|
||||
idx := 4 * (y*w + x)
|
||||
for j := 0; j < height; j++ {
|
||||
copy(i.basePixels[idx:idx+4*width], pixels[4*j*width:4*(j+1)*width])
|
||||
idx += 4 * w
|
||||
if pixels != nil {
|
||||
for j := 0; j < height; j++ {
|
||||
copy(i.basePixels[idx:idx+4*width], pixels[4*j*width:4*(j+1)*width])
|
||||
idx += 4 * w
|
||||
}
|
||||
} else {
|
||||
zeros := make([]byte, 4*width)
|
||||
for j := 0; j < height; j++ {
|
||||
copy(i.basePixels[idx:idx+4*width], zeros)
|
||||
idx += 4 * w
|
||||
}
|
||||
}
|
||||
i.stale = false
|
||||
}
|
||||
|
@ -569,4 +569,69 @@ func TestDoubleResolve(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestClear(t *testing.T) {
|
||||
pix := make([]uint8, 4*4*4)
|
||||
for i := range pix {
|
||||
pix[i] = 0xff
|
||||
}
|
||||
|
||||
img := NewImage(4, 4, false)
|
||||
img.ReplacePixels(pix, 0, 0, 4, 4)
|
||||
// This doesn't make the image stale. Its base pixels are available.
|
||||
img.ReplacePixels(nil, 1, 1, 2, 2)
|
||||
|
||||
cases := []struct {
|
||||
Index int
|
||||
Want color.RGBA
|
||||
}{
|
||||
{
|
||||
Index: 0,
|
||||
Want: color.RGBA{0xff, 0xff, 0xff, 0xff},
|
||||
},
|
||||
{
|
||||
Index: 3,
|
||||
Want: color.RGBA{0xff, 0xff, 0xff, 0xff},
|
||||
},
|
||||
{
|
||||
Index: 4,
|
||||
Want: color.RGBA{0xff, 0xff, 0xff, 0xff},
|
||||
},
|
||||
{
|
||||
Index: 5,
|
||||
Want: color.RGBA{0, 0, 0, 0},
|
||||
},
|
||||
{
|
||||
Index: 7,
|
||||
Want: color.RGBA{0xff, 0xff, 0xff, 0xff},
|
||||
},
|
||||
{
|
||||
Index: 8,
|
||||
Want: color.RGBA{0xff, 0xff, 0xff, 0xff},
|
||||
},
|
||||
{
|
||||
Index: 10,
|
||||
Want: color.RGBA{0, 0, 0, 0},
|
||||
},
|
||||
{
|
||||
Index: 11,
|
||||
Want: color.RGBA{0xff, 0xff, 0xff, 0xff},
|
||||
},
|
||||
{
|
||||
Index: 12,
|
||||
Want: color.RGBA{0xff, 0xff, 0xff, 0xff},
|
||||
},
|
||||
{
|
||||
Index: 15,
|
||||
Want: color.RGBA{0xff, 0xff, 0xff, 0xff},
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
got := byteSliceToColor(img.BasePixelsForTesting(), c.Index)
|
||||
want := c.Want
|
||||
if got != want {
|
||||
t.Errorf("base pixel [%d]: got %v, want %v", c.Index, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: How about volatile/screen images?
|
||||
|
@ -189,7 +189,8 @@ func (i *Image) dispose() {
|
||||
i.backend.page.Free(i.node)
|
||||
if !i.backend.page.IsEmpty() {
|
||||
// As this part can be reused, this should be cleared explicitly.
|
||||
i.backend.restorable.Clear(i.region())
|
||||
x0, y0, x1, y1 := i.region()
|
||||
i.backend.restorable.ReplacePixels(nil, x0, y0, x1, y1)
|
||||
return
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user