mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 04:57:26 +01:00
internal/graphicscommand: introduce commandQueuePool and commandQueueManager
This removes the restriction of the number of command queues. Updates #1704
This commit is contained in:
parent
d2dd62b6db
commit
810b62f83e
@ -71,5 +71,5 @@ func (t *temporaryBytes) reset() {
|
|||||||
//
|
//
|
||||||
// Be careful that the returned pixels might not be zero-cleared.
|
// Be careful that the returned pixels might not be zero-cleared.
|
||||||
func AllocBytes(size int) []byte {
|
func AllocBytes(size int) []byte {
|
||||||
return currentCommandQueue().temporaryBytes.alloc(size)
|
return theCommandQueueManager.allocBytes(size)
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
"image"
|
"image"
|
||||||
"math"
|
"math"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/v2/internal/debug"
|
"github.com/hajimehoshi/ebiten/v2/internal/debug"
|
||||||
@ -81,24 +82,6 @@ type commandQueue struct {
|
|||||||
err atomic.Value
|
err atomic.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
// theCommandQueues is the set of command queues for the current process.
|
|
||||||
var (
|
|
||||||
theCommandQueues = [...]*commandQueue{
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
}
|
|
||||||
commandQueueIndex int
|
|
||||||
)
|
|
||||||
|
|
||||||
func currentCommandQueue() *commandQueue {
|
|
||||||
return theCommandQueues[commandQueueIndex]
|
|
||||||
}
|
|
||||||
|
|
||||||
func switchCommandQueue() {
|
|
||||||
commandQueueIndex++
|
|
||||||
commandQueueIndex = commandQueueIndex % len(theCommandQueues)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *commandQueue) appendIndices(indices []uint16, offset uint16) {
|
func (q *commandQueue) appendIndices(indices []uint16, offset uint16) {
|
||||||
n := len(q.indices)
|
n := len(q.indices)
|
||||||
q.indices = append(q.indices, indices...)
|
q.indices = append(q.indices, indices...)
|
||||||
@ -217,6 +200,8 @@ func (q *commandQueue) Flush(graphicsDriver graphicsdriver.Graphics, endFrame bo
|
|||||||
if endFrame && swapBuffersForGL != nil {
|
if endFrame && swapBuffersForGL != nil {
|
||||||
swapBuffersForGL()
|
swapBuffersForGL()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
theCommandQueueManager.putCommandQueue(q)
|
||||||
}, sync)
|
}, sync)
|
||||||
|
|
||||||
if sync && flushErr != nil {
|
if sync && flushErr != nil {
|
||||||
@ -312,9 +297,7 @@ func (q *commandQueue) flush(graphicsDriver graphicsdriver.Graphics, endFrame bo
|
|||||||
// If endFrame is true, the current screen might be used to present.
|
// If endFrame is true, the current screen might be used to present.
|
||||||
func FlushCommands(graphicsDriver graphicsdriver.Graphics, endFrame bool, swapBuffersForGL func()) error {
|
func FlushCommands(graphicsDriver graphicsdriver.Graphics, endFrame bool, swapBuffersForGL func()) error {
|
||||||
flushImageBuffers()
|
flushImageBuffers()
|
||||||
q := currentCommandQueue()
|
if err := theCommandQueueManager.flush(graphicsDriver, endFrame, swapBuffersForGL); err != nil {
|
||||||
switchCommandQueue()
|
|
||||||
if err := q.Flush(graphicsDriver, endFrame, swapBuffersForGL); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -651,6 +634,89 @@ func MaxImageSize(graphicsDriver graphicsdriver.Graphics) int {
|
|||||||
return size
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type commandQueuePool struct {
|
||||||
|
cache []*commandQueue
|
||||||
|
m sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *commandQueuePool) get() (*commandQueue, error) {
|
||||||
|
c.m.Lock()
|
||||||
|
defer c.m.Unlock()
|
||||||
|
|
||||||
|
if len(c.cache) == 0 {
|
||||||
|
return &commandQueue{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, q := range c.cache {
|
||||||
|
if err := q.err.Load(); err != nil {
|
||||||
|
return nil, err.(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
q := c.cache[len(c.cache)-1]
|
||||||
|
c.cache[len(c.cache)-1] = nil
|
||||||
|
c.cache = c.cache[:len(c.cache)-1]
|
||||||
|
return q, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *commandQueuePool) put(queue *commandQueue) {
|
||||||
|
c.m.Lock()
|
||||||
|
defer c.m.Unlock()
|
||||||
|
|
||||||
|
c.cache = append(c.cache, queue)
|
||||||
|
}
|
||||||
|
|
||||||
|
type commandQueueManager struct {
|
||||||
|
pool commandQueuePool
|
||||||
|
current *commandQueue
|
||||||
|
}
|
||||||
|
|
||||||
|
var theCommandQueueManager commandQueueManager
|
||||||
|
|
||||||
|
func (c *commandQueueManager) allocBytes(size int) []byte {
|
||||||
|
if c.current == nil {
|
||||||
|
c.current, _ = c.pool.get()
|
||||||
|
}
|
||||||
|
return c.current.temporaryBytes.alloc(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *commandQueueManager) enqueueCommand(command command) {
|
||||||
|
if c.current == nil {
|
||||||
|
c.current, _ = c.pool.get()
|
||||||
|
}
|
||||||
|
c.current.Enqueue(command)
|
||||||
|
}
|
||||||
|
|
||||||
|
// put can be called from any goroutines.
|
||||||
|
func (c *commandQueueManager) putCommandQueue(commandQueue *commandQueue) {
|
||||||
|
c.pool.put(commandQueue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *commandQueueManager) enqueueDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, evenOdd bool) {
|
||||||
|
if c.current == nil {
|
||||||
|
c.current, _ = c.pool.get()
|
||||||
|
}
|
||||||
|
c.current.EnqueueDrawTrianglesCommand(dst, srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, evenOdd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *commandQueueManager) flush(graphicsDriver graphicsdriver.Graphics, endFrame bool, swapBuffersForGL func()) error {
|
||||||
|
// Switch the command queue.
|
||||||
|
prev := c.current
|
||||||
|
q, err := c.pool.get()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.current = q
|
||||||
|
|
||||||
|
if prev == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err := prev.Flush(graphicsDriver, endFrame, swapBuffersForGL); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func max(a, b int) int {
|
func max(a, b int) int {
|
||||||
if a < b {
|
if a < b {
|
||||||
return b
|
return b
|
||||||
|
@ -88,7 +88,7 @@ func NewImage(width, height int, screenFramebuffer bool) *Image {
|
|||||||
height: height,
|
height: height,
|
||||||
screen: screenFramebuffer,
|
screen: screenFramebuffer,
|
||||||
}
|
}
|
||||||
currentCommandQueue().Enqueue(c)
|
theCommandQueueManager.enqueueCommand(c)
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ func (i *Image) flushBufferedWritePixels() {
|
|||||||
dst: i,
|
dst: i,
|
||||||
args: i.bufferedWritePixelsArgs,
|
args: i.bufferedWritePixelsArgs,
|
||||||
}
|
}
|
||||||
currentCommandQueue().Enqueue(c)
|
theCommandQueueManager.enqueueCommand(c)
|
||||||
|
|
||||||
i.bufferedWritePixelsArgs = nil
|
i.bufferedWritePixelsArgs = nil
|
||||||
}
|
}
|
||||||
@ -110,7 +110,7 @@ func (i *Image) Dispose() {
|
|||||||
c := &disposeImageCommand{
|
c := &disposeImageCommand{
|
||||||
target: i,
|
target: i,
|
||||||
}
|
}
|
||||||
currentCommandQueue().Enqueue(c)
|
theCommandQueueManager.enqueueCommand(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) InternalSize() (int, int) {
|
func (i *Image) InternalSize() (int, int) {
|
||||||
@ -159,7 +159,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [
|
|||||||
}
|
}
|
||||||
i.flushBufferedWritePixels()
|
i.flushBufferedWritePixels()
|
||||||
|
|
||||||
currentCommandQueue().EnqueueDrawTrianglesCommand(i, srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, evenOdd)
|
theCommandQueueManager.enqueueDrawTrianglesCommand(i, srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, evenOdd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadPixels reads the image's pixels.
|
// ReadPixels reads the image's pixels.
|
||||||
@ -170,8 +170,8 @@ func (i *Image) ReadPixels(graphicsDriver graphicsdriver.Graphics, args []graphi
|
|||||||
img: i,
|
img: i,
|
||||||
args: args,
|
args: args,
|
||||||
}
|
}
|
||||||
currentCommandQueue().Enqueue(c)
|
theCommandQueueManager.enqueueCommand(c)
|
||||||
if err := currentCommandQueue().Flush(graphicsDriver, false, nil); err != nil {
|
if err := theCommandQueueManager.flush(graphicsDriver, false, nil); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -200,8 +200,8 @@ func (i *Image) IsInvalidated(graphicsDriver graphicsdriver.Graphics) (bool, err
|
|||||||
c := &isInvalidatedCommand{
|
c := &isInvalidatedCommand{
|
||||||
image: i,
|
image: i,
|
||||||
}
|
}
|
||||||
currentCommandQueue().Enqueue(c)
|
theCommandQueueManager.enqueueCommand(c)
|
||||||
if err := currentCommandQueue().Flush(graphicsDriver, false, nil); err != nil {
|
if err := theCommandQueueManager.flush(graphicsDriver, false, nil); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
return c.result, nil
|
return c.result, nil
|
||||||
|
@ -32,7 +32,7 @@ func NewShader(ir *shaderir.Program) *Shader {
|
|||||||
result: s,
|
result: s,
|
||||||
ir: ir,
|
ir: ir,
|
||||||
}
|
}
|
||||||
currentCommandQueue().Enqueue(c)
|
theCommandQueueManager.enqueueCommand(c)
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ func (s *Shader) Dispose() {
|
|||||||
c := &disposeShaderCommand{
|
c := &disposeShaderCommand{
|
||||||
target: s,
|
target: s,
|
||||||
}
|
}
|
||||||
currentCommandQueue().Enqueue(c)
|
theCommandQueueManager.enqueueCommand(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Shader) unit() shaderir.Unit {
|
func (s *Shader) unit() shaderir.Unit {
|
||||||
|
Loading…
Reference in New Issue
Block a user