graphics: Calculate vertices ahead of locking

This commit is contained in:
Hajime Hoshi 2016-04-08 03:18:52 +09:00
parent 492f471ec3
commit b2c5cb164a
5 changed files with 34 additions and 41 deletions

View File

@ -88,15 +88,8 @@ func (i *Image) fill(clr color.Color) (err error) {
// Be careful that this method is potentially slow. // Be careful that this method is potentially slow.
// It would be better if you could call this method fewer times. // It would be better if you could call this method fewer times.
func (i *Image) DrawImage(image *Image, options *DrawImageOptions) (err error) { func (i *Image) DrawImage(image *Image, options *DrawImageOptions) (err error) {
imageM.Lock() // Calculate vertices before locking because the user can do anything in
defer imageM.Unlock() // options.ImageParts interface without deadlock (e.g. Call Image functions).
if i.isDisposed() {
return errors.New("ebiten: image is already disposed")
}
if i == image {
return errors.New("ebiten: Image.DrawImage: image should be different from the receiver")
}
i.pixels = nil
if options == nil { if options == nil {
options = &DrawImageOptions{} options = &DrawImageOptions{}
} }
@ -111,8 +104,24 @@ func (i *Image) DrawImage(image *Image, options *DrawImageOptions) (err error) {
} }
} }
quads := &textureQuads{parts: parts, width: image.width, height: image.height} quads := &textureQuads{parts: parts, width: image.width, height: image.height}
// TODO: Reuse one vertices instead of making here, but this would need locking.
vertices := make([]int16, 16*graphics.MaxQuads)
n := quads.vertices(vertices)
if n == 0 {
return nil
}
imageM.Lock()
defer imageM.Unlock()
if i.isDisposed() {
return errors.New("ebiten: image is already disposed")
}
if i == image {
return errors.New("ebiten: Image.DrawImage: image should be different from the receiver")
}
i.pixels = nil
m := opengl.CompositeMode(options.CompositeMode) m := opengl.CompositeMode(options.CompositeMode)
return i.framebuffer.DrawTexture(glContext, image.texture, quads, &options.GeoM, &options.ColorM, m) return i.framebuffer.DrawTexture(glContext, image.texture, vertices[:16*n], &options.GeoM, &options.ColorM, m)
} }
// Bounds returns the bounds of the image. // Bounds returns the bounds of the image.

View File

