mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 04:57:26 +01:00
shareable: Use CopyPixels
CopyPixels is basically Pixels and ReplacePixels, but executed lazily while Pixels reads pixels from GPU immediately. Thanks to this, restorable.Image no longer need to keep pixel data if not needed.
This commit is contained in:
parent
b89602d900
commit
d3d56c076d
@ -316,6 +316,45 @@ func (c *replacePixelsCommand) CanMerge(dst, src *Image, color *affine.ColorM, m
|
||||
return false
|
||||
}
|
||||
|
||||
type copyPixelsCommand struct {
|
||||
dst *Image
|
||||
src *Image
|
||||
}
|
||||
|
||||
func (c *copyPixelsCommand) String() string {
|
||||
return fmt.Sprintf("copy-pixels: dst: %p <- src: %p", c.dst, c.src)
|
||||
}
|
||||
|
||||
func (c *copyPixelsCommand) Exec(indexOffset int) error {
|
||||
p, err := c.src.image.Pixels()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.dst.width < c.src.width || c.dst.height < c.src.height {
|
||||
return fmt.Errorf("graphicscommand: the destination size (%d, %d) must include the source size (%d, %d)", c.dst.width, c.dst.height, c.src.width, c.src.height)
|
||||
}
|
||||
c.dst.image.ReplacePixels(p, 0, 0, c.src.width, c.src.height)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *copyPixelsCommand) NumVertices() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c *copyPixelsCommand) NumIndices() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c *copyPixelsCommand) AddNumVertices(n int) {
|
||||
}
|
||||
|
||||
func (c *copyPixelsCommand) AddNumIndices(n int) {
|
||||
}
|
||||
|
||||
func (c *copyPixelsCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter, address graphics.Address) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type pixelsCommand struct {
|
||||
result []byte
|
||||
img *Image
|
||||
|
@ -131,6 +131,24 @@ func (i *Image) ReplacePixels(p []byte, x, y, width, height int) {
|
||||
i.lastCommand = lastCommandReplacePixels
|
||||
}
|
||||
|
||||
// CopyPixels is basically same as Pixels and ReplacePixels, but reading pixels from GPU is done lazily.
|
||||
func (i *Image) CopyPixels(src *Image) {
|
||||
if i.lastCommand == lastCommandDrawImage {
|
||||
if i.width != src.width || i.height != src.height {
|
||||
panic("graphicscommand: Copy for a part after DrawImage is forbidden")
|
||||
}
|
||||
}
|
||||
|
||||
c := ©PixelsCommand{
|
||||
dst: i,
|
||||
src: src,
|
||||
}
|
||||
theCommandQueue.Enqueue(c)
|
||||
|
||||
// The execution is basically same as replacing pixels.
|
||||
i.lastCommand = lastCommandReplacePixels
|
||||
}
|
||||
|
||||
func (i *Image) IsInvalidated() bool {
|
||||
// i.image can be nil before initializing.
|
||||
if i.image == nil {
|
||||
|
@ -168,6 +168,17 @@ func (i *Image) makeStale() {
|
||||
// the former image can be restored from the latest state of the latter image.
|
||||
}
|
||||
|
||||
func (i *Image) CopyPixels(src *Image) {
|
||||
// TODO: Avoid making other images stale if possible. (#514)
|
||||
// For this purpuse, images should remember which part of that is used for DrawImage.
|
||||
theImages.makeStaleIfDependingOn(i)
|
||||
|
||||
i.image.CopyPixels(src.image)
|
||||
|
||||
// As pixels should not be obtained here, making the image stale is inevitable.
|
||||
i.makeStale()
|
||||
}
|
||||
|
||||
// ReplacePixels replaces the image pixels with the given pixels slice.
|
||||
//
|
||||
// If pixels is nil, ReplacePixels clears the specified reagion.
|
||||
@ -189,13 +200,10 @@ func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) {
|
||||
}
|
||||
i.image.ReplacePixels(pixels, x, y, width, height)
|
||||
|
||||
// TODO: We wanted to skip copying pixels, but this can cause reading-pixels before the driver is initialized.
|
||||
// For example, Pixels() is called at shareable package when enlarging the shareable images.
|
||||
//
|
||||
// if !IsRestoringEnabled() {
|
||||
// i.makeStale()
|
||||
// return
|
||||
// }
|
||||
if !IsRestoringEnabled() {
|
||||
i.makeStale()
|
||||
return
|
||||
}
|
||||
|
||||
if x == 0 && y == 0 && width == w && height == h {
|
||||
if pixels != nil {
|
||||
|
@ -63,13 +63,9 @@ func (b *backend) TryAlloc(width, height int) (*packing.Node, bool) {
|
||||
s := b.page.Size()
|
||||
newImg := restorable.NewImage(s, s, false)
|
||||
oldImg := b.restorable
|
||||
w, h := oldImg.Size()
|
||||
// Do not use DrawImage here. ReplacePixels will be called on a part of newImg later, and it looked like
|
||||
// ReplacePixels on a part of image deletes other region that are rendered by DrawImage (#593, #758).
|
||||
//
|
||||
// Pixels() returns immediately as long as only oldImg.ReplacePixels is called.
|
||||
pix := oldImg.Pixels()
|
||||
newImg.ReplacePixels(pix, 0, 0, w, h)
|
||||
newImg.CopyPixels(oldImg)
|
||||
oldImg.Dispose()
|
||||
b.restorable = newImg
|
||||
|
||||
|
@ -293,3 +293,5 @@ func TestReplacePixelsAfterDrawImage(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Add tests to extend shareable image out of the main loop
|
||||
|
Loading…
Reference in New Issue
Block a user