From 637afe6d67c44c5e56a9e7f6b14e21d56e10c1de Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sun, 26 Jul 2020 12:23:55 +0900 Subject: [PATCH] mipmap: Skip mipmap calculation if possible If we know we can skip mipmap calculation from GeoM, let's skip it. Updates #1265 --- image.go | 33 +++++++++++++++++++++++---------- internal/mipmap/mipmap.go | 4 ++-- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/image.go b/image.go index 16d6447c0..22fefa0a9 100644 --- a/image.go +++ b/image.go @@ -93,6 +93,17 @@ func (i *Image) Fill(clr color.Color) error { return nil } +func canSkipMipmap(geom GeoM, filter driver.Filter) bool { + det := geom.det2x2() + if filter == driver.FilterNearest && det <= 1.1 { + return true + } + if filter == driver.FilterLinear && det >= 0.9 { + return true + } + return false +} + // DrawImageOptions represents options for DrawImage. type DrawImageOptions struct { // GeoM is a geometry matrix to draw. @@ -242,10 +253,12 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) error { mode := driver.CompositeMode(options.CompositeMode) filter := driver.FilterNearest - if options.Filter != FilterDefault { - filter = driver.Filter(options.Filter) - } else if img.filter != FilterDefault { - filter = driver.Filter(img.filter) + if options.Shader == nil { + if options.Filter != FilterDefault { + filter = driver.Filter(options.Filter) + } else if img.filter != FilterDefault { + filter = driver.Filter(img.filter) + } } a, b, c, d, tx, ty := options.GeoM.elements32() @@ -259,11 +272,11 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) error { srcs := [graphics.ShaderImageNum]*mipmap.Mipmap{img.mipmap} if options.Shader == nil { - i.mipmap.DrawTriangles(srcs, vs, is, options.ColorM.impl, mode, filter, driver.AddressUnsafe, driver.Region{}, nil, nil) + i.mipmap.DrawTriangles(srcs, vs, is, options.ColorM.impl, mode, filter, driver.AddressUnsafe, driver.Region{}, nil, nil, canSkipMipmap(options.GeoM, filter)) return nil } - i.mipmap.DrawTriangles(srcs, vs, is, nil, mode, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, options.Shader.shader, options.Uniforms) + i.mipmap.DrawTriangles(srcs, vs, is, nil, mode, filter, driver.AddressUnsafe, driver.Region{}, options.Shader.shader, options.Uniforms, canSkipMipmap(options.GeoM, filter)) return nil } @@ -424,10 +437,10 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o } if options.Shader == nil { - i.mipmap.DrawTriangles(srcs, vs, is, options.ColorM.impl, mode, filter, driver.Address(options.Address), sr, nil, nil) + i.mipmap.DrawTriangles(srcs, vs, is, options.ColorM.impl, mode, filter, driver.Address(options.Address), sr, nil, nil, false) return } - i.mipmap.DrawTriangles(srcs, vs, is, nil, mode, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, options.Shader.shader, options.Uniforms) + i.mipmap.DrawTriangles(srcs, vs, is, nil, mode, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, options.Shader.shader, options.Uniforms, false) } // DrawRectShaderOptions represents options for DrawRectShader @@ -504,7 +517,7 @@ func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawR vs := graphics.QuadVertices(0, 0, float32(width), float32(height), a, b, c, d, tx, ty, 1, 1, 1, 1, false) is := graphics.QuadIndices() - i.mipmap.DrawTriangles(imgs, vs, is, nil, mode, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, shader.shader, options.Uniforms) + i.mipmap.DrawTriangles(imgs, vs, is, nil, mode, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, shader.shader, options.Uniforms, canSkipMipmap(options.GeoM, driver.FilterNearest)) } // DrawTrianglesShaderOptions represents options for DrawTrianglesShader @@ -600,7 +613,7 @@ func (i *Image) DrawTrianglesShader(vertices []Vertex, indices []uint16, shader is := make([]uint16, len(indices)) copy(is, indices) - i.mipmap.DrawTriangles(imgs, vs, is, nil, mode, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, shader.shader, options.Uniforms) + i.mipmap.DrawTriangles(imgs, vs, is, nil, mode, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, shader.shader, options.Uniforms, false) } // SubImage returns an image representing the portion of the image p visible through r. diff --git a/internal/mipmap/mipmap.go b/internal/mipmap/mipmap.go index d11acb541..1d8e58b45 100644 --- a/internal/mipmap/mipmap.go +++ b/internal/mipmap/mipmap.go @@ -90,10 +90,10 @@ func (m *Mipmap) Pixels(x, y, width, height int) ([]byte, error) { return m.orig.Pixels(x, y, width, height) } -func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderImageNum]*Mipmap, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, sourceRegion driver.Region, shader *Shader, uniforms []interface{}) { +func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderImageNum]*Mipmap, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, sourceRegion driver.Region, shader *Shader, uniforms []interface{}, canSkipMipmap bool) { level := 0 // TODO: Do we need to check all the sources' states of being volatile? - if srcs[0] != nil && !srcs[0].volatile && filter != driver.FilterScreen { + if !canSkipMipmap && srcs[0] != nil && !srcs[0].volatile && filter != driver.FilterScreen { level = math.MaxInt32 for i := 0; i < len(indices)/3; i++ { const n = graphics.VertexFloatNum