mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 03:08:54 +01:00
internal/graphics: remove the common vertices backend
It was actually impossible to use the common vertices backend in a thread-safe manner, and actually this caused race conditions. This changes fixes the issue by giving up a central backend, and letting images have their own vertices buffer. Closes #2473
This commit is contained in:
parent
d407607168
commit
61f1d8b69f
20
image.go
20
image.go
@ -40,6 +40,9 @@ type Image struct {
|
|||||||
|
|
||||||
// Do not add a 'buffering' member that are resolved lazily.
|
// Do not add a 'buffering' member that are resolved lazily.
|
||||||
// This tends to forget resolving the buffer easily (#2362).
|
// This tends to forget resolving the buffer easily (#2362).
|
||||||
|
|
||||||
|
// tmpVertices must not be reused until the vertices are sent to the graphics command queue.
|
||||||
|
tmpVertices []float32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) copyCheck() {
|
func (i *Image) copyCheck() {
|
||||||
@ -241,7 +244,8 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) {
|
|||||||
sx1, sy1 := img.adjustPosition(bounds.Max.X, bounds.Max.Y)
|
sx1, sy1 := img.adjustPosition(bounds.Max.X, bounds.Max.Y)
|
||||||
colorm, cr, cg, cb, ca := colorMToScale(options.ColorM.affineColorM())
|
colorm, cr, cg, cb, ca := colorMToScale(options.ColorM.affineColorM())
|
||||||
cr, cg, cb, ca = options.ColorScale.apply(cr, cg, cb, ca)
|
cr, cg, cb, ca = options.ColorScale.apply(cr, cg, cb, ca)
|
||||||
vs := graphics.QuadVertices(float32(sx0), float32(sy0), float32(sx1), float32(sy1), a, b, c, d, tx, ty, cr, cg, cb, ca)
|
vs := i.ensureTmpVertices(4 * graphics.VertexFloatCount)
|
||||||
|
graphics.QuadVertices(vs, float32(sx0), float32(sy0), float32(sx1), float32(sy1), a, b, c, d, tx, ty, cr, cg, cb, ca)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
|
|
||||||
srcs := [graphics.ShaderImageCount]*ui.Image{img.image}
|
srcs := [graphics.ShaderImageCount]*ui.Image{img.image}
|
||||||
@ -441,7 +445,7 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o
|
|||||||
|
|
||||||
colorm, cr, cg, cb, ca := colorMToScale(options.ColorM.affineColorM())
|
colorm, cr, cg, cb, ca := colorMToScale(options.ColorM.affineColorM())
|
||||||
|
|
||||||
vs := graphics.Vertices(len(vertices))
|
vs := i.ensureTmpVertices(len(vertices) * graphics.VertexFloatCount)
|
||||||
dst := i
|
dst := i
|
||||||
if options.ColorScaleMode == ColorScaleModeStraightAlpha {
|
if options.ColorScaleMode == ColorScaleModeStraightAlpha {
|
||||||
for i, v := range vertices {
|
for i, v := range vertices {
|
||||||
@ -577,7 +581,7 @@ func (i *Image) DrawTrianglesShader(vertices []Vertex, indices []uint16, shader
|
|||||||
blend = options.CompositeMode.blend().internalBlend()
|
blend = options.CompositeMode.blend().internalBlend()
|
||||||
}
|
}
|
||||||
|
|
||||||
vs := graphics.Vertices(len(vertices))
|
vs := i.ensureTmpVertices(len(vertices) * graphics.VertexFloatCount)
|
||||||
dst := i
|
dst := i
|
||||||
src := options.Images[0]
|
src := options.Images[0]
|
||||||
for i, v := range vertices {
|
for i, v := range vertices {
|
||||||
@ -732,7 +736,8 @@ func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawR
|
|||||||
}
|
}
|
||||||
a, b, c, d, tx, ty := options.GeoM.elements32()
|
a, b, c, d, tx, ty := options.GeoM.elements32()
|
||||||
cr, cg, cb, ca := options.ColorScale.elements()
|
cr, cg, cb, ca := options.ColorScale.elements()
|
||||||
vs := graphics.QuadVertices(float32(sx), float32(sy), float32(sx+width), float32(sy+height), a, b, c, d, tx, ty, cr, cg, cb, ca)
|
vs := i.ensureTmpVertices(4 * graphics.VertexFloatCount)
|
||||||
|
graphics.QuadVertices(vs, float32(sx), float32(sy), float32(sx+width), float32(sy+height), a, b, c, d, tx, ty, cr, cg, cb, ca)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
|
|
||||||
var offsets [graphics.ShaderImageCount - 1][2]float32
|
var offsets [graphics.ShaderImageCount - 1][2]float32
|
||||||
@ -1143,6 +1148,13 @@ func colorMToScale(colorm affine.ColorM) (newColorM affine.ColorM, r, g, b, a fl
|
|||||||
return affine.ColorMIdentity{}, r * a, g * a, b * a, a
|
return affine.ColorMIdentity{}, r * a, g * a, b * a, a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *Image) ensureTmpVertices(n int) []float32 {
|
||||||
|
if cap(i.tmpVertices) < n {
|
||||||
|
i.tmpVertices = make([]float32, n)
|
||||||
|
}
|
||||||
|
return i.tmpVertices[:n]
|
||||||
|
}
|
||||||
|
|
||||||
// private implements FinalScreen.
|
// private implements FinalScreen.
|
||||||
func (*Image) private() {
|
func (*Image) private() {
|
||||||
}
|
}
|
||||||
|
@ -321,7 +321,8 @@ func (i *Image) putOnAtlas(graphicsDriver graphicsdriver.Graphics) error {
|
|||||||
newI := NewImage(i.width, i.height, ImageTypeRegular)
|
newI := NewImage(i.width, i.height, ImageTypeRegular)
|
||||||
|
|
||||||
w, h := float32(i.width), float32(i.height)
|
w, h := float32(i.width), float32(i.height)
|
||||||
vs := graphics.QuadVertices(0, 0, w, h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
vs := make([]float32, 4*graphics.VertexFloatCount)
|
||||||
|
graphics.QuadVertices(vs, 0, 0, w, h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
dr := graphicsdriver.Region{
|
dr := graphicsdriver.Region{
|
||||||
X: 0,
|
X: 0,
|
||||||
|
@ -148,9 +148,13 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [
|
|||||||
}
|
}
|
||||||
|
|
||||||
if maybeCanAddDelayedCommand() {
|
if maybeCanAddDelayedCommand() {
|
||||||
|
vs := make([]float32, len(vertices))
|
||||||
|
copy(vs, vertices)
|
||||||
|
is := make([]uint16, len(indices))
|
||||||
|
copy(is, indices)
|
||||||
|
// TODO: Copy uniform variables. Now this is created for each call, so copying is not necessary, but this is fragile.
|
||||||
if tryAddDelayedCommand(func() {
|
if tryAddDelayedCommand(func() {
|
||||||
// Arguments are not copied. Copying is the caller's responsibility.
|
i.DrawTriangles(srcs, vs, is, blend, dstRegion, srcRegion, subimageOffsets, shader, uniforms, evenOdd)
|
||||||
i.DrawTriangles(srcs, vertices, indices, blend, dstRegion, srcRegion, subimageOffsets, shader, uniforms, evenOdd)
|
|
||||||
}) {
|
}) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -14,10 +14,6 @@
|
|||||||
|
|
||||||
package graphics
|
package graphics
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ShaderImageCount = 4
|
ShaderImageCount = 4
|
||||||
|
|
||||||
@ -55,138 +51,53 @@ func QuadIndices() []uint16 {
|
|||||||
return quadIndices
|
return quadIndices
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
// QuadVertices sets a float32 slice for a quadrangle.
|
||||||
theVerticesBackend = &verticesBackend{}
|
// QuadVertices sets a slice that never overlaps with other slices returned this function,
|
||||||
)
|
|
||||||
|
|
||||||
// TODO: The logic is very similar to atlas.temporaryPixels. Unify them.
|
|
||||||
|
|
||||||
type verticesBackend struct {
|
|
||||||
backend []float32
|
|
||||||
pos int
|
|
||||||
notFullyUsedTime int
|
|
||||||
|
|
||||||
m sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
func verticesBackendFloat32Size(size int) int {
|
|
||||||
l := 128 * VertexFloatCount
|
|
||||||
for l < size {
|
|
||||||
l *= 2
|
|
||||||
}
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
|
|
||||||
func max(a, b int) int {
|
|
||||||
if a > b {
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *verticesBackend) slice(n int) []float32 {
|
|
||||||
v.m.Lock()
|
|
||||||
defer v.m.Unlock()
|
|
||||||
|
|
||||||
need := n * VertexFloatCount
|
|
||||||
if len(v.backend) < v.pos+need {
|
|
||||||
v.backend = make([]float32, max(len(v.backend)*2, verticesBackendFloat32Size(need)))
|
|
||||||
v.pos = 0
|
|
||||||
}
|
|
||||||
s := v.backend[v.pos : v.pos+need]
|
|
||||||
v.pos += need
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *verticesBackend) lockAndReset(f func() error) error {
|
|
||||||
v.m.Lock()
|
|
||||||
defer v.m.Unlock()
|
|
||||||
|
|
||||||
if err := f(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
const maxNotFullyUsedTime = 60
|
|
||||||
if verticesBackendFloat32Size(v.pos) < len(v.backend) {
|
|
||||||
if v.notFullyUsedTime < maxNotFullyUsedTime {
|
|
||||||
v.notFullyUsedTime++
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
v.notFullyUsedTime = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
if v.notFullyUsedTime == maxNotFullyUsedTime && len(v.backend) > 0 {
|
|
||||||
v.backend = nil
|
|
||||||
v.notFullyUsedTime = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
v.pos = 0
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vertices returns a float32 slice for n vertices.
|
|
||||||
// Vertices returns a slice that never overlaps with other slices returned this function,
|
|
||||||
// and users can do optimization based on this fact.
|
// and users can do optimization based on this fact.
|
||||||
func Vertices(n int) []float32 {
|
func QuadVertices(dst []float32, sx0, sy0, sx1, sy1 float32, a, b, c, d, tx, ty float32, cr, cg, cb, ca float32) {
|
||||||
return theVerticesBackend.slice(n)
|
|
||||||
}
|
|
||||||
|
|
||||||
func LockAndResetVertices(f func() error) error {
|
|
||||||
return theVerticesBackend.lockAndReset(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// QuadVertices returns a float32 slice for a quadrangle.
|
|
||||||
// QuadVertices returns a slice that never overlaps with other slices returned this function,
|
|
||||||
// and users can do optimization based on this fact.
|
|
||||||
func QuadVertices(sx0, sy0, sx1, sy1 float32, a, b, c, d, tx, ty float32, cr, cg, cb, ca float32) []float32 {
|
|
||||||
x := sx1 - sx0
|
x := sx1 - sx0
|
||||||
y := 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)
|
||||||
|
|
||||||
// Use the vertex backend instead of calling make to reduce GCs (#1521).
|
|
||||||
vs := theVerticesBackend.slice(4)
|
|
||||||
|
|
||||||
// This function is very performance-sensitive and implement in a very dumb way.
|
// This function is very performance-sensitive and implement in a very dumb way.
|
||||||
_ = vs[:4*VertexFloatCount]
|
_ = dst[:4*VertexFloatCount]
|
||||||
|
|
||||||
vs[0] = adjustDestinationPixel(tx)
|
dst[0] = adjustDestinationPixel(tx)
|
||||||
vs[1] = adjustDestinationPixel(ty)
|
dst[1] = adjustDestinationPixel(ty)
|
||||||
vs[2] = u0
|
dst[2] = u0
|
||||||
vs[3] = v0
|
dst[3] = v0
|
||||||
vs[4] = cr
|
dst[4] = cr
|
||||||
vs[5] = cg
|
dst[5] = cg
|
||||||
vs[6] = cb
|
dst[6] = cb
|
||||||
vs[7] = ca
|
dst[7] = ca
|
||||||
|
|
||||||
vs[8] = adjustDestinationPixel(ax + tx)
|
dst[8] = adjustDestinationPixel(ax + tx)
|
||||||
vs[9] = adjustDestinationPixel(cx + ty)
|
dst[9] = adjustDestinationPixel(cx + ty)
|
||||||
vs[10] = u1
|
dst[10] = u1
|
||||||
vs[11] = v0
|
dst[11] = v0
|
||||||
vs[12] = cr
|
dst[12] = cr
|
||||||
vs[13] = cg
|
dst[13] = cg
|
||||||
vs[14] = cb
|
dst[14] = cb
|
||||||
vs[15] = ca
|
dst[15] = ca
|
||||||
|
|
||||||
vs[16] = adjustDestinationPixel(by + tx)
|
dst[16] = adjustDestinationPixel(by + tx)
|
||||||
vs[17] = adjustDestinationPixel(dy + ty)
|
dst[17] = adjustDestinationPixel(dy + ty)
|
||||||
vs[18] = u0
|
dst[18] = u0
|
||||||
vs[19] = v1
|
dst[19] = v1
|
||||||
vs[20] = cr
|
dst[20] = cr
|
||||||
vs[21] = cg
|
dst[21] = cg
|
||||||
vs[22] = cb
|
dst[22] = cb
|
||||||
vs[23] = ca
|
dst[23] = ca
|
||||||
|
|
||||||
vs[24] = adjustDestinationPixel(ax + by + tx)
|
dst[24] = adjustDestinationPixel(ax + by + tx)
|
||||||
vs[25] = adjustDestinationPixel(cx + dy + ty)
|
dst[25] = adjustDestinationPixel(cx + dy + ty)
|
||||||
vs[26] = u1
|
dst[26] = u1
|
||||||
vs[27] = v1
|
dst[27] = v1
|
||||||
vs[28] = cr
|
dst[28] = cr
|
||||||
vs[29] = cg
|
dst[29] = cg
|
||||||
vs[30] = cb
|
dst[30] = cb
|
||||||
vs[31] = ca
|
dst[31] = ca
|
||||||
|
|
||||||
return vs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func adjustDestinationPixel(x float32) float32 {
|
func adjustDestinationPixel(x float32) float32 {
|
||||||
|
@ -148,12 +148,12 @@ func (m *Mipmap) level(level int) *buffered.Image {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var src *buffered.Image
|
var src *buffered.Image
|
||||||
var vs []float32
|
vs := make([]float32, 4*graphics.VertexFloatCount)
|
||||||
shader := NearestFilterShader
|
shader := NearestFilterShader
|
||||||
switch {
|
switch {
|
||||||
case level == 1:
|
case level == 1:
|
||||||
src = m.orig
|
src = m.orig
|
||||||
vs = graphics.QuadVertices(0, 0, float32(m.width), float32(m.height), 0.5, 0, 0, 0.5, 0, 0, 1, 1, 1, 1)
|
graphics.QuadVertices(vs, 0, 0, float32(m.width), float32(m.height), 0.5, 0, 0, 0.5, 0, 0, 1, 1, 1, 1)
|
||||||
shader = LinearFilterShader
|
shader = LinearFilterShader
|
||||||
case level > 1:
|
case level > 1:
|
||||||
src = m.level(level - 1)
|
src = m.level(level - 1)
|
||||||
@ -163,7 +163,7 @@ func (m *Mipmap) level(level int) *buffered.Image {
|
|||||||
}
|
}
|
||||||
w := sizeForLevel(m.width, level-1)
|
w := sizeForLevel(m.width, level-1)
|
||||||
h := sizeForLevel(m.height, level-1)
|
h := sizeForLevel(m.height, level-1)
|
||||||
vs = graphics.QuadVertices(0, 0, float32(w), float32(h), 0.5, 0, 0, 0.5, 0, 0, 1, 1, 1, 1)
|
graphics.QuadVertices(vs, 0, 0, float32(w), float32(h), 0.5, 0, 0, 0.5, 0, 0, 1, 1, 1, 1)
|
||||||
shader = LinearFilterShader
|
shader = LinearFilterShader
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("mipmap: invalid level: %d", level))
|
panic(fmt.Sprintf("mipmap: invalid level: %d", level))
|
||||||
|
@ -21,7 +21,6 @@ import (
|
|||||||
"github.com/hajimehoshi/ebiten/v2/internal/buffered"
|
"github.com/hajimehoshi/ebiten/v2/internal/buffered"
|
||||||
"github.com/hajimehoshi/ebiten/v2/internal/clock"
|
"github.com/hajimehoshi/ebiten/v2/internal/clock"
|
||||||
"github.com/hajimehoshi/ebiten/v2/internal/debug"
|
"github.com/hajimehoshi/ebiten/v2/internal/debug"
|
||||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
|
||||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||||
"github.com/hajimehoshi/ebiten/v2/internal/hooks"
|
"github.com/hajimehoshi/ebiten/v2/internal/hooks"
|
||||||
"github.com/hajimehoshi/ebiten/v2/internal/mipmap"
|
"github.com/hajimehoshi/ebiten/v2/internal/mipmap"
|
||||||
@ -105,15 +104,7 @@ func (c *context) updateFrameImpl(graphicsDriver graphicsdriver.Graphics, update
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
// All the vertices data are consumed at the end of the frame, and the data backend can be
|
if err1 := buffered.EndFrame(graphicsDriver); err == nil && err1 != nil {
|
||||||
// available after that. Until then, lock the vertices backend.
|
|
||||||
err1 := graphics.LockAndResetVertices(func() error {
|
|
||||||
if err := buffered.EndFrame(graphicsDriver); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err == nil {
|
|
||||||
err = err1
|
err = err1
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -49,6 +49,12 @@ type Image struct {
|
|||||||
// drawCallback is a callback called when DrawTriangles or WritePixels is called.
|
// drawCallback is a callback called when DrawTriangles or WritePixels is called.
|
||||||
// drawCallback is useful to detect whether the image is manipulated or not after a certain time.
|
// drawCallback is useful to detect whether the image is manipulated or not after a certain time.
|
||||||
drawCallback func()
|
drawCallback func()
|
||||||
|
|
||||||
|
// These temporary vertices must not be reused until the vertices are sent to the graphics command queue.
|
||||||
|
|
||||||
|
tmpVerticesForFlushing []float32
|
||||||
|
tmpVerticesForCopying []float32
|
||||||
|
tmpVerticesForFill []float32
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewImage(width, height int, imageType atlas.ImageType) *Image {
|
func NewImage(width, height int, imageType atlas.ImageType) *Image {
|
||||||
@ -106,7 +112,11 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [
|
|||||||
// Copy the current rendering result to get the correct blending result.
|
// Copy the current rendering result to get the correct blending result.
|
||||||
if blend != graphicsdriver.BlendSourceOver && !i.bigOffscreenBufferDirty {
|
if blend != graphicsdriver.BlendSourceOver && !i.bigOffscreenBufferDirty {
|
||||||
srcs := [graphics.ShaderImageCount]*Image{i}
|
srcs := [graphics.ShaderImageCount]*Image{i}
|
||||||
vs := graphics.QuadVertices(
|
if len(i.tmpVerticesForCopying) < 4*graphics.VertexFloatCount {
|
||||||
|
i.tmpVerticesForCopying = make([]float32, 4*graphics.VertexFloatCount)
|
||||||
|
}
|
||||||
|
graphics.QuadVertices(
|
||||||
|
i.tmpVerticesForCopying,
|
||||||
0, 0, float32(i.width), float32(i.height),
|
0, 0, float32(i.width), float32(i.height),
|
||||||
bigOffscreenScale, 0, 0, bigOffscreenScale, 0, 0,
|
bigOffscreenScale, 0, 0, bigOffscreenScale, 0, 0,
|
||||||
1, 1, 1, 1)
|
1, 1, 1, 1)
|
||||||
@ -117,7 +127,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [
|
|||||||
Width: float32(i.width * bigOffscreenScale),
|
Width: float32(i.width * bigOffscreenScale),
|
||||||
Height: float32(i.height * bigOffscreenScale),
|
Height: float32(i.height * bigOffscreenScale),
|
||||||
}
|
}
|
||||||
i.bigOffscreenBuffer.DrawTriangles(srcs, vs, is, graphicsdriver.BlendCopy, dstRegion, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, NearestFilterShader, nil, false, true, false)
|
i.bigOffscreenBuffer.DrawTriangles(srcs, i.tmpVerticesForCopying, is, graphicsdriver.BlendCopy, dstRegion, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, NearestFilterShader, nil, false, true, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < len(vertices); i += graphics.VertexFloatCount {
|
for i := 0; i < len(vertices); i += graphics.VertexFloatCount {
|
||||||
@ -221,7 +231,7 @@ func (i *Image) flushDotsBufferIfNeeded() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
l := len(i.dotsBuffer)
|
l := len(i.dotsBuffer)
|
||||||
vs := graphics.Vertices(l * 4)
|
vs := make([]float32, l*4*graphics.VertexFloatCount)
|
||||||
is := make([]uint16, l*6)
|
is := make([]uint16, l*6)
|
||||||
sx, sy := float32(1), float32(1)
|
sx, sy := float32(1), float32(1)
|
||||||
var idx int
|
var idx int
|
||||||
@ -296,7 +306,11 @@ func (i *Image) flushBigOffscreenBufferIfNeeded() {
|
|||||||
i.bigOffscreenBufferDirty = false
|
i.bigOffscreenBufferDirty = false
|
||||||
|
|
||||||
srcs := [graphics.ShaderImageCount]*Image{i.bigOffscreenBuffer}
|
srcs := [graphics.ShaderImageCount]*Image{i.bigOffscreenBuffer}
|
||||||
vs := graphics.QuadVertices(
|
if len(i.tmpVerticesForFlushing) < 4*graphics.VertexFloatCount {
|
||||||
|
i.tmpVerticesForFlushing = make([]float32, 4*graphics.VertexFloatCount)
|
||||||
|
}
|
||||||
|
graphics.QuadVertices(
|
||||||
|
i.tmpVerticesForFlushing,
|
||||||
0, 0, float32(i.width*bigOffscreenScale), float32(i.height*bigOffscreenScale),
|
0, 0, float32(i.width*bigOffscreenScale), float32(i.height*bigOffscreenScale),
|
||||||
1.0/bigOffscreenScale, 0, 0, 1.0/bigOffscreenScale, 0, 0,
|
1.0/bigOffscreenScale, 0, 0, 1.0/bigOffscreenScale, 0, 0,
|
||||||
1, 1, 1, 1)
|
1, 1, 1, 1)
|
||||||
@ -311,7 +325,7 @@ func (i *Image) flushBigOffscreenBufferIfNeeded() {
|
|||||||
if i.bigOffscreenBufferBlend != graphicsdriver.BlendSourceOver {
|
if i.bigOffscreenBufferBlend != graphicsdriver.BlendSourceOver {
|
||||||
blend = graphicsdriver.BlendCopy
|
blend = graphicsdriver.BlendCopy
|
||||||
}
|
}
|
||||||
i.DrawTriangles(srcs, vs, is, blend, dstRegion, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, LinearFilterShader, nil, false, true, false)
|
i.DrawTriangles(srcs, i.tmpVerticesForFlushing, is, blend, dstRegion, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, LinearFilterShader, nil, false, true, false)
|
||||||
|
|
||||||
i.bigOffscreenBuffer.clear()
|
i.bigOffscreenBuffer.clear()
|
||||||
i.bigOffscreenBufferDirty = false
|
i.bigOffscreenBufferDirty = false
|
||||||
@ -346,7 +360,11 @@ func (i *Image) Fill(r, g, b, a float32, x, y, width, height int) {
|
|||||||
Height: float32(height),
|
Height: float32(height),
|
||||||
}
|
}
|
||||||
|
|
||||||
vs := graphics.QuadVertices(
|
if len(i.tmpVerticesForFill) < 4*graphics.VertexFloatCount {
|
||||||
|
i.tmpVerticesForFill = make([]float32, 4*graphics.VertexFloatCount)
|
||||||
|
}
|
||||||
|
graphics.QuadVertices(
|
||||||
|
i.tmpVerticesForFill,
|
||||||
1, 1, float32(whiteImage.width-1), float32(whiteImage.height-1),
|
1, 1, float32(whiteImage.width-1), float32(whiteImage.height-1),
|
||||||
float32(i.width), 0, 0, float32(i.height), 0, 0,
|
float32(i.width), 0, 0, float32(i.height), 0, 0,
|
||||||
r, g, b, a)
|
r, g, b, a)
|
||||||
@ -354,5 +372,5 @@ func (i *Image) Fill(r, g, b, a float32, x, y, width, height int) {
|
|||||||
|
|
||||||
srcs := [graphics.ShaderImageCount]*Image{whiteImage}
|
srcs := [graphics.ShaderImageCount]*Image{whiteImage}
|
||||||
|
|
||||||
i.DrawTriangles(srcs, vs, is, graphicsdriver.BlendCopy, dstRegion, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, NearestFilterShader, nil, false, true, false)
|
i.DrawTriangles(srcs, i.tmpVerticesForFill, is, graphicsdriver.BlendCopy, dstRegion, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, NearestFilterShader, nil, false, true, false)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user