graphics: Improve speed by merging vertices arrays into one

This commit is contained in:
Hajime Hoshi 2017-01-19 01:26:56 +09:00
parent a744285b51
commit 333b0956ff
2 changed files with 41 additions and 29 deletions

View File

@ -32,11 +32,25 @@ type command interface {
type commandQueue struct { type commandQueue struct {
commands []command commands []command
vertices []float32
verticesNum int
m sync.Mutex m sync.Mutex
} }
var theCommandQueue = &commandQueue{ var theCommandQueue = &commandQueue{
commands: []command{}, commands: []command{},
vertices: []float32{},
}
func (q *commandQueue) AppendVertices(vertices []float32) {
q.m.Lock()
defer q.m.Unlock()
if len(q.vertices) < q.verticesNum+len(vertices) {
n := q.verticesNum + len(vertices) - len(q.vertices)
q.vertices = append(q.vertices, make([]float32, n)...)
}
copy(q.vertices[q.verticesNum:q.verticesNum+len(vertices)], vertices)
q.verticesNum += len(vertices)
} }
func (q *commandQueue) Enqueue(command command) { func (q *commandQueue) Enqueue(command command) {
@ -46,7 +60,7 @@ func (q *commandQueue) Enqueue(command command) {
if c1, ok := q.commands[len(q.commands)-1].(*drawImageCommand); ok { if c1, ok := q.commands[len(q.commands)-1].(*drawImageCommand); ok {
if c2, ok := command.(*drawImageCommand); ok { if c2, ok := command.(*drawImageCommand); ok {
if c1.isMergeable(c2) { if c1.isMergeable(c2) {
c1.vertices = append(c1.vertices, c2.vertices...) c1.verticesNum += c2.verticesNum
return return
} }
} }
@ -91,27 +105,21 @@ func (q *commandQueue) Flush(context *opengl.Context) error {
defer q.m.Unlock() defer q.m.Unlock()
// glViewport must be called at least at every frame on iOS. // glViewport must be called at least at every frame on iOS.
context.ResetViewportSize() context.ResetViewportSize()
for _, g := range q.commandGroups() {
n := 0 n := 0
lastN := 0
for _, g := range q.commandGroups() {
for _, c := range g { for _, c := range g {
switch c := c.(type) { switch c := c.(type) {
case *drawImageCommand: case *drawImageCommand:
n += len(c.vertices) n += c.verticesNum
} }
} }
vertices := make([]float32, 0, n) if 0 < n-lastN {
for _, c := range g { context.BufferSubData(opengl.ArrayBuffer, q.vertices[lastN:n])
switch c := c.(type) {
case *drawImageCommand:
vertices = append(vertices, c.vertices...)
}
}
if 0 < len(vertices) {
context.BufferSubData(opengl.ArrayBuffer, vertices)
} }
// NOTE: WebGL doesn't seem to have Check gl.MAX_ELEMENTS_VERTICES or gl.MAX_ELEMENTS_INDICES so far. // NOTE: WebGL doesn't seem to have Check gl.MAX_ELEMENTS_VERTICES or gl.MAX_ELEMENTS_INDICES so far.
// Let's use them to compare to len(quads) in the future. // Let's use them to compare to len(quads) in the future.
if maxQuads < len(vertices)*opengl.Float.SizeInBytes()/QuadVertexSizeInBytes() { if maxQuads < (n-lastN)*opengl.Float.SizeInBytes()/QuadVertexSizeInBytes() {
return fmt.Errorf("len(quads) must be equal to or less than %d", maxQuads) return fmt.Errorf("len(quads) must be equal to or less than %d", maxQuads)
} }
numc := len(g) numc := len(g)
@ -121,7 +129,7 @@ func (q *commandQueue) Flush(context *opengl.Context) error {
return err return err
} }
if c, ok := c.(*drawImageCommand); ok { if c, ok := c.(*drawImageCommand); ok {
n := len(c.vertices) * opengl.Float.SizeInBytes() / QuadVertexSizeInBytes() n := c.verticesNum * opengl.Float.SizeInBytes() / QuadVertexSizeInBytes()
indexOffsetInBytes += 6 * n * 2 indexOffsetInBytes += 6 * n * 2
} }
} }
@ -129,8 +137,10 @@ func (q *commandQueue) Flush(context *opengl.Context) error {
// Call glFlush to prevent black flicking (especially on Android (#226) and iOS). // Call glFlush to prevent black flicking (especially on Android (#226) and iOS).
context.Flush() context.Flush()
} }
lastN = n
} }
q.commands = []command{} q.commands = []command{}
q.verticesNum = 0
return nil return nil
} }
@ -163,7 +173,7 @@ func (c *fillCommand) Exec(context *opengl.Context, indexOffsetInBytes int) erro
type drawImageCommand struct { type drawImageCommand struct {
dst *Image dst *Image
src *Image src *Image
vertices []float32 verticesNum int
color affine.ColorM color affine.ColorM
mode opengl.CompositeMode mode opengl.CompositeMode
} }
@ -209,8 +219,9 @@ func (c *drawImageCommand) split(quadsNum int) [2]*drawImageCommand {
c1 := *c c1 := *c
c2 := *c c2 := *c
s := opengl.Float.SizeInBytes() s := opengl.Float.SizeInBytes()
c1.vertices = c.vertices[:quadsNum*QuadVertexSizeInBytes()/s] n := quadsNum * QuadVertexSizeInBytes() / s
c2.vertices = c.vertices[quadsNum*QuadVertexSizeInBytes()/s:] c1.verticesNum = n
c2.verticesNum -= n
return [2]*drawImageCommand{&c1, &c2} return [2]*drawImageCommand{&c1, &c2}
} }
@ -231,7 +242,7 @@ func (c *drawImageCommand) isMergeable(other *drawImageCommand) bool {
} }
func (c *drawImageCommand) quadsNum() int { func (c *drawImageCommand) quadsNum() int {
return len(c.vertices) * opengl.Float.SizeInBytes() / QuadVertexSizeInBytes() return c.verticesNum * opengl.Float.SizeInBytes() / QuadVertexSizeInBytes()
} }
type replacePixelsCommand struct { type replacePixelsCommand struct {

View File

@ -147,10 +147,11 @@ func (i *Image) DrawImage(src *Image, vertices []float32, clr affine.ColorM, mod
c := &drawImageCommand{ c := &drawImageCommand{
dst: i, dst: i,
src: src, src: src,
vertices: vertices, verticesNum: len(vertices),
color: clr, color: clr,
mode: mode, mode: mode,
} }
theCommandQueue.AppendVertices(vertices)
theCommandQueue.Enqueue(c) theCommandQueue.Enqueue(c)
return nil return nil
} }