ebiten: add Draw{Image,Triangles}Options.DisableMipmaps

Mipmaps could be unexpectedly expensive even when we don't need mipmaps.
In order to improve performance, let's add an option to disable mipmaps.

Closes #3095
This commit is contained in:
Hajime Hoshi 2024-09-12 22:17:02 +09:00
parent 355dd453bd
commit 4b1ae72f59
2 changed files with 57 additions and 12 deletions

View File

@ -32,7 +32,7 @@ import (
)
const (
screenWidth = 800
screenWidth = 1000
screenHeight = 480
)
@ -44,20 +44,28 @@ type Game struct {
rotate bool
clip bool
counter int
pause bool
}
func (g *Game) Update() error {
g.counter++
if g.counter == 480 {
g.counter = 0
}
if inpututil.IsKeyJustPressed(ebiten.KeyR) {
g.rotate = !g.rotate
}
if inpututil.IsKeyJustPressed(ebiten.KeyC) {
g.clip = !g.clip
}
if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) {
g.pause = !g.pause
}
if g.pause {
return nil
}
g.counter++
if g.counter == 480 {
g.counter = 0
}
return nil
}
@ -65,7 +73,8 @@ func (g *Game) Draw(screen *ebiten.Image) {
s := 1.5 / math.Pow(1.01, float64(g.counter))
clippedGophersImage := gophersImage.SubImage(image.Rect(100, 100, 200, 200)).(*ebiten.Image)
for i, f := range []ebiten.Filter{ebiten.FilterNearest, ebiten.FilterLinear} {
for i := range 3 {
//for i, f := range []ebiten.Filter{ebiten.FilterNearest, ebiten.FilterLinear} {
w, h := gophersImage.Bounds().Dx(), gophersImage.Bounds().Dy()
op := &ebiten.DrawImageOptions{}
@ -75,8 +84,15 @@ func (g *Game) Draw(screen *ebiten.Image) {
op.GeoM.Translate(float64(w)/2, float64(h)/2)
}
op.GeoM.Scale(s, s)
op.GeoM.Translate(32+float64(i*w)*s+float64(i*4), 64)
op.Filter = f
op.GeoM.Translate(32+float64(i*w)*s+float64(i*4), 100)
if i == 0 {
op.Filter = ebiten.FilterNearest
} else {
op.Filter = ebiten.FilterLinear
}
if i == 2 {
op.DisableMipmaps = true
}
if g.clip {
screen.DrawImage(clippedGophersImage, op)
} else {
@ -84,9 +100,10 @@ func (g *Game) Draw(screen *ebiten.Image) {
}
}
msg := fmt.Sprintf(`Minifying images (Nearest filter vs Linear filter):
msg := fmt.Sprintf(`Minifying images (Nearest filter, Linear filter (w/ mipmaps), and Linear Filter (w/o mipmaps)):
Press R to rotate the images.
Press C to clip the images.
Click to pause and resume.
Scale: %0.2f`, s)
ebitenutil.DebugPrint(screen, msg)
}

View File

@ -144,6 +144,16 @@ type DrawImageOptions struct {
// Filter is a type of texture filter.
// The default (zero) value is FilterNearest.
Filter Filter
// DisableMipmaps disables mipmaps.
// When Filter is FilterLinear and GeoM shrinks the image, mipmaps are used by default.
// Mipmap is useful to render a shrunk image with high quality.
// However, mipmaps can be expensive, especially on mobiles.
// When DisableMipmaps is true, mipmap is not used.
// When Filter is not FilterLinear, DisableMipmaps is ignored.
//
// The default (zero) value is false.
DisableMipmaps bool
}
// adjustPosition converts the position in the *ebiten.Image coordinate to the *ui.Image coordinate.
@ -273,7 +283,11 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) {
hint = restorable.HintOverwriteDstRegion
}
i.image.DrawTriangles(srcs, vs, is, blend, dr, [graphics.ShaderSrcImageCount]image.Rectangle{img.adjustedBounds()}, shader.shader, i.tmpUniforms, graphicsdriver.FillRuleFillAll, canSkipMipmap(geoM, filter), false, hint)
skipMipmap := options.DisableMipmaps
if !skipMipmap {
skipMipmap = canSkipMipmap(geoM, filter)
}
i.image.DrawTriangles(srcs, vs, is, blend, dr, [graphics.ShaderSrcImageCount]image.Rectangle{img.adjustedBounds()}, shader.shader, i.tmpUniforms, graphicsdriver.FillRuleFillAll, skipMipmap, false, hint)
}
// overwritesDstRegion reports whether the given parameters overwrite the destination region completely.
@ -447,6 +461,16 @@ type DrawTrianglesOptions struct {
//
// The default (zero) value is false.
AntiAlias bool
// DisableMipmaps disables mipmaps.
// When Filter is FilterLinear and GeoM shrinks the image, mipmaps are used by default.
// Mipmap is useful to render a shrunk image with high quality.
// However, mipmaps can be expensive, especially on mobiles.
// When DisableMipmaps is true, mipmap is not used.
// When Filter is not FilterLinear, DisableMipmaps is ignored.
//
// The default (zero) value is false.
DisableMipmaps bool
}
// MaxIndicesCount is the maximum number of indices for DrawTriangles and DrawTrianglesShader.
@ -576,7 +600,11 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o
})
}
i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedBounds(), [graphics.ShaderSrcImageCount]image.Rectangle{img.adjustedBounds()}, shader.shader, i.tmpUniforms, graphicsdriver.FillRule(options.FillRule), filter != builtinshader.FilterLinear, options.AntiAlias, restorable.HintNone)
skipMipmap := options.DisableMipmaps
if !skipMipmap {
skipMipmap = filter != builtinshader.FilterLinear
}
i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedBounds(), [graphics.ShaderSrcImageCount]image.Rectangle{img.adjustedBounds()}, shader.shader, i.tmpUniforms, graphicsdriver.FillRule(options.FillRule), skipMipmap, options.AntiAlias, restorable.HintNone)
}
// DrawTrianglesShaderOptions represents options for DrawTrianglesShader.