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.
// It would be better if you could call this method fewer times.
func (i *Image) DrawImage(image *Image, options *DrawImageOptions) (err error) {
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
// Calculate vertices before locking because the user can do anything in
// options.ImageParts interface without deadlock (e.g. Call Image functions).
if options == nil {
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}
// 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)
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.

View File

@ -88,12 +88,8 @@ type textureQuads struct {
height int
}
func (t *textureQuads) Len() int {
return t.parts.Len()
}
func (t *textureQuads) SetVertices(vertices []int16) int {
l := t.Len()
func (t *textureQuads) vertices(vertices []int16) int {
l := t.parts.Len()
if len(vertices) < l*16 {
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
}
var vertices = make([]int16, 16*quadsMaxNum)
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)
// 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
}
l := quads.Len()
if l == 0 {
n := len(vertices) / 16
if n == 0 {
return nil
}
if quadsMaxNum < l {
return errors.New(fmt.Sprintf("len(quads) must be equal to or less than %d", quadsMaxNum))
if MaxQuads < n/16 {
return errors.New(fmt.Sprintf("len(quads) must be equal to or less than %d", MaxQuads))
}
p := programContext{
@ -66,10 +64,6 @@ func drawTexture(c *opengl.Context, texture opengl.Texture, projectionMatrix *[4
geoM: geo,
colorM: color,
}
n := quads.SetVertices(vertices)
if n == 0 {
return nil
}
p.begin()
defer p.end()
c.BufferSubData(c.ArrayBuffer, vertices[:16*n])

View File

@ -21,11 +21,6 @@ import (
"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 {
e11 := float64(2) / float64(right-left)
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)
}
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 {
return err
}
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) {

View File

@ -16,7 +16,6 @@ package graphics
import (
"github.com/hajimehoshi/ebiten/internal/graphics/opengl"
"math"
)
var (
@ -28,8 +27,8 @@ var (
programTexture opengl.Program
)
const indicesNum = math.MaxUint16 + 1
const quadsMaxNum = indicesNum / 6
const indicesNum = 1 << 16
const MaxQuads = indicesNum / 6
// unsafe.SizeOf can't be used because unsafe doesn't work with GopherJS.
const int16Size = 2
@ -56,12 +55,12 @@ func initialize(c *opengl.Context) error {
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
c.NewBuffer(c.ArrayBuffer, 4*stride*quadsMaxNum, c.DynamicDraw)
c.NewBuffer(c.ArrayBuffer, 4*stride*MaxQuads, c.DynamicDraw)
indices := make([]uint16, 6*quadsMaxNum)
for i := uint16(0); i < quadsMaxNum; i++ {
indices := make([]uint16, 6*MaxQuads)
for i := uint16(0); i < MaxQuads; i++ {
indices[6*i+0] = 4*i + 0
indices[6*i+1] = 4*i + 1
indices[6*i+2] = 4*i + 2