comparison semiconginev2/rendering.nim @ 1218:56781cc0fc7c compiletime-tests

did: renamge main package
author sam <sam@basx.dev>
date Wed, 17 Jul 2024 21:01:37 +0700
parents semicongine/rendering.nim@04e446a7eb2b
children a3fa15c25026
comparison
equal deleted inserted replaced
1217:f819a874058f 1218:56781cc0fc7c
1 # in this file:
2 # - const defintions for rendering
3 # - custom pragma defintions for rendering
4 # - type defintions for rendering
5 # - some utils code that is used in mutiple rendering files
6 # - inclusion of all rendering files
7
8
9 # const definitions
10 const INFLIGHTFRAMES* = 2'u32
11 const BUFFER_ALIGNMENT = 64'u64 # align offsets inside buffers along this alignment
12 const MEMORY_BLOCK_ALLOCATION_SIZE = 100_000_000'u64 # ca. 100mb per block, seems reasonable
13 const BUFFER_ALLOCATION_SIZE = 9_000_000'u64 # ca. 9mb per block, seems reasonable, can put 10 buffers into one memory block
14 const MAX_DESCRIPTORSETS = 4
15
16 # custom pragmas to classify shader attributes
17 template VertexAttribute* {.pragma.}
18 template InstanceAttribute* {.pragma.}
19 template Pass* {.pragma.}
20 template PassFlat* {.pragma.}
21 template ShaderOutput* {.pragma.}
22 template DescriptorSets* {.pragma.}
23
24 # there is a big, bad global vulkan object
25 # believe me, this makes everything much, much easier
26
27 include ./platform/window # for NativeWindow
28 include ./platform/surface # For CreateNativeSurface
29
30 type
31 VulkanGlobals* = object
32 # populated through InitVulkan proc
33 instance*: VkInstance
34 device*: VkDevice
35 physicalDevice*: VkPhysicalDevice
36 surface: VkSurfaceKHR
37 window: NativeWindow
38 graphicsQueueFamily*: uint32
39 graphicsQueue*: VkQueue
40 debugMessenger: VkDebugUtilsMessengerEXT
41 # unclear as of yet
42 anisotropy*: float32 = 0 # needs to be enable during device creation
43 Swapchain* = object
44 # parameters to InitSwapchain, required for swapchain recreation
45 renderPass: VkRenderPass
46 vSync: bool
47 samples*: VkSampleCountFlagBits
48 # populated through InitSwapchain proc
49 vk: VkSwapchainKHR
50 width*: uint32
51 height*: uint32
52 msaaImage: VkImage
53 msaaMemory: VkDeviceMemory
54 msaaImageView: VkImageView
55 framebuffers: seq[VkFramebuffer]
56 framebufferViews: seq[VkImageView]
57 currentFramebufferIndex: uint32
58 commandBufferPool: VkCommandPool
59 # frame-in-flight handling
60 currentFiF: range[0 .. (INFLIGHTFRAMES - 1).int]
61 queueFinishedFence*: array[INFLIGHTFRAMES.int, VkFence]
62 imageAvailableSemaphore*: array[INFLIGHTFRAMES.int, VkSemaphore]
63 renderFinishedSemaphore*: array[INFLIGHTFRAMES.int, VkSemaphore]
64 commandBuffers: array[INFLIGHTFRAMES.int, VkCommandBuffer]
65 oldSwapchain: ref Swapchain
66 oldSwapchainCounter: int # swaps until old swapchain will be destroyed
67
68 var vulkan*: VulkanGlobals
69
70 func currentFiF*(swapchain: Swapchain): int = swapchain.currentFiF
71
72 type
73 # type aliases
74 SupportedGPUType = float32 | float64 | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64 | TVec2[int32] | TVec2[int64] | TVec3[int32] | TVec3[int64] | TVec4[int32] | TVec4[int64] | TVec2[uint32] | TVec2[uint64] | TVec3[uint32] | TVec3[uint64] | TVec4[uint32] | TVec4[uint64] | TVec2[float32] | TVec2[float64] | TVec3[float32] | TVec3[float64] | TVec4[float32] | TVec4[float64] | TMat2[float32] | TMat2[float64] | TMat23[float32] | TMat23[float64] | TMat32[float32] | TMat32[float64] | TMat3[float32] | TMat3[float64] | TMat34[float32] | TMat34[float64] | TMat43[float32] | TMat43[float64] | TMat4[float32] | TMat4[float64]
75 TextureType = TVec1[uint8] | TVec4[uint8]
76
77 # shader related types
78 DescriptorSet*[T: object] = object
79 data*: T
80 vk: array[INFLIGHTFRAMES.int, VkDescriptorSet]
81 Pipeline*[TShader] = object
82 vk: VkPipeline
83 vertexShaderModule: VkShaderModule
84 fragmentShaderModule: VkShaderModule
85 layout: VkPipelineLayout
86 descriptorSetLayouts*: array[MAX_DESCRIPTORSETS, VkDescriptorSetLayout]
87
88 # memory/buffer related types
89 MemoryBlock* = object
90 vk: VkDeviceMemory
91 size: uint64
92 rawPointer: pointer # if not nil, this is mapped memory
93 offsetNextFree: uint64
94 BufferType* = enum
95 VertexBuffer
96 VertexBufferMapped
97 IndexBuffer
98 IndexBufferMapped
99 UniformBuffer
100 UniformBufferMapped
101 Buffer* = object
102 vk: VkBuffer
103 size: uint64
104 rawPointer: pointer # if not nil, buffer is using mapped memory
105 offsetNextFree: uint64
106 Texture*[T: TextureType] = object
107 width*: uint32
108 height*: uint32
109 interpolation*: VkFilter = VK_FILTER_LINEAR
110 data*: seq[T]
111 vk*: VkImage
112 imageview*: VkImageView
113 sampler*: VkSampler
114 isRenderTarget*: bool = false
115 GPUArray*[T: SupportedGPUType, TBuffer: static BufferType] = object
116 data*: seq[T]
117 buffer*: Buffer
118 offset*: uint64
119 GPUValue*[T: object, TBuffer: static BufferType] = object
120 data*: T
121 buffer: Buffer
122 offset: uint64
123 GPUData = GPUArray | GPUValue
124
125 RenderData* = object
126 descriptorPool: VkDescriptorPool
127 memory: array[VK_MAX_MEMORY_TYPES.int, seq[MemoryBlock]]
128 buffers: array[BufferType, seq[Buffer]]
129 images: seq[VkImage]
130 imageViews: seq[VkImageView]
131 samplers: seq[VkSampler]
132
133 template ForDescriptorFields(shader: typed, fieldname, valuename, typename, countname, bindingNumber, body: untyped): untyped =
134 var `bindingNumber` {.inject.} = 0'u32
135 for theFieldname, value in fieldPairs(shader):
136 when typeof(value) is Texture:
137 block:
138 const `fieldname` {.inject.} = theFieldname
139 const `typename` {.inject.} = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
140 const `countname` {.inject.} = 1'u32
141 let `valuename` {.inject.} = value
142 body
143 `bindingNumber`.inc
144 elif typeof(value) is GPUValue:
145 block:
146 const `fieldname` {.inject.} = theFieldname
147 const `typename` {.inject.} = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
148 const `countname` {.inject.} = 1'u32
149 let `valuename` {.inject.} = value
150 body
151 `bindingNumber`.inc
152 elif typeof(value) is array:
153 when elementType(value) is Texture:
154 block:
155 const `fieldname` {.inject.} = theFieldname
156 const `typename` {.inject.} = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
157 const `countname` {.inject.} = uint32(typeof(value).len)
158 let `valuename` {.inject.} = value
159 body
160 `bindingNumber`.inc
161 elif elementType(value) is GPUValue:
162 block:
163 const `fieldname` {.inject.} = theFieldname
164 const `typename` {.inject.} = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
165 const `countname` {.inject.} = len(value).uint32
166 let `valuename` {.inject.} = value
167 body
168 `bindingNumber`.inc
169 else:
170 {.error: "Unsupported descriptor type: " & typetraits.name(typeof(value)).}
171 else:
172 {.error: "Unsupported descriptor type: " & typetraits.name(typeof(value)).}
173
174 include ./rendering/vulkan_wrappers
175 include ./rendering/renderpasses
176 include ./rendering/swapchain
177 include ./rendering/shaders
178 include ./rendering/renderer
179
180 proc debugCallback(
181 messageSeverity: VkDebugUtilsMessageSeverityFlagBitsEXT,
182 messageTypes: VkDebugUtilsMessageTypeFlagsEXT,
183 pCallbackData: ptr VkDebugUtilsMessengerCallbackDataEXT,
184 userData: pointer
185 ): VkBool32 {.cdecl.} =
186 const LOG_LEVEL_MAPPING = {
187 VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: lvlDebug,
188 VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: lvlInfo,
189 VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: lvlWarn,
190 VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: lvlError,
191 }.toTable
192 log LOG_LEVEL_MAPPING[messageSeverity], &"{toEnums messageTypes}: {pCallbackData.pMessage}"
193 if messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
194 stderr.writeLine "-----------------------------------"
195 stderr.write getStackTrace()
196 stderr.writeLine LOG_LEVEL_MAPPING[messageSeverity], &"{toEnums messageTypes}: {pCallbackData.pMessage}"
197 stderr.writeLine "-----------------------------------"
198 let errorMsg = getStackTrace() & &"\n{toEnums messageTypes}: {pCallbackData.pMessage}"
199 raise newException(Exception, errorMsg)
200 return false
201
202 proc InitVulkan*(appName: string = "semicongine app") =
203
204 include ./platform/vulkan_extensions # for REQUIRED_PLATFORM_EXTENSIONS
205
206 # instance creation
207
208 # enagle all kind of debug stuff
209 when not defined(release):
210 let requiredExtensions = REQUIRED_PLATFORM_EXTENSIONS & @["VK_KHR_surface", "VK_EXT_debug_utils"]
211 let layers: seq[string] = if hasValidationLayer(): @["VK_LAYER_KHRONOS_validation"] else: @[]
212 putEnv("VK_LAYER_ENABLES", "VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_AMD,VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_NVIDIA,VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXTVK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT,VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT")
213 else:
214 let requiredExtensions = REQUIRED_PLATFORM_EXTENSIONS & @["VK_KHR_surface"]
215 let layers: seq[string]
216
217 var
218 layersC = allocCStringArray(layers)
219 instanceExtensionsC = allocCStringArray(requiredExtensions)
220 defer:
221 deallocCStringArray(layersC)
222 deallocCStringArray(instanceExtensionsC)
223
224 var
225 appinfo = VkApplicationInfo(
226 sType: VK_STRUCTURE_TYPE_APPLICATION_INFO,
227 pApplicationName: appName,
228 pEngineName: "semicongine",
229 apiVersion: VK_MAKE_API_VERSION(0, 1, 3, 0),
230 )
231 createinfo = VkInstanceCreateInfo(
232 sType: VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
233 pApplicationInfo: addr(appinfo),
234 enabledLayerCount: layers.len.uint32,
235 ppEnabledLayerNames: layersC,
236 enabledExtensionCount: requiredExtensions.len.uint32,
237 ppEnabledExtensionNames: instanceExtensionsC
238 )
239 checkVkResult vkCreateInstance(addr(createinfo), nil, addr(vulkan.instance))
240 loadVulkan(vulkan.instance)
241
242 # load extensions
243 #
244 for extension in requiredExtensions:
245 loadExtension(vulkan.instance, $extension)
246 vulkan.window = CreateWindow(appName)
247 vulkan.surface = CreateNativeSurface(vulkan.instance, vulkan.window)
248
249 # logical device creation
250
251 # TODO: allowing support for physical devices without hasUniformBufferStandardLayout
252 # would require us to ship different shaders, so we don't support standard layout
253 # if that will be added, check the function vulkan/shaders.nim:glslUniforms and update accordingly
254 # let hasUniformBufferStandardLayout = "VK_KHR_uniform_buffer_standard_layout" in physicalDevice.getExtensions()
255 # var deviceExtensions = @["VK_KHR_swapchain", "VK_KHR_uniform_buffer_standard_layout"]
256 var deviceExtensions = @["VK_KHR_swapchain"]
257 for extension in deviceExtensions:
258 loadExtension(vulkan.instance, extension)
259
260 when not defined(release):
261 var debugMessengerCreateInfo = VkDebugUtilsMessengerCreateInfoEXT(
262 sType: VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
263 messageSeverity: VkDebugUtilsMessageSeverityFlagBitsEXT.items.toSeq.toBits,
264 messageType: VkDebugUtilsMessageTypeFlagBitsEXT.items.toSeq.toBits,
265 pfnUserCallback: debugCallback,
266 pUserData: nil,
267 )
268 checkVkResult vkCreateDebugUtilsMessengerEXT(
269 vulkan.instance,
270 addr(debugMessengerCreateInfo),
271 nil,
272 addr(vulkan.debugMessenger)
273 )
274
275 # get physical device and graphics queue family
276 vulkan.physicalDevice = GetBestPhysicalDevice(vulkan.instance)
277 vulkan.graphicsQueueFamily = GetQueueFamily(vulkan.physicalDevice, VK_QUEUE_GRAPHICS_BIT)
278
279 let
280 priority = cfloat(1)
281 queueInfo = VkDeviceQueueCreateInfo(
282 sType: VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
283 queueFamilyIndex: vulkan.graphicsQueueFamily,
284 queueCount: 1,
285 pQueuePriorities: addr(priority),
286 )
287 deviceExtensionsC = allocCStringArray(deviceExtensions)
288 defer: deallocCStringArray(deviceExtensionsC)
289 var createDeviceInfo = VkDeviceCreateInfo(
290 sType: VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
291 queueCreateInfoCount: 1,
292 pQueueCreateInfos: addr(queueInfo),
293 enabledLayerCount: 0,
294 ppEnabledLayerNames: nil,
295 enabledExtensionCount: uint32(deviceExtensions.len),
296 ppEnabledExtensionNames: deviceExtensionsC,
297 pEnabledFeatures: nil,
298 )
299 checkVkResult vkCreateDevice(
300 physicalDevice = vulkan.physicalDevice,
301 pCreateInfo = addr createDeviceInfo,
302 pAllocator = nil,
303 pDevice = addr vulkan.device
304 )
305 vulkan.graphicsQueue = svkGetDeviceQueue(vulkan.device, vulkan.graphicsQueueFamily, VK_QUEUE_GRAPHICS_BIT)
306
307 proc DestroyVulkan*() =
308 vkDestroyDevice(vulkan.device, nil)
309 vkDestroySurfaceKHR(vulkan.instance, vulkan.surface, nil)
310 vkDestroyDebugUtilsMessengerEXT(vulkan.instance, vulkan.debugMessenger, nil)
311 vkDestroyInstance(vulkan.instance, nil)