186 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			186 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								package graph
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import (
							 | 
						||
| 
								 | 
							
									"fmt"
							 | 
						||
| 
								 | 
							
									"github.com/vkngwrapper/core/v2/core1_0"
							 | 
						||
| 
								 | 
							
									"zworld/engine/object"
							 | 
						||
| 
								 | 
							
									"zworld/engine/renderapi"
							 | 
						||
| 
								 | 
							
									"zworld/engine/renderapi/command"
							 | 
						||
| 
								 | 
							
									"zworld/engine/renderapi/sync"
							 | 
						||
| 
								 | 
							
									"zworld/engine/renderapi/vulkan"
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type NodePass interface {
							 | 
						||
| 
								 | 
							
									Name() string
							 | 
						||
| 
								 | 
							
									Record(command.Recorder, renderapi.Args, object.Component)
							 | 
						||
| 
								 | 
							
									Destroy()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type Node interface {
							 | 
						||
| 
								 | 
							
									After(nd Node, mask core1_0.PipelineStageFlags)
							 | 
						||
| 
								 | 
							
									Before(nd Node, mask core1_0.PipelineStageFlags, signal []sync.Semaphore)
							 | 
						||
| 
								 | 
							
									Requires() []Node
							 | 
						||
| 
								 | 
							
									Dependants() []Node
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									Name() string
							 | 
						||
| 
								 | 
							
									Draw(command.Worker, renderapi.Args, object.Component)
							 | 
						||
| 
								 | 
							
									Detach(Node)
							 | 
						||
| 
								 | 
							
									Destroy()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type node struct {
							 | 
						||
| 
								 | 
							
									name       string
							 | 
						||
| 
								 | 
							
									app        vulkan.App
							 | 
						||
| 
								 | 
							
									pass       NodePass
							 | 
						||
| 
								 | 
							
									after      map[string]edge
							 | 
						||
| 
								 | 
							
									before     map[string]edge
							 | 
						||
| 
								 | 
							
									requires   []Node
							 | 
						||
| 
								 | 
							
									dependants []Node
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type edge struct {
							 | 
						||
| 
								 | 
							
									node   Node
							 | 
						||
| 
								 | 
							
									mask   core1_0.PipelineStageFlags
							 | 
						||
| 
								 | 
							
									signal []sync.Semaphore
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func newNode(app vulkan.App, name string, pass NodePass) *node {
							 | 
						||
| 
								 | 
							
									return &node{
							 | 
						||
| 
								 | 
							
										app:        app,
							 | 
						||
| 
								 | 
							
										name:       name,
							 | 
						||
| 
								 | 
							
										pass:       pass,
							 | 
						||
| 
								 | 
							
										after:      make(map[string]edge, 4),
							 | 
						||
| 
								 | 
							
										before:     make(map[string]edge, 4),
							 | 
						||
| 
								 | 
							
										requires:   make([]Node, 0, 4),
							 | 
						||
| 
								 | 
							
										dependants: make([]Node, 0, 4),
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (n *node) Requires() []Node   { return n.requires }
							 | 
						||
| 
								 | 
							
								func (n *node) Dependants() []Node { return n.dependants }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (n *node) After(nd Node, mask core1_0.PipelineStageFlags) {
							 | 
						||
| 
								 | 
							
									if _, exists := n.after[nd.Name()]; exists {
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									signal := sync.NewSemaphoreArray(n.app.Device(), fmt.Sprintf("%s->%s", nd.Name(), n.name), 3)
							 | 
						||
| 
								 | 
							
									n.after[nd.Name()] = edge{
							 | 
						||
| 
								 | 
							
										node:   nd,
							 | 
						||
| 
								 | 
							
										mask:   mask,
							 | 
						||
| 
								 | 
							
										signal: signal,
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									nd.Before(n, mask, signal)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									n.refresh()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (n *node) Before(nd Node, mask core1_0.PipelineStageFlags, signal []sync.Semaphore) {
							 | 
						||
| 
								 | 
							
									if _, exists := n.before[nd.Name()]; exists {
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									n.before[nd.Name()] = edge{
							 | 
						||
| 
								 | 
							
										node:   nd,
							 | 
						||
| 
								 | 
							
										mask:   mask,
							 | 
						||
| 
								 | 
							
										signal: signal,
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									nd.After(n, mask)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									n.refresh()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (n *node) refresh() {
							 | 
						||
| 
								 | 
							
									// recompute signals
							 | 
						||
| 
								 | 
							
									n.dependants = make([]Node, 0, len(n.after))
							 | 
						||
| 
								 | 
							
									for _, edge := range n.before {
							 | 
						||
| 
								 | 
							
										n.dependants = append(n.dependants, edge.node)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// recompute waits
							 | 
						||
| 
								 | 
							
									n.requires = make([]Node, 0, len(n.after))
							 | 
						||
| 
								 | 
							
									for _, edge := range n.after {
							 | 
						||
| 
								 | 
							
										if edge.signal == nil {
							 | 
						||
| 
								 | 
							
											// skip nil signals
							 | 
						||
| 
								 | 
							
											continue
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										n.requires = append(n.requires, edge.node)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (n *node) Detach(nd Node) {
							 | 
						||
| 
								 | 
							
									if _, exists := n.before[nd.Name()]; exists {
							 | 
						||
| 
								 | 
							
										delete(n.before, nd.Name())
							 | 
						||
| 
								 | 
							
										nd.Detach(n)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if edge, exists := n.after[nd.Name()]; exists {
							 | 
						||
| 
								 | 
							
										delete(n.after, nd.Name())
							 | 
						||
| 
								 | 
							
										nd.Detach(n)
							 | 
						||
| 
								 | 
							
										// free semaphores
							 | 
						||
| 
								 | 
							
										for _, signal := range edge.signal {
							 | 
						||
| 
								 | 
							
											signal.Destroy()
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									n.refresh()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (n *node) Name() string {
							 | 
						||
| 
								 | 
							
									return n.name
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (n *node) Destroy() {
							 | 
						||
| 
								 | 
							
									for _, edge := range n.before {
							 | 
						||
| 
								 | 
							
										before := edge.node
							 | 
						||
| 
								 | 
							
										before.Detach(n)
							 | 
						||
| 
								 | 
							
										for _, s := range edge.signal {
							 | 
						||
| 
								 | 
							
											s.Destroy()
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									for _, edge := range n.after {
							 | 
						||
| 
								 | 
							
										after := edge.node
							 | 
						||
| 
								 | 
							
										after.Detach(n)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if n.pass != nil {
							 | 
						||
| 
								 | 
							
										n.pass.Destroy()
							 | 
						||
| 
								 | 
							
										n.pass = nil
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									n.before = nil
							 | 
						||
| 
								 | 
							
									n.after = nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (n *node) waits(index int) []command.Wait {
							 | 
						||
| 
								 | 
							
									waits := make([]command.Wait, 0, len(n.after))
							 | 
						||
| 
								 | 
							
									for _, after := range n.after {
							 | 
						||
| 
								 | 
							
										if after.signal == nil {
							 | 
						||
| 
								 | 
							
											// skip nil signals
							 | 
						||
| 
								 | 
							
											continue
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										waits = append(waits, command.Wait{
							 | 
						||
| 
								 | 
							
											Semaphore: after.signal[index],
							 | 
						||
| 
								 | 
							
											Mask:      after.mask,
							 | 
						||
| 
								 | 
							
										})
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return waits
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (n *node) signals(index int) []sync.Semaphore {
							 | 
						||
| 
								 | 
							
									signals := make([]sync.Semaphore, 0, len(n.before))
							 | 
						||
| 
								 | 
							
									for _, edge := range n.before {
							 | 
						||
| 
								 | 
							
										signals = append(signals, edge.signal[index])
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return signals
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (n *node) Draw(worker command.Worker, args renderapi.Args, scene object.Component) {
							 | 
						||
| 
								 | 
							
									if n.pass == nil {
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									cmds := command.NewRecorder()
							 | 
						||
| 
								 | 
							
									n.pass.Record(cmds, args, scene)
							 | 
						||
| 
								 | 
							
									worker.Queue(cmds.Apply)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									worker.Submit(command.SubmitInfo{
							 | 
						||
| 
								 | 
							
										Marker: n.pass.Name(),
							 | 
						||
| 
								 | 
							
										Wait:   n.waits(args.Frame),
							 | 
						||
| 
								 | 
							
										Signal: n.signals(args.Frame),
							 | 
						||
| 
								 | 
							
									})
							 | 
						||
| 
								 | 
							
								}
							 |