zorldo

Goofing around with Ebiten
git clone git://bsandro.tech/zorldo
Log | Files | Refs | README

command.go (2497B)


      1 // Copyright 2019 The Ebiten Authors
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 package buffered
     16 
     17 import (
     18 	"sync"
     19 	"sync/atomic"
     20 )
     21 
     22 var (
     23 	// delayedCommands represents a queue for image operations that are ordered before the game starts
     24 	// (BeginFrame). Before the game starts, the package shareable doesn't determine the minimum/maximum texture
     25 	// sizes (#879).
     26 	delayedCommands = []func() error{}
     27 
     28 	delayedCommandsM       sync.Mutex
     29 	delayedCommandsFlushed uint32
     30 )
     31 
     32 func flushDelayedCommands() error {
     33 	fs := getDelayedFuncsAndClear()
     34 	for _, f := range fs {
     35 		if err := f(); err != nil {
     36 			return err
     37 		}
     38 	}
     39 	return nil
     40 
     41 }
     42 
     43 func getDelayedFuncsAndClear() []func() error {
     44 	if atomic.LoadUint32(&delayedCommandsFlushed) == 0 {
     45 		// Outline the slow-path to expect the fast-path is inlined.
     46 		return getDelayedFuncsAndClearSlow()
     47 	}
     48 	return nil
     49 }
     50 
     51 func getDelayedFuncsAndClearSlow() []func() error {
     52 	delayedCommandsM.Lock()
     53 	defer delayedCommandsM.Unlock()
     54 
     55 	if delayedCommandsFlushed == 0 {
     56 		defer atomic.StoreUint32(&delayedCommandsFlushed, 1)
     57 
     58 		fs := make([]func() error, len(delayedCommands))
     59 		copy(fs, delayedCommands)
     60 		delayedCommands = nil
     61 		return fs
     62 	}
     63 
     64 	return nil
     65 }
     66 
     67 // maybeCanAddDelayedCommand returns false if the delayed commands cannot be added.
     68 // Otherwise, maybeCanAddDelayedCommand's returning value is not determined.
     69 // For example, maybeCanAddDelayedCommand can return true even when flusing is being processed.
     70 func maybeCanAddDelayedCommand() bool {
     71 	return atomic.LoadUint32(&delayedCommandsFlushed) == 0
     72 }
     73 
     74 func tryAddDelayedCommand(f func() error) bool {
     75 	delayedCommandsM.Lock()
     76 	defer delayedCommandsM.Unlock()
     77 
     78 	if delayedCommandsFlushed == 0 {
     79 		delayedCommands = append(delayedCommands, func() error {
     80 			return f()
     81 		})
     82 		return true
     83 	}
     84 
     85 	return false
     86 }
     87 
     88 func checkDelayedCommandsFlushed(fname string) {
     89 	if atomic.LoadUint32(&delayedCommandsFlushed) == 0 {
     90 		panic("buffered: the command queue is not available yet at " + fname)
     91 	}
     92 }