graphics: Split the notion of vertices and elements

This commit is contained in:
Hajime Hoshi 2018-06-03 15:16:30 +09:00
parent a54b6060bd
commit 525ad04568
2 changed files with 61 additions and 22 deletions

View File

@ -31,7 +31,9 @@ import (
type command interface { type command interface {
Exec(indexOffsetInBytes int) error Exec(indexOffsetInBytes int) error
NumVertices() int NumVertices() int
NumElements() int
AddNumVertices(n int) AddNumVertices(n int)
AddNumElements(n int)
CanMerge(dst, src *Image, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) bool CanMerge(dst, src *Image, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) bool
} }
@ -48,7 +50,7 @@ type commandQueue struct {
// vertices is never shrunk since re-extending a vertices buffer is heavy. // vertices is never shrunk since re-extending a vertices buffer is heavy.
nvertices int nvertices int
indices []uint16 elements []uint16
} }
// theCommandQueue is the command queue for the current process. // theCommandQueue is the command queue for the current process.
@ -56,15 +58,15 @@ var theCommandQueue = &commandQueue{}
func init() { func init() {
q := theCommandQueue q := theCommandQueue
// Initialize indices for drawImageCommand. // Initialize elements for drawImageCommand.
q.indices = make([]uint16, 6*maxQuads) q.elements = make([]uint16, 6*maxQuads)
for i := uint16(0); i < maxQuads; i++ { for i := uint16(0); i < maxQuads; i++ {
q.indices[6*i+0] = 4*i + 0 q.elements[6*i+0] = 4*i + 0
q.indices[6*i+1] = 4*i + 1 q.elements[6*i+1] = 4*i + 1
q.indices[6*i+2] = 4*i + 2 q.elements[6*i+2] = 4*i + 2
q.indices[6*i+3] = 4*i + 1 q.elements[6*i+3] = 4*i + 1
q.indices[6*i+4] = 4*i + 2 q.elements[6*i+4] = 4*i + 2
q.indices[6*i+5] = 4*i + 3 q.elements[6*i+5] = 4*i + 3
} }
} }
@ -86,10 +88,12 @@ func (q *commandQueue) appendVertices(vertices []float32) {
func (q *commandQueue) EnqueueDrawImageCommand(dst, src *Image, vertices []float32, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) { func (q *commandQueue) EnqueueDrawImageCommand(dst, src *Image, vertices []float32, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) {
// Avoid defer for performance // Avoid defer for performance
q.appendVertices(vertices) q.appendVertices(vertices)
ne := 6 * len(vertices) * opengl.Float.SizeInBytes() / QuadVertexSizeInBytes()
if 0 < len(q.commands) { if 0 < len(q.commands) {
last := q.commands[len(q.commands)-1] last := q.commands[len(q.commands)-1]
if last.CanMerge(dst, src, color, mode, filter) { if last.CanMerge(dst, src, color, mode, filter) {
last.AddNumVertices(len(vertices)) last.AddNumVertices(len(vertices))
last.AddNumElements(ne)
return return
} }
} }
@ -97,6 +101,7 @@ func (q *commandQueue) EnqueueDrawImageCommand(dst, src *Image, vertices []float
dst: dst, dst: dst,
src: src, src: src,
nvertices: len(vertices), nvertices: len(vertices),
nelements: ne,
color: color, color: color,
mode: mode, mode: mode,
filter: filter, filter: filter,
@ -125,6 +130,9 @@ func (q *commandQueue) commandGroups() [][]command {
c := cs[0] c := cs[0]
switch c := c.(type) { switch c := c.(type) {
case *drawImageCommand: case *drawImageCommand:
// NOTE: WebGL doesn't seem to have gl.MAX_ELEMENTS_VERTICES or
// gl.MAX_ELEMENTS_INDICES so far.
// Let's use them to compare to len(quads) in the future.
if maxQuads >= quads+c.quadsNum() { if maxQuads >= quads+c.quadsNum() {
quads += c.quadsNum() quads += c.quadsNum()
break break
@ -156,26 +164,19 @@ func (q *commandQueue) Flush() error {
// Note that the vertices passed to BufferSubData is not under GC management // Note that the vertices passed to BufferSubData is not under GC management
// in opengl package due to unsafe-way. // in opengl package due to unsafe-way.
// See BufferSubData in context_mobile.go. // See BufferSubData in context_mobile.go.
opengl.GetContext().ElementArrayBufferSubData(q.indices) opengl.GetContext().ElementArrayBufferSubData(q.elements)
opengl.GetContext().ArrayBufferSubData(q.vertices[lastN:n]) opengl.GetContext().ArrayBufferSubData(q.vertices[lastN:n])
} }
// NOTE: WebGL doesn't seem to have gl.MAX_ELEMENTS_VERTICES or
// gl.MAX_ELEMENTS_INDICES so far.
// Let's use them to compare to len(quads) in the future.
if maxQuads < (n-lastN)*opengl.Float.SizeInBytes()/QuadVertexSizeInBytes() {
return fmt.Errorf("len(quads) must be equal to or less than %d", maxQuads)
}
numc := len(g) numc := len(g)
indexOffsetInBytes := 0 indexOffsetInBytes := 0
for _, c := range g { for _, c := range g {
if err := c.Exec(indexOffsetInBytes); err != nil { if err := c.Exec(indexOffsetInBytes); err != nil {
return err return err
} }
n := c.NumVertices() * opengl.Float.SizeInBytes() / QuadVertexSizeInBytes()
// TODO: indexOffsetInBytes should be reset if the command type is different // TODO: indexOffsetInBytes should be reset if the command type is different
// from the previous one. This fix is needed when another drawing command is // from the previous one. This fix is needed when another drawing command is
// introduced than drawImageCommand. // introduced than drawImageCommand.
indexOffsetInBytes += 6 * n * 2 indexOffsetInBytes += c.NumElements() * 2 // 2 is uint16 size in bytes
} }
if 0 < numc { if 0 < numc {
// Call glFlush to prevent black flicking (especially on Android (#226) and iOS). // Call glFlush to prevent black flicking (especially on Android (#226) and iOS).
@ -198,6 +199,7 @@ type drawImageCommand struct {
dst *Image dst *Image
src *Image src *Image
nvertices int nvertices int
nelements int
color *affine.ColorM color *affine.ColorM
mode opengl.CompositeMode mode opengl.CompositeMode
filter Filter filter Filter
@ -218,13 +220,12 @@ func (c *drawImageCommand) Exec(indexOffsetInBytes int) error {
opengl.GetContext().BlendFunc(c.mode) opengl.GetContext().BlendFunc(c.mode)
n := c.quadsNum() if c.nelements == 0 {
if n == 0 {
return nil return nil
} }
proj := f.projectionMatrix() proj := f.projectionMatrix()
theOpenGLState.useProgram(proj, c.src.texture.native, c.dst, c.src, c.color, c.filter) theOpenGLState.useProgram(proj, c.src.texture.native, c.dst, c.src, c.color, c.filter)
opengl.GetContext().DrawElements(opengl.Triangles, 6*n, indexOffsetInBytes) opengl.GetContext().DrawElements(opengl.Triangles, c.nelements, indexOffsetInBytes)
// glFlush() might be necessary at least on MacBook Pro (a smilar problem at #419), // glFlush() might be necessary at least on MacBook Pro (a smilar problem at #419),
// but basically this pass the tests (esp. TestImageTooManyFill). // but basically this pass the tests (esp. TestImageTooManyFill).
@ -237,10 +238,18 @@ func (c *drawImageCommand) NumVertices() int {
return c.nvertices return c.nvertices
} }
func (c *drawImageCommand) NumElements() int {
return c.nelements
}
func (c *drawImageCommand) AddNumVertices(n int) { func (c *drawImageCommand) AddNumVertices(n int) {
c.nvertices += n c.nvertices += n
} }
func (c *drawImageCommand) AddNumElements(n int) {
c.nelements += n
}
// split splits the drawImageCommand c into two drawImageCommands. // split splits the drawImageCommand c into two drawImageCommands.
// //
// split is called when the number of vertices reaches of the maximum and // split is called when the number of vertices reaches of the maximum and
@ -252,6 +261,8 @@ func (c *drawImageCommand) split(quadsNum int) [2]*drawImageCommand {
n := quadsNum * QuadVertexSizeInBytes() / s n := quadsNum * QuadVertexSizeInBytes() / s
c1.nvertices = n c1.nvertices = n
c2.nvertices -= n c2.nvertices -= n
c1.nelements = 6 * quadsNum
c2.nelements -= 6 * quadsNum
return [2]*drawImageCommand{&c1, &c2} return [2]*drawImageCommand{&c1, &c2}
} }
@ -305,9 +316,16 @@ func (c *replacePixelsCommand) NumVertices() int {
return 0 return 0
} }
func (c *replacePixelsCommand) NumElements() int {
return 0
}
func (c *replacePixelsCommand) AddNumVertices(n int) { func (c *replacePixelsCommand) AddNumVertices(n int) {
} }
func (c *replacePixelsCommand) AddNumElements(n int) {
}
func (c *replacePixelsCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) bool { func (c *replacePixelsCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) bool {
return false return false
} }
@ -333,9 +351,16 @@ func (c *disposeCommand) NumVertices() int {
return 0 return 0
} }
func (c *disposeCommand) NumElements() int {
return 0
}
func (c *disposeCommand) AddNumVertices(n int) { func (c *disposeCommand) AddNumVertices(n int) {
} }
func (c *disposeCommand) AddNumElements(n int) {
}
func (c *disposeCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) bool { func (c *disposeCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) bool {
return false return false
} }
@ -382,9 +407,16 @@ func (c *newImageCommand) NumVertices() int {
return 0 return 0
} }
func (c *newImageCommand) NumElements() int {
return 0
}
func (c *newImageCommand) AddNumVertices(n int) { func (c *newImageCommand) AddNumVertices(n int) {
} }
func (c *newImageCommand) AddNumElements(n int) {
}
func (c *newImageCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) bool { func (c *newImageCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) bool {
return false return false
} }
@ -410,9 +442,16 @@ func (c *newScreenFramebufferImageCommand) NumVertices() int {
return 0 return 0
} }
func (c *newScreenFramebufferImageCommand) NumElements() int {
return 0
}
func (c *newScreenFramebufferImageCommand) AddNumVertices(n int) { func (c *newScreenFramebufferImageCommand) AddNumVertices(n int) {
} }
func (c *newScreenFramebufferImageCommand) AddNumElements(n int) {
}
func (c *newScreenFramebufferImageCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) bool { func (c *newScreenFramebufferImageCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) bool {
return false return false
} }

View File

@ -131,7 +131,7 @@ var (
) )
const ( const (
indicesNum = 1 << 16 indicesNum = (1 << 16) / 3 * 3 // Adjust num for triangles.
maxTriangles = indicesNum / 3 maxTriangles = indicesNum / 3
maxQuads = maxTriangles / 2 maxQuads = maxTriangles / 2
) )