zworld/engine/renderapi/renderpass/renderpass.go
2024-01-14 22:56:06 +08:00

201 lines
5.5 KiB
Go

package renderpass
import (
"fmt"
"log"
"zworld/engine/renderapi/device"
"zworld/engine/renderapi/renderpass/attachment"
"zworld/engine/util"
"github.com/vkngwrapper/core/v2/core1_0"
"github.com/vkngwrapper/core/v2/driver"
)
type T interface {
device.Resource[core1_0.RenderPass]
Depth() attachment.T
Attachment(name attachment.Name) attachment.T
Attachments() []attachment.T
Subpass(name Name) Subpass
Clear() []core1_0.ClearValue
Name() string
}
type renderpass struct {
device device.T
ptr core1_0.RenderPass
subpasses []Subpass
passIndices map[Name]int
attachments []attachment.T
depth attachment.T
indices map[attachment.Name]int
clear []core1_0.ClearValue
name string
}
func New(device device.T, args Args) T {
clear := make([]core1_0.ClearValue, 0, len(args.ColorAttachments)+1)
attachments := make([]attachment.T, len(args.ColorAttachments))
attachmentIndices := make(map[attachment.Name]int)
log.Println("create renderpass", args.Name)
log.Println("attachments")
for index, desc := range args.ColorAttachments {
attachment := attachment.NewColor(device, desc)
clear = append(clear, attachment.Clear())
attachments[index] = attachment
attachmentIndices[attachment.Name()] = index
log.Printf(" %d: %s", index, desc.Name)
}
var depth attachment.T
if args.DepthAttachment != nil {
index := len(attachments)
attachmentIndices[attachment.DepthName] = index
depth = attachment.NewDepth(device, *args.DepthAttachment)
clear = append(clear, depth.Clear())
log.Printf(" %d: %s", index, attachment.DepthName)
}
descriptions := make([]core1_0.AttachmentDescription, 0, len(args.ColorAttachments)+1)
for _, attachment := range attachments {
descriptions = append(descriptions, attachment.Description())
}
if depth != nil {
descriptions = append(descriptions, depth.Description())
}
subpasses := make([]core1_0.SubpassDescription, 0, len(args.Subpasses))
subpassIndices := make(map[Name]int)
for idx, subpass := range args.Subpasses {
log.Println("subpass", idx)
var depthRef *core1_0.AttachmentReference
if depth != nil && subpass.Depth {
idx := attachmentIndices[attachment.DepthName]
depthRef = &core1_0.AttachmentReference{
Attachment: idx,
Layout: core1_0.ImageLayoutDepthStencilAttachmentOptimal,
}
log.Printf(" depth -> %s (%d)\n", attachment.DepthName, idx)
}
subpasses = append(subpasses, core1_0.SubpassDescription{
PipelineBindPoint: core1_0.PipelineBindPointGraphics,
ColorAttachments: util.MapIdx(
subpass.ColorAttachments,
func(name attachment.Name, i int) core1_0.AttachmentReference {
idx := attachmentIndices[name]
log.Printf(" color %d -> %s (%d)\n", i, name, idx)
return core1_0.AttachmentReference{
Attachment: idx,
Layout: core1_0.ImageLayoutColorAttachmentOptimal,
}
}),
InputAttachments: util.MapIdx(
subpass.InputAttachments,
func(name attachment.Name, i int) core1_0.AttachmentReference {
idx := attachmentIndices[name]
log.Printf(" input %d -> %s (%d)\n", i, name, idx)
return core1_0.AttachmentReference{
Attachment: idx,
Layout: core1_0.ImageLayoutShaderReadOnlyOptimal,
}
}),
DepthStencilAttachment: depthRef,
})
subpassIndices[subpass.Name] = idx
args.Subpasses[idx].index = idx
}
dependencies := make([]core1_0.SubpassDependency, len(args.Dependencies))
for idx, dependency := range args.Dependencies {
src := core1_0.SubpassExternal
if dependency.Src != ExternalSubpass {
src = subpassIndices[dependency.Src]
}
dst := core1_0.SubpassExternal
if dependency.Dst != ExternalSubpass {
dst = subpassIndices[dependency.Dst]
}
dependencies[idx] = core1_0.SubpassDependency{
SrcSubpass: src,
DstSubpass: dst,
SrcStageMask: core1_0.PipelineStageFlags(dependency.SrcStageMask),
SrcAccessMask: core1_0.AccessFlags(dependency.SrcAccessMask),
DstStageMask: core1_0.PipelineStageFlags(dependency.DstStageMask),
DstAccessMask: core1_0.AccessFlags(dependency.DstAccessMask),
DependencyFlags: core1_0.DependencyFlags(dependency.Flags),
}
}
ptr, _, err := device.Ptr().CreateRenderPass(nil, core1_0.RenderPassCreateInfo{
Attachments: descriptions,
Subpasses: subpasses,
SubpassDependencies: dependencies,
})
if err != nil {
panic(err)
}
// set object name
device.SetDebugObjectName(driver.VulkanHandle(ptr.Handle()), core1_0.ObjectTypeRenderPass, args.Name)
return &renderpass{
device: device,
ptr: ptr,
depth: depth,
indices: attachmentIndices,
attachments: attachments,
passIndices: subpassIndices,
subpasses: args.Subpasses,
clear: clear,
name: args.Name,
}
}
func (r *renderpass) Ptr() core1_0.RenderPass { return r.ptr }
func (r *renderpass) Depth() attachment.T { return r.depth }
func (r *renderpass) Name() string { return r.name }
func (r *renderpass) Attachment(name attachment.Name) attachment.T {
if name == attachment.DepthName {
return r.depth
}
index := r.indices[name]
return r.attachments[index]
}
func (r *renderpass) Clear() []core1_0.ClearValue {
return r.clear
}
func (r *renderpass) Attachments() []attachment.T {
return r.attachments
}
func (r *renderpass) Subpass(name Name) Subpass {
if name == "" {
return r.subpasses[0]
}
idx, exists := r.passIndices[name]
if !exists {
panic(fmt.Sprintf("unknown subpass %s", name))
}
return r.subpasses[idx]
}
func (r *renderpass) Destroy() {
if r.ptr != nil {
r.ptr.Destroy(nil)
r.ptr = nil
}
}