zworld/engine/renderapi/material/material.go

129 lines
2.9 KiB
Go
Raw Permalink Normal View History

2024-01-14 22:56:06 +08:00
package material
import (
"fmt"
"log"
"zworld/engine/renderapi/command"
"zworld/engine/renderapi/descriptor"
"zworld/engine/renderapi/device"
"zworld/engine/renderapi/pipeline"
"zworld/engine/renderapi/renderpass"
"zworld/engine/renderapi/shader"
"zworld/engine/renderapi/texture"
"zworld/engine/renderapi/vertex"
"zworld/engine/util"
"github.com/vkngwrapper/core/v2/core1_0"
)
// Materials combine pipelines and descriptors into a common unit.
type Material[D descriptor.Set] struct {
device device.T
dlayout descriptor.SetLayoutTyped[D]
shader shader.T
layout pipeline.Layout
pipe pipeline.T
pass renderpass.T
}
type Args struct {
Shader shader.T
Pass renderpass.T
Subpass renderpass.Name
Constants []pipeline.PushConstant
Pointers vertex.Pointers
Primitive vertex.Primitive
DepthTest bool
DepthWrite bool
DepthClamp bool
DepthBias float32
DepthSlope float32
DepthFunc core1_0.CompareOp
CullMode vertex.CullMode
}
func New[D descriptor.Set](device device.T, args Args, descriptors D) *Material[D] {
if device == nil {
panic("device is nil")
}
if args.Shader == nil {
panic("shader is nil")
}
for i, ptr := range args.Pointers {
if index, kind, exists := args.Shader.Input(ptr.Name); exists {
ptr.Bind(index, kind)
args.Pointers[i] = ptr
} else {
log.Printf("no attribute in shader %s\n", ptr.Name)
}
}
if args.Primitive == 0 {
args.Primitive = vertex.Triangles
}
// create new descriptor set layout
// ... this could be cached ...
descLayout := descriptor.New(device, descriptors, args.Shader)
// crete pipeline layout
// ... this could be cached ...
layout := pipeline.NewLayout(device, []descriptor.SetLayout{descLayout}, args.Constants)
pipelineName := fmt.Sprintf("%s/%s", args.Pass.Name(), args.Shader.Name())
pipe := pipeline.New(device, pipeline.Args{
Key: pipelineName,
Layout: layout,
Pass: args.Pass,
Subpass: args.Subpass,
Shader: args.Shader,
Pointers: args.Pointers,
Primitive: args.Primitive,
DepthTest: args.DepthTest,
DepthWrite: args.DepthWrite,
DepthClamp: args.DepthClamp,
DepthFunc: args.DepthFunc,
CullMode: args.CullMode,
})
return &Material[D]{
device: device,
shader: args.Shader,
dlayout: descLayout,
layout: layout,
pipe: pipe,
pass: args.Pass,
}
}
func (m *Material[D]) Bind(cmd command.Buffer) {
cmd.CmdBindGraphicsPipeline(m.pipe)
}
func (m *Material[D]) TextureSlots() []texture.Slot {
return m.shader.Textures()
}
func (m *Material[D]) Destroy() {
m.dlayout.Destroy()
m.pipe.Destroy()
m.layout.Destroy()
}
func (m *Material[D]) Instantiate(pool descriptor.Pool) *Instance[D] {
set := m.dlayout.Instantiate(pool)
return &Instance[D]{
material: m,
set: set,
}
}
func (m *Material[D]) InstantiateMany(pool descriptor.Pool, n int) []*Instance[D] {
return util.Map(util.Range(0, n, 1), func(i int) *Instance[D] { return m.Instantiate(pool) })
}