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

175 lines
4.4 KiB
Go

package device
import (
"log"
"zworld/engine/renderapi/vulkan/instance"
"github.com/vkngwrapper/core/v2/core1_0"
"github.com/vkngwrapper/core/v2/driver"
"github.com/vkngwrapper/extensions/v2/ext_debug_utils"
)
type Resource[T any] interface {
Destroy()
Ptr() T
}
type T interface {
Resource[core1_0.Device]
Physical() core1_0.PhysicalDevice
Allocate(key string, req core1_0.MemoryRequirements, flags core1_0.MemoryPropertyFlags) Memory
GetQueue(queueIndex int, flags core1_0.QueueFlags) core1_0.Queue
GetQueueFamilyIndex(flags core1_0.QueueFlags) int
GetDepthFormat() core1_0.Format
GetMemoryTypeIndex(uint32, core1_0.MemoryPropertyFlags) int
GetLimits() *core1_0.PhysicalDeviceLimits
WaitIdle()
SetDebugObjectName(ptr driver.VulkanHandle, objType core1_0.ObjectType, name string)
}
type device struct {
physical core1_0.PhysicalDevice
ptr core1_0.Device
limits *core1_0.PhysicalDeviceLimits
debug ext_debug_utils.Extension
memtypes map[memtype]int
queues map[core1_0.QueueFlags]int
}
func New(instance instance.T, physDevice core1_0.PhysicalDevice) (T, error) {
log.Println("creating device with extensions", deviceExtensions)
families := physDevice.QueueFamilyProperties()
log.Println("Queue families:", len(families))
for index, family := range families {
log.Printf(" [%d,%d]: %d\n", index, family.QueueCount, family.QueueFlags)
}
dev, _, err := physDevice.CreateDevice(nil, core1_0.DeviceCreateInfo{
NextOptions: _NextOptions(),
EnabledExtensionNames: _DeviceExtension(),
QueueCreateInfos: _QueueCreateInfos(families),
EnabledFeatures: _EnabledFeatures(),
})
if err != nil {
return nil, err
}
properties, err := physDevice.Properties()
if err != nil {
return nil, err
}
log.Println("minimum uniform buffer alignment:", properties.Limits.MinUniformBufferOffsetAlignment)
log.Println("minimum storage buffer alignment:", properties.Limits.MinStorageBufferOffsetAlignment)
debug := ext_debug_utils.CreateExtensionFromInstance(instance.Ptr())
return &device{
ptr: dev,
debug: debug,
physical: physDevice,
limits: properties.Limits,
memtypes: make(map[memtype]int),
queues: make(map[core1_0.QueueFlags]int),
}, nil
}
func (d *device) Ptr() core1_0.Device {
return d.ptr
}
func (d *device) Physical() core1_0.PhysicalDevice {
return d.physical
}
func (d *device) GetQueue(queueIndex int, flags core1_0.QueueFlags) core1_0.Queue {
return d.ptr.GetQueue(queueIndex, 0)
}
func (d *device) GetQueueFamilyIndex(flags core1_0.QueueFlags) int {
if q, ok := d.queues[flags]; ok {
return q
}
families := d.physical.QueueFamilyProperties()
for index, family := range families {
if family.QueueFlags&flags == flags {
d.queues[flags] = index
return index
}
}
panic("no such queue available")
}
func (d *device) GetDepthFormat() core1_0.Format {
depthFormats := []core1_0.Format{
core1_0.FormatD32SignedFloatS8UnsignedInt,
core1_0.FormatD32SignedFloat,
core1_0.FormatD24UnsignedNormalizedS8UnsignedInt,
core1_0.FormatD16UnsignedNormalizedS8UnsignedInt,
core1_0.FormatD16UnsignedNormalized,
}
for _, format := range depthFormats {
props := d.physical.FormatProperties(format)
if props.OptimalTilingFeatures&core1_0.FormatFeatureDepthStencilAttachment == core1_0.FormatFeatureDepthStencilAttachment {
return format
}
}
return depthFormats[0]
}
func (d *device) GetMemoryTypeIndex(typeBits uint32, flags core1_0.MemoryPropertyFlags) int {
mtype := memtype{typeBits, flags}
if t, ok := d.memtypes[mtype]; ok {
return t
}
props := d.physical.MemoryProperties()
for i, kind := range props.MemoryTypes {
if typeBits&1 == 1 {
if kind.PropertyFlags&flags == flags {
d.memtypes[mtype] = i
return i
}
}
typeBits >>= 1
}
d.memtypes[mtype] = 0
return 0
}
func (d *device) GetLimits() *core1_0.PhysicalDeviceLimits {
return d.limits
}
func (d *device) Allocate(key string, req core1_0.MemoryRequirements, flags core1_0.MemoryPropertyFlags) Memory {
if req.Size == 0 {
panic("allocating 0 bytes of memory")
}
return alloc(d, key, req, flags)
}
func (d *device) Destroy() {
d.ptr.Destroy(nil)
d.ptr = nil
}
func (d *device) WaitIdle() {
d.ptr.WaitIdle()
}
func (d *device) SetDebugObjectName(handle driver.VulkanHandle, objType core1_0.ObjectType, name string) {
d.debug.SetDebugUtilsObjectName(d.ptr, ext_debug_utils.DebugUtilsObjectNameInfo{
ObjectName: name,
ObjectHandle: handle,
ObjectType: objType,
})
}