package framebuffer import ( "zworld/engine/renderapi/device" "zworld/engine/renderapi/image" "zworld/engine/renderapi/renderpass" "zworld/engine/renderapi/renderpass/attachment" "zworld/engine/renderapi/vkerror" "zworld/engine/util" "github.com/vkngwrapper/core/v2/core1_0" "github.com/vkngwrapper/core/v2/driver" ) type T interface { device.Resource[core1_0.Framebuffer] Attachment(attachment.Name) image.View Size() (int, int) } type framebuf struct { ptr core1_0.Framebuffer device device.T name string attachments map[attachment.Name]image.View views []image.View images []image.T width int height int } func New(device device.T, name string, width, height int, pass renderpass.T) (T, error) { attachments := pass.Attachments() depth := pass.Depth() images := make([]image.T, 0, len(attachments)+1) views := make([]image.View, 0, len(attachments)+1) attachs := make(map[attachment.Name]image.View) cleanup := func() { // clean up the mess we've made so far for _, view := range views { view.Destroy() } for _, image := range images { image.Destroy() } } allocate := func(attach attachment.T, aspect core1_0.ImageAspectFlags) error { img, ownership, err := attach.Image().Next( device, name, width, height, ) if err != nil { return err } if ownership { // the framebuffer is responsible for deallocating the image images = append(images, img) } view, err := img.View(img.Format(), core1_0.ImageAspectFlags(aspect)) if err != nil { return err } views = append(views, view) attachs[attach.Name()] = view return nil } for _, attach := range attachments { if err := allocate(attach, core1_0.ImageAspectColor); err != nil { cleanup() return nil, err } } if depth != nil { if err := allocate(depth, core1_0.ImageAspectDepth); err != nil { cleanup() return nil, err } } info := core1_0.FramebufferCreateInfo{ RenderPass: pass.Ptr(), Attachments: util.Map(views, func(v image.View) core1_0.ImageView { return v.Ptr() }), Width: width, Height: height, Layers: 1, } var ptr core1_0.Framebuffer ptr, result, err := device.Ptr().CreateFramebuffer(nil, info) if err != nil { panic(err) } if result != core1_0.VKSuccess { cleanup() return nil, vkerror.FromResult(result) } device.SetDebugObjectName(driver.VulkanHandle(ptr.Handle()), core1_0.ObjectTypeFramebuffer, name) return &framebuf{ ptr: ptr, device: device, name: name, width: width, height: height, images: images, views: views, attachments: attachs, }, nil } func (b *framebuf) Ptr() core1_0.Framebuffer { return b.ptr } func (b *framebuf) Size() (int, int) { return b.width, b.height } func (b *framebuf) Attachment(name attachment.Name) image.View { return b.attachments[name] } func (b *framebuf) Destroy() { if b.ptr == nil { panic("framebuffer already destroyed") } for _, image := range b.images { image.Destroy() } b.images = nil for _, view := range b.views { view.Destroy() } b.views = nil b.attachments = nil b.ptr.Destroy(nil) b.ptr = nil b.device = nil }