Mercurial > games > semicongine
comparison static_utils.nim @ 1179:e1830f9b8af4 compiletime-tests
sync to notebook in bedroom
| author | sam <sam@basx.dev> |
|---|---|
| date | Mon, 01 Jul 2024 20:32:00 +0700 |
| parents | ec4ff70299f2 |
| children | d554f8185815 |
comparison
equal
deleted
inserted
replaced
| 1178:ec4ff70299f2 | 1179:e1830f9b8af4 |
|---|---|
| 10 import semicongine/core/utils | 10 import semicongine/core/utils |
| 11 import semicongine/core/imagetypes | 11 import semicongine/core/imagetypes |
| 12 import semicongine/core/vector | 12 import semicongine/core/vector |
| 13 import semicongine/core/matrix | 13 import semicongine/core/matrix |
| 14 import semicongine/core/vulkanapi | 14 import semicongine/core/vulkanapi |
| 15 import semicongine/vulkan/buffer | 15 |
| 16 | 16 template VertexAttribute {.pragma.} |
| 17 template VertexAttribute* {.pragma.} | 17 template InstanceAttribute {.pragma.} |
| 18 template InstanceAttribute* {.pragma.} | 18 template Pass {.pragma.} |
| 19 template Pass* {.pragma.} | 19 template PassFlat {.pragma.} |
| 20 template PassFlat* {.pragma.} | 20 template ShaderOutput {.pragma.} |
| 21 template ShaderOutput* {.pragma.} | 21 template VertexIndices{.pragma.} |
| 22 template VertexIndices*{.pragma.} | |
| 23 | 22 |
| 24 const INFLIGHTFRAMES = 2'u32 | 23 const INFLIGHTFRAMES = 2'u32 |
| 24 const ACTIVE_DESCRIPTORSETS = 2 | |
| 25 const MEMORY_ALIGNMENT = 65536'u64 # Align buffers inside memory along this alignment | 25 const MEMORY_ALIGNMENT = 65536'u64 # Align buffers inside memory along this alignment |
| 26 const BUFFER_ALIGNMENT = 64'u64 # align offsets inside buffers along this alignment | 26 const BUFFER_ALIGNMENT = 64'u64 # align offsets inside buffers along this alignment |
| 27 | 27 |
| 28 # some globals that will (likely?) never change during the life time of the engine | |
| 28 type | 29 type |
| 29 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] | 30 VulkanGlobals = object |
| 30 ShaderObject*[TShader] = object | 31 instance: VkInstance |
| 32 device: VkDevice | |
| 33 physicalDevice: VkPhysicalDevice | |
| 34 queueFamilyIndex: uint32 | |
| 35 queue: VkQueue | |
| 36 var vulkan: VulkanGlobals | |
| 37 | |
| 38 type | |
| 39 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] | |
| 40 ShaderObject[TShader] = object | |
| 31 vertexShader: VkShaderModule | 41 vertexShader: VkShaderModule |
| 32 fragmentShader: VkShaderModule | 42 fragmentShader: VkShaderModule |
| 33 | 43 |
| 34 func alignedTo[T: SomeInteger](value: T, alignment: T) = | 44 func alignedTo[T: SomeInteger](value: T, alignment: T): T = |
| 35 let remainder = value mod alignment | 45 let remainder = value mod alignment |
| 36 if remainder == 0: | 46 if remainder == 0: |
| 37 return value | 47 return value |
| 38 else: | 48 else: |
| 39 return value + alignment - remainder | 49 return value + alignment - remainder |
| 121 elif T is TMat4[float32]: "mat4" | 131 elif T is TMat4[float32]: "mat4" |
| 122 elif T is TMat4[float64]: "dmat4" | 132 elif T is TMat4[float64]: "dmat4" |
| 123 elif T is Texture: "sampler2D" | 133 elif T is Texture: "sampler2D" |
| 124 else: {.error: "Unsupported data type on GPU".} | 134 else: {.error: "Unsupported data type on GPU".} |
| 125 | 135 |
| 126 template ForVertexDataFields*(inputData: typed, fieldname, valuename, isinstancename, body: untyped): untyped = | 136 template ForVertexDataFields(shader: typed, fieldname, valuename, isinstancename, body: untyped): untyped = |
| 127 for theFieldname, value in fieldPairs(inputData): | 137 for theFieldname, value in fieldPairs(shader): |
| 128 when hasCustomPragma(value, VertexAttribute) or hasCustomPragma(value, InstanceAttribute): | 138 when hasCustomPragma(value, VertexAttribute) or hasCustomPragma(value, InstanceAttribute): |
| 129 when not typeof(value) is seq: | 139 when not typeof(value) is seq: |
| 130 {.error: "field '" & theFieldname & "' needs to be a seq".} | 140 {.error: "field '" & theFieldname & "' needs to be a seq".} |
| 131 when not typeof(value) is SupportedGPUType: | 141 when not typeof(value) is SupportedGPUType: |
| 132 {.error: "field '" & theFieldname & "' is not a supported GPU type".} | 142 {.error: "field '" & theFieldname & "' is not a supported GPU type".} |
| 133 block: | 143 block: |
| 134 let `fieldname` {.inject.} = theFieldname | 144 const `fieldname` {.inject.} = theFieldname |
| 135 let `valuename` {.inject.} = value | 145 let `valuename` {.inject.} = value |
| 136 let `isinstancename` {.inject.} = hasCustomPragma(value, InstanceAttribute) | 146 const `isinstancename` {.inject.} = hasCustomPragma(value, InstanceAttribute) |
| 137 body | 147 body |
| 138 | 148 |
| 139 template ForDescriptorFields*(inputData: typed, fieldname, typename, countname, bindingNumber, body: untyped): untyped = | 149 template ForDescriptorFields(shader: typed, fieldname, typename, countname, bindingNumber, body: untyped): untyped = |
| 140 var `bindingNumber` {.inject.} = 1'u32 | 150 var `bindingNumber` {.inject.} = 1'u32 |
| 141 for theFieldname, value in fieldPairs(inputData): | 151 for theFieldname, value in fieldPairs(shader): |
| 142 let `fieldname` {.inject.} = theFieldname | 152 const `fieldname` {.inject.} = theFieldname |
| 143 when typeof(value) is Texture: | 153 when typeof(value) is Texture: |
| 144 block: | 154 block: |
| 145 let `typename` {.inject.} = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER | 155 const `typename` {.inject.} = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER |
| 146 let `countname` {.inject.} = 1'u32 | 156 const `countname` {.inject.} = 1'u32 |
| 147 body | 157 body |
| 148 `bindingNumber`.inc | 158 `bindingNumber`.inc |
| 149 elif typeof(value) is object: | 159 elif typeof(value) is object: |
| 150 block: | 160 block: |
| 151 let `typename` {.inject.} = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER | 161 const `typename` {.inject.} = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER |
| 152 let `countname` {.inject.} = 1'u32 | 162 const `countname` {.inject.} = 1'u32 |
| 153 body | 163 body |
| 154 `bindingNumber`.inc | 164 `bindingNumber`.inc |
| 155 elif typeof(value) is array: | 165 elif typeof(value) is array: |
| 156 when elementType(value) is Texture: | 166 when elementType(value) is Texture: |
| 157 block: | 167 block: |
| 158 let `typename` {.inject.} = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER | 168 const `typename` {.inject.} = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER |
| 159 let `countname` {.inject.} = uint32(typeof(value).len) | 169 const `countname` {.inject.} = uint32(typeof(value).len) |
| 160 body | 170 body |
| 161 `bindingNumber`.inc | 171 `bindingNumber`.inc |
| 162 elif elementType(value) is object: | 172 elif elementType(value) is object: |
| 163 block: | 173 block: |
| 164 let `typename` {.inject.} = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER | 174 const `typename` {.inject.} = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER |
| 165 let `countname` {.inject.} = uint32(typeof(value).len) | 175 const `countname` {.inject.} = uint32(typeof(value).len) |
| 166 body | 176 body |
| 167 `bindingNumber`.inc | 177 `bindingNumber`.inc |
| 168 | 178 |
| 169 func NumberOfVertexInputAttributeDescriptors[T: SupportedGPUType|Texture](value: T): uint32 = | 179 func NumberOfVertexInputAttributeDescriptors[T: SupportedGPUType|Texture](value: T): uint32 = |
| 170 when T is TMat2[float32] or T is TMat2[float64] or T is TMat23[float32] or T is TMat23[float64]: | 180 when T is TMat2[float32] or T is TMat2[float64] or T is TMat23[float32] or T is TMat23[float64]: |
| 236 GPUData = GPUArray | GPUValue | 246 GPUData = GPUArray | GPUValue |
| 237 | 247 |
| 238 Pipeline[TShader] = object | 248 Pipeline[TShader] = object |
| 239 pipeline: VkPipeline | 249 pipeline: VkPipeline |
| 240 layout: VkPipelineLayout | 250 layout: VkPipelineLayout |
| 241 descriptorSetLayout: VkDescriptorSetLayout | 251 descriptorSetLayouts: array[ACTIVE_DESCRIPTORSETS, VkDescriptorSetLayout] |
| 242 BufferType = enum | 252 BufferType = enum |
| 243 VertexBuffer, IndexBuffer, UniformBuffer | 253 VertexBuffer, IndexBuffer, UniformBuffer |
| 244 RenderData = object | 254 RenderData = object |
| 245 descriptorPool: VkDescriptorPool | 255 descriptorPool: VkDescriptorPool |
| 246 # tuple is memory and offset to next free allocation in that memory | 256 # tuple is memory and offset to next free allocation in that memory |
| 247 indirectMemory: seq[tuple[memory: IndirectGPUMemory, nextFree: uint64]] | 257 indirectMemory: seq[tuple[memory: IndirectGPUMemory, usedOffset: uint64]] |
| 248 directMemory: seq[tuple[memory: DirectGPUMemory, nextFree: uint64]] | 258 directMemory: seq[tuple[memory: DirectGPUMemory, usedOffset: uint64]] |
| 249 indirectBuffers: seq[tuple[buffer: Buffer[IndirectGPUMemory], btype: BufferType, nextFree: uint64]] | 259 indirectBuffers: seq[tuple[buffer: Buffer[IndirectGPUMemory], btype: BufferType, usedOffset: uint64]] |
| 250 directBuffers: seq[tuple[buffer: Buffer[DirectGPUMemory], btype: BufferType, nextFree: uint64]] | 260 directBuffers: seq[tuple[buffer: Buffer[DirectGPUMemory], btype: BufferType, usedOffset: uint64]] |
| 251 | 261 |
| 252 template UsesIndirectMemory(gpuData: GPUData): untyped = | 262 template UsesIndirectMemory(gpuData: GPUData): untyped = |
| 253 get(genericParams(typeof(gpuData)), 1) is IndirectGPUMemory | 263 get(genericParams(typeof(gpuData)), 1) is IndirectGPUMemory |
| 254 template UsesDirectMemory(gpuData: GPUData): untyped = | 264 template UsesDirectMemory(gpuData: GPUData): untyped = |
| 255 get(genericParams(typeof(gpuData)), 1) is DirectGPUMemory | 265 get(genericParams(typeof(gpuData)), 1) is DirectGPUMemory |
| 256 | 266 |
| 257 template size(gpuArray: GPUArray): uint64 = | 267 template size(gpuArray: GPUArray): uint64 = |
| 258 result += (gpuArray.data.len * sizeof(elementType(gpuArray.data))).uint64 | 268 (gpuArray.data.len * sizeof(elementType(gpuArray.data))).uint64 |
| 259 template size(gpuValue: GPUValue): uint64 = | 269 template size(gpuValue: GPUValue): uint64 = |
| 260 result += sizeof(gpuValue.data).uint64 | 270 sizeof(gpuValue.data).uint64 |
| 261 | 271 |
| 262 proc GetPhysicalDevice(): VkPhysicalDevice = | 272 template datapointer(gpuArray: GPUArray): pointer = |
| 273 addr(gpuArray.data[0]) | |
| 274 template datapointer(gpuValue: GPUValue): pointer = | |
| 275 addr(gpuValue.data) | |
| 276 | |
| 277 proc AllocationSize(buffer: Buffer): uint64 = | |
| 278 var req: VkMemoryRequirements | |
| 279 vkGetBufferMemoryRequirements(vulkan.device, buffer.vk, addr(req)) | |
| 280 return req.size | |
| 281 | |
| 282 proc GetPhysicalDevice(instance: VkInstance): VkPhysicalDevice = | |
| 263 var nDevices: uint32 | 283 var nDevices: uint32 |
| 264 checkVkResult vkEnumeratePhysicalDevices(instance.vk, addr(nDevices), nil) | 284 checkVkResult vkEnumeratePhysicalDevices(instance, addr(nDevices), nil) |
| 265 var devices = newSeq[VkPhysicalDevice](nDevices) | 285 var devices = newSeq[VkPhysicalDevice](nDevices) |
| 266 checkVkResult vkEnumeratePhysicalDevices(instance.vk, addr(nDevices), devices.ToCPointer) | 286 checkVkResult vkEnumeratePhysicalDevices(instance, addr(nDevices), devices.ToCPointer) |
| 267 | 287 |
| 268 var score = 0 | 288 var score = 0'u32 |
| 269 for pDevice in devices: | 289 for pDevice in devices: |
| 270 var props: VkPhysicalDeviceProperties | 290 var props: VkPhysicalDeviceProperties |
| 271 vkGetPhysicalDeviceProperties(pDevice, addr(props)) | 291 vkGetPhysicalDeviceProperties(pDevice, addr(props)) |
| 272 if props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU and props.maxImageDimension2D > score: | 292 if props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU and props.limits.maxImageDimension2D > score: |
| 273 score = props.maxImageDimension2D | 293 score = props.limits.maxImageDimension2D |
| 274 result = pDevice | 294 result = pDevice |
| 275 | 295 |
| 276 if score == 0 | 296 if score == 0: |
| 277 for pDevice in devices: | 297 for pDevice in devices: |
| 278 var props: VkPhysicalDeviceProperties | 298 var props: VkPhysicalDeviceProperties |
| 279 vkGetPhysicalDeviceProperties(pDevice, addr(props)) | 299 vkGetPhysicalDeviceProperties(pDevice, addr(props)) |
| 280 if props.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU and props.maxImageDimension2D > score: | 300 if props.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU and props.limits.maxImageDimension2D > score: |
| 281 score = props.maxImageDimension2D | 301 score = props.limits.maxImageDimension2D |
| 282 result = pDevice | 302 result = pDevice |
| 283 | 303 |
| 284 assert score > 0, "Unable to find integrated or discrete GPU" | 304 assert score > 0, "Unable to find integrated or discrete GPU" |
| 285 | 305 |
| 286 | 306 |
| 287 proc GetDirectMemoryTypeIndex() | 307 proc GetDirectMemoryTypeIndex(): uint32 = |
| 288 var physicalProperties: VkPhysicalDeviceMemoryProperties | 308 var physicalProperties: VkPhysicalDeviceMemoryProperties |
| 289 checkVkResult vkGetPhysicalDeviceMemoryProperties(GetPhysicalDevice(), addr physicalProperties) | 309 vkGetPhysicalDeviceMemoryProperties(vulkan.physicalDevice, addr(physicalProperties)) |
| 290 | 310 |
| 291 var biggestHeap: uint64 = 0 | 311 var biggestHeap: uint64 = 0 |
| 292 result = high(uint32) | 312 result = high(uint32) |
| 293 # try to find host-visible type | 313 # try to find host-visible type |
| 294 for i in 0 ..< physicalProperties.memoryTypeCount: | 314 for i in 0'u32 ..< physicalProperties.memoryTypeCount: |
| 295 let flags = toEnums(physicalProperties.memoryTypes[i].propertyFlags) | 315 let flags = toEnums(physicalProperties.memoryTypes[i].propertyFlags) |
| 296 if VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT in flags: | 316 if VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT in flags: |
| 297 let size = physicalProperties.memoryHeaps[physicalProperties.memoryTypes[i].heapIndex].size | 317 let size = physicalProperties.memoryHeaps[physicalProperties.memoryTypes[i].heapIndex].size |
| 298 if size > biggestHeap: | 318 if size > biggestHeap: |
| 299 biggestHeap = size | 319 biggestHeap = size |
| 300 result = i | 320 result = i |
| 301 assert result != high(uint32), "There is not host visible memory. This is likely a driver bug." | 321 assert result != high(uint32), "There is not host visible memory. This is likely a driver bug." |
| 302 | 322 |
| 303 proc GetQueueFamily(device: VkDevice, qType = VK_QUEUE_GRAPHICS_BIT): VkQueue = | 323 proc GetQueueFamily(pDevice: VkPhysicalDevice, qType: VkQueueFlagBits): uint32 = |
| 304 assert device.vk.Valid | |
| 305 var nQueuefamilies: uint32 | 324 var nQueuefamilies: uint32 |
| 306 checkVkResult vkGetPhysicalDeviceQueueFamilyProperties(device.vk, addr nQueuefamilies, nil) | 325 vkGetPhysicalDeviceQueueFamilyProperties(pDevice, addr nQueuefamilies, nil) |
| 307 var queuFamilies = newSeq[VkQueueFamilyProperties](nQueuefamilies) | 326 var queuFamilies = newSeq[VkQueueFamilyProperties](nQueuefamilies) |
| 308 checkVkResult vkGetPhysicalDeviceQueueFamilyProperties(device.vk, addr nQueuefamilies, queuFamilies.ToCPointer) | 327 vkGetPhysicalDeviceQueueFamilyProperties(pDevice, addr nQueuefamilies, queuFamilies.ToCPointer) |
| 309 for i in 0 ..< nQueuefamilies: | 328 for i in 0'u32 ..< nQueuefamilies: |
| 310 if qType in toEnums(queuFamilies[i].queueFlags): | 329 if qType in toEnums(queuFamilies[i].queueFlags): |
| 311 return i | 330 return i |
| 312 assert false, &"Queue of type {qType} not found" | 331 assert false, &"Queue of type {qType} not found" |
| 313 | 332 |
| 314 proc GetQueue(device: VkDevice, qType = VK_QUEUE_GRAPHICS_BIT): VkQueue = | 333 proc GetQueue(device: VkDevice, queueFamilyIndex: uint32, qType: VkQueueFlagBits): VkQueue = |
| 315 checkVkResult vkGetDeviceQueue( | 334 vkGetDeviceQueue( |
| 316 device, | 335 device, |
| 317 GetQueueFamily(device, qType), | 336 queueFamilyIndex, |
| 318 0, | 337 0, |
| 319 addr(result), | 338 addr(result), |
| 320 ) | 339 ) |
| 321 | 340 |
| 322 #[ | 341 proc GetSurfaceFormat(): VkFormat = |
| 323 TODO: Finish this, allow fore easy access to main format | 342 # EVERY windows driver and almost every linux driver should support this |
| 324 proc GetSurfaceFormat*(device: PhysicalDevice): VkFormat = | 343 VK_FORMAT_B8G8R8A8_SRGB |
| 325 var n_formats: uint32 | 344 |
| 326 checkVkResult vkGetPhysicalDeviceSurfaceFormatsKHR(device.vk, device.surface, addr(n_formats), nil) | 345 template WithSingleUseCommandBuffer(device: VkDevice, cmd, body: untyped): untyped = |
| 327 result = newSeq[VkSurfaceFormatKHR](n_formats) | |
| 328 checkVkResult vkGetPhysicalDeviceSurfaceFormatsKHR(device.vk, device.surface, addr(n_formats), result.ToCPointer) | |
| 329 ]# | |
| 330 | |
| 331 template WithSingleUseCommandBuffer*(device: VkDevice, cmd, body: untyped): untyped = | |
| 332 # TODO? This is super slow, because we call vkQueueWaitIdle | |
| 333 block: | 346 block: |
| 334 var commandBufferPool: VkCommandPool | 347 var |
| 335 createInfo = VkCommandPoolCreateInfo( | 348 commandBufferPool: VkCommandPool |
| 349 createInfo = VkCommandPoolCreateInfo( | |
| 336 sType: VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, | 350 sType: VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, |
| 337 flags: toBits [VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT], | 351 flags: toBits [VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT], |
| 338 queueFamilyIndex: GetQueueFamily(device), | 352 queueFamilyIndex: vulkan.queueFamilyIndex, |
| 339 ) | 353 ) |
| 340 checkVkResult vkCreateCommandPool(device, addr createInfo, nil, addr(commandBufferPool)) | 354 checkVkResult vkCreateCommandPool(device, addr createInfo, nil, addr(commandBufferPool)) |
| 341 var | 355 var |
| 342 `cmd` {.inject.}: VkCommandBuffer | 356 `cmd` {.inject.}: VkCommandBuffer |
| 343 allocInfo = VkCommandBufferAllocateInfo( | 357 allocInfo = VkCommandBufferAllocateInfo( |
| 344 sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, | 358 sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, |
| 345 commandPool: commandBufferPool, | 359 commandPool: commandBufferPool, |
| 346 level: VK_COMMAND_BUFFER_LEVEL_PRIMARY, | 360 level: VK_COMMAND_BUFFER_LEVEL_PRIMARY, |
| 347 commandBufferCount: 1, | 361 commandBufferCount: 1, |
| 348 ) | 362 ) |
| 349 checkVkResult device.vk.vkAllocateCommandBuffers(addr allocInfo, addr(`cmd`)) | 363 checkVkResult device.vkAllocateCommandBuffers(addr allocInfo, addr(`cmd`)) |
| 350 beginInfo = VkCommandBufferBeginInfo( | 364 var beginInfo = VkCommandBufferBeginInfo( |
| 351 sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, | 365 sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, |
| 352 flags: VkCommandBufferUsageFlags(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT), | 366 flags: VkCommandBufferUsageFlags(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT), |
| 353 ) | 367 ) |
| 354 checkVkResult `cmd`.vkBeginCommandBuffer(addr beginInfo) | 368 checkVkResult `cmd`.vkBeginCommandBuffer(addr beginInfo) |
| 355 | 369 |
| 359 var submitInfo = VkSubmitInfo( | 373 var submitInfo = VkSubmitInfo( |
| 360 sType: VK_STRUCTURE_TYPE_SUBMIT_INFO, | 374 sType: VK_STRUCTURE_TYPE_SUBMIT_INFO, |
| 361 commandBufferCount: 1, | 375 commandBufferCount: 1, |
| 362 pCommandBuffers: addr(`cmd`), | 376 pCommandBuffers: addr(`cmd`), |
| 363 ) | 377 ) |
| 364 checkVkResult vkQueueSubmit(GetQueue(), 1, addr submitInfo, VkFence(0)) | 378 |
| 365 checkVkResult vkQueueWaitIdle(GetQueue()) # because we want to destroy the commandbuffer pool | 379 var |
| 380 fence: VkFence | |
| 381 fenceInfo = VkFenceCreateInfo( | |
| 382 sType: VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, | |
| 383 # flags: toBits [VK_FENCE_CREATE_SIGNALED_BIT] | |
| 384 ) | |
| 385 checkVkResult device.vkCreateFence(addr(fenceInfo), nil, addr(fence)) | |
| 386 checkVkResult vkQueueSubmit(vulkan.queue, 1, addr(submitInfo), fence) | |
| 387 checkVkResult vkWaitForFences(device, 1, addr fence, false, high(uint64)) | |
| 366 vkDestroyCommandPool(device, commandBufferPool, nil) | 388 vkDestroyCommandPool(device, commandBufferPool, nil) |
| 367 | 389 |
| 368 | 390 |
| 369 proc UpdateGPUBuffer*(device: VkDevice, gpuData: GPUArray) = | 391 proc UpdateGPUBuffer(gpuData: GPUData) = |
| 392 if gpuData.size == 0: | |
| 393 return | |
| 370 when UsesDirectMemory(gpuData): | 394 when UsesDirectMemory(gpuData): |
| 371 copyMem(cast[pointer](cast[uint64](gpuData.buffer.memory.data) + gpuData.buffer.offset + gpuData.offset), addr(gpuData.data[0]), gpuData.size) | 395 copyMem(cast[pointer](cast[uint64](gpuData.buffer.memory.data) + gpuData.buffer.offset + gpuData.offset), gpuData.datapointer, gpuData.size) |
| 372 else: | 396 else: |
| 373 var | 397 var |
| 374 stagingBuffer: VkBuffer | 398 stagingBuffer: VkBuffer |
| 375 createInfo = VkBufferCreateInfo( | 399 createInfo = VkBufferCreateInfo( |
| 376 sType: VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 400 sType: VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 378 size: gpuData.size, | 402 size: gpuData.size, |
| 379 usage: toBits([VK_BUFFER_USAGE_TRANSFER_SRC_BIT]), | 403 usage: toBits([VK_BUFFER_USAGE_TRANSFER_SRC_BIT]), |
| 380 sharingMode: VK_SHARING_MODE_EXCLUSIVE, | 404 sharingMode: VK_SHARING_MODE_EXCLUSIVE, |
| 381 ) | 405 ) |
| 382 checkVkResult vkCreateBuffer( | 406 checkVkResult vkCreateBuffer( |
| 383 device = device, | 407 device = vulkan.device, |
| 384 pCreateInfo = addr(createInfo), | 408 pCreateInfo = addr(createInfo), |
| 385 pAllocator = nil, | 409 pAllocator = nil, |
| 386 pBuffer = addr(stagingBuffer), | 410 pBuffer = addr(stagingBuffer), |
| 387 ) | 411 ) |
| 388 var | 412 var |
| 389 stagingMemory: VkDeviceMemory | 413 stagingMemory: VkDeviceMemory |
| 390 stagingPtr: pointer | 414 stagingPtr: pointer |
| 391 memoryAllocationInfo = VkMemoryAllocateInfo( | 415 memoryAllocationInfo = VkMemoryAllocateInfo( |
| 392 sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, | 416 sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, |
| 393 allocationSize: gpuData.size, | 417 allocationSize: gpuData.buffer.AllocationSize(), |
| 394 memoryTypeIndex: GetDirectMemoryTypeIndex(), | 418 memoryTypeIndex: GetDirectMemoryTypeIndex(), |
| 395 ) | 419 ) |
| 396 checkVkResult vkAllocateMemory( | 420 checkVkResult vkAllocateMemory( |
| 397 device, | 421 vulkan.device, |
| 398 addr(memoryAllocationInfo), | 422 addr(memoryAllocationInfo), |
| 399 nil, | 423 nil, |
| 400 addr(stagingMemory), | 424 addr(stagingMemory), |
| 401 ) | 425 ) |
| 402 checkVkResult vkBindBufferMemory(device, stagingBuffer, stagingMemory, 0) | 426 checkVkResult vkBindBufferMemory(vulkan.device, stagingBuffer, stagingMemory, 0) |
| 403 checkVkResult vkMapMemory( | 427 checkVkResult vkMapMemory( |
| 404 device = device, | 428 device = vulkan.device, |
| 405 memory = stagingMemory, | 429 memory = stagingMemory, |
| 406 offset = 0'u64, | 430 offset = 0'u64, |
| 407 size = VK_WHOLE_SIZE, | 431 size = VK_WHOLE_SIZE, |
| 408 flags = VkMemoryMapFlags(0), | 432 flags = VkMemoryMapFlags(0), |
| 409 ppData = stagingPtr | 433 ppData = addr(stagingPtr) |
| 410 ) | 434 ) |
| 411 copyMem(stagingPtr, addr(gpuData.data[0]), gpuData.size) | 435 copyMem(stagingPtr, gpuData.datapointer, gpuData.size) |
| 412 var stagingRange = VkMappedMemoryRange( | 436 var stagingRange = VkMappedMemoryRange( |
| 413 sType: VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, | 437 sType: VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, |
| 414 memory: stagingMemory, | 438 memory: stagingMemory, |
| 415 size: VK_WHOLE_SIZE, | 439 size: VK_WHOLE_SIZE, |
| 416 ) | 440 ) |
| 417 checkVkResult vkFlushMappedMemoryRanges(device, 1, addr(stagingRange)) | 441 checkVkResult vkFlushMappedMemoryRanges(vulkan.device, 1, addr(stagingRange)) |
| 418 | 442 |
| 419 WithSingleUseCommandBuffer(device, commandBuffer): | 443 WithSingleUseCommandBuffer(vulkan.device, commandBuffer): |
| 420 var copyRegion = VkBufferCopy(size: gpuData.size) | 444 var copyRegion = VkBufferCopy(size: gpuData.size) |
| 421 vkCmdCopyBuffer(commandBuffer, stagingBuffer, gpuData.buffer.vk, 1, addr(copyRegion)) | 445 vkCmdCopyBuffer(commandBuffer, stagingBuffer, gpuData.buffer.vk, 1, addr(copyRegion)) |
| 422 | 446 |
| 423 checkVkResult vkDestroyBuffer(device, stagingBuffer, nil) | 447 vkDestroyBuffer(vulkan.device, stagingBuffer, nil) |
| 424 checkVkResult vkFreeMemory(device, stagingMemory, nil) | 448 vkFreeMemory(vulkan.device, stagingMemory, nil) |
| 449 | |
| 450 proc UpdateAllGPUBuffers[T](value: T) = | |
| 451 for name, fieldvalue in value.fieldPairs(): | |
| 452 when typeof(fieldvalue) is GPUData: | |
| 453 UpdateGPUBuffer(fieldvalue) | |
| 425 | 454 |
| 426 converter toVkIndexType(indexType: IndexType): VkIndexType = | 455 converter toVkIndexType(indexType: IndexType): VkIndexType = |
| 427 case indexType: | 456 case indexType: |
| 428 of None: VK_INDEX_TYPE_NONE_KHR | 457 of None: VK_INDEX_TYPE_NONE_KHR |
| 429 of UInt8: VK_INDEX_TYPE_UINT8_EXT | 458 of UInt8: VK_INDEX_TYPE_UINT8_EXT |
| 430 of UInt16: VK_INDEX_TYPE_UINT16 | 459 of UInt16: VK_INDEX_TYPE_UINT16 |
| 431 of UInt32: VK_INDEX_TYPE_UINT32 | 460 of UInt32: VK_INDEX_TYPE_UINT32 |
| 432 | 461 |
| 433 proc CreateRenderPass*( | 462 proc CreateRenderPass(format: VkFormat): VkRenderPass = |
| 434 device: VkDevice, | |
| 435 format: VkFormat, | |
| 436 ): VkRenderPass = | |
| 437 | |
| 438 var | 463 var |
| 439 attachments = @[VkAttachmentDescription( | 464 attachments = @[VkAttachmentDescription( |
| 440 format: format, | 465 format: format, |
| 441 samples: VK_SAMPLE_COUNT_1_BIT, | 466 samples: VK_SAMPLE_COUNT_1_BIT, |
| 442 loadOp: VK_ATTACHMENT_LOAD_OP_CLEAR, | 467 loadOp: VK_ATTACHMENT_LOAD_OP_CLEAR, |
| 483 subpassCount: uint32(subpassesList.len), | 508 subpassCount: uint32(subpassesList.len), |
| 484 pSubpasses: subpassesList.ToCPointer, | 509 pSubpasses: subpassesList.ToCPointer, |
| 485 dependencyCount: uint32(dependencies.len), | 510 dependencyCount: uint32(dependencies.len), |
| 486 pDependencies: dependencies.ToCPointer, | 511 pDependencies: dependencies.ToCPointer, |
| 487 ) | 512 ) |
| 488 checkVkResult device.vkCreateRenderPass(addr(createInfo), nil, addr(result)) | 513 checkVkResult vulkan.device.vkCreateRenderPass(addr(createInfo), nil, addr(result)) |
| 489 | 514 |
| 490 proc compileGlslToSPIRV(stage: VkShaderStageFlagBits, shaderSource: string): seq[uint32] {.compileTime.} = | 515 proc compileGlslToSPIRV(stage: VkShaderStageFlagBits, shaderSource: string): seq[uint32] {.compileTime.} = |
| 491 func stage2string(stage: VkShaderStageFlagBits): string {.compileTime.} = | 516 func stage2string(stage: VkShaderStageFlagBits): string {.compileTime.} = |
| 492 case stage | 517 case stage |
| 493 of VK_SHADER_STAGE_VERTEX_BIT: "vert" | 518 of VK_SHADER_STAGE_VERTEX_BIT: "vert" |
| 603 uniforms & | 628 uniforms & |
| 604 samplers & | 629 samplers & |
| 605 fsOutput & | 630 fsOutput & |
| 606 @[shader.fragmentCode]).join("\n") | 631 @[shader.fragmentCode]).join("\n") |
| 607 | 632 |
| 608 proc CompileShader[TShader](device: VkDevice, shader: static TShader): ShaderObject[TShader] = | 633 proc CompileShader[TShader](shader: static TShader): ShaderObject[TShader] = |
| 609 const (vertexShaderSource, fragmentShaderSource) = generateShaderSource(shader) | 634 const (vertexShaderSource, fragmentShaderSource) = generateShaderSource(shader) |
| 610 | 635 |
| 611 let vertexBinary = compileGlslToSPIRV(VK_SHADER_STAGE_VERTEX_BIT, vertexShaderSource) | 636 let vertexBinary = compileGlslToSPIRV(VK_SHADER_STAGE_VERTEX_BIT, vertexShaderSource) |
| 612 let fragmentBinary = compileGlslToSPIRV(VK_SHADER_STAGE_FRAGMENT_BIT, fragmentShaderSource) | 637 let fragmentBinary = compileGlslToSPIRV(VK_SHADER_STAGE_FRAGMENT_BIT, fragmentShaderSource) |
| 613 | 638 |
| 614 var createInfoVertex = VkShaderModuleCreateInfo( | 639 var createInfoVertex = VkShaderModuleCreateInfo( |
| 615 sType: VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, | 640 sType: VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, |
| 616 codeSize: csize_t(vertexBinary.len * sizeof(uint32)), | 641 codeSize: csize_t(vertexBinary.len * sizeof(uint32)), |
| 617 pCode: vertexBinary.ToCPointer, | 642 pCode: vertexBinary.ToCPointer, |
| 618 ) | 643 ) |
| 619 checkVkResult device.vkCreateShaderModule(addr(createInfoVertex), nil, addr(result.vertexShader)) | 644 checkVkResult vulkan.device.vkCreateShaderModule(addr(createInfoVertex), nil, addr(result.vertexShader)) |
| 620 var createInfoFragment = VkShaderModuleCreateInfo( | 645 var createInfoFragment = VkShaderModuleCreateInfo( |
| 621 sType: VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, | 646 sType: VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, |
| 622 codeSize: csize_t(fragmentBinary.len * sizeof(uint32)), | 647 codeSize: csize_t(fragmentBinary.len * sizeof(uint32)), |
| 623 pCode: fragmentBinary.ToCPointer, | 648 pCode: fragmentBinary.ToCPointer, |
| 624 ) | 649 ) |
| 625 checkVkResult device.vkCreateShaderModule(addr(createInfoFragment), nil, addr(result.fragmentShader)) | 650 checkVkResult vulkan.device.vkCreateShaderModule(addr(createInfoFragment), nil, addr(result.fragmentShader)) |
| 626 | 651 |
| 627 | 652 |
| 628 proc CreatePipeline*[TShader]( | 653 proc CreatePipeline[TShader]( |
| 629 device: VkDevice, | |
| 630 renderPass: VkRenderPass, | 654 renderPass: VkRenderPass, |
| 631 shader: ShaderObject[TShader], | 655 shader: ShaderObject[TShader], |
| 632 topology: VkPrimitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, | 656 topology: VkPrimitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, |
| 633 polygonMode: VkPolygonMode = VK_POLYGON_MODE_FILL, | 657 polygonMode: VkPolygonMode = VK_POLYGON_MODE_FILL, |
| 634 cullMode: VkCullModeFlagBits = VK_CULL_MODE_BACK_BIT, | 658 cullMode: VkCullModeFlagBits = VK_CULL_MODE_BACK_BIT, |
| 645 stageFlags: VkShaderStageFlags(VK_SHADER_STAGE_ALL_GRAPHICS), | 669 stageFlags: VkShaderStageFlags(VK_SHADER_STAGE_ALL_GRAPHICS), |
| 646 pImmutableSamplers: nil, | 670 pImmutableSamplers: nil, |
| 647 ) | 671 ) |
| 648 var layoutCreateInfo = VkDescriptorSetLayoutCreateInfo( | 672 var layoutCreateInfo = VkDescriptorSetLayoutCreateInfo( |
| 649 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, | 673 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, |
| 650 bindingCount: uint32(layoutbindings.len), | 674 bindingCount: layoutbindings.len.uint32, |
| 651 pBindings: layoutbindings.ToCPointer | 675 pBindings: layoutbindings.ToCPointer |
| 652 ) | 676 ) |
| 653 checkVkResult vkCreateDescriptorSetLayout(device, addr(layoutCreateInfo), nil, addr(result.descriptorSetLayout)) | 677 checkVkResult vkCreateDescriptorSetLayout(vulkan.device, addr(layoutCreateInfo), nil, addr(result.descriptorSetLayouts)) |
| 654 let pipelineLayoutInfo = VkPipelineLayoutCreateInfo( | 678 let pipelineLayoutInfo = VkPipelineLayoutCreateInfo( |
| 655 sType: VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, | 679 sType: VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, |
| 656 setLayoutCount: 1, | 680 setLayoutCount: result.descriptorSetLayouts.len.uint32, |
| 657 pSetLayouts: addr(result.descriptorSetLayout), | 681 pSetLayouts: descriptorSetLayouts.ToCPointer, |
| 658 # pushConstantRangeCount: uint32(pushConstants.len), | 682 # pushConstantRangeCount: uint32(pushConstants.len), |
| 659 # pPushConstantRanges: pushConstants.ToCPointer, | 683 # pPushConstantRanges: pushConstants.ToCPointer, |
| 660 ) | 684 ) |
| 661 checkVkResult vkCreatePipelineLayout(device, addr(pipelineLayoutInfo), nil, addr(result.layout)) | 685 checkVkResult vkCreatePipelineLayout(vulkan.device, addr(pipelineLayoutInfo), nil, addr(result.layout)) |
| 662 | 686 |
| 663 let stages = [ | 687 let stages = [ |
| 664 VkPipelineShaderStageCreateInfo( | 688 VkPipelineShaderStageCreateInfo( |
| 665 sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | 689 sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, |
| 666 stage: VK_SHADER_STAGE_VERTEX_BIT, | 690 stage: VK_SHADER_STAGE_VERTEX_BIT, |
| 776 subpass: 0, | 800 subpass: 0, |
| 777 basePipelineHandle: VkPipeline(0), | 801 basePipelineHandle: VkPipeline(0), |
| 778 basePipelineIndex: -1, | 802 basePipelineIndex: -1, |
| 779 ) | 803 ) |
| 780 checkVkResult vkCreateGraphicsPipelines( | 804 checkVkResult vkCreateGraphicsPipelines( |
| 781 device, | 805 vulkan.device, |
| 782 VkPipelineCache(0), | 806 VkPipelineCache(0), |
| 783 1, | 807 1, |
| 784 addr(createInfo), | 808 addr(createInfo), |
| 785 nil, | 809 nil, |
| 786 addr(result.pipeline) | 810 addr(result.pipeline) |
| 787 ) | 811 ) |
| 788 | 812 |
| 789 proc AllocateIndirectMemory(device: VkDevice, pDevice: VkPhysicalDevice, size: uint64): IndirectGPUMemory = | 813 proc AllocateIndirectMemory(size: uint64): IndirectGPUMemory = |
| 790 # chooses biggest memory type that has NOT VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | 814 # chooses biggest memory type that has NOT VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
| 791 result.size = size | 815 result.size = size |
| 792 result.needsTransfer = true | 816 result.needsTransfer = true |
| 793 | 817 |
| 794 # find a good memory type | 818 # find a good memory type |
| 795 var physicalProperties: VkPhysicalDeviceMemoryProperties | 819 var physicalProperties: VkPhysicalDeviceMemoryProperties |
| 796 checkVkResult vkGetPhysicalDeviceMemoryProperties(pDevice, addr physicalProperties) | 820 vkGetPhysicalDeviceMemoryProperties(vulkan.physicalDevice, addr physicalProperties) |
| 797 | 821 |
| 798 var biggestHeap: uint64 = 0 | 822 var biggestHeap: uint64 = 0 |
| 799 var memoryTypeIndex = high(uint32) | 823 var memoryTypeIndex = high(uint32) |
| 800 # try to find non-host-visible type | 824 # try to find non-host-visible type |
| 801 for i in 0'u32 ..< physicalProperties.memoryTypeCount: | 825 for i in 0'u32 ..< physicalProperties.memoryTypeCount: |
| 819 sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, | 843 sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, |
| 820 allocationSize: result.size, | 844 allocationSize: result.size, |
| 821 memoryTypeIndex: memoryTypeIndex, | 845 memoryTypeIndex: memoryTypeIndex, |
| 822 ) | 846 ) |
| 823 checkVkResult vkAllocateMemory( | 847 checkVkResult vkAllocateMemory( |
| 824 device, | 848 vulkan.device, |
| 825 addr allocationInfo, | 849 addr allocationInfo, |
| 826 nil, | 850 nil, |
| 827 addr result.vk | 851 addr result.vk |
| 828 ) | 852 ) |
| 829 | 853 |
| 830 proc AllocateDirectMemory(device: VkDevice, pDevice: VkPhysicalDevice, size: uint64): DirectGPUMemory = | 854 proc AllocateDirectMemory(size: uint64): DirectGPUMemory = |
| 831 result.size = size | 855 result.size = size |
| 832 result.needsFlush = true | 856 result.needsFlush = true |
| 833 | 857 |
| 834 # find a good memory type | 858 # find a good memory type |
| 835 var physicalProperties: VkPhysicalDeviceMemoryProperties | 859 var physicalProperties: VkPhysicalDeviceMemoryProperties |
| 836 checkVkResult vkGetPhysicalDeviceMemoryProperties(pDevice, addr physicalProperties) | 860 vkGetPhysicalDeviceMemoryProperties(vulkan.physicalDevice, addr physicalProperties) |
| 837 | 861 |
| 838 var biggestHeap: uint64 = 0 | 862 var biggestHeap: uint64 = 0 |
| 839 var memoryTypeIndex = high(uint32) | 863 var memoryTypeIndex = high(uint32) |
| 840 # try to find host-visible type | 864 # try to find host-visible type |
| 841 for i in 0 ..< physicalProperties.memoryTypeCount: | 865 for i in 0 ..< physicalProperties.memoryTypeCount: |
| 849 | 873 |
| 850 assert memoryTypeIndex != high(uint32), "Unable to find indirect memory type" | 874 assert memoryTypeIndex != high(uint32), "Unable to find indirect memory type" |
| 851 var allocationInfo = VkMemoryAllocateInfo( | 875 var allocationInfo = VkMemoryAllocateInfo( |
| 852 sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, | 876 sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, |
| 853 allocationSize: result.size, | 877 allocationSize: result.size, |
| 854 memoryTypeIndex: FindDirectMemoryTypeIndex(pDevice), | 878 memoryTypeIndex: GetDirectMemoryTypeIndex(), |
| 855 ) | 879 ) |
| 856 checkVkResult vkAllocateMemory( | 880 checkVkResult vkAllocateMemory( |
| 857 device, | 881 vulkan.device, |
| 858 addr allocationInfo, | 882 addr allocationInfo, |
| 859 nil, | 883 nil, |
| 860 addr result.vk | 884 addr result.vk |
| 861 ) | 885 ) |
| 862 checkVkResult vkMapMemory( | 886 checkVkResult vkMapMemory( |
| 863 device = device, | 887 device = vulkan.device, |
| 864 memory = result.vk, | 888 memory = result.vk, |
| 865 offset = 0'u64, | 889 offset = 0'u64, |
| 866 size = result.size, | 890 size = result.size, |
| 867 flags = VkMemoryMapFlags(0), | 891 flags = VkMemoryMapFlags(0), |
| 868 ppData = addr(result.data) | 892 ppData = addr(result.data) |
| 869 ) | 893 ) |
| 870 | 894 |
| 871 proc AllocateIndirectBuffer(device: VkDevice, renderData: var RenderData, size: uint64, btype: BufferType) = | 895 proc AllocateIndirectBuffer(renderData: var RenderData, size: uint64, btype: BufferType) = |
| 872 assert size > 0, "Buffer sizes must be larger than 0" | 896 if size == 0: |
| 897 return | |
| 873 var buffer = Buffer[IndirectGPUMemory](size: size) | 898 var buffer = Buffer[IndirectGPUMemory](size: size) |
| 874 | 899 |
| 875 let usageFlags = case btype: | 900 let usageFlags = case btype: |
| 876 of VertexBuffer: [VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT] | 901 of VertexBuffer: [VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT] |
| 877 of IndexBuffer: [VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT] | 902 of IndexBuffer: [VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT] |
| 878 of UniformBuffer: [VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT] | 903 of UniformBuffer: [VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT] |
| 879 | 904 |
| 880 # iterate through memory areas to find big enough free space | 905 # iterate through memory areas to find big enough free space |
| 881 for (memory, offset) in renderData.indirectMemory.mitems: | 906 # TODO: dynamically expand memory allocations |
| 882 if memory.size - offset >= size: | 907 for (memory, usedOffset) in renderData.indirectMemory.mitems: |
| 883 buffer.offset = offset | 908 if memory.size - usedOffset >= size: |
| 909 buffer.offset = usedOffset | |
| 884 # create buffer | 910 # create buffer |
| 885 var createInfo = VkBufferCreateInfo( | 911 var createInfo = VkBufferCreateInfo( |
| 886 sType: VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 912 sType: VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 887 flags: VkBufferCreateFlags(0), | 913 flags: VkBufferCreateFlags(0), |
| 888 size: buffer.size, | 914 size: buffer.size, |
| 889 usage: toBits(usageFlags), | 915 usage: toBits(usageFlags), |
| 890 sharingMode: VK_SHARING_MODE_EXCLUSIVE, | 916 sharingMode: VK_SHARING_MODE_EXCLUSIVE, |
| 891 ) | 917 ) |
| 892 checkVkResult vkCreateBuffer( | 918 checkVkResult vkCreateBuffer( |
| 893 device = device, | 919 device = vulkan.device, |
| 894 pCreateInfo = addr createInfo, | 920 pCreateInfo = addr createInfo, |
| 895 pAllocator = nil, | 921 pAllocator = nil, |
| 896 pBuffer = addr(buffer.vk) | 922 pBuffer = addr(buffer.vk) |
| 897 ) | 923 ) |
| 898 checkVkResult vkBindBufferMemory(device, buffer.vk, memory.vk, buffer.offset) | 924 checkVkResult vkBindBufferMemory(vulkan.device, buffer.vk, memory.vk, buffer.offset) |
| 899 renderData.indirectBuffers.add (buffer, btype, 0'u64) | 925 renderData.indirectBuffers.add (buffer, btype, 0'u64) |
| 900 # update memory area offset | 926 # update memory area offset |
| 901 offset = alignedTo(offset + size, MEMORY_ALIGNMENT) | 927 usedOffset = alignedTo(usedOffset + size, MEMORY_ALIGNMENT) |
| 902 return | 928 return |
| 903 | 929 |
| 904 assert false, "Did not find allocated memory region with enough space" | 930 assert false, "Did not find allocated memory region with enough space" |
| 905 | 931 |
| 906 proc AllocateDirectBuffer(device: VkDevice, renderData: var RenderData, size: uint64, btype: BufferType) = | 932 proc AllocateDirectBuffer(renderData: var RenderData, size: uint64, btype: BufferType) = |
| 907 assert size > 0, "Buffer sizes must be larger than 0" | 933 if size == 0: |
| 934 return | |
| 935 | |
| 908 var buffer = Buffer[DirectGPUMemory](size: size) | 936 var buffer = Buffer[DirectGPUMemory](size: size) |
| 909 | 937 |
| 910 let usageFlags = case btype: | 938 let usageFlags = case btype: |
| 911 of VertexBuffer: [VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT] | 939 of VertexBuffer: [VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT] |
| 912 of IndexBuffer: [VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT] | 940 of IndexBuffer: [VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT] |
| 913 of UniformBuffer: [VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT] | 941 of UniformBuffer: [VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT] |
| 914 | 942 |
| 915 # iterate through memory areas to find big enough free space | 943 # iterate through memory areas to find big enough free space |
| 916 for (memory, offset) in renderData.directMemory.mitems: | 944 # TODO: dynamically expand memory allocations |
| 917 if memory.size - offset >= size: | 945 for (memory, usedOffset) in renderData.directMemory.mitems: |
| 918 buffer.offset = offset | 946 if memory.size - usedOffset >= size: |
| 947 buffer.offset = usedOffset | |
| 919 # create buffer | 948 # create buffer |
| 920 var createInfo = VkBufferCreateInfo( | 949 var createInfo = VkBufferCreateInfo( |
| 921 sType: VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 950 sType: VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 922 flags: VkBufferCreateFlags(0), | 951 flags: VkBufferCreateFlags(0), |
| 923 size: buffer.size, | 952 size: buffer.size, |
| 924 usage: toBits(usageFlags), | 953 usage: toBits(usageFlags), |
| 925 sharingMode: VK_SHARING_MODE_EXCLUSIVE, | 954 sharingMode: VK_SHARING_MODE_EXCLUSIVE, |
| 926 ) | 955 ) |
| 927 checkVkResult vkCreateBuffer( | 956 checkVkResult vkCreateBuffer( |
| 928 device = device, | 957 device = vulkan.device, |
| 929 pCreateInfo = addr createInfo, | 958 pCreateInfo = addr createInfo, |
| 930 pAllocator = nil, | 959 pAllocator = nil, |
| 931 pBuffer = addr(buffer.vk) | 960 pBuffer = addr(buffer.vk) |
| 932 ) | 961 ) |
| 933 checkVkResult vkBindBufferMemory(device, buffer.vk, memory.vk, buffer.offset) | 962 checkVkResult vkBindBufferMemory(vulkan.device, buffer.vk, memory.vk, buffer.offset) |
| 934 renderData.directBuffers.add (buffer, btype, 0'u64) | 963 renderData.directBuffers.add (buffer, btype, 0'u64) |
| 935 # update memory area offset | 964 # update memory area offset |
| 936 offset = alignedTo(offset + size, MEMORY_ALIGNMENT) | 965 usedOffset = alignedTo(usedOffset + size, MEMORY_ALIGNMENT) |
| 937 return | 966 return |
| 938 | 967 |
| 939 assert false, "Did not find allocated memory region with enough space" | 968 assert false, "Did not find allocated memory region with enough space" |
| 940 | 969 |
| 941 proc InitRenderData(device: VkDevice, pDevice: VkPhysicalDevice, descriptorPoolLimit = 1024'u32): RenderData = | 970 proc InitRenderData(descriptorPoolLimit = 1024'u32): RenderData = |
| 942 # allocate descriptor pools | 971 # allocate descriptor pools |
| 943 var poolSizes = [ | 972 var poolSizes = [ |
| 944 VkDescriptorPoolSize(thetype: VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, descriptorCount: descriptorPoolLimit), | 973 VkDescriptorPoolSize(thetype: VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, descriptorCount: descriptorPoolLimit), |
| 945 VkDescriptorPoolSize(thetype: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: descriptorPoolLimit), | 974 VkDescriptorPoolSize(thetype: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: descriptorPoolLimit), |
| 946 ] | 975 ] |
| 948 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, | 977 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, |
| 949 poolSizeCount: poolSizes.len.uint32, | 978 poolSizeCount: poolSizes.len.uint32, |
| 950 pPoolSizes: poolSizes.ToCPointer, | 979 pPoolSizes: poolSizes.ToCPointer, |
| 951 maxSets: descriptorPoolLimit, | 980 maxSets: descriptorPoolLimit, |
| 952 ) | 981 ) |
| 953 checkVkResult vkCreateDescriptorPool(device, addr(poolInfo), nil, addr(result.descriptorPool)) | 982 checkVkResult vkCreateDescriptorPool(vulkan.device, addr(poolInfo), nil, addr(result.descriptorPool)) |
| 954 | 983 |
| 955 # allocate some memory | 984 # allocate some memory |
| 956 var initialAllocationSize = 1_000_000_000'u64 # TODO: make this more dynamic or something | 985 var initialAllocationSize = 1_000_000_000'u64 # TODO: make this more dynamic or something |
| 957 result.indirectMemory = @[(AllocateIndirectMemory(device, pDevice, size = initialAllocationSize), 0'u64)] | 986 result.indirectMemory = @[(memory: AllocateIndirectMemory(size = initialAllocationSize), usedOffset: 0'u64)] |
| 958 result.directMemory = @[(AllocateDirectMemory(device, pDevice, size = initialAllocationSize), 0'u64)] | 987 result.directMemory = @[(memory: AllocateDirectMemory(size = initialAllocationSize), usedOffset: 0'u64)] |
| 988 | |
| 989 proc FlushDirectMemory(renderData: RenderData) = | |
| 990 var flushRegions = newSeqOfCap[VkMappedMemoryRange](renderData.directMemory.len) | |
| 991 for entry in renderData.directMemory: | |
| 992 if entry.usedOffset > 0: | |
| 993 flushRegions.add VkMappedMemoryRange( | |
| 994 sType: VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, | |
| 995 memory: entry.memory.vk, | |
| 996 size: entry.usedOffset, | |
| 997 ) | |
| 998 if flushRegions.len > 0: | |
| 999 checkVkResult vkFlushMappedMemoryRanges(vulkan.device, flushRegions.len.uint32, flushRegions.ToCPointer()) | |
| 959 | 1000 |
| 960 # For the Get*BufferSize: | 1001 # For the Get*BufferSize: |
| 961 # BUFFER_ALIGNMENT is just added for a rough estimate, to ensure we have enough space to align when binding | 1002 # BUFFER_ALIGNMENT is just added for a rough estimate, to ensure we have enough space to align when binding |
| 962 proc GetIndirectBufferSizes[T](data: T): uint64 = | 1003 proc GetIndirectBufferSizes[T](data: T): uint64 = |
| 963 for name, value in fieldPairs(data): | 1004 for name, value in fieldPairs(data): |
| 984 static: assert typeof(value) is GPUArray, "Index buffers must be of type GPUArray" | 1025 static: assert typeof(value) is GPUArray, "Index buffers must be of type GPUArray" |
| 985 static: assert elementType(value.data) is uint8 or elementType(value.data) is uint16 or elementType(value.data) is uint32 | 1026 static: assert elementType(value.data) is uint8 or elementType(value.data) is uint16 or elementType(value.data) is uint32 |
| 986 when UsesDirectMemory(value): | 1027 when UsesDirectMemory(value): |
| 987 result += value.size + BUFFER_ALIGNMENT | 1028 result += value.size + BUFFER_ALIGNMENT |
| 988 | 1029 |
| 989 proc AssignIndirectBuffers[T](data: T, renderdata: var RenderData, btype: BufferType) = | 1030 proc AssignIndirectBuffers[T](renderdata: var RenderData, btype: BufferType, data: var T) = |
| 990 for name, value in fieldPairs(data): | 1031 for name, value in fieldPairs(data): |
| 991 when typeof(value) is GPUData: | 1032 when typeof(value) is GPUData: |
| 992 when UsesIndirectMemory(value): | 1033 when UsesIndirectMemory(value): |
| 993 # find next buffer of correct type with enough free space | 1034 # find next buffer of correct type with enough free space |
| 994 var foundBuffer = false | 1035 if btype == IndexBuffer == value.hasCustomPragma(VertexIndices): |
| 995 for (buffer, bt, offset) in renderData.indirectBuffers.mitems: | 1036 var foundBuffer = false |
| 996 if bt == btype and buffer.size - offset >= size: | 1037 for (buffer, bt, offset) in renderData.indirectBuffers.mitems: |
| 997 assert not value.buffer.vk.Valid, "GPUData-Buffer has already been assigned" | 1038 if bt == btype and buffer.size - offset >= value.size: |
| 998 assert buffer.vk.Valid, "RenderData-Buffer has not yet been created" | 1039 assert not value.buffer.vk.Valid, "GPUData-Buffer has already been assigned" |
| 999 value.buffer = buffer | 1040 assert buffer.vk.Valid, "RenderData-Buffer has not yet been created" |
| 1000 value.offset = offset | 1041 value.buffer = buffer |
| 1001 offset = alignedTo(offset + value.size, BUFFER_ALIGNMENT) | 1042 value.offset = offset |
| 1002 foundBuffer = true | 1043 offset = alignedTo(offset + value.size, BUFFER_ALIGNMENT) |
| 1003 break | 1044 foundBuffer = true |
| 1004 assert foundBuffer, &"Unable to find large enough '{btype}' for '{data}'" | 1045 break |
| 1005 proc AssignDirectBuffers[T](data: T, renderdata: var RenderData, btype: BufferType) = | 1046 assert foundBuffer, &"Unable to find large enough '{btype}' for '{data}'" |
| 1047 proc AssignDirectBuffers[T](renderdata: var RenderData, btype: BufferType, data: var T) = | |
| 1006 for name, value in fieldPairs(data): | 1048 for name, value in fieldPairs(data): |
| 1007 when typeof(value) is GPUData: | 1049 when typeof(value) is GPUData: |
| 1008 when UsesDirectMemory(value): | 1050 when UsesDirectMemory(value): |
| 1009 # find next buffer of correct type with enough free space | 1051 # find next buffer of correct type with enough free space |
| 1010 var foundBuffer = false | 1052 if btype == IndexBuffer == value.hasCustomPragma(VertexIndices): |
| 1011 for (buffer, bt, offset) in renderData.directBuffers.mitems: | 1053 var foundBuffer = false |
| 1012 if bt == btype and buffer.size - offset >= size: | 1054 for (buffer, bt, offset) in renderData.directBuffers.mitems: |
| 1013 assert not value.buffer.vk.Valid, "GPUData-Buffer has already been assigned" | 1055 if bt == btype and buffer.size - offset >= value.size: |
| 1014 assert buffer.vk.Valid, "RenderData-Buffer has not yet been created" | 1056 assert not value.buffer.vk.Valid, "GPUData-Buffer has already been assigned" |
| 1015 value.buffer = buffer | 1057 assert buffer.vk.Valid, "RenderData-Buffer has not yet been created" |
| 1016 value.offset = offset | 1058 value.buffer = buffer |
| 1017 offset = alignedTo(offset + value.size, BUFFER_ALIGNMENT) | 1059 value.offset = offset |
| 1018 foundBuffer = true | 1060 offset = alignedTo(offset + value.size, BUFFER_ALIGNMENT) |
| 1019 break | 1061 foundBuffer = true |
| 1020 assert foundBuffer, &"Unable to find large enough '{btype}' for '{data}'" | 1062 break |
| 1021 | 1063 assert foundBuffer, &"Unable to find large enough '{btype}' for '{data}'" |
| 1022 proc WriteDescriptors[TShader](device: VkDevice, descriptorSets: array[INFLIGHTFRAMES.int, VkDescriptorSet]) = | 1064 |
| 1065 proc HasGPUValueField[T](name: static string): bool {.compileTime.} = | |
| 1066 for fieldname, value in default(T).fieldPairs(): | |
| 1067 when typeof(value) is GPUValue and fieldname == name: return true | |
| 1068 return false | |
| 1069 | |
| 1070 template WithGPUValueField(obj: object, name: static string, fieldvalue, body: untyped): untyped = | |
| 1071 # HasGPUValueField MUST be used to check if this is supported | |
| 1072 for fieldname, value in obj.fieldPairs(): | |
| 1073 when fieldname == name: | |
| 1074 block: | |
| 1075 let `fieldvalue` {.inject.} = value | |
| 1076 body | |
| 1077 | |
| 1078 proc WriteDescriptors[TShader, TUniforms, TGlobals](renderData: RenderData, uniforms: TUniforms, globals: TGlobals) = | |
| 1023 var descriptorSetWrites: seq[VkWriteDescriptorSet] | 1079 var descriptorSetWrites: seq[VkWriteDescriptorSet] |
| 1024 # map (buffer + offset + range) to descriptor | 1080 # map (buffer + offset + range) to descriptor |
| 1025 # map (texture) to descriptor | 1081 # map (texture) to descriptor |
| 1026 ForDescriptorFields(default(TShader), fieldName, descriptorType, descriptorCount, descriptorBindingNumber): | 1082 ForDescriptorFields(default(TShader), fieldName, descriptorType, descriptorCount, descriptorBindingNumber): |
| 1027 for frameInFlight in 0 ..< descriptorSets.len: | 1083 static: echo fieldName, " ", descriptorType, " ", descriptorCount |
| 1084 for frameInFlight in 0 ..< renderData.descriptorSets.len: | |
| 1028 when descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: | 1085 when descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: |
| 1029 # TODO | 1086 when HasGPUValueField[TUniforms](fieldName): |
| 1030 let bufferInfo = VkDescriptorBufferInfo( | 1087 WithGPUValueField(uniforms, fieldName, gpuValue): |
| 1031 buffer: VkBuffer(0), | 1088 let bufferInfo = VkDescriptorBufferInfo( |
| 1032 offset: 0, | 1089 buffer: gpuValue.buffer.vk, |
| 1033 range: 1, | 1090 offset: gpuValue.buffer.offset, |
| 1034 ) | 1091 range: gpuValue.buffer.size, |
| 1035 descriptorSetWrites.add VkWriteDescriptorSet( | 1092 ) |
| 1036 sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, | 1093 descriptorSetWrites.add VkWriteDescriptorSet( |
| 1037 dstSet: descriptorSets[frameInFlight], | 1094 sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, |
| 1038 dstBinding: descriptorBindingNumber, | 1095 dstSet: renderData.descriptorSets[frameInFlight], |
| 1039 dstArrayElement: uint32(0), | 1096 dstBinding: descriptorBindingNumber, |
| 1040 descriptorType: descriptorType, | 1097 dstArrayElement: uint32(0), |
| 1041 descriptorCount: descriptorCount, | 1098 descriptorType: descriptorType, |
| 1042 pImageInfo: nil, | 1099 descriptorCount: descriptorCount, |
| 1043 pBufferInfo: addr(bufferInfo), | 1100 pImageInfo: nil, |
| 1044 ) | 1101 pBufferInfo: addr(bufferInfo), |
| 1102 ) | |
| 1103 elif HasGPUValueField[TGlobals](fieldName): | |
| 1104 WithGPUValueField(globals, fieldName, theValue): | |
| 1105 let bufferInfo = VkDescriptorBufferInfo( | |
| 1106 buffer: theValue.buffer.vk, | |
| 1107 offset: theValue.buffer.offset, | |
| 1108 range: theValue.buffer.size, | |
| 1109 ) | |
| 1110 descriptorSetWrites.add VkWriteDescriptorSet( | |
| 1111 sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, | |
| 1112 dstSet: renderData.descriptorSets[frameInFlight], | |
| 1113 dstBinding: descriptorBindingNumber, | |
| 1114 dstArrayElement: uint32(0), | |
| 1115 descriptorType: descriptorType, | |
| 1116 descriptorCount: descriptorCount, | |
| 1117 pImageInfo: nil, | |
| 1118 pBufferInfo: addr(bufferInfo), | |
| 1119 ) | |
| 1120 else: | |
| 1121 {.error: "Unable to find field '" & fieldName & "' in uniforms or globals".} | |
| 1045 elif descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: | 1122 elif descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: |
| 1046 # TODO | 1123 # TODO |
| 1047 let imageInfo = VkDescriptorImageInfo( | 1124 let imageInfo = VkDescriptorImageInfo( |
| 1048 sampler: VkSampler(0), | 1125 sampler: VkSampler(0), |
| 1049 imageView: VkImageView(0), | 1126 imageView: VkImageView(0), |
| 1050 imageLayout: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, | 1127 imageLayout: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, |
| 1051 ) | 1128 ) |
| 1052 descriptorSetWrites.add VkWriteDescriptorSet( | 1129 descriptorSetWrites.add VkWriteDescriptorSet( |
| 1053 sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, | 1130 sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, |
| 1054 dstSet: descriptorSets[frameInFlight], | 1131 dstSet: renderData.descriptorSets[frameInFlight], |
| 1055 dstBinding: descriptorBindingNumber, | 1132 dstBinding: descriptorBindingNumber, |
| 1056 dstArrayElement: uint32(0), | 1133 dstArrayElement: 0'u32, |
| 1057 descriptorType: descriptorType, | 1134 descriptorType: descriptorType, |
| 1058 descriptorCount: descriptorCount, | 1135 descriptorCount: descriptorCount, |
| 1059 pImageInfo: addr(imageInfo), | 1136 pImageInfo: addr(imageInfo), |
| 1060 pBufferInfo: nil, | 1137 pBufferInfo: nil, |
| 1061 ) | 1138 ) |
| 1062 checkVkResult vkUpdateDescriptorSets(device, uint32(descriptorSetWrites.len), descriptorSetWrites.ToCPointer, 0, nil) | 1139 else: |
| 1140 assert false, "Unsupported descriptor type" | |
| 1141 echo descriptorSetWrites | |
| 1142 vkUpdateDescriptorSets(vulkan.device, uint32(descriptorSetWrites.len), descriptorSetWrites.ToCPointer, 0, nil) | |
| 1063 | 1143 |
| 1064 proc Bind[T](pipeline: Pipeline[T], commandBuffer: VkCommandBuffer, currentFrameInFlight: int) = | 1144 proc Bind[T](pipeline: Pipeline[T], commandBuffer: VkCommandBuffer, currentFrameInFlight: int) = |
| 1065 commandBuffer.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipeline) | 1145 commandBuffer.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipeline) |
| 1066 #[ | 1146 #[ |
| 1067 commandBuffer.vkCmdBindDescriptorSets( | 1147 commandBuffer.vkCmdBindDescriptorSets( |
| 1252 vertexCode: string = "void main() {}" | 1332 vertexCode: string = "void main() {}" |
| 1253 fragmentCode: string = "void main() {}" | 1333 fragmentCode: string = "void main() {}" |
| 1254 | 1334 |
| 1255 let w = CreateWindow("test2") | 1335 let w = CreateWindow("test2") |
| 1256 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") | 1336 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") |
| 1257 let vulkan = w.CreateInstance( | 1337 |
| 1338 # TODO: remove those ugly wrappers | |
| 1339 let theInstance = w.CreateInstance( | |
| 1258 vulkanVersion = VK_MAKE_API_VERSION(0, 1, 3, 0), | 1340 vulkanVersion = VK_MAKE_API_VERSION(0, 1, 3, 0), |
| 1259 instanceExtensions = @[], | 1341 instanceExtensions = @[], |
| 1260 layers = @["VK_LAYER_KHRONOS_validation"], | 1342 layers = @["VK_LAYER_KHRONOS_validation"], |
| 1261 ) | 1343 ) |
| 1262 | 1344 |
| 1263 let dev = vulkan.CreateDevice( | 1345 let dev = theInstance.CreateDevice( |
| 1264 GetPhysicalDevice(), | 1346 theInstance.GetPhysicalDevices().FilterBestGraphics(), |
| 1265 enabledExtensions = @[], | 1347 enabledExtensions = @[], |
| 1266 [GetQueueFamily()], | 1348 theInstance.GetPhysicalDevices().FilterBestGraphics().FilterForGraphicsPresentationQueues() |
| 1267 ) | 1349 ).vk |
| 1268 let frameWidth = 100'u32 | 1350 let frameWidth = 100'u32 |
| 1269 let frameHeight = 100'u32 | 1351 let frameHeight = 100'u32 |
| 1352 | |
| 1353 # TODO: pack this stuff into a setup method and condense everything a bit | |
| 1354 let pDevice = theInstance.vk.GetPhysicalDevice() | |
| 1355 let qfi = pDevice.GetQueueFamily(VK_QUEUE_GRAPHICS_BIT) | |
| 1356 vulkan = VulkanGlobals( | |
| 1357 instance: theInstance.vk, | |
| 1358 device: dev, | |
| 1359 physicalDevice: pDevice, | |
| 1360 queueFamilyIndex: qfi, | |
| 1361 queue: dev.GetQueue(qfi, VK_QUEUE_GRAPHICS_BIT) | |
| 1362 ) | |
| 1270 | 1363 |
| 1271 var myMesh1 = MeshA( | 1364 var myMesh1 = MeshA( |
| 1272 position: GPUArray[Vec3f, IndirectGPUMemory](data: @[NewVec3f(0, 0, ), NewVec3f(0, 0, ), NewVec3f(0, 0, )]), | 1365 position: GPUArray[Vec3f, IndirectGPUMemory](data: @[NewVec3f(0, 0, ), NewVec3f(0, 0, ), NewVec3f(0, 0, )]), |
| 1273 ) | 1366 ) |
| 1274 var uniforms1 = UniformsA( | 1367 var uniforms1 = UniformsA( |
| 1288 objPosition: GPUArray[Vec3f, IndirectGPUMemory](data: @[NewVec3f(0, 0, 0), NewVec3f(1, 1, 1)]), | 1381 objPosition: GPUArray[Vec3f, IndirectGPUMemory](data: @[NewVec3f(0, 0, 0), NewVec3f(1, 1, 1)]), |
| 1289 ) | 1382 ) |
| 1290 var myGlobals: GlobalsA | 1383 var myGlobals: GlobalsA |
| 1291 | 1384 |
| 1292 # setup for rendering (TODO: swapchain & framebuffers) | 1385 # setup for rendering (TODO: swapchain & framebuffers) |
| 1293 | 1386 let renderpass = CreateRenderPass(GetSurfaceFormat()) |
| 1294 # renderpass | |
| 1295 let renderpass = CreateRenderPass(dev.vk, dev.physicalDevice.GetSurfaceFormats().FilterSurfaceFormat().format) | |
| 1296 | 1387 |
| 1297 # shaders | 1388 # shaders |
| 1298 const shader = ShaderA() | 1389 const shader = ShaderA() |
| 1299 let shaderObject = dev.vk.CompileShader(shader) | 1390 let shaderObject = CompileShader(shader) |
| 1300 var pipeline1 = CreatePipeline(device = dev.vk, renderPass = renderpass, shader = shaderObject) | 1391 var pipeline1 = CreatePipeline(renderPass = renderpass, shader = shaderObject) |
| 1301 | 1392 |
| 1302 var renderdata = InitRenderData(dev.vk, dev.physicalDevice.vk) | 1393 var renderdata = InitRenderData() |
| 1303 | 1394 |
| 1304 # create descriptor sets | 1395 # TODO: Textures |
| 1305 #[ | |
| 1306 var descriptorSets: array[INFLIGHTFRAMES.int, VkDescriptorSet] | |
| 1307 var layouts = newSeqWith(descriptorSets.len, pipeline.descriptorSetLayout) | |
| 1308 var allocInfo = VkDescriptorSetAllocateInfo( | |
| 1309 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, | |
| 1310 descriptorPool: pool, | |
| 1311 descriptorSetCount: uint32(layouts.len), | |
| 1312 pSetLayouts: layouts.ToCPointer, | |
| 1313 ) | |
| 1314 checkVkResult vkAllocateDescriptorSets(device, addr(allocInfo), descriptorSets.ToCPointer) | |
| 1315 ]# | |
| 1316 | |
| 1317 #[ | |
| 1318 # TODO: | |
| 1319 # | |
| 1320 # assign indirect buffers to vertex data, can happen through the GPUArray/GPUValue-wrappers, they know buffers | |
| 1321 # assign direct buffers to vertex data | |
| 1322 # assign indirect buffers to uniform data | |
| 1323 # assign direct buffers to uniform data | |
| 1324 # | |
| 1325 # upload all textures | 1396 # upload all textures |
| 1326 # write descriptors for textures and uniform buffers | 1397 # write descriptors for textures and uniform buffers |
| 1327 # | |
| 1328 ]# | |
| 1329 | 1398 |
| 1330 # buffer allocation | 1399 # buffer allocation |
| 1331 var | 1400 var |
| 1332 indirectVertexSizes = 0'u64 | 1401 indirectVertexSizes = 0'u64 |
| 1333 directVertexSizes = 0'u64 | 1402 directVertexSizes = 0'u64 |
| 1334 indirectIndexSizes = 0'u64 | 1403 indirectIndexSizes = 0'u64 |
| 1335 directIndexSizes = 0'u64 | 1404 directIndexSizes = 0'u64 |
| 1336 indirectUniformSizes = 0'u64 | 1405 indirectUniformSizes = 0'u64 |
| 1337 directUniformSizes = 0'u64 | 1406 directUniformSizes = 0'u64 |
| 1338 | 1407 |
| 1408 # buffer allocation | |
| 1409 | |
| 1410 echo "Allocating GPU buffers" | |
| 1339 indirectVertexSizes += GetIndirectBufferSizes(myMesh1) | 1411 indirectVertexSizes += GetIndirectBufferSizes(myMesh1) |
| 1340 indirectVertexSizes += GetIndirectBufferSizes(instances1) | 1412 indirectVertexSizes += GetIndirectBufferSizes(instances1) |
| 1341 if indirectVertexSizes > 0: | 1413 AllocateIndirectBuffer(renderdata, indirectVertexSizes, VertexBuffer) |
| 1342 AllocateIndirectBuffer(dev.vk, renderdata, indirectVertexSizes, VertexBuffer) | |
| 1343 | 1414 |
| 1344 directVertexSizes += GetDirectBufferSizes(myMesh1) | 1415 directVertexSizes += GetDirectBufferSizes(myMesh1) |
| 1345 directVertexSizes += GetDirectBufferSizes(instances1) | 1416 directVertexSizes += GetDirectBufferSizes(instances1) |
| 1346 if directVertexSizes > 0: | 1417 AllocateDirectBuffer(renderdata, directVertexSizes, VertexBuffer) |
| 1347 AllocateDirectBuffer(dev.vk, renderdata, directVertexSizes, VertexBuffer) | |
| 1348 | 1418 |
| 1349 indirectIndexSizes += GetIndirectIndexBufferSizes(myMesh1) | 1419 indirectIndexSizes += GetIndirectIndexBufferSizes(myMesh1) |
| 1350 if indirectIndexSizes > 0: | 1420 AllocateIndirectBuffer(renderdata, indirectIndexSizes, IndexBuffer) |
| 1351 AllocateIndirectBuffer(dev.vk, renderdata, indirectIndexSizes, IndexBuffer) | |
| 1352 | 1421 |
| 1353 directIndexSizes += GetDirectIndexBufferSizes(myMesh1) | 1422 directIndexSizes += GetDirectIndexBufferSizes(myMesh1) |
| 1354 if directIndexSizes > 0: | 1423 AllocateDirectBuffer(renderdata, directIndexSizes, IndexBuffer) |
| 1355 AllocateDirectBuffer(dev.vk, renderdata, directIndexSizes, IndexBuffer) | |
| 1356 | 1424 |
| 1357 indirectUniformSizes += GetIndirectBufferSizes(uniforms1) | 1425 indirectUniformSizes += GetIndirectBufferSizes(uniforms1) |
| 1358 indirectUniformSizes += GetIndirectBufferSizes(myGlobals) | 1426 indirectUniformSizes += GetIndirectBufferSizes(myGlobals) |
| 1359 if indirectUniformSizes > 0: | 1427 AllocateIndirectBuffer(renderdata, indirectUniformSizes, UniformBuffer) |
| 1360 AllocateIndirectBuffer(dev.vk, renderdata, indirectUniformSizes, UniformBuffer) | |
| 1361 | 1428 |
| 1362 directUniformSizes += GetDirectBufferSizes(uniforms1) | 1429 directUniformSizes += GetDirectBufferSizes(uniforms1) |
| 1363 directUniformSizes += GetDirectBufferSizes(myGlobals) | 1430 directUniformSizes += GetDirectBufferSizes(myGlobals) |
| 1364 if directUniformSizes > 0: | 1431 AllocateDirectBuffer(renderdata, directUniformSizes, UniformBuffer) |
| 1365 AllocateDirectBuffer(dev.vk, renderdata, directUniformSizes, UniformBuffer) | |
| 1366 | 1432 |
| 1367 # buffer assignment | 1433 # buffer assignment |
| 1368 | 1434 # |
| 1369 AssignIndirectBuffers(data = myMesh1, renderdata = RenderData, btype = VertexBuffer) | 1435 echo "Assigning buffers to GPUData fields" |
| 1370 AssignDirectBuffers(data = myMesh1, renderdata = RenderData, btype = VertexBuffer) | 1436 |
| 1371 AssignIndirectBuffers(data = myMesh1, renderdata = RenderData, btype = IndexBuffer) | 1437 # for meshes we do: |
| 1372 AssignDirectBuffers(data = myMesh1, renderdata = RenderData, btype = IndexBuffer) | 1438 renderdata.AssignIndirectBuffers(VertexBuffer, myMesh1) |
| 1373 | 1439 renderdata.AssignDirectBuffers(VertexBuffer, myMesh1) |
| 1374 AssignIndirectBuffers(data = instances1, renderdata = RenderData, btype = VertexBuffer) | 1440 renderdata.AssignIndirectBuffers(IndexBuffer, myMesh1) |
| 1375 AssignDirectBuffers(data = instances1, renderdata = RenderData, btype = VertexBuffer) | 1441 renderdata.AssignDirectBuffers(IndexBuffer, myMesh1) |
| 1376 | 1442 |
| 1377 AssignIndirectBuffers(data = uniforms1, renderdata = RenderData, btype = UniformBuffer) | 1443 # for instances we do: |
| 1378 AssignDirectBuffers(data = uniforms1, renderdata = RenderData, btype = UniformBuffer) | 1444 renderdata.AssignIndirectBuffers(VertexBuffer, instances1) |
| 1379 AssignIndirectBuffers(data = myGlobals, renderdata = RenderData, btype = UniformBuffer) | 1445 renderdata.AssignDirectBuffers(VertexBuffer, instances1) |
| 1380 AssignDirectBuffers(data = myGlobals, renderdata = RenderData, btype = UniformBuffer) | 1446 |
| 1381 | 1447 # for uniforms/globals we do: |
| 1382 UpdateGPUBuffer() | 1448 renderdata.AssignIndirectBuffers(UniformBuffer, uniforms1) |
| 1449 renderdata.AssignDirectBuffers(UniformBuffer, uniforms1) | |
| 1450 renderdata.AssignIndirectBuffers(UniformBuffer, myGlobals) | |
| 1451 renderdata.AssignDirectBuffers(UniformBuffer, myGlobals) | |
| 1452 | |
| 1453 # buffer filling | |
| 1454 | |
| 1455 echo "Copying all data to GPU memory" | |
| 1456 | |
| 1457 # copy everything to GPU | |
| 1458 UpdateAllGPUBuffers(myMesh1) | |
| 1459 UpdateAllGPUBuffers(instances1) | |
| 1460 UpdateAllGPUBuffers(uniforms1) | |
| 1461 UpdateAllGPUBuffers(myGlobals) | |
| 1462 renderdata.FlushDirectMemory() | |
| 1383 | 1463 |
| 1384 # descriptors | 1464 # descriptors |
| 1385 # WriteDescriptors(dev.vk, pipeline1) | 1465 WriteDescriptors[ShaderA, UniformsA, GlobalsA](renderdata, uniforms1, myGlobals) |
| 1466 | |
| 1467 # create descriptor sets | |
| 1468 #[ | |
| 1469 var descriptorSets: array[INFLIGHTFRAMES.int, VkDescriptorSet] | |
| 1470 var layouts = newSeqWith(descriptorSets.len, pipeline.descriptorSetLayouts) | |
| 1471 var allocInfo = VkDescriptorSetAllocateInfo( | |
| 1472 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, | |
| 1473 descriptorPool: pool, | |
| 1474 descriptorSetCount: uint32(layouts.len), | |
| 1475 pSetLayouts: layouts.ToCPointer, | |
| 1476 ) | |
| 1477 checkVkResult vkAllocateDescriptorSets(device, addr(allocInfo), descriptorSets.ToCPointer) | |
| 1478 ]# | |
| 1479 | |
| 1480 | |
| 1386 | 1481 |
| 1387 # command buffer | 1482 # command buffer |
| 1388 var | 1483 var |
| 1389 commandBufferPool: VkCommandPool | 1484 commandBufferPool: VkCommandPool |
| 1390 createInfo = VkCommandPoolCreateInfo( | 1485 createInfo = VkCommandPoolCreateInfo( |
| 1391 sType: VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, | 1486 sType: VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, |
| 1392 flags: toBits [VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT], | 1487 flags: toBits [VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT], |
| 1393 queueFamilyIndex: GetQueueFamily(dev.vk), | 1488 queueFamilyIndex: vulkan.queueFamilyIndex, |
| 1394 ) | 1489 ) |
| 1395 checkVkResult vkCreateCommandPool(dev.vk, addr createInfo, nil, addr commandBufferPool) | 1490 checkVkResult vkCreateCommandPool(vulkan.device, addr createInfo, nil, addr commandBufferPool) |
| 1396 var | 1491 var |
| 1397 cmdBuffers: array[INFLIGHTFRAMES.int, VkCommandBuffer] | 1492 cmdBuffers: array[INFLIGHTFRAMES.int, VkCommandBuffer] |
| 1398 allocInfo = VkCommandBufferAllocateInfo( | 1493 allocInfo = VkCommandBufferAllocateInfo( |
| 1399 sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, | 1494 sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, |
| 1400 commandPool: commandBufferPool, | 1495 commandPool: commandBufferPool, |
| 1401 level: VK_COMMAND_BUFFER_LEVEL_PRIMARY, | 1496 level: VK_COMMAND_BUFFER_LEVEL_PRIMARY, |
| 1402 commandBufferCount: INFLIGHTFRAMES, | 1497 commandBufferCount: INFLIGHTFRAMES, |
| 1403 ) | 1498 ) |
| 1404 checkVkResult vkAllocateCommandBuffers(dev.vk, addr allocInfo, cmdBuffers.ToCPointer) | 1499 checkVkResult vkAllocateCommandBuffers(vulkan.device, addr allocInfo, cmdBuffers.ToCPointer) |
| 1405 | 1500 |
| 1406 # start command buffer | 1501 # start command buffer |
| 1407 block: | 1502 block: |
| 1408 let | 1503 let |
| 1409 currentFramebuffer = VkFramebuffer(0) # TODO | 1504 currentFramebuffer = VkFramebuffer(0) # TODO |
| 1441 ) | 1536 ) |
| 1442 scissor = VkRect2D( | 1537 scissor = VkRect2D( |
| 1443 offset: VkOffset2D(x: 0, y: 0), | 1538 offset: VkOffset2D(x: 0, y: 0), |
| 1444 extent: VkExtent2D(width: frameWidth, height: frameHeight) | 1539 extent: VkExtent2D(width: frameWidth, height: frameHeight) |
| 1445 ) | 1540 ) |
| 1446 checkVkResult vkCmdBeginRenderPass(cmd, addr(renderPassInfo), VK_SUBPASS_CONTENTS_INLINE) | 1541 vkCmdBeginRenderPass(cmd, addr(renderPassInfo), VK_SUBPASS_CONTENTS_INLINE) |
| 1447 | 1542 |
| 1448 # setup viewport | 1543 # setup viewport |
| 1449 vkCmdSetViewport(cmd, firstViewport = 0, viewportCount = 1, addr(viewport)) | 1544 vkCmdSetViewport(cmd, firstViewport = 0, viewportCount = 1, addr(viewport)) |
| 1450 vkCmdSetScissor(cmd, firstScissor = 0, scissorCount = 1, addr(scissor)) | 1545 vkCmdSetScissor(cmd, firstScissor = 0, scissorCount = 1, addr(scissor)) |
| 1451 | 1546 |
