mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 04:57:26 +01:00
shareable: Rename notUpdatedCount -> usedAsSourceCount and modify implementation
Before this change, the image automatically becomes on a shareable texture again when the image is not modified for a while. This was problematic when an offscreen is not updated for a while, but used as a render target again, as an independent image for the image is created every time when the image is used as a render target. After this change, the count is updated only when the image is used as a rendering source. Closes #1465
This commit is contained in:
parent
2432530b51
commit
0c578f1670
@ -85,8 +85,8 @@ const CountForStartSyncing = MaxCountForShare / 2
|
||||
|
||||
func makeImagesShared() error {
|
||||
for i := range imagesToMakeShared {
|
||||
i.nonUpdatedCount++
|
||||
if i.nonUpdatedCount >= CountForStartSyncing && i.syncing == nil {
|
||||
i.usedAsSourceCount++
|
||||
if i.usedAsSourceCount >= CountForStartSyncing && i.syncing == nil {
|
||||
// Sync the pixel data on CPU and GPU sides explicitly in order not to block this process.
|
||||
ch, err := i.backend.restorable.Sync()
|
||||
if err != nil {
|
||||
@ -94,7 +94,7 @@ func makeImagesShared() error {
|
||||
}
|
||||
i.syncing = ch
|
||||
}
|
||||
if i.nonUpdatedCount >= MaxCountForShare {
|
||||
if i.usedAsSourceCount >= MaxCountForShare {
|
||||
// TODO: Instead of waiting for the channel, use select-case and continue the loop if this
|
||||
// channel is blocking. However, this might make the tests difficult.
|
||||
<-i.syncing
|
||||
@ -102,11 +102,14 @@ func makeImagesShared() error {
|
||||
if err := i.makeShared(); err != nil {
|
||||
return err
|
||||
}
|
||||
i.nonUpdatedCount = 0
|
||||
i.usedAsSourceCount = 0
|
||||
delete(imagesToMakeShared, i)
|
||||
i.syncing = nil
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the images. The images will be registered again when it is used as a rendering source.
|
||||
imagesToMakeShared = map[*Image]struct{}{}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -188,15 +191,16 @@ type Image struct {
|
||||
|
||||
node *packing.Node
|
||||
|
||||
// nonUpdatedCount represents how long the image is kept not modified with DrawTriangles.
|
||||
// usedAsSourceCount represents how long the image is used as a rendering source and kept not modified with
|
||||
// DrawTriangles.
|
||||
// In the current implementation, if an image is being modified by DrawTriangles, the image is separated from
|
||||
// a shared (restorable) image by ensureNotShared.
|
||||
//
|
||||
// nonUpdatedCount is increased every frame if the image is not modified, or set to 0 if the image is
|
||||
// usedAsSourceCount is increased if the image is used as a rendering source, or set to 0 if the image is
|
||||
// modified.
|
||||
//
|
||||
// ReplacePixels doesn't affect this value since ReplacePixels can be done on shared images.
|
||||
nonUpdatedCount int
|
||||
usedAsSourceCount int
|
||||
|
||||
syncing <-chan struct{}
|
||||
}
|
||||
@ -214,14 +218,14 @@ func (i *Image) isShared() bool {
|
||||
return i.node != nil
|
||||
}
|
||||
|
||||
func (i *Image) resetNonUpdatedCount() {
|
||||
i.nonUpdatedCount = 0
|
||||
func (i *Image) resetUsedAsSourceCount() {
|
||||
i.usedAsSourceCount = 0
|
||||
delete(imagesToMakeShared, i)
|
||||
i.syncing = nil
|
||||
}
|
||||
|
||||
func (i *Image) ensureNotShared() {
|
||||
i.resetNonUpdatedCount()
|
||||
i.resetUsedAsSourceCount()
|
||||
|
||||
if i.backend == nil {
|
||||
i.allocate(false)
|
||||
@ -297,7 +301,7 @@ func (i *Image) makeShared() error {
|
||||
}
|
||||
newI.replacePixels(pixels)
|
||||
newI.moveTo(i)
|
||||
i.nonUpdatedCount = 0
|
||||
i.usedAsSourceCount = 0
|
||||
i.syncing = nil
|
||||
return nil
|
||||
}
|
||||
@ -443,7 +447,7 @@ func (i *Image) replacePixels(pix []byte) {
|
||||
panic("shareable: the image must not be disposed at replacePixels")
|
||||
}
|
||||
|
||||
i.resetNonUpdatedCount()
|
||||
i.resetUsedAsSourceCount()
|
||||
|
||||
if i.backend == nil {
|
||||
if pix == nil {
|
||||
@ -535,7 +539,7 @@ func (i *Image) dispose(markDisposed bool) {
|
||||
}
|
||||
}()
|
||||
|
||||
i.resetNonUpdatedCount()
|
||||
i.resetUsedAsSourceCount()
|
||||
|
||||
if i.disposed {
|
||||
return
|
||||
|
@ -584,4 +584,61 @@ func TestDisposedAndReshared(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Issue #1456
|
||||
func TestImageIsNotResharedWithoutUsingAsSource(t *testing.T) {
|
||||
const size = 16
|
||||
|
||||
src := NewImage(size, size)
|
||||
defer src.MarkDisposed()
|
||||
src2 := NewImage(size, size)
|
||||
defer src2.MarkDisposed()
|
||||
dst := NewImage(size, size)
|
||||
defer dst.MarkDisposed()
|
||||
|
||||
// Use src as a render target so that src is not on the shared image.
|
||||
vs := quadVertices(size, size, 0, 0, 1)
|
||||
is := graphics.QuadIndices()
|
||||
dr := driver.Region{
|
||||
X: 0,
|
||||
Y: 0,
|
||||
Width: size,
|
||||
Height: size,
|
||||
}
|
||||
|
||||
// Use src2 as a rendering target, and make src2 an independent image.
|
||||
src2.DrawTriangles([graphics.ShaderImageNum]*Image{src}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil)
|
||||
if got, want := src2.IsSharedForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
|
||||
// Update the count without using src2 as a rendering source.
|
||||
// This should not affect whether src2 is on a shareable image or not.
|
||||
for i := 0; i < MaxCountForShare; i++ {
|
||||
if err := MakeImagesSharedForTesting(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got, want := src2.IsSharedForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// Update the count with using src2 as a rendering source.
|
||||
for i := 0; i < MaxCountForShare; i++ {
|
||||
if err := MakeImagesSharedForTesting(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src2}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil)
|
||||
if got, want := src2.IsSharedForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
if err := MakeImagesSharedForTesting(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got, want := src2.IsSharedForTesting(), true; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Add tests to extend shareable image out of the main loop
|
||||
|
Loading…
Reference in New Issue
Block a user