mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 10:48:53 +01:00
Rename internal/shareable -> internal/atlas
Also the terms are renamed: * shared -> on an atlas * not shared -> isolated Closes #1529
This commit is contained in:
parent
d2be9beb2d
commit
ec677a258f
@ -23,7 +23,7 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shareable"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/atlas"
|
||||
)
|
||||
|
||||
// availableFilename returns a filename that is valid as a new file or directory.
|
||||
@ -73,7 +73,7 @@ func dumpInternalImages() error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := shareable.DumpImages(dir); err != nil {
|
||||
if err := atlas.DumpImages(dir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -12,14 +12,14 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package shareable
|
||||
package atlas
|
||||
|
||||
const (
|
||||
BaseCountForShare = baseCountForShare
|
||||
BaseCountToPutOnAtlas = baseCountToPutOnAtlas
|
||||
)
|
||||
|
||||
func MakeImagesSharedForTesting() error {
|
||||
return makeImagesShared()
|
||||
func PutImagesOnAtlasForTesting() error {
|
||||
return putImagesOnAtlas()
|
||||
}
|
||||
|
||||
var (
|
||||
@ -45,16 +45,16 @@ func ResetBackendsForTesting() {
|
||||
theBackends = nil
|
||||
}
|
||||
|
||||
func (i *Image) IsSharedForTesting() bool {
|
||||
func (i *Image) IsOnAtlasForTesting() bool {
|
||||
backendsM.Lock()
|
||||
defer backendsM.Unlock()
|
||||
return i.isShared()
|
||||
return i.isOnAtlas()
|
||||
}
|
||||
|
||||
func (i *Image) EnsureNotSharedForTesting() {
|
||||
func (i *Image) EnsureIsolatedForTesting() {
|
||||
backendsM.Lock()
|
||||
defer backendsM.Unlock()
|
||||
i.ensureNotShared()
|
||||
i.ensureIsolated()
|
||||
}
|
||||
|
||||
func ResolveDeferredForTesting() {
|
@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package shareable
|
||||
package atlas
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -51,7 +51,7 @@ func init() {
|
||||
defer backendsM.Unlock()
|
||||
|
||||
resolveDeferred()
|
||||
return makeImagesShared()
|
||||
return putImagesOnAtlas()
|
||||
})
|
||||
}
|
||||
|
||||
@ -66,9 +66,9 @@ func resolveDeferred() {
|
||||
}
|
||||
}
|
||||
|
||||
// baseCountForShare represents the base time duration when the image can become shared.
|
||||
// baseCountToPutOnAtlas represents the base time duration when the image can be put onto an atlas.
|
||||
// Actual time duration is increased in an exponential way for each usages as a rendering target.
|
||||
const baseCountForShare = 10
|
||||
const baseCountToPutOnAtlas = 10
|
||||
|
||||
func min(a, b uint) uint {
|
||||
if a < b {
|
||||
@ -77,33 +77,35 @@ func min(a, b uint) uint {
|
||||
return b
|
||||
}
|
||||
|
||||
func makeImagesShared() error {
|
||||
for i := range imagesToMakeShared {
|
||||
func putImagesOnAtlas() error {
|
||||
for i := range imagesToPutOnAtlas {
|
||||
i.usedAsSourceCount++
|
||||
if i.usedAsSourceCount >= baseCountForShare*(1<<min(uint(i.notSharedCount), 31)) {
|
||||
if err := i.makeShared(); err != nil {
|
||||
if i.usedAsSourceCount >= baseCountToPutOnAtlas*(1<<min(uint(i.isolatedCount), 31)) {
|
||||
if err := i.putOnAtlas(); err != nil {
|
||||
return err
|
||||
}
|
||||
i.usedAsSourceCount = 0
|
||||
delete(imagesToMakeShared, i)
|
||||
delete(imagesToPutOnAtlas, i)
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the images. The images will be registered again when it is used as a rendering source.
|
||||
for k := range imagesToMakeShared {
|
||||
delete(imagesToMakeShared, k)
|
||||
for k := range imagesToPutOnAtlas {
|
||||
delete(imagesToPutOnAtlas, k)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type backend struct {
|
||||
// restorable is an atlas on which there might be multiple images.
|
||||
restorable *restorable.Image
|
||||
|
||||
// If page is nil, the backend is not shared.
|
||||
// page is an atlas map. Each part is called a node.
|
||||
// If page is nil, the backend's image is isolated and not on an atlas.
|
||||
page *packing.Page
|
||||
}
|
||||
|
||||
func (b *backend) TryAlloc(width, height int) (*packing.Node, bool) {
|
||||
func (b *backend) tryAlloc(width, height int) (*packing.Node, bool) {
|
||||
// If the region is allocated without any extension, that's fine.
|
||||
if n := b.page.Alloc(width, height); n != nil {
|
||||
return n, true
|
||||
@ -129,7 +131,7 @@ func (b *backend) TryAlloc(width, height int) (*packing.Node, bool) {
|
||||
b.restorable = b.restorable.Extend(s, s)
|
||||
|
||||
if n == nil {
|
||||
panic("shareable: Alloc result must not be nil at TryAlloc")
|
||||
panic("atlas: Alloc result must not be nil at TryAlloc")
|
||||
}
|
||||
return n, true
|
||||
}
|
||||
@ -140,10 +142,10 @@ var (
|
||||
|
||||
initOnce sync.Once
|
||||
|
||||
// theBackends is a set of actually shared images.
|
||||
// theBackends is a set of atlases.
|
||||
theBackends = []*backend{}
|
||||
|
||||
imagesToMakeShared = map[*Image]struct{}{}
|
||||
imagesToPutOnAtlas = map[*Image]struct{}{}
|
||||
|
||||
deferred []func()
|
||||
|
||||
@ -163,6 +165,7 @@ func init() {
|
||||
backendsM.Lock()
|
||||
}
|
||||
|
||||
// Image is a renctangle pixel set that might be on an atlas.
|
||||
type Image struct {
|
||||
width int
|
||||
height int
|
||||
@ -177,17 +180,17 @@ type Image struct {
|
||||
// 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.
|
||||
// a restorable image on an atlas by ensureIsolated.
|
||||
//
|
||||
// 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.
|
||||
// ReplacePixels doesn't affect this value since ReplacePixels can be done on images on an atlas.
|
||||
usedAsSourceCount int
|
||||
|
||||
// notSharedCount represents how many times the image on a texture atlas is changed into an isolated image.
|
||||
// notSharedCount affects the calculation when to make the image onto a texture atlas again.
|
||||
notSharedCount int
|
||||
// isolatedCount represents how many times the image on a texture atlas is changed into an isolated image.
|
||||
// isolatedCount affects the calculation when to put the image onto a texture atlas again.
|
||||
isolatedCount int
|
||||
}
|
||||
|
||||
func (i *Image) moveTo(dst *Image) {
|
||||
@ -199,16 +202,16 @@ func (i *Image) moveTo(dst *Image) {
|
||||
runtime.SetFinalizer(i, nil)
|
||||
}
|
||||
|
||||
func (i *Image) isShared() bool {
|
||||
func (i *Image) isOnAtlas() bool {
|
||||
return i.node != nil
|
||||
}
|
||||
|
||||
func (i *Image) resetUsedAsSourceCount() {
|
||||
i.usedAsSourceCount = 0
|
||||
delete(imagesToMakeShared, i)
|
||||
delete(imagesToPutOnAtlas, i)
|
||||
}
|
||||
|
||||
func (i *Image) ensureNotShared() {
|
||||
func (i *Image) ensureIsolated() {
|
||||
i.resetUsedAsSourceCount()
|
||||
|
||||
if i.backend == nil {
|
||||
@ -216,7 +219,7 @@ func (i *Image) ensureNotShared() {
|
||||
return
|
||||
}
|
||||
|
||||
if !i.isShared() {
|
||||
if !i.isOnAtlas() {
|
||||
return
|
||||
}
|
||||
|
||||
@ -253,21 +256,21 @@ func (i *Image) ensureNotShared() {
|
||||
restorable: newImg,
|
||||
}
|
||||
|
||||
i.notSharedCount++
|
||||
i.isolatedCount++
|
||||
}
|
||||
|
||||
func (i *Image) makeShared() error {
|
||||
func (i *Image) putOnAtlas() error {
|
||||
if i.backend == nil {
|
||||
i.allocate(true)
|
||||
return nil
|
||||
}
|
||||
|
||||
if i.isShared() {
|
||||
if i.isOnAtlas() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !i.shareable() {
|
||||
panic("shareable: makeShared cannot be called on a non-shareable image")
|
||||
if !i.canBePutOnAtlas() {
|
||||
panic("atlas: putOnAtlas cannot be called on a image that cannot be on an atlas")
|
||||
}
|
||||
|
||||
newI := NewImage(i.width, i.height)
|
||||
@ -275,7 +278,7 @@ func (i *Image) makeShared() error {
|
||||
|
||||
if restorable.NeedsRestoring() {
|
||||
// If the underlying graphics driver requires restoring from the context lost, the pixel data is
|
||||
// needed. A shared image must have its complete pixel data in this case.
|
||||
// needed. A image on an atlas must have its complete pixel data in this case.
|
||||
pixels := make([]byte, 4*i.width*i.height)
|
||||
for y := 0; y < i.height; y++ {
|
||||
for x := 0; x < i.width; x++ {
|
||||
@ -312,9 +315,9 @@ func (i *Image) makeShared() error {
|
||||
|
||||
func (i *Image) regionWithPadding() (x, y, width, height int) {
|
||||
if i.backend == nil {
|
||||
panic("shareable: backend must not be nil: not allocated yet?")
|
||||
panic("atlas: backend must not be nil: not allocated yet?")
|
||||
}
|
||||
if !i.isShared() {
|
||||
if !i.isOnAtlas() {
|
||||
return 0, 0, i.width + 2*paddingSize, i.height + 2*paddingSize
|
||||
}
|
||||
return i.node.Region()
|
||||
@ -325,16 +328,16 @@ func (i *Image) processSrc(src *Image) {
|
||||
return
|
||||
}
|
||||
if src.disposed {
|
||||
panic("shareable: the drawing source image must not be disposed (DrawTriangles)")
|
||||
panic("atlas: the drawing source image must not be disposed (DrawTriangles)")
|
||||
}
|
||||
if src.backend == nil {
|
||||
src.allocate(true)
|
||||
}
|
||||
|
||||
// Compare i and source images after ensuring i is not shared, or
|
||||
// i and a source image might share the same texture even though i != src.
|
||||
// Compare i and source images after ensuring i is not on an atlas, or
|
||||
// i and a source image might share the same atlas even though i != src.
|
||||
if i.backend.restorable == src.backend.restorable {
|
||||
panic("shareable: Image.DrawTriangles: source must be different from the receiver")
|
||||
panic("atlas: Image.DrawTriangles: source must be different from the receiver")
|
||||
}
|
||||
}
|
||||
|
||||
@ -356,16 +359,16 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, vertices []f
|
||||
i.drawTriangles(srcs, vertices, indices, colorm, mode, filter, address, dstRegion, srcRegion, subimageOffsets, shader, uniforms, false)
|
||||
}
|
||||
|
||||
func (i *Image) drawTriangles(srcs [graphics.ShaderImageNum]*Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, subimageOffsets [graphics.ShaderImageNum - 1][2]float32, shader *Shader, uniforms []interface{}, keepShared bool) {
|
||||
func (i *Image) drawTriangles(srcs [graphics.ShaderImageNum]*Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, subimageOffsets [graphics.ShaderImageNum - 1][2]float32, shader *Shader, uniforms []interface{}, keepOnAtlas bool) {
|
||||
if i.disposed {
|
||||
panic("shareable: the drawing target image must not be disposed (DrawTriangles)")
|
||||
panic("atlas: the drawing target image must not be disposed (DrawTriangles)")
|
||||
}
|
||||
if keepShared {
|
||||
if keepOnAtlas {
|
||||
if i.backend == nil {
|
||||
i.allocate(true)
|
||||
}
|
||||
} else {
|
||||
i.ensureNotShared()
|
||||
i.ensureIsolated()
|
||||
}
|
||||
|
||||
for _, src := range srcs {
|
||||
@ -441,9 +444,9 @@ func (i *Image) drawTriangles(srcs [graphics.ShaderImageNum]*Image, vertices []f
|
||||
if src == nil {
|
||||
continue
|
||||
}
|
||||
if !src.isShared() && src.shareable() {
|
||||
if !src.isOnAtlas() && src.canBePutOnAtlas() {
|
||||
// src might already registered, but assiging it again is not harmful.
|
||||
imagesToMakeShared[src] = struct{}{}
|
||||
imagesToPutOnAtlas[src] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -456,7 +459,7 @@ func (i *Image) ReplacePixels(pix []byte) {
|
||||
|
||||
func (i *Image) replacePixels(pix []byte) {
|
||||
if i.disposed {
|
||||
panic("shareable: the image must not be disposed at replacePixels")
|
||||
panic("atlas: the image must not be disposed at replacePixels")
|
||||
}
|
||||
|
||||
i.resetUsedAsSourceCount()
|
||||
@ -476,7 +479,7 @@ func (i *Image) replacePixels(pix []byte) {
|
||||
|
||||
ow, oh := w-2*paddingSize, h-2*paddingSize
|
||||
if l := 4 * ow * oh; len(pix) != l {
|
||||
panic(fmt.Sprintf("shareable: len(p) must be %d but %d", l, len(pix)))
|
||||
panic(fmt.Sprintf("atlas: len(p) must be %d but %d", l, len(pix)))
|
||||
}
|
||||
|
||||
// Add a padding around the image.
|
||||
@ -562,7 +565,7 @@ func (i *Image) dispose(markDisposed bool) {
|
||||
return
|
||||
}
|
||||
|
||||
if !i.isShared() {
|
||||
if !i.isOnAtlas() {
|
||||
i.backend.restorable.Dispose()
|
||||
return
|
||||
}
|
||||
@ -583,7 +586,7 @@ func (i *Image) dispose(markDisposed bool) {
|
||||
}
|
||||
}
|
||||
if index == -1 {
|
||||
panic("shareable: backend not found at an image being disposed")
|
||||
panic("atlas: backend not found at an image being disposed")
|
||||
}
|
||||
theBackends = append(theBackends[:index], theBackends[index+1:]...)
|
||||
}
|
||||
@ -602,14 +605,14 @@ func (i *Image) SetVolatile(volatile bool) {
|
||||
return
|
||||
}
|
||||
if i.volatile {
|
||||
i.ensureNotShared()
|
||||
i.ensureIsolated()
|
||||
}
|
||||
i.backend.restorable.SetVolatile(i.volatile)
|
||||
}
|
||||
|
||||
func (i *Image) shareable() bool {
|
||||
func (i *Image) canBePutOnAtlas() bool {
|
||||
if minSize == 0 || maxSize == 0 {
|
||||
panic("shareable: minSize or maxSize must be initialized")
|
||||
panic("atlas: minSize or maxSize must be initialized")
|
||||
}
|
||||
if i.volatile {
|
||||
return false
|
||||
@ -620,9 +623,9 @@ func (i *Image) shareable() bool {
|
||||
return i.width+2*paddingSize <= maxSize && i.height+2*paddingSize <= maxSize
|
||||
}
|
||||
|
||||
func (i *Image) allocate(shareable bool) {
|
||||
func (i *Image) allocate(putOnAtlas bool) {
|
||||
if i.backend != nil {
|
||||
panic("shareable: the image is already allocated")
|
||||
panic("atlas: the image is already allocated")
|
||||
}
|
||||
|
||||
runtime.SetFinalizer(i, (*Image).MarkDisposed)
|
||||
@ -635,7 +638,7 @@ func (i *Image) allocate(shareable bool) {
|
||||
return
|
||||
}
|
||||
|
||||
if !shareable || !i.shareable() {
|
||||
if !putOnAtlas || !i.canBePutOnAtlas() {
|
||||
i.backend = &backend{
|
||||
restorable: restorable.NewImage(i.width+2*paddingSize, i.height+2*paddingSize),
|
||||
}
|
||||
@ -644,7 +647,7 @@ func (i *Image) allocate(shareable bool) {
|
||||
}
|
||||
|
||||
for _, b := range theBackends {
|
||||
if n, ok := b.TryAlloc(i.width+2*paddingSize, i.height+2*paddingSize); ok {
|
||||
if n, ok := b.tryAlloc(i.width+2*paddingSize, i.height+2*paddingSize); ok {
|
||||
i.backend = b
|
||||
i.node = n
|
||||
return
|
||||
@ -653,7 +656,7 @@ func (i *Image) allocate(shareable bool) {
|
||||
size := minSize
|
||||
for i.width+2*paddingSize > size || i.height+2*paddingSize > size {
|
||||
if size == maxSize {
|
||||
panic(fmt.Sprintf("shareable: the image being shared is too big: width: %d, height: %d", i.width, i.height))
|
||||
panic(fmt.Sprintf("atlas: the image being put on an atlas is too big: width: %d, height: %d", i.width, i.height))
|
||||
}
|
||||
size *= 2
|
||||
}
|
||||
@ -667,7 +670,7 @@ func (i *Image) allocate(shareable bool) {
|
||||
|
||||
n := b.page.Alloc(i.width+2*paddingSize, i.height+2*paddingSize)
|
||||
if n == nil {
|
||||
panic("shareable: Alloc result must not be nil at allocate")
|
||||
panic("atlas: Alloc result must not be nil at allocate")
|
||||
}
|
||||
i.backend = b
|
||||
i.node = n
|
||||
@ -706,7 +709,7 @@ func BeginFrame() error {
|
||||
return
|
||||
}
|
||||
if len(theBackends) != 0 {
|
||||
panic("shareable: all the images must be not-shared before the game starts")
|
||||
panic("atlas: all the images must be not on an atlas before the game starts")
|
||||
}
|
||||
minSize = 1024
|
||||
maxSize = max(minSize, restorable.MaxImageSize())
|
@ -12,16 +12,16 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package shareable_test
|
||||
package atlas_test
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
. "github.com/hajimehoshi/ebiten/v2/internal/atlas"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/driver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
. "github.com/hajimehoshi/ebiten/v2/internal/shareable"
|
||||
t "github.com/hajimehoshi/ebiten/v2/internal/testing"
|
||||
)
|
||||
|
||||
@ -55,7 +55,7 @@ func quadVertices(sw, sh, x, y int, scalex float32) []float32 {
|
||||
|
||||
const bigSize = 2049
|
||||
|
||||
func TestEnsureNotShared(t *testing.T) {
|
||||
func TestEnsureIsolated(t *testing.T) {
|
||||
// Create img1 and img2 with this size so that the next images are allocated
|
||||
// with non-upper-left location.
|
||||
img1 := NewImage(bigSize, 100)
|
||||
@ -93,7 +93,7 @@ func TestEnsureNotShared(t *testing.T) {
|
||||
dx1 = size * 3 / 4
|
||||
dy1 = size * 3 / 4
|
||||
)
|
||||
// img4.ensureNotShared() should be called.
|
||||
// img4.EnsureIsolated() should be called.
|
||||
vs := quadVertices(size/2, size/2, size/4, size/4, 1)
|
||||
is := graphics.QuadIndices()
|
||||
dr := driver.Region{
|
||||
@ -104,7 +104,7 @@ func TestEnsureNotShared(t *testing.T) {
|
||||
}
|
||||
img4.DrawTriangles([graphics.ShaderImageNum]*Image{img3}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil)
|
||||
want := false
|
||||
if got := img4.IsSharedForTesting(); got != want {
|
||||
if got := img4.IsOnAtlasForTesting(); got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
|
||||
@ -135,7 +135,7 @@ func TestEnsureNotShared(t *testing.T) {
|
||||
img4.DrawTriangles([graphics.ShaderImageNum]*Image{img3}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil)
|
||||
}
|
||||
|
||||
func TestReshared(t *testing.T) {
|
||||
func TestReputOnAtlas(t *testing.T) {
|
||||
const size = 16
|
||||
|
||||
img0 := NewImage(size, size)
|
||||
@ -145,7 +145,7 @@ func TestReshared(t *testing.T) {
|
||||
img1 := NewImage(size, size)
|
||||
defer img1.MarkDisposed()
|
||||
img1.ReplacePixels(make([]byte, 4*size*size))
|
||||
if got, want := img1.IsSharedForTesting(), true; got != want {
|
||||
if got, want := img1.IsOnAtlasForTesting(), true; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
|
||||
@ -166,7 +166,7 @@ func TestReshared(t *testing.T) {
|
||||
img3.SetVolatile(true)
|
||||
defer img3.MarkDisposed()
|
||||
img1.ReplacePixels(make([]byte, 4*size*size))
|
||||
if got, want := img3.IsSharedForTesting(), false; got != want {
|
||||
if got, want := img3.IsOnAtlasForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
|
||||
@ -180,23 +180,23 @@ func TestReshared(t *testing.T) {
|
||||
Height: size,
|
||||
}
|
||||
img1.DrawTriangles([graphics.ShaderImageNum]*Image{img2}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil)
|
||||
if got, want := img1.IsSharedForTesting(), false; got != want {
|
||||
if got, want := img1.IsOnAtlasForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
|
||||
// Use img1 as a render source.
|
||||
// Use the doubled count since img1 was on a texture atlas and became an isolated image once.
|
||||
// Then, img1 requires longer time to recover to be on a textur atlas again.
|
||||
for i := 0; i < BaseCountForShare*2; i++ {
|
||||
if err := MakeImagesSharedForTesting(); err != nil {
|
||||
for i := 0; i < BaseCountToPutOnAtlas*2; i++ {
|
||||
if err := PutImagesOnAtlasForTesting(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
img0.DrawTriangles([graphics.ShaderImageNum]*Image{img1}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil)
|
||||
if got, want := img1.IsSharedForTesting(), false; got != want {
|
||||
if got, want := img1.IsOnAtlasForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
}
|
||||
if err := MakeImagesSharedForTesting(); err != nil {
|
||||
if err := PutImagesOnAtlasForTesting(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@ -218,9 +218,9 @@ func TestReshared(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// img1 is on a shared image again.
|
||||
// img1 is on an atlas again.
|
||||
img0.DrawTriangles([graphics.ShaderImageNum]*Image{img1}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil)
|
||||
if got, want := img1.IsSharedForTesting(), true; got != want {
|
||||
if got, want := img1.IsOnAtlasForTesting(), true; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
|
||||
@ -244,39 +244,39 @@ func TestReshared(t *testing.T) {
|
||||
|
||||
// Use img1 as a render target again.
|
||||
img1.DrawTriangles([graphics.ShaderImageNum]*Image{img2}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil)
|
||||
if got, want := img1.IsSharedForTesting(), false; got != want {
|
||||
if got, want := img1.IsOnAtlasForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
|
||||
// Use img1 as a render source, but call ReplacePixels.
|
||||
// Now use 4x count as img1 became an isolated image again.
|
||||
for i := 0; i < BaseCountForShare*4; i++ {
|
||||
if err := MakeImagesSharedForTesting(); err != nil {
|
||||
for i := 0; i < BaseCountToPutOnAtlas*4; i++ {
|
||||
if err := PutImagesOnAtlasForTesting(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
img1.ReplacePixels(make([]byte, 4*size*size))
|
||||
img0.DrawTriangles([graphics.ShaderImageNum]*Image{img1}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil)
|
||||
if got, want := img1.IsSharedForTesting(), false; got != want {
|
||||
if got, want := img1.IsOnAtlasForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
}
|
||||
if err := MakeImagesSharedForTesting(); err != nil {
|
||||
if err := PutImagesOnAtlasForTesting(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// img1 is not on a shared image due to ReplacePixels.
|
||||
// img1 is not on an atlas due to ReplacePixels.
|
||||
img0.DrawTriangles([graphics.ShaderImageNum]*Image{img1}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil)
|
||||
if got, want := img1.IsSharedForTesting(), false; got != want {
|
||||
if got, want := img1.IsOnAtlasForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
|
||||
// Use img3 as a render source. As img3 is volatile, img3 never uses a shared texture.
|
||||
for i := 0; i < BaseCountForShare*2; i++ {
|
||||
if err := MakeImagesSharedForTesting(); err != nil {
|
||||
// Use img3 as a render source. As img3 is volatile, img3 is never on an atlas.
|
||||
for i := 0; i < BaseCountToPutOnAtlas*2; i++ {
|
||||
if err := PutImagesOnAtlasForTesting(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
img0.DrawTriangles([graphics.ShaderImageNum]*Image{img3}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil)
|
||||
if got, want := img3.IsSharedForTesting(), false; got != want {
|
||||
if got, want := img3.IsOnAtlasForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
}
|
||||
@ -495,11 +495,11 @@ func TestDisposeImmediately(t *testing.T) {
|
||||
// This tests restorable.Image.ClearPixels is called but ReplacePixels is not called.
|
||||
|
||||
img0 := NewImage(16, 16)
|
||||
img0.EnsureNotSharedForTesting()
|
||||
img0.EnsureIsolatedForTesting()
|
||||
defer img0.MarkDisposed()
|
||||
|
||||
img1 := NewImage(16, 16)
|
||||
img1.EnsureNotSharedForTesting()
|
||||
img1.EnsureIsolatedForTesting()
|
||||
defer img1.MarkDisposed()
|
||||
|
||||
// img0 and img1 should share the same backend in 99.9999% possibility.
|
||||
@ -540,7 +540,7 @@ func TestMinImageSize(t *testing.T) {
|
||||
}
|
||||
|
||||
// Issue #1421
|
||||
func TestDisposedAndReshared(t *testing.T) {
|
||||
func TestDisposedAndReputOnAtlas(t *testing.T) {
|
||||
const size = 16
|
||||
|
||||
src := NewImage(size, size)
|
||||
@ -550,7 +550,7 @@ func TestDisposedAndReshared(t *testing.T) {
|
||||
dst := NewImage(size, size)
|
||||
defer dst.MarkDisposed()
|
||||
|
||||
// Use src as a render target so that src is not on the shared image.
|
||||
// Use src as a render target so that src is not on an atlas.
|
||||
vs := quadVertices(size, size, 0, 0, 1)
|
||||
is := graphics.QuadIndices()
|
||||
dr := driver.Region{
|
||||
@ -560,35 +560,35 @@ func TestDisposedAndReshared(t *testing.T) {
|
||||
Height: size,
|
||||
}
|
||||
src.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 := src.IsSharedForTesting(), false; got != want {
|
||||
if got, want := src.IsOnAtlasForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
|
||||
// Use src as a render source.
|
||||
for i := 0; i < BaseCountForShare/2; i++ {
|
||||
if err := MakeImagesSharedForTesting(); err != nil {
|
||||
for i := 0; i < BaseCountToPutOnAtlas/2; i++ {
|
||||
if err := PutImagesOnAtlasForTesting(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dst.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 := src.IsSharedForTesting(), false; got != want {
|
||||
if got, want := src.IsOnAtlasForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// Before MakeImagesSharedForTesting, dispose the image.
|
||||
// Before PutImaegsOnAtlasForTesting, dispose the image.
|
||||
src.MarkDisposed()
|
||||
|
||||
// Force to dispose the image.
|
||||
ResolveDeferredForTesting()
|
||||
|
||||
// Confirm that MakeImagesSharedForTesting doesn't panic.
|
||||
if err := MakeImagesSharedForTesting(); err != nil {
|
||||
// Confirm that PutImagesOnAtlasForTesting doesn't panic.
|
||||
if err := PutImagesOnAtlasForTesting(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Issue #1456
|
||||
func TestImageIsNotResharedWithoutUsingAsSource(t *testing.T) {
|
||||
func TestImageIsNotReputOnAtlasWithoutUsingAsSource(t *testing.T) {
|
||||
const size = 16
|
||||
|
||||
src := NewImage(size, size)
|
||||
@ -598,7 +598,7 @@ func TestImageIsNotResharedWithoutUsingAsSource(t *testing.T) {
|
||||
dst := NewImage(size, size)
|
||||
defer dst.MarkDisposed()
|
||||
|
||||
// Use src as a render target so that src is not on the shared image.
|
||||
// Use src as a render target so that src is not on an atlas.
|
||||
vs := quadVertices(size, size, 0, 0, 1)
|
||||
is := graphics.QuadIndices()
|
||||
dr := driver.Region{
|
||||
@ -610,38 +610,38 @@ func TestImageIsNotResharedWithoutUsingAsSource(t *testing.T) {
|
||||
|
||||
// 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 {
|
||||
if got, want := src2.IsOnAtlasForTesting(), 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 < BaseCountForShare; i++ {
|
||||
if err := MakeImagesSharedForTesting(); err != nil {
|
||||
// This should not affect whether src2 is on an atlas or not.
|
||||
for i := 0; i < BaseCountToPutOnAtlas; i++ {
|
||||
if err := PutImagesOnAtlasForTesting(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got, want := src2.IsSharedForTesting(), false; got != want {
|
||||
if got, want := src2.IsOnAtlasForTesting(), 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 < BaseCountForShare; i++ {
|
||||
if err := MakeImagesSharedForTesting(); err != nil {
|
||||
for i := 0; i < BaseCountToPutOnAtlas; i++ {
|
||||
if err := PutImagesOnAtlasForTesting(); 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 {
|
||||
if got, want := src2.IsOnAtlasForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
if err := MakeImagesSharedForTesting(); err != nil {
|
||||
if err := PutImagesOnAtlasForTesting(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got, want := src2.IsSharedForTesting(), true; got != want {
|
||||
if got, want := src2.IsOnAtlasForTesting(), true; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Add tests to extend shareable image out of the main loop
|
||||
// TODO: Add tests to extend image on an atlas out of the main loop
|
@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package shareable
|
||||
package atlas
|
||||
|
||||
import (
|
||||
"runtime"
|
@ -19,14 +19,14 @@ import (
|
||||
"image"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/affine"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/atlas"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/driver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shareable"
|
||||
)
|
||||
|
||||
type Image struct {
|
||||
img *shareable.Image
|
||||
img *atlas.Image
|
||||
width int
|
||||
height int
|
||||
|
||||
@ -35,14 +35,14 @@ type Image struct {
|
||||
}
|
||||
|
||||
func BeginFrame() error {
|
||||
if err := shareable.BeginFrame(); err != nil {
|
||||
if err := atlas.BeginFrame(); err != nil {
|
||||
return err
|
||||
}
|
||||
return flushDelayedCommands()
|
||||
}
|
||||
|
||||
func EndFrame() error {
|
||||
return shareable.EndFrame()
|
||||
return atlas.EndFrame()
|
||||
}
|
||||
|
||||
func NewImage(width, height int) *Image {
|
||||
@ -60,7 +60,7 @@ func (i *Image) initialize(width, height int) {
|
||||
return
|
||||
}
|
||||
}
|
||||
i.img = shareable.NewImage(width, height)
|
||||
i.img = atlas.NewImage(width, height)
|
||||
i.width = width
|
||||
i.height = height
|
||||
}
|
||||
@ -93,7 +93,7 @@ func (i *Image) initializeAsScreenFramebuffer(width, height int) {
|
||||
}
|
||||
}
|
||||
|
||||
i.img = shareable.NewScreenFramebufferImage(width, height)
|
||||
i.img = atlas.NewScreenFramebufferImage(width, height)
|
||||
i.width = width
|
||||
i.height = height
|
||||
}
|
||||
@ -219,8 +219,8 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, vertices []f
|
||||
}
|
||||
}
|
||||
|
||||
var s *shareable.Shader
|
||||
var imgs [graphics.ShaderImageNum]*shareable.Image
|
||||
var s *atlas.Shader
|
||||
var imgs [graphics.ShaderImageNum]*atlas.Image
|
||||
if shader == nil {
|
||||
// Fast path for rendering without a shader (#1355).
|
||||
img := srcs[0]
|
||||
@ -243,12 +243,12 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, vertices []f
|
||||
}
|
||||
|
||||
type Shader struct {
|
||||
shader *shareable.Shader
|
||||
shader *atlas.Shader
|
||||
}
|
||||
|
||||
func NewShader(program *shaderir.Program) *Shader {
|
||||
return &Shader{
|
||||
shader: shareable.NewShader(program),
|
||||
shader: atlas.NewShader(program),
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user