comparison semiconginev2/rendering/renderer.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/renderer.nim@04e446a7eb2b
children 4e465583ea32
comparison
equal deleted inserted replaced
1217:f819a874058f 1218:56781cc0fc7c
1 func pointerAddOffset[T: SomeInteger](p: pointer, offset: T): pointer =
2 cast[pointer](cast[T](p) + offset)
3
4 func usage(bType: BufferType): seq[VkBufferUsageFlagBits] =
5 case bType:
6 of VertexBuffer: @[VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT]
7 of VertexBufferMapped: @[VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT]
8 of IndexBuffer: @[VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT]
9 of IndexBufferMapped: @[VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT]
10 of UniformBuffer: @[VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT]
11 of UniformBufferMapped: @[VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT]
12
13 proc GetVkFormat(grayscale: bool, usage: openArray[VkImageUsageFlagBits]): VkFormat =
14 let formats = if grayscale: [VK_FORMAT_R8_SRGB, VK_FORMAT_R8_UNORM]
15 else: [VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_B8G8R8A8_UNORM]
16
17 var formatProperties = VkImageFormatProperties2(sType: VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2)
18 for format in formats:
19 var formatInfo = VkPhysicalDeviceImageFormatInfo2(
20 sType: VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
21 format: format,
22 thetype: VK_IMAGE_TYPE_2D,
23 tiling: VK_IMAGE_TILING_OPTIMAL,
24 usage: usage.toBits,
25 )
26 let formatCheck = vkGetPhysicalDeviceImageFormatProperties2(
27 vulkan.physicalDevice,
28 addr formatInfo,
29 addr formatProperties,
30 )
31 if formatCheck == VK_SUCCESS: # found suitable format
32 return format
33 elif formatCheck == VK_ERROR_FORMAT_NOT_SUPPORTED: # nope, try to find other format
34 continue
35 else: # raise error
36 checkVkResult formatCheck
37
38 assert false, "Unable to find format for textures"
39
40
41 func alignedTo[T: SomeInteger](value: T, alignment: T): T =
42 let remainder = value mod alignment
43 if remainder == 0:
44 return value
45 else:
46 return value + alignment - remainder
47
48 template sType(descriptorSet: DescriptorSet): untyped =
49 get(genericParams(typeof(descriptorSet)), 1)
50
51 template bufferType(gpuData: GPUData): untyped =
52 typeof(gpuData).TBuffer
53 func NeedsMapping(bType: BufferType): bool =
54 bType in [VertexBufferMapped, IndexBufferMapped, UniformBufferMapped]
55 template NeedsMapping(gpuData: GPUData): untyped =
56 gpuData.bufferType.NeedsMapping
57
58 template size(gpuArray: GPUArray): uint64 =
59 (gpuArray.data.len * sizeof(elementType(gpuArray.data))).uint64
60 template size(gpuValue: GPUValue): uint64 =
61 sizeof(gpuValue.data).uint64
62 func size(texture: Texture): uint64 =
63 texture.data.len.uint64 * sizeof(elementType(texture.data)).uint64
64
65 template rawPointer(gpuArray: GPUArray): pointer =
66 addr(gpuArray.data[0])
67 template rawPointer(gpuValue: GPUValue): pointer =
68 addr(gpuValue.data)
69
70 proc IsMappable(memoryTypeIndex: uint32): bool =
71 var physicalProperties: VkPhysicalDeviceMemoryProperties
72 vkGetPhysicalDeviceMemoryProperties(vulkan.physicalDevice, addr(physicalProperties))
73 let flags = toEnums(physicalProperties.memoryTypes[memoryTypeIndex].propertyFlags)
74 return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT in flags
75
76 proc InitDescriptorSet*(
77 renderData: RenderData,
78 layout: VkDescriptorSetLayout,
79 descriptorSet: var DescriptorSet,
80 ) =
81
82 # santization checks
83 for theName, value in descriptorSet.data.fieldPairs:
84 when typeof(value) is GPUValue:
85 assert value.buffer.vk.Valid
86 elif typeof(value) is Texture:
87 assert value.vk.Valid
88 assert value.imageview.Valid
89 assert value.sampler.Valid
90 elif typeof(value) is array:
91 when elementType(value) is Texture:
92 for t in value:
93 assert t.vk.Valid
94 assert t.imageview.Valid
95 assert t.sampler.Valid
96 elif elementType(value) is GPUValue:
97 for t in value:
98 assert t.buffer.vk.Valid
99 else:
100 {.error: "Unsupported descriptor set field: '" & theName & "'".}
101 else:
102 {.error: "Unsupported descriptor set field: '" & theName & "'".}
103
104 # allocate
105 var layouts = newSeqWith(descriptorSet.vk.len, layout)
106 var allocInfo = VkDescriptorSetAllocateInfo(
107 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
108 descriptorPool: renderData.descriptorPool,
109 descriptorSetCount: uint32(layouts.len),
110 pSetLayouts: layouts.ToCPointer,
111 )
112 checkVkResult vkAllocateDescriptorSets(vulkan.device, addr(allocInfo), descriptorSet.vk.ToCPointer)
113
114 # allocate seq with high cap to prevent realocation while adding to set
115 # (which invalidates pointers that are passed to the vulkan api call)
116 var descriptorSetWrites = newSeqOfCap[VkWriteDescriptorSet](1024)
117 var imageWrites = newSeqOfCap[VkDescriptorImageInfo](1024)
118 var bufferWrites = newSeqOfCap[VkDescriptorBufferInfo](1024)
119
120 ForDescriptorFields(descriptorSet.data, fieldName, fieldValue, descriptorType, descriptorCount, descriptorBindingNumber):
121 for i in 0 ..< descriptorSet.vk.len:
122 when typeof(fieldValue) is GPUValue:
123 bufferWrites.add VkDescriptorBufferInfo(
124 buffer: fieldValue.buffer.vk,
125 offset: fieldValue.offset,
126 range: fieldValue.size,
127 )
128 descriptorSetWrites.add VkWriteDescriptorSet(
129 sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
130 dstSet: descriptorSet.vk[i],
131 dstBinding: descriptorBindingNumber,
132 dstArrayElement: 0,
133 descriptorType: descriptorType,
134 descriptorCount: descriptorCount,
135 pImageInfo: nil,
136 pBufferInfo: addr(bufferWrites[^1]),
137 )
138 elif typeof(fieldValue) is Texture:
139 imageWrites.add VkDescriptorImageInfo(
140 sampler: fieldValue.sampler,
141 imageView: fieldValue.imageView,
142 imageLayout: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
143 )
144 descriptorSetWrites.add VkWriteDescriptorSet(
145 sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
146 dstSet: descriptorSet.vk[i],
147 dstBinding: descriptorBindingNumber,
148 dstArrayElement: 0,
149 descriptorType: descriptorType,
150 descriptorCount: descriptorCount,
151 pImageInfo: addr(imageWrites[^1]),
152 pBufferInfo: nil,
153 )
154 elif typeof(fieldValue) is array:
155 when elementType(fieldValue) is Texture:
156 for texture in fieldValue:
157 imageWrites.add VkDescriptorImageInfo(
158 sampler: texture.sampler,
159 imageView: texture.imageView,
160 imageLayout: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
161 )
162 descriptorSetWrites.add VkWriteDescriptorSet(
163 sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
164 dstSet: descriptorSet.vk[i],
165 dstBinding: descriptorBindingNumber,
166 dstArrayElement: 0,
167 descriptorType: descriptorType,
168 descriptorCount: descriptorCount,
169 pImageInfo: addr(imageWrites[^descriptorCount.int]),
170 pBufferInfo: nil,
171 )
172 elif elementType(fieldValue) is GPUValue:
173 for entry in fieldValue:
174 bufferWrites.add VkDescriptorBufferInfo(
175 buffer: entry.buffer.vk,
176 offset: entry.offset,
177 range: entry.size,
178 )
179 descriptorSetWrites.add VkWriteDescriptorSet(
180 sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
181 dstSet: descriptorSet.vk[i],
182 dstBinding: descriptorBindingNumber,
183 dstArrayElement: 0,
184 descriptorType: descriptorType,
185 descriptorCount: descriptorCount,
186 pImageInfo: nil,
187 pBufferInfo: addr(bufferWrites[^descriptorCount.int]),
188 )
189 else:
190 {.error: "Unsupported descriptor type: " & typetraits.name(typeof(fieldValue)).}
191 else:
192 {.error: "Unsupported descriptor type: " & typetraits.name(typeof(fieldValue)).}
193
194 vkUpdateDescriptorSets(
195 device = vulkan.device,
196 descriptorWriteCount = descriptorSetWrites.len.uint32,
197 pDescriptorWrites = descriptorSetWrites.ToCPointer,
198 descriptorCopyCount = 0,
199 pDescriptorCopies = nil,
200 )
201
202 proc AllocateNewMemoryBlock(size: uint64, mType: uint32): MemoryBlock =
203 result = MemoryBlock(
204 vk: svkAllocateMemory(size, mType),
205 size: size,
206 rawPointer: nil,
207 offsetNextFree: 0,
208 )
209 if mType.IsMappable():
210 checkVkResult vkMapMemory(
211 device = vulkan.device,
212 memory = result.vk,
213 offset = 0'u64,
214 size = result.size,
215 flags = VkMemoryMapFlags(0),
216 ppData = addr(result.rawPointer)
217 )
218
219 proc FlushAllMemory*(renderData: RenderData) =
220 var flushRegions = newSeq[VkMappedMemoryRange]()
221 for memoryBlocks in renderData.memory:
222 for memoryBlock in memoryBlocks:
223 if memoryBlock.rawPointer != nil and memoryBlock.offsetNextFree > 0:
224 flushRegions.add VkMappedMemoryRange(
225 sType: VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
226 memory: memoryBlock.vk,
227 size: alignedTo(memoryBlock.offsetNextFree, svkGetPhysicalDeviceProperties().limits.nonCoherentAtomSize),
228 )
229 if flushRegions.len > 0:
230 checkVkResult vkFlushMappedMemoryRanges(vulkan.device, flushRegions.len.uint32, flushRegions.ToCPointer())
231
232 proc AllocateNewBuffer(renderData: var RenderData, size: uint64, bufferType: BufferType): Buffer =
233 result = Buffer(
234 vk: svkCreateBuffer(size, bufferType.usage),
235 size: size,
236 rawPointer: nil,
237 offsetNextFree: 0,
238 )
239 let memoryRequirements = svkGetBufferMemoryRequirements(result.vk)
240 let memoryType = BestMemory(mappable = bufferType.NeedsMapping, filter = memoryRequirements.memoryTypes)
241
242 # check if there is an existing allocated memory block that is large enough to be used
243 var selectedBlockI = -1
244 for i in 0 ..< renderData.memory[memoryType].len:
245 let memoryBlock = renderData.memory[memoryType][i]
246 if memoryBlock.size - alignedTo(memoryBlock.offsetNextFree, memoryRequirements.alignment) >= memoryRequirements.size:
247 selectedBlockI = i
248 break
249 # otherwise, allocate a new block of memory and use that
250 if selectedBlockI < 0:
251 selectedBlockI = renderData.memory[memoryType].len
252 renderData.memory[memoryType].add AllocateNewMemoryBlock(
253 size = max(memoryRequirements.size, MEMORY_BLOCK_ALLOCATION_SIZE),
254 mType = memoryType
255 )
256
257 let selectedBlock = renderData.memory[memoryType][selectedBlockI]
258 renderData.memory[memoryType][selectedBlockI].offsetNextFree = alignedTo(
259 selectedBlock.offsetNextFree,
260 memoryRequirements.alignment,
261 )
262 checkVkResult vkBindBufferMemory(
263 vulkan.device,
264 result.vk,
265 selectedBlock.vk,
266 selectedBlock.offsetNextFree,
267 )
268 result.rawPointer = selectedBlock.rawPointer.pointerAddOffset(selectedBlock.offsetNextFree)
269 renderData.memory[memoryType][selectedBlockI].offsetNextFree += memoryRequirements.size
270
271 proc UpdateGPUBuffer*(gpuData: GPUData) =
272 if gpuData.size == 0:
273 return
274 when NeedsMapping(gpuData):
275 copyMem(pointerAddOffset(gpuData.buffer.rawPointer, gpuData.offset), gpuData.rawPointer, gpuData.size)
276 else:
277 WithStagingBuffer((gpuData.buffer.vk, gpuData.offset), gpuData.size, stagingPtr):
278 copyMem(stagingPtr, gpuData.rawPointer, gpuData.size)
279
280 proc UpdateAllGPUBuffers*[T](value: T) =
281 for name, fieldvalue in value.fieldPairs():
282 when typeof(fieldvalue) is GPUData:
283 UpdateGPUBuffer(fieldvalue)
284 when typeof(fieldvalue) is array:
285 when elementType(fieldvalue) is GPUData:
286 for entry in fieldvalue:
287 UpdateGPUBuffer(entry)
288
289 proc AssignGPUData(renderdata: var RenderData, value: var GPUData) =
290 # find buffer that has space
291 var selectedBufferI = -1
292
293 for i in 0 ..< renderData.buffers[value.bufferType].len:
294 let buffer = renderData.buffers[value.bufferType][i]
295 if buffer.size - alignedTo(buffer.offsetNextFree, BUFFER_ALIGNMENT) >= value.size:
296 selectedBufferI = i
297
298 # otherwise create new buffer
299 if selectedBufferI < 0:
300 selectedBufferI = renderdata.buffers[value.bufferType].len
301 renderdata.buffers[value.bufferType].add renderdata.AllocateNewBuffer(
302 size = max(value.size, BUFFER_ALLOCATION_SIZE),
303 bufferType = value.bufferType,
304 )
305
306 # assigne value
307 let selectedBuffer = renderdata.buffers[value.bufferType][selectedBufferI]
308 renderdata.buffers[value.bufferType][selectedBufferI].offsetNextFree = alignedTo(
309 selectedBuffer.offsetNextFree,
310 BUFFER_ALIGNMENT
311 )
312 value.buffer = selectedBuffer
313 value.offset = renderdata.buffers[value.bufferType][selectedBufferI].offsetNextFree
314 renderdata.buffers[value.bufferType][selectedBufferI].offsetNextFree += value.size
315
316 proc AssignBuffers*[T](renderdata: var RenderData, data: var T, uploadData = true) =
317 for name, value in fieldPairs(data):
318
319 when typeof(value) is GPUData:
320 AssignGPUData(renderdata, value)
321 elif typeof(value) is array:
322 when elementType(value) is GPUValue:
323 for v in value.mitems:
324 AssignGPUData(renderdata, v)
325
326 if uploadData:
327 UpdateAllGPUBuffers(data)
328
329 proc AssignBuffers*(renderdata: var RenderData, descriptorSet: var DescriptorSet, uploadData = true) =
330 AssignBuffers(renderdata, descriptorSet.data, uploadData = uploadData)
331
332 proc InitRenderData*(descriptorPoolLimit = 1024'u32): RenderData =
333 # allocate descriptor pools
334 var poolSizes = [
335 VkDescriptorPoolSize(thetype: VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, descriptorCount: descriptorPoolLimit),
336 VkDescriptorPoolSize(thetype: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: descriptorPoolLimit),
337 ]
338 var poolInfo = VkDescriptorPoolCreateInfo(
339 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
340 poolSizeCount: poolSizes.len.uint32,
341 pPoolSizes: poolSizes.ToCPointer,
342 maxSets: descriptorPoolLimit,
343 )
344 checkVkResult vkCreateDescriptorPool(vulkan.device, addr(poolInfo), nil, addr(result.descriptorPool))
345
346 proc DestroyRenderData*(renderData: RenderData) =
347 vkDestroyDescriptorPool(vulkan.device, renderData.descriptorPool, nil)
348
349 for buffers in renderData.buffers:
350 for buffer in buffers:
351 vkDestroyBuffer(vulkan.device, buffer.vk, nil)
352
353 for imageView in renderData.imageViews:
354 vkDestroyImageView(vulkan.device, imageView, nil)
355
356 for sampler in renderData.samplers:
357 vkDestroySampler(vulkan.device, sampler, nil)
358
359 for image in renderData.images:
360 vkDestroyImage(vulkan.device, image, nil)
361
362 for memoryBlocks in renderData.memory:
363 for memory in memoryBlocks:
364 vkFreeMemory(vulkan.device, memory.vk, nil)
365
366 proc TransitionImageLayout(image: VkImage, oldLayout, newLayout: VkImageLayout) =
367 var
368 barrier = VkImageMemoryBarrier(
369 sType: VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
370 oldLayout: oldLayout,
371 newLayout: newLayout,
372 srcQueueFamilyIndex: VK_QUEUE_FAMILY_IGNORED,
373 dstQueueFamilyIndex: VK_QUEUE_FAMILY_IGNORED,
374 image: image,
375 subresourceRange: VkImageSubresourceRange(
376 aspectMask: toBits [VK_IMAGE_ASPECT_COLOR_BIT],
377 baseMipLevel: 0,
378 levelCount: 1,
379 baseArrayLayer: 0,
380 layerCount: 1,
381 ),
382 )
383 srcStage: VkPipelineStageFlagBits
384 dstStage: VkPipelineStageFlagBits
385
386 if oldLayout == VK_IMAGE_LAYOUT_UNDEFINED and newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
387 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
388 barrier.srcAccessMask = VkAccessFlags(0)
389 dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT
390 barrier.dstAccessMask = [VK_ACCESS_TRANSFER_WRITE_BIT].toBits
391 elif oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL and newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
392 srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT
393 barrier.srcAccessMask = [VK_ACCESS_TRANSFER_WRITE_BIT].toBits
394 dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
395 barrier.dstAccessMask = [VK_ACCESS_SHADER_READ_BIT].toBits
396 else:
397 raise newException(Exception, "Unsupported layout transition!")
398
399 WithSingleUseCommandBuffer(commandBuffer):
400 vkCmdPipelineBarrier(
401 commandBuffer,
402 srcStageMask = [srcStage].toBits,
403 dstStageMask = [dstStage].toBits,
404 dependencyFlags = VkDependencyFlags(0),
405 memoryBarrierCount = 0,
406 pMemoryBarriers = nil,
407 bufferMemoryBarrierCount = 0,
408 pBufferMemoryBarriers = nil,
409 imageMemoryBarrierCount = 1,
410 pImageMemoryBarriers = addr(barrier),
411 )
412
413 proc createSampler(
414 magFilter = VK_FILTER_LINEAR,
415 minFilter = VK_FILTER_LINEAR,
416 addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT,
417 addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT,
418 ): VkSampler =
419
420 let samplerInfo = VkSamplerCreateInfo(
421 sType: VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
422 magFilter: magFilter,
423 minFilter: minFilter,
424 addressModeU: addressModeU,
425 addressModeV: addressModeV,
426 addressModeW: VK_SAMPLER_ADDRESS_MODE_REPEAT,
427 anisotropyEnable: vulkan.anisotropy > 0,
428 maxAnisotropy: vulkan.anisotropy,
429 borderColor: VK_BORDER_COLOR_INT_OPAQUE_BLACK,
430 unnormalizedCoordinates: VK_FALSE,
431 compareEnable: VK_FALSE,
432 compareOp: VK_COMPARE_OP_ALWAYS,
433 mipmapMode: VK_SAMPLER_MIPMAP_MODE_LINEAR,
434 mipLodBias: 0,
435 minLod: 0,
436 maxLod: 0,
437 )
438 checkVkResult vkCreateSampler(vulkan.device, addr(samplerInfo), nil, addr(result))
439
440 proc createTextureImage(renderData: var RenderData, texture: var Texture) =
441 assert texture.vk == VkImage(0), "Texture has already been created"
442 var usage = @[VK_IMAGE_USAGE_TRANSFER_DST_BIT, VK_IMAGE_USAGE_SAMPLED_BIT]
443 if texture.isRenderTarget:
444 usage.add VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
445 let format = GetVkFormat(elementType(texture.data) is TVec1[uint8], usage = usage)
446
447 texture.vk = svkCreate2DImage(texture.width, texture.height, format, usage)
448 renderData.images.add texture.vk
449 texture.sampler = createSampler(magFilter = texture.interpolation, minFilter = texture.interpolation)
450 renderData.samplers.add texture.sampler
451
452 let memoryRequirements = texture.vk.svkGetImageMemoryRequirements()
453 let memoryType = BestMemory(mappable = false, filter = memoryRequirements.memoryTypes)
454 # check if there is an existing allocated memory block that is large enough to be used
455 var selectedBlockI = -1
456 for i in 0 ..< renderData.memory[memoryType].len:
457 let memoryBlock = renderData.memory[memoryType][i]
458 if memoryBlock.size - alignedTo(memoryBlock.offsetNextFree, memoryRequirements.alignment) >= memoryRequirements.size:
459 selectedBlockI = i
460 break
461 # otherwise, allocate a new block of memory and use that
462 if selectedBlockI < 0:
463 selectedBlockI = renderData.memory[memoryType].len
464 renderData.memory[memoryType].add AllocateNewMemoryBlock(
465 size = max(memoryRequirements.size, MEMORY_BLOCK_ALLOCATION_SIZE),
466 mType = memoryType
467 )
468 let selectedBlock = renderData.memory[memoryType][selectedBlockI]
469 renderData.memory[memoryType][selectedBlockI].offsetNextFree = alignedTo(
470 selectedBlock.offsetNextFree,
471 memoryRequirements.alignment,
472 )
473
474 checkVkResult vkBindImageMemory(
475 vulkan.device,
476 texture.vk,
477 selectedBlock.vk,
478 renderData.memory[memoryType][selectedBlockI].offsetNextFree,
479 )
480 renderData.memory[memoryType][selectedBlockI].offsetNextFree += memoryRequirements.size
481
482 # imageview can only be created after memory is bound
483 texture.imageview = svkCreate2DImageView(texture.vk, format)
484 renderData.imageViews.add texture.imageview
485
486 # data transfer and layout transition
487 TransitionImageLayout(texture.vk, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
488 WithStagingBuffer(
489 (texture.vk, texture.width, texture.height),
490 memoryRequirements.size,
491 stagingPtr
492 ):
493 copyMem(stagingPtr, texture.data.ToCPointer, texture.size)
494 TransitionImageLayout(texture.vk, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
495
496
497 proc UploadTextures*(renderdata: var RenderData, descriptorSet: var DescriptorSet) =
498 for name, value in fieldPairs(descriptorSet.data):
499 when typeof(value) is Texture:
500 renderdata.createTextureImage(value)
501 elif typeof(value) is array:
502 when elementType(value) is Texture:
503 for texture in value.mitems:
504 renderdata.createTextureImage(texture)
505
506 proc HasGPUValueField[T](name: static string): bool {.compileTime.} =
507 for fieldname, value in default(T).fieldPairs():
508 when typeof(value) is GPUValue and fieldname == name: return true
509 return false
510
511 template WithGPUValueField(obj: object, name: static string, fieldvalue, body: untyped): untyped =
512 # HasGPUValueField MUST be used to check if this is supported
513 for fieldname, value in obj.fieldPairs():
514 when fieldname == name:
515 block:
516 let `fieldvalue` {.inject.} = value
517 body
518
519 template WithBind*[A, B, C, D](commandBuffer: VkCommandBuffer, sets: (DescriptorSet[A], DescriptorSet[B], DescriptorSet[C], DescriptorSet[D]), pipeline: Pipeline, currentFiF: int, body: untyped): untyped =
520 block:
521 var descriptorSets: seq[VkDescriptorSet]
522 for dSet in sets.fields:
523 assert dSet.vk[currentFiF].Valid, "DescriptorSet not initialized, maybe forgot to call InitDescriptorSet"
524 descriptorSets.add dSet.vk[currentFiF]
525 svkCmdBindDescriptorSets(commandBuffer, descriptorSets, pipeline.layout)
526 body
527 template WithBind*[A, B, C](commandBuffer: VkCommandBuffer, sets: (DescriptorSet[A], DescriptorSet[B], DescriptorSet[C]), pipeline: Pipeline, currentFiF: int, body: untyped): untyped =
528 block:
529 var descriptorSets: seq[VkDescriptorSet]
530 for dSet in sets.fields:
531 assert dSet.vk[currentFiF].Valid, "DescriptorSet not initialized, maybe forgot to call InitDescriptorSet"
532 descriptorSets.add dSet.vk[currentFiF]
533 svkCmdBindDescriptorSets(commandBuffer, descriptorSets, pipeline.layout)
534 body
535 template WithBind*[A, B](commandBuffer: VkCommandBuffer, sets: (DescriptorSet[A], DescriptorSet[B]), pipeline: Pipeline, currentFiF: int, body: untyped): untyped =
536 block:
537 var descriptorSets: seq[VkDescriptorSet]
538 for dSet in sets.fields:
539 assert dSet.vk[currentFiF].Valid, "DescriptorSet not initialized, maybe forgot to call InitDescriptorSet"
540 descriptorSets.add dSet.vk[currentFiF]
541 svkCmdBindDescriptorSets(commandBuffer, descriptorSets, pipeline.layout)
542 body
543 template WithBind*[A](commandBuffer: VkCommandBuffer, sets: (DescriptorSet[A], ), pipeline: Pipeline, currentFiF: int, body: untyped): untyped =
544 block:
545 var descriptorSets: seq[VkDescriptorSet]
546 for dSet in sets.fields:
547 assert dSet.vk[currentFiF].Valid, "DescriptorSet not initialized, maybe forgot to call InitDescriptorSet"
548 descriptorSets.add dSet.vk[currentFiF]
549 svkCmdBindDescriptorSets(commandBuffer, descriptorSets, pipeline.layout)
550 body
551
552 proc Render*[TShader, TMesh, TInstance](
553 commandBuffer: VkCommandBuffer,
554 pipeline: Pipeline[TShader],
555 mesh: TMesh,
556 instances: TInstance,
557 ) =
558
559 var vertexBuffers: seq[VkBuffer]
560 var vertexBuffersOffsets: seq[uint64]
561 var elementCount = 0'u32
562 var instanceCount = 1'u32
563
564 for shaderAttributeName, shaderAttribute in default(TShader).fieldPairs:
565 when hasCustomPragma(shaderAttribute, VertexAttribute):
566 for meshName, meshValue in mesh.fieldPairs:
567 when meshName == shaderAttributeName:
568 vertexBuffers.add meshValue.buffer.vk
569 vertexBuffersOffsets.add meshValue.offset
570 elementCount = meshValue.data.len.uint32
571 elif hasCustomPragma(shaderAttribute, InstanceAttribute):
572 for instanceName, instanceValue in instances.fieldPairs:
573 when instanceName == shaderAttributeName:
574 vertexBuffers.add instanceValue.buffer.vk
575 vertexBuffersOffsets.add instanceValue.offset
576 instanceCount = instanceValue.data.len.uint32
577
578 if vertexBuffers.len > 0:
579 vkCmdBindVertexBuffers(
580 commandBuffer = commandBuffer,
581 firstBinding = 0'u32,
582 bindingCount = uint32(vertexBuffers.len),
583 pBuffers = vertexBuffers.ToCPointer(),
584 pOffsets = vertexBuffersOffsets.ToCPointer()
585 )
586
587 var indexBuffer: VkBuffer
588 var indexBufferOffset: uint64
589 var indexType = VK_INDEX_TYPE_NONE_KHR
590
591 for meshName, meshValue in mesh.fieldPairs:
592 when typeof(meshValue) is GPUArray[uint8, IndexBuffer]:
593 indexBuffer = meshValue.buffer.vk
594 indexBufferOffset = meshValue.offset
595 indexType = VK_INDEX_TYPE_UINT8_EXT
596 elementCount = meshValue.data.len.uint32
597 elif typeof(meshValue) is GPUArray[uint16, IndexBuffer]:
598 indexBuffer = meshValue.buffer.vk
599 indexBufferOffset = meshValue.offset
600 indexType = VK_INDEX_TYPE_UINT16
601 elementCount = meshValue.data.len.uint32
602 elif typeof(meshValue) is GPUArray[uint32, IndexBuffer]:
603 indexBuffer = meshValue.buffer.vk
604 indexBufferOffset = meshValue.offset
605 indexType = VK_INDEX_TYPE_UINT32
606 elementCount = meshValue.data.len.uint32
607
608 assert elementCount > 0
609
610 if indexType != VK_INDEX_TYPE_NONE_KHR:
611 vkCmdBindIndexBuffer(
612 commandBuffer,
613 indexBuffer,
614 indexBufferOffset,
615 indexType,
616 )
617 vkCmdDrawIndexed(
618 commandBuffer = commandBuffer,
619 indexCount = elementCount,
620 instanceCount = instanceCount,
621 firstIndex = 0,
622 vertexOffset = 0,
623 firstInstance = 0
624 )
625 else:
626 vkCmdDraw(
627 commandBuffer = commandBuffer,
628 vertexCount = elementCount,
629 instanceCount = instanceCount,
630 firstVertex = 0,
631 firstInstance = 0
632 )
633
634 type EMPTY = object
635
636 proc Render*[TShader, TMesh](
637 commandBuffer: VkCommandBuffer,
638 pipeline: Pipeline[TShader],
639 mesh: TMesh,
640 ) =
641 Render(commandBuffer, pipeline, mesh, EMPTY())
642
643 proc asGPUArray*[T](data: openArray[T], bufferType: static BufferType): auto =
644 GPUArray[T, bufferType](data: @data)
645
646 proc asGPUValue*[T](data: T, bufferType: static BufferType): auto =
647 GPUValue[T, bufferType](data: data)
648
649 proc asDescriptorSet*[T](data: T): auto =
650 DescriptorSet[T](data: data)