-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathdevice.go
140 lines (120 loc) · 3.91 KB
/
device.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// Copyright (c) 2022, Cogent Core. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package vgpu
import (
"errors"
"unsafe"
vk "github.com/goki/vulkan"
)
// Device holds Device and associated Queue info
type Device struct {
// logical device
Device vk.Device
// queue index for device
QueueIndex uint32
// queue for device
Queue vk.Queue
}
// Init initializes a device based on QueueFlagBits
func (dv *Device) Init(gp *GPU, flags vk.QueueFlagBits) error {
err := dv.FindQueue(gp, flags)
if err != nil {
return err
}
dv.MakeDevice(gp)
return nil
}
// FindQueue finds queue for given flag bits, sets in QueueIndex
// returns error if not found.
func (dv *Device) FindQueue(gp *GPU, flags vk.QueueFlagBits) error {
// Get queue family properties
var queueCount uint32
vk.GetPhysicalDeviceQueueFamilyProperties(gp.GPU, &queueCount, nil)
queueProperties := make([]vk.QueueFamilyProperties, queueCount)
vk.GetPhysicalDeviceQueueFamilyProperties(gp.GPU, &queueCount, queueProperties)
if queueCount == 0 { // probably should try another GPU
return errors.New("vulkan error: no queue families found on GPU 0")
}
// Find a suitable queue family for the target Vulkan mode
found := false
required := vk.QueueFlags(flags)
for i := uint32(0); i < queueCount; i++ {
queueProperties[i].Deref()
if queueProperties[i].QueueFlags&required != 0 {
dv.QueueIndex = i
found = true
break
}
}
if !found {
err := errors.New("GPU vulkan error: could not found queue with graphics capabilities")
return err
}
return nil
}
// MakeDevice and Queue based on QueueIndex
func (dv *Device) MakeDevice(gp *GPU) {
queueInfos := []vk.DeviceQueueCreateInfo{{
SType: vk.StructureTypeDeviceQueueCreateInfo,
QueueFamilyIndex: dv.QueueIndex,
QueueCount: 1,
PQueuePriorities: []float32{1.0},
}}
feats := vk.PhysicalDeviceFeatures{
SamplerAnisotropy: vk.True, // used in Sampler.Config
ShaderSampledImageArrayDynamicIndexing: vk.True,
ShaderUniformBufferArrayDynamicIndexing: vk.True,
ShaderStorageBufferArrayDynamicIndexing: vk.True,
}
gp.SetGPUOpts(&feats, gp.EnabledOpts)
// log.Printf("features: %#v\n", feats)
var device vk.Device
ret := vk.CreateDevice(gp.GPU, &vk.DeviceCreateInfo{
SType: vk.StructureTypeDeviceCreateInfo,
QueueCreateInfoCount: uint32(len(queueInfos)),
PQueueCreateInfos: queueInfos,
EnabledExtensionCount: uint32(len(gp.DeviceExts)),
PpEnabledExtensionNames: gp.DeviceExts,
EnabledLayerCount: uint32(len(gp.ValidationLayers)),
PpEnabledLayerNames: gp.ValidationLayers,
PEnabledFeatures: []vk.PhysicalDeviceFeatures{feats},
PNext: unsafe.Pointer(gp.DeviceFeaturesNeeded),
}, nil, &device)
IfPanic(NewError(ret))
/* note: not using this for PNext:
unsafe.Pointer(&vk.PhysicalDeviceShaderAtomicFloatFeatures{
SType: vk.StructureTypePhysicalDeviceShaderAtomicFloatFeatures,
ShaderBufferFloat32AtomicAdd: vk.True,
}),
*/
// _ = ret
dv.Device = device
var queue vk.Queue
vk.GetDeviceQueue(dv.Device, dv.QueueIndex, 0, &queue)
dv.Queue = queue
}
func (dv *Device) Destroy() {
if dv.Device == nil {
return
}
vk.DeviceWaitIdle(dv.Device)
vk.DestroyDevice(dv.Device, nil)
dv.Device = nil
}
// DeviceWaitIdle waits until the device is idle and ready
// for commands -- maybe useful to call if getting not ready
// errors in particular situations
func (dv *Device) DeviceWaitIdle() {
vk.DeviceWaitIdle(dv.Device)
}
// NewGraphicsDevice returns a new Graphics Device, on given GPU.
// This is suitable for no display offscreen rendering.
// Typically use the Surface Device for rendering to a display window.
func NewGraphicsDevice(gp *GPU) (*Device, error) {
dev := &Device{}
if err := dev.Init(gp, vk.QueueGraphicsBit); err != nil {
return nil, err
}
return dev, nil
}