internal/atlas: change when to count up usedAsDestinationCount

An image has a counter to count how many times an image is used.

Before this change, the counter was updated only when an image was moved
from a source backend to a destination backend. This seemed not enough,
and an image was likely moved to a source backend more often than
necessary (#2676).

However, there was also an issue that the counter was updated too
aggressively and the image was unlikely moved from a destination to
a source image (#2586).

In order to resolve this dilemma, let's adopt an intermediate way:
count up the counter at most once per frame.

Updates #2586
Updates #2676
This commit is contained in:
Hajime Hoshi 2023-08-06 13:27:28 +09:00
parent 3bc970e898
commit 1ae5e022b6

View File

@ -64,9 +64,15 @@ func flushDeferred() {
const baseCountToPutOnSourceBackend = 10
func putImagesOnSourceBackend(graphicsDriver graphicsdriver.Graphics) error {
// The counter usedAsDestinationCount is updated at most once per frame (#2676).
for i := range imagesUsedAsDestination {
i.usedAsDestinationCount++
delete(imagesUsedAsDestination, i)
}
for i := range imagesToPutOnSourceBackend {
i.usedAsSourceCount++
if i.usedAsSourceCount >= baseCountToPutOnSourceBackend*(1<<uint(min(i.destinationCount, 31))) {
if i.usedAsSourceCount >= baseCountToPutOnSourceBackend*(1<<uint(min(i.usedAsDestinationCount, 31))) {
if err := i.putOnSourceBackend(graphicsDriver); err != nil {
return err
}
@ -123,6 +129,8 @@ var (
imagesToPutOnSourceBackend = map[*Image]struct{}{}
imagesUsedAsDestination = map[*Image]struct{}{}
deferred []func()
// deferredM is a mutex for the slice operations. This must not be used for other usages.
@ -172,10 +180,11 @@ type Image struct {
// WritePixels doesn't affect this value since WritePixels can be done on images on an atlas.
usedAsSourceCount int
// destinationCount represents how many times an image switches its backend when the image is used
// as a rendering destination at DrawTriangles.
// destinationCount affects the calculation when to put the image onto a texture atlas again.
destinationCount int
// usedAsDestinationCount represents how many times an image is used as a rendering destination at DrawTriangles.
// usedAsDestinationCount affects the calculation when to put the image onto a texture atlas again.
//
// usedAsDestinationCount is never reset.
usedAsDestinationCount int
}
// moveTo moves its content to the given image dst.
@ -231,6 +240,8 @@ func (i *Image) ensureIsolatedFromSource(backends []*backend) {
return
}
imagesUsedAsDestination[i] = struct{}{}
// Check if i has the same backend as the given backends.
var needsIsolation bool
for _, b := range backends {
@ -270,10 +281,6 @@ func (i *Image) ensureIsolatedFromSource(backends []*backend) {
delete(theSourceBackendsForOneFrame, origBackend)
newI.moveTo(i)
// Count up only when the backend is switched. (#2586).
// This counting up must be done after moveTo.
i.destinationCount++
}
func (i *Image) putOnSourceBackend(graphicsDriver graphicsdriver.Graphics) error {