# HG changeset patch # User sam # Date 1758732936 -25200 # Node ID 56aa8fe70e9ea161eb9944a85d45909eff577e7c # Parent 0615cd5bfd971a1be9cfa79e0d5bdc44b52b1b68 add: super suboptimal implementation to support per-frame descriptor sets diff -r 0615cd5bfd97 -r 56aa8fe70e9e semicongine/core/types.nim --- a/semicongine/core/types.nim Wed Sep 24 22:17:43 2025 +0700 +++ b/semicongine/core/types.nim Wed Sep 24 23:55:36 2025 +0700 @@ -101,7 +101,7 @@ # shader related types DescriptorSetData*[T: object] = object - data*: T + data*: array[INFLIGHTFRAMES.int, T] vk*: array[INFLIGHTFRAMES.int, VkDescriptorSet] Pipeline*[TShader] = object diff -r 0615cd5bfd97 -r 56aa8fe70e9e semicongine/fonts.nim --- a/semicongine/fonts.nim Wed Sep 24 22:17:43 2025 +0700 +++ b/semicongine/fonts.nim Wed Sep 24 23:55:36 2025 +0700 @@ -147,7 +147,8 @@ # generate glyph atlas from bitmaps let packed = pack(bitmaps) - result.descriptorSet.data.fontAtlas = packed.atlas + for i in 0 ..< INFLIGHTFRAMES: + result.descriptorSet.data[i].fontAtlas = packed.atlas # generate quad-information for use in shader for i in 0 ..< codePoints.len: @@ -161,8 +162,8 @@ result.advance[codePoint] = advanceUnscaled.float32 * glyph2QuadScale let - atlasW = float32(result.descriptorSet.data.fontAtlas.width) - atlasH = float32(result.descriptorSet.data.fontAtlas.height) + atlasW = float32(result.descriptorSet.data[0].fontAtlas.width) + atlasH = float32(result.descriptorSet.data[0].fontAtlas.height) uv = vec2(packed.coords[i].x, packed.coords[i].y) bitmapW = float32(bitmaps[i].width) bitmapH = float32(bitmaps[i].height) @@ -173,16 +174,17 @@ top = -offsetY[codePoint].float32 / lineHeightPixels bottom = top - bitmapH / lineHeightPixels - template glyphquads(): untyped = - result.descriptorSet.data.glyphquads.data + template glyphquads_t(j: int): untyped = + result.descriptorSet.data[j].glyphquads.data - glyphquads.pos[i] = vec4(left, bottom, right, top) - glyphquads.uv[i] = vec4( - (uv.x + 0.5) / atlasW, # left - (uv.y + bitmapH - 0.5) / atlasH, # bottom - (uv.x + bitmapW - 0.5) / atlasW, # right - (uv.y + 0.5) / atlasH, # top - ) + for k in 0 ..< INFLIGHTFRAMES.int: + glyphquads_t(k).pos[i] = vec4(left, bottom, right, top) + glyphquads_t(k).uv[i] = vec4( + (uv.x + 0.5) / atlasW, # left + (uv.y + bitmapH - 0.5) / atlasH, # bottom + (uv.x + bitmapW - 0.5) / atlasW, # right + (uv.y + 0.5) / atlasH, # top + ) if i == 0: result.fallbackCharacter = codePoint result.descriptorGlyphIndex[codePoint] = i.uint16 diff -r 0615cd5bfd97 -r 56aa8fe70e9e semicongine/rendering/memory.nim --- a/semicongine/rendering/memory.nim Wed Sep 24 22:17:43 2025 +0700 +++ b/semicongine/rendering/memory.nim Wed Sep 24 23:55:36 2025 +0700 @@ -119,7 +119,7 @@ descriptorSet: DescriptorSetData, ) = # santization checks - for theName, value in descriptorSet.data.fieldPairs: + for theName, value in descriptorSet.data[0].fieldPairs: when typeof(value) is GPUValue: assert value.buffer.vk.Valid, "Invalid buffer, did you call 'assignBuffers' for this buffer?" @@ -159,85 +159,80 @@ var imageWrites = newSeqOfCap[VkDescriptorImageInfo](1024) var bufferWrites = newSeqOfCap[VkDescriptorBufferInfo](1024) - for theFieldname, fieldvalue in fieldPairs(descriptorSet.data): - const descriptorType = getDescriptorType[typeof(fieldvalue)]() - const descriptorCount = getDescriptorCount[typeof(fieldvalue)]() - const descriptorBindingNumber = - getBindingNumber[typeof(descriptorSet.data)](theFieldname) - for i in 0 ..< descriptorSet.vk.len: - when typeof(fieldvalue) is GPUValue: - bufferWrites.add VkDescriptorBufferInfo( - buffer: fieldvalue.buffer.vk, - offset: fieldvalue.offset, - range: fieldvalue.size, - ) - descriptorSetWrites.add VkWriteDescriptorSet( - sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - dstSet: descriptorSet.vk[i], - dstBinding: descriptorBindingNumber, - dstArrayElement: 0, - descriptorType: descriptorType, - descriptorCount: descriptorCount, - pImageInfo: nil, - pBufferInfo: addr(bufferWrites[^1]), - ) - elif typeof(fieldvalue) is ImageObject: - imageWrites.add VkDescriptorImageInfo( - sampler: fieldvalue.sampler, - imageView: fieldvalue.imageView, - imageLayout: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - ) - descriptorSetWrites.add VkWriteDescriptorSet( - sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - dstSet: descriptorSet.vk[i], - dstBinding: descriptorBindingNumber, - dstArrayElement: 0, - descriptorType: descriptorType, - descriptorCount: descriptorCount, - pImageInfo: addr(imageWrites[^1]), - pBufferInfo: nil, - ) - elif typeof(fieldvalue) is array: - when elementType(fieldvalue) is ImageObject: - for image in fieldvalue.litems: - imageWrites.add VkDescriptorImageInfo( - sampler: image.sampler, - imageView: image.imageView, - imageLayout: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - ) + for fI in 0 ..< INFLIGHTFRAMES: + for theFieldname, fieldvalue in fieldPairs(descriptorSet.data[fI]): + const descriptorType = getDescriptorType[typeof(fieldvalue)]() + const descriptorCount = getDescriptorCount[typeof(fieldvalue)]() + const descriptorBindingNumber = getBindingNumber[typeof(descriptorSet.data[fI])](theFieldname) + when typeof(fieldvalue) is GPUValue: + bufferWrites.add VkDescriptorBufferInfo( + buffer: fieldvalue.buffer.vk, + offset: fieldvalue.offset, + range: fieldvalue.size, + ) descriptorSetWrites.add VkWriteDescriptorSet( sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - dstSet: descriptorSet.vk[i], - dstBinding: descriptorBindingNumber, - dstArrayElement: 0, - descriptorType: descriptorType, - descriptorCount: descriptorCount, - pImageInfo: addr(imageWrites[^descriptorCount.int]), - pBufferInfo: nil, - ) - elif elementType(fieldvalue) is GPUValue: - for entry in fieldvalue.litems: - bufferWrites.add VkDescriptorBufferInfo( - buffer: entry.buffer.vk, offset: entry.offset, range: entry.size - ) - descriptorSetWrites.add VkWriteDescriptorSet( - sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - dstSet: descriptorSet.vk[i], + dstSet: descriptorSet.vk[fI], dstBinding: descriptorBindingNumber, dstArrayElement: 0, descriptorType: descriptorType, descriptorCount: descriptorCount, pImageInfo: nil, - pBufferInfo: addr(bufferWrites[^descriptorCount.int]), + pBufferInfo: addr(bufferWrites[^1]), + ) + elif typeof(fieldvalue) is ImageObject: + imageWrites.add VkDescriptorImageInfo( + sampler: fieldvalue.sampler, + imageView: fieldvalue.imageView, + imageLayout: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + ) + descriptorSetWrites.add VkWriteDescriptorSet( + sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + dstSet: descriptorSet.vk[fI], + dstBinding: descriptorBindingNumber, + dstArrayElement: 0, + descriptorType: descriptorType, + descriptorCount: descriptorCount, + pImageInfo: addr(imageWrites[^1]), + pBufferInfo: nil, ) + elif typeof(fieldvalue) is array: + when elementType(fieldvalue) is ImageObject: + for image in fieldvalue.litems: + imageWrites.add VkDescriptorImageInfo( + sampler: image.sampler, + imageView: image.imageView, + imageLayout: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + ) + descriptorSetWrites.add VkWriteDescriptorSet( + sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + dstSet: descriptorSet.vk[fI], + dstBinding: descriptorBindingNumber, + dstArrayElement: 0, + descriptorType: descriptorType, + descriptorCount: descriptorCount, + pImageInfo: addr(imageWrites[^descriptorCount.int]), + pBufferInfo: nil, + ) + elif elementType(fieldvalue) is GPUValue: + for entry in fieldvalue.litems: + bufferWrites.add VkDescriptorBufferInfo( + buffer: entry.buffer.vk, offset: entry.offset, range: entry.size + ) + descriptorSetWrites.add VkWriteDescriptorSet( + sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + dstSet: descriptorSet.vk[fI], + dstBinding: descriptorBindingNumber, + dstArrayElement: 0, + descriptorType: descriptorType, + descriptorCount: descriptorCount, + pImageInfo: nil, + pBufferInfo: addr(bufferWrites[^descriptorCount.int]), + ) + else: + {.error: "Unsupported descriptor type: " & typetraits.name(typeof(fieldvalue)).} else: - {. - error: "Unsupported descriptor type: " & typetraits.name(typeof(fieldvalue)) - .} - else: - {. - error: "Unsupported descriptor type: " & typetraits.name(typeof(fieldvalue)) - .} + {.error: "Unsupported descriptor type: " & typetraits.name(typeof(fieldvalue)).} vkUpdateDescriptorSets( device = engine().vulkan.device, @@ -402,7 +397,8 @@ (value.buffer, value.offset) = allocateGPUData(renderdata, value.bufferType, value.size) elif typeof(value) is DescriptorSetData: - assignBuffers(renderdata, value.data, uploadData = uploadData) + for i in 0 ..< INFLIGHTFRAMES: + assignBuffers(renderdata, value.data[i], uploadData = uploadData) elif typeof(value) is array: when elementType(value) is GPUValue: for v in value.mitems: @@ -414,7 +410,8 @@ proc assignBuffers*( renderdata: var RenderData, descriptorSet: var DescriptorSetData, uploadData = true ) = - assignBuffers(renderdata, descriptorSet.data, uploadData = uploadData) + for i in 0 ..< INFLIGHTFRAMES: + assignBuffers(renderdata, descriptorSet.data[i], uploadData = uploadData) proc asGPUArray*[T](data: sink openArray[T], bufferType: static BufferType): auto = GPUArray[T, bufferType](data: @data) diff -r 0615cd5bfd97 -r 56aa8fe70e9e semicongine/rendering/renderer.nim --- a/semicongine/rendering/renderer.nim Wed Sep 24 22:17:43 2025 +0700 +++ b/semicongine/rendering/renderer.nim Wed Sep 24 23:55:36 2025 +0700 @@ -191,13 +191,14 @@ ) proc uploadImages*(renderdata: var RenderData, descriptorSet: var DescriptorSetData) = - for name, value in fieldPairs(descriptorSet.data): - when typeof(value) is ImageObject: - renderdata.createVulkanImage(value) - elif typeof(value) is array: - when elementType(value) is ImageObject: - for image in value.mitems: - renderdata.createVulkanImage(image) + for i in 0 ..< INFLIGHTFRAMES: + for name, value in fieldPairs(descriptorSet.data[i]): + when typeof(value) is ImageObject: + renderdata.createVulkanImage(value) + elif typeof(value) is array: + when elementType(value) is ImageObject: + for image in value.mitems: + renderdata.createVulkanImage(image) type EMPTY = object # only used for static assertions