mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 03:08:54 +01:00
mipmap: Do not allocate independent mipmaps for each sub-image
Fixes #1247
This commit is contained in:
parent
2a9fd5ef13
commit
f8956941b7
@ -54,28 +54,32 @@ func (g *GeoM) det() float32 {
|
|||||||
return g.A*g.D - g.B*g.C
|
return g.A*g.D - g.B*g.C
|
||||||
}
|
}
|
||||||
|
|
||||||
type levelToImage map[int]*shareable.Image
|
|
||||||
|
|
||||||
// Mipmap is a set of shareable.Image sorted by the order of mipmap level.
|
// Mipmap is a set of shareable.Image sorted by the order of mipmap level.
|
||||||
// The level 0 image is a regular image and higher-level images are used for mipmap.
|
// The level 0 image is a regular image and higher-level images are used for mipmap.
|
||||||
type Mipmap struct {
|
type Mipmap struct {
|
||||||
|
width int
|
||||||
|
height int
|
||||||
volatile bool
|
volatile bool
|
||||||
orig *shareable.Image
|
orig *shareable.Image
|
||||||
imgs map[image.Rectangle]levelToImage
|
imgs map[int]*shareable.Image
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(width, height int, volatile bool) *Mipmap {
|
func New(width, height int, volatile bool) *Mipmap {
|
||||||
return &Mipmap{
|
return &Mipmap{
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
volatile: volatile,
|
volatile: volatile,
|
||||||
orig: shareable.NewImage(width, height, volatile),
|
orig: shareable.NewImage(width, height, volatile),
|
||||||
imgs: map[image.Rectangle]levelToImage{},
|
imgs: map[int]*shareable.Image{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewScreenFramebufferMipmap(width, height int) *Mipmap {
|
func NewScreenFramebufferMipmap(width, height int) *Mipmap {
|
||||||
return &Mipmap{
|
return &Mipmap{
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
orig: shareable.NewScreenFramebufferImage(width, height),
|
orig: shareable.NewScreenFramebufferImage(width, height),
|
||||||
imgs: map[image.Rectangle]levelToImage{},
|
imgs: map[int]*shareable.Image{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,17 +153,24 @@ func (m *Mipmap) DrawImage(src *Mipmap, bounds image.Rectangle, geom GeoM, color
|
|||||||
|
|
||||||
a, b, c, d, tx, ty := geom.A, geom.B, geom.C, geom.D, geom.Tx, geom.Ty
|
a, b, c, d, tx, ty := geom.A, geom.B, geom.C, geom.D, geom.Tx, geom.Ty
|
||||||
if level == 0 {
|
if level == 0 {
|
||||||
vs := quadVertices(bounds.Min.X, bounds.Min.Y, bounds.Max.X, bounds.Max.Y, a, b, c, d, tx, ty, cr, cg, cb, ca, screen)
|
sx0 := float32(bounds.Min.X)
|
||||||
|
sy0 := float32(bounds.Min.Y)
|
||||||
|
sx1 := float32(bounds.Max.X)
|
||||||
|
sy1 := float32(bounds.Max.Y)
|
||||||
|
vs := quadVertices(sx0, sy0, sx1, sy1, a, b, c, d, tx, ty, cr, cg, cb, ca, screen)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
m.orig.DrawTriangles(src.orig, vs, is, colorm, mode, filter, driver.AddressUnsafe, driver.Region{}, nil, nil, nil)
|
m.orig.DrawTriangles(src.orig, vs, is, colorm, mode, filter, driver.AddressUnsafe, driver.Region{}, nil, nil, nil)
|
||||||
} else if buf := src.level(bounds, level); buf != nil {
|
} else if buf := src.level(level); buf != nil {
|
||||||
w, h := sizeForLevel(bounds.Dx(), bounds.Dy(), level)
|
|
||||||
s := pow2(level)
|
s := pow2(level)
|
||||||
|
sx0 := float32(sizeForLevel(bounds.Min.X, level))
|
||||||
|
sy0 := float32(sizeForLevel(bounds.Min.Y, level))
|
||||||
|
sx1 := float32(sizeForLevel(bounds.Max.X, level))
|
||||||
|
sy1 := float32(sizeForLevel(bounds.Max.Y, level))
|
||||||
a *= s
|
a *= s
|
||||||
b *= s
|
b *= s
|
||||||
c *= s
|
c *= s
|
||||||
d *= s
|
d *= s
|
||||||
vs := quadVertices(0, 0, w, h, a, b, c, d, tx, ty, cr, cg, cb, ca, false)
|
vs := quadVertices(sx0, sy0, sx1, sy1, a, b, c, d, tx, ty, cr, cg, cb, ca, false)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
m.orig.DrawTriangles(buf, vs, is, colorm, mode, filter, driver.AddressUnsafe, driver.Region{}, nil, nil, nil)
|
m.orig.DrawTriangles(buf, vs, is, colorm, mode, filter, driver.AddressUnsafe, driver.Region{}, nil, nil, nil)
|
||||||
}
|
}
|
||||||
@ -204,7 +215,7 @@ func (m *Mipmap) DrawTriangles(src *Mipmap, vertices []float32, indices []uint16
|
|||||||
m.disposeMipmaps()
|
m.disposeMipmaps()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mipmap) level(r image.Rectangle, level int) *shareable.Image {
|
func (m *Mipmap) level(level int) *shareable.Image {
|
||||||
if level == 0 {
|
if level == 0 {
|
||||||
panic("ebiten: level must be non-zero at level")
|
panic("ebiten: level must be non-zero at level")
|
||||||
}
|
}
|
||||||
@ -213,12 +224,7 @@ func (m *Mipmap) level(r image.Rectangle, level int) *shareable.Image {
|
|||||||
panic("ebiten: mipmap images for a volatile image is not implemented yet")
|
panic("ebiten: mipmap images for a volatile image is not implemented yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := m.imgs[r]; !ok {
|
if img, ok := m.imgs[level]; ok {
|
||||||
m.imgs[r] = levelToImage{}
|
|
||||||
}
|
|
||||||
imgs := m.imgs[r]
|
|
||||||
|
|
||||||
if img, ok := imgs[level]; ok {
|
|
||||||
return img
|
return img
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,65 +234,64 @@ func (m *Mipmap) level(r image.Rectangle, level int) *shareable.Image {
|
|||||||
switch {
|
switch {
|
||||||
case level == 1:
|
case level == 1:
|
||||||
src = m.orig
|
src = m.orig
|
||||||
vs = quadVertices(r.Min.X, r.Min.Y, r.Max.X, r.Max.Y, 0.5, 0, 0, 0.5, 0, 0, 1, 1, 1, 1, false)
|
vs = quadVertices(0, 0, float32(m.width), float32(m.height), 0.5, 0, 0, 0.5, 0, 0, 1, 1, 1, 1, false)
|
||||||
filter = driver.FilterLinear
|
filter = driver.FilterLinear
|
||||||
case level > 1:
|
case level > 1:
|
||||||
src = m.level(r, level-1)
|
src = m.level(level - 1)
|
||||||
if src == nil {
|
if src == nil {
|
||||||
imgs[level] = nil
|
m.imgs[level] = nil
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
w, h := sizeForLevel(r.Dx(), r.Dy(), level-1)
|
w := sizeForLevel(m.width, level-1)
|
||||||
vs = quadVertices(0, 0, w, h, 0.5, 0, 0, 0.5, 0, 0, 1, 1, 1, 1, false)
|
h := sizeForLevel(m.height, level-1)
|
||||||
|
vs = quadVertices(0, 0, float32(w), float32(h), 0.5, 0, 0, 0.5, 0, 0, 1, 1, 1, 1, false)
|
||||||
filter = driver.FilterLinear
|
filter = driver.FilterLinear
|
||||||
case level == -1:
|
case level == -1:
|
||||||
src = m.orig
|
src = m.orig
|
||||||
vs = quadVertices(r.Min.X, r.Min.Y, r.Max.X, r.Max.Y, 2, 0, 0, 2, 0, 0, 1, 1, 1, 1, false)
|
vs = quadVertices(0, 0, float32(m.width), float32(m.height), 2, 0, 0, 2, 0, 0, 1, 1, 1, 1, false)
|
||||||
filter = driver.FilterNearest
|
filter = driver.FilterNearest
|
||||||
case level < -1:
|
case level < -1:
|
||||||
src = m.level(r, level+1)
|
src = m.level(level + 1)
|
||||||
if src == nil {
|
if src == nil {
|
||||||
imgs[level] = nil
|
m.imgs[level] = nil
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
w, h := sizeForLevel(r.Dx(), r.Dy(), level+1)
|
w := sizeForLevel(m.width, level-1)
|
||||||
vs = quadVertices(0, 0, w, h, 2, 0, 0, 2, 0, 0, 1, 1, 1, 1, false)
|
h := sizeForLevel(m.height, level-1)
|
||||||
|
vs = quadVertices(0, 0, float32(w), float32(h), 2, 0, 0, 2, 0, 0, 1, 1, 1, 1, false)
|
||||||
filter = driver.FilterNearest
|
filter = driver.FilterNearest
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("ebiten: invalid level: %d", level))
|
panic(fmt.Sprintf("ebiten: invalid level: %d", level))
|
||||||
}
|
}
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
|
|
||||||
w2, h2 := sizeForLevel(r.Dx(), r.Dy(), level)
|
w2 := sizeForLevel(m.width, level-1)
|
||||||
|
h2 := sizeForLevel(m.height, level-1)
|
||||||
if w2 == 0 || h2 == 0 {
|
if w2 == 0 || h2 == 0 {
|
||||||
imgs[level] = nil
|
m.imgs[level] = nil
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
s := shareable.NewImage(w2, h2, m.volatile)
|
s := shareable.NewImage(w2, h2, m.volatile)
|
||||||
s.DrawTriangles(src, vs, is, nil, driver.CompositeModeCopy, filter, driver.AddressUnsafe, driver.Region{}, nil, nil, nil)
|
s.DrawTriangles(src, vs, is, nil, driver.CompositeModeCopy, filter, driver.AddressUnsafe, driver.Region{}, nil, nil, nil)
|
||||||
imgs[level] = s
|
m.imgs[level] = s
|
||||||
|
|
||||||
return imgs[level]
|
return m.imgs[level]
|
||||||
}
|
}
|
||||||
|
|
||||||
func sizeForLevel(origWidth, origHeight int, level int) (width, height int) {
|
func sizeForLevel(x int, level int) int {
|
||||||
width = origWidth
|
|
||||||
height = origHeight
|
|
||||||
if level > 0 {
|
if level > 0 {
|
||||||
for i := 0; i < level; i++ {
|
for i := 0; i < level; i++ {
|
||||||
width /= 2
|
x /= 2
|
||||||
height /= 2
|
if x == 0 {
|
||||||
if width == 0 || height == 0 {
|
return 0
|
||||||
return 0, 0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for i := 0; i < -level; i++ {
|
for i := 0; i < -level; i++ {
|
||||||
width *= 2
|
x *= 2
|
||||||
height *= 2
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return x
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mipmap) MarkDisposed() {
|
func (m *Mipmap) MarkDisposed() {
|
||||||
@ -296,11 +301,9 @@ func (m *Mipmap) MarkDisposed() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mipmap) disposeMipmaps() {
|
func (m *Mipmap) disposeMipmaps() {
|
||||||
for _, a := range m.imgs {
|
for _, img := range m.imgs {
|
||||||
for _, img := range a {
|
|
||||||
img.MarkDisposed()
|
img.MarkDisposed()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
for k := range m.imgs {
|
for k := range m.imgs {
|
||||||
delete(m.imgs, k)
|
delete(m.imgs, k)
|
||||||
}
|
}
|
||||||
|
@ -60,9 +60,9 @@ func vertexSlice(n int, last bool) []float32 {
|
|||||||
return make([]float32, n*graphics.VertexFloatNum)
|
return make([]float32, n*graphics.VertexFloatNum)
|
||||||
}
|
}
|
||||||
|
|
||||||
func quadVertices(sx0, sy0, sx1, sy1 int, a, b, c, d, tx, ty float32, cr, cg, cb, ca float32, last bool) []float32 {
|
func quadVertices(sx0, sy0, sx1, sy1 float32, a, b, c, d, tx, ty float32, cr, cg, cb, ca float32, last bool) []float32 {
|
||||||
x := float32(sx1 - sx0)
|
x := sx1 - sx0
|
||||||
y := float32(sy1 - sy0)
|
y := sy1 - sy0
|
||||||
ax, by, cx, dy := a*x, b*y, c*x, d*y
|
ax, by, cx, dy := a*x, b*y, c*x, d*y
|
||||||
u0, v0, u1, v1 := float32(sx0), float32(sy0), float32(sx1), float32(sy1)
|
u0, v0, u1, v1 := float32(sx0), float32(sy0), float32(sx1), float32(sy1)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user