@ -88,12 +88,8 @@ type textureQuads struct {
height int height int
} }
func (t *textureQuads) Len() int { func (t *textureQuads) vertices(vertices []int16) int {
return t.parts.Len() l := t.parts.Len()
}
func (t *textureQuads) SetVertices(vertices []int16) int {
l := t.Len()
if len(vertices) < l*16 { if len(vertices) < l*16 {
panic(fmt.Sprintf("graphics: vertices size must be greater than %d but %d", l*16, len(vertices))) panic(fmt.Sprintf("graphics: vertices size must be greater than %d but %d", l*16, len(vertices)))
} }

View File

@ -33,11 +33,9 @@ type Matrix interface {
Element(i, j int) float64 Element(i, j int) float64
} }
var vertices = make([]int16, 16*quadsMaxNum)
var shadersInitialized = false var shadersInitialized = false
func drawTexture(c *opengl.Context, texture opengl.Texture, projectionMatrix *[4][4]float64, quads TextureQuads, geo Matrix, color Matrix, mode opengl.CompositeMode) error { func drawTexture(c *opengl.Context, texture opengl.Texture, projectionMatrix *[4][4]float64, vertices []int16, geo Matrix, color Matrix, mode opengl.CompositeMode) error {
c.BlendFunc(mode) c.BlendFunc(mode)
// 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.
@ -50,12 +48,12 @@ func drawTexture(c *opengl.Context, texture opengl.Texture, projectionMatrix *[4
shadersInitialized = true shadersInitialized = true
} }
l := quads.Len() n := len(vertices) / 16
if l == 0 { if n == 0 {
return nil return nil
} }
if quadsMaxNum < l { if MaxQuads < n/16 {
return errors.New(fmt.Sprintf("len(quads) must be equal to or less than %d", quadsMaxNum)) return errors.New(fmt.Sprintf("len(quads) must be equal to or less than %d", MaxQuads))
} }
p := programContext{ p := programContext{
@ -66,10 +64,6 @@ func drawTexture(c *opengl.Context, texture opengl.Texture, projectionMatrix *[4
geoM: geo, geoM: geo,
colorM: color, colorM: color,
} }
n := quads.SetVertices(vertices)
if n == 0 {
return nil
}
p.begin() p.begin()
defer p.end() defer p.end()
c.BufferSubData(c.ArrayBuffer, vertices[:16*n]) c.BufferSubData(c.ArrayBuffer, vertices[:16*n])

View File

@ -21,11 +21,6 @@ import (
"github.com/hajimehoshi/ebiten/internal/graphics/opengl" "github.com/hajimehoshi/ebiten/internal/graphics/opengl"
) )
type TextureQuads interface {
Len() int
SetVertices(vertices []int16) int
}
func orthoProjectionMatrix(left, right, bottom, top int) *[4][4]float64 { func orthoProjectionMatrix(left, right, bottom, top int) *[4][4]float64 {
e11 := float64(2) / float64(right-left) e11 := float64(2) / float64(right-left)
e22 := float64(2) / float64(top-bottom) e22 := float64(2) / float64(top-bottom)
@ -116,12 +111,12 @@ func (f *Framebuffer) Fill(c *opengl.Context, clr color.Color) error {
return c.FillFramebuffer(r, g, b, a) return c.FillFramebuffer(r, g, b, a)
} }
func (f *Framebuffer) DrawTexture(c *opengl.Context, t *Texture, quads TextureQuads, geo, clr Matrix, mode opengl.CompositeMode) error { func (f *Framebuffer) DrawTexture(c *opengl.Context, t *Texture, vertices []int16, geo, clr Matrix, mode opengl.CompositeMode) error {
if err := f.setAsViewport(c); err != nil { if err := f.setAsViewport(c); err != nil {
return err return err
} }
p := f.projectionMatrix() p := f.projectionMatrix()
return drawTexture(c, t.native, p, quads, geo, clr, mode) return drawTexture(c, t.native, p, vertices, geo, clr, mode)
} }
func (f *Framebuffer) Pixels(c *opengl.Context) ([]uint8, error) { func (f *Framebuffer) Pixels(c *opengl.Context) ([]uint8, error) {

View File

@ -16,7 +16,6 @@ package graphics
import ( import (
"github.com/hajimehoshi/ebiten/internal/graphics/opengl" "github.com/hajimehoshi/ebiten/internal/graphics/opengl"
"math"
) )
var ( var (
@ -28,8 +27,8 @@ var (
programTexture opengl.Program programTexture opengl.Program
) )
const indicesNum = math.MaxUint16 + 1 const indicesNum = 1 << 16
const quadsMaxNum = indicesNum / 6 const MaxQuads = indicesNum / 6
// unsafe.SizeOf can't be used because unsafe doesn't work with GopherJS. // unsafe.SizeOf can't be used because unsafe doesn't work with GopherJS.
const int16Size = 2 const int16Size = 2
@ -56,12 +55,12 @@ func initialize(c *opengl.Context) error {
return err return err
} }
// 16 [bytse] is an arbitrary number which seems enough to draw anything. Fix this if necessary. // 16 [bytes] is an arbitrary number which seems enough to draw anything. Fix this if necessary.
const stride = 16 const stride = 16
c.NewBuffer(c.ArrayBuffer, 4*stride*quadsMaxNum, c.DynamicDraw) c.NewBuffer(c.ArrayBuffer, 4*stride*MaxQuads, c.DynamicDraw)
indices := make([]uint16, 6*quadsMaxNum) indices := make([]uint16, 6*MaxQuads)
for i := uint16(0); i < quadsMaxNum; i++ { for i := uint16(0); i < MaxQuads; i++ {
indices[6*i+0] = 4*i + 0 indices[6*i+0] = 4*i + 0
indices[6*i+1] = 4*i + 1 indices[6*i+1] = 4*i + 1
indices[6*i+2] = 4*i + 2 indices[6*i+2] = 4*i + 2