# HG changeset patch # User sam # Date 1723721400 -25200 # Node ID 4a1c2b1128bc4cd69c87c488f2235ac2dad5a8d5 # Parent 385dbd68a947decfe8a29da1da378fda89c7cbd9 did: improve handling of descriptor sets diff -r 385dbd68a947 -r 4a1c2b1128bc semicongine/rendering.nim --- a/semicongine/rendering.nim Thu Aug 15 12:12:27 2024 +0700 +++ b/semicongine/rendering.nim Thu Aug 15 18:30:00 2024 +0700 @@ -31,13 +31,14 @@ const PUSH_CONSTANT_SIZE = 128 # custom pragmas to classify shader attributes +type DescriptorSetIndex = range[0 .. MAX_DESCRIPTORSETS - 1] template VertexAttribute* {.pragma.} template InstanceAttribute* {.pragma.} -template PushConstantAttribute* {.pragma.} +template PushConstant* {.pragma.} template Pass* {.pragma.} template PassFlat* {.pragma.} template ShaderOutput* {.pragma.} -template DescriptorSets* {.pragma.} +template DescriptorSet*(index: DescriptorSetIndex) {.pragma.} # there is a big, bad global vulkan object # believe me, this makes everything much, much easier @@ -99,7 +100,7 @@ oldSwapchainCounter: int # swaps until old swapchain will be destroyed # shader related types - DescriptorSet*[T: object] = object + DescriptorSetData*[T: object] = object data*: T vk: array[INFLIGHTFRAMES.int, VkDescriptorSet] Pipeline*[TShader] = object @@ -156,7 +157,7 @@ proc `=copy`[T, S](dest: var GPUArray[T, S]; source: GPUArray[T, S]) {.error.} proc `=copy`(dest: var MemoryBlock; source: MemoryBlock) {.error.} proc `=copy`[T](dest: var Pipeline[T]; source: Pipeline[T]) {.error.} -proc `=copy`[T](dest: var DescriptorSet[T]; source: DescriptorSet[T]) {.error.} +proc `=copy`[T](dest: var DescriptorSetData[T]; source: DescriptorSetData[T]) {.error.} template forDescriptorFields(shader: typed, valuename, typename, countname, bindingNumber, body: untyped): untyped = var `bindingNumber` {.inject.} = 0'u32 @@ -191,6 +192,10 @@ else: {.error: "Unsupported descriptor type: " & typetraits.name(typeof(`valuename`)).} +proc currentFiF*(): int = + assert vulkan.swapchain != nil, "Swapchain has not been initialized yet" + vulkan.swapchain.currentFiF + include ./rendering/vulkan_wrappers include ./rendering/renderpasses include ./rendering/swapchain @@ -357,10 +362,6 @@ assert vulkan.swapchain != nil, "Swapchain has not been initialized yet" vulkan.swapchain.width.float32 / vulkan.swapchain.height.float32 -proc currentFiF*(): int = - assert vulkan.swapchain != nil, "Swapchain has not been initialized yet" - vulkan.swapchain.currentFiF - proc maxFramebufferSampleCount*(maxSamples = VK_SAMPLE_COUNT_8_BIT): VkSampleCountFlagBits = let limits = svkGetPhysicalDeviceProperties().limits let available = VkSampleCountFlags( diff -r 385dbd68a947 -r 4a1c2b1128bc semicongine/rendering/platform/linux.nim --- a/semicongine/rendering/platform/linux.nim Thu Aug 15 12:12:27 2024 +0700 +++ b/semicongine/rendering/platform/linux.nim Thu Aug 15 18:30:00 2024 +0700 @@ -1,6 +1,4 @@ -import std/logging import std/options -import std/strformat import std/tables import ../../thirdparty/x11/xlib diff -r 385dbd68a947 -r 4a1c2b1128bc semicongine/rendering/renderer.nim --- a/semicongine/rendering/renderer.nim Thu Aug 15 12:12:27 2024 +0700 +++ b/semicongine/rendering/renderer.nim Thu Aug 15 18:30:00 2024 +0700 @@ -73,7 +73,7 @@ proc initDescriptorSet*( renderData: RenderData, layout: VkDescriptorSetLayout, - descriptorSet: var DescriptorSet, + descriptorSet: var DescriptorSetData, ) = # santization checks @@ -336,7 +336,7 @@ when typeof(value) is GPUData: (value.buffer, value.offset) = allocateGPUData(renderdata, value.bufferType, value.size) - elif typeof(value) is DescriptorSet: + elif typeof(value) is DescriptorSetData: assignBuffers(renderdata, value.data, uploadData = uploadData) elif typeof(value) is array: @@ -347,7 +347,7 @@ if uploadData: updateAllGPUBuffers(data, flush = true) -proc assignBuffers*(renderdata: var RenderData, descriptorSet: var DescriptorSet, uploadData = true) = +proc assignBuffers*(renderdata: var RenderData, descriptorSet: var DescriptorSetData, uploadData = true) = assignBuffers(renderdata, descriptorSet.data, uploadData = uploadData) proc initRenderData*(descriptorPoolLimit = 1024'u32): RenderData = @@ -520,7 +520,7 @@ transitionImageLayout(image.vk, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) -proc uploadImages*(renderdata: var RenderData, descriptorSet: var DescriptorSet) = +proc uploadImages*(renderdata: var RenderData, descriptorSet: var DescriptorSetData) = for name, value in fieldPairs(descriptorSet.data): when typeof(value) is Image: renderdata.createVulkanImage(value) @@ -531,75 +531,17 @@ type EMPTY = object # only used for static assertions -proc assertAllDescriptorsBound(A, B, C, D, TShader: typedesc) = - var foundDescriptorSets = false - for attrName, attrValue in default(TShader).fieldPairs(): - when hasCustomPragma(attrValue, DescriptorSets): - assert not foundDescriptorSets, "Only one shader attribute is allowed to have the pragma 'DescriptorSets'" - when not (A is EMPTY): assert typeof(attrValue[0]) is A - when not (B is EMPTY): assert typeof(attrValue[1]) is B - when not (C is EMPTY): assert typeof(attrValue[2]) is C - when not (D is EMPTY): assert typeof(attrValue[3]) is D - -var hasBoundDescriptorSets {.compileTime.} = false # okay, I am not sure if this is clean, unproblematic or sane. Just trying to get some comptime-validation -var hasDescriptorSets {.compileTime} = false +proc assertCompatibleDescriptorSet(TDescriptorSet, TShader: typedesc, index: static DescriptorSetIndex) = + for _, fieldvalue in default(TShader).fieldPairs: + when fieldvalue.hasCustomPragma(DescriptorSet): + when fieldvalue.getCustomPragmaVal(DescriptorSet) == index: + assert TDescriptorSet is typeof(fieldvalue), "Incompatible descriptor set types for set number " & $index & " in shader " & name(TShader) -template withBind*[A, B, C, D, TShader](commandBuffer: VkCommandBuffer, sets: (DescriptorSet[A], DescriptorSet[B], DescriptorSet[C], DescriptorSet[D]), pipeline: Pipeline[TShader], body: untyped): untyped = - static: assertAllDescriptorsBound(A, B, C, D, TShader) - block: - var descriptorSets: seq[VkDescriptorSet] - for dSet in sets.fields: - assert dSet.vk[currentFiF()].Valid, "DescriptorSet not initialized, maybe forgot to call initDescriptorSet" - descriptorSets.add dSet.vk[currentFiF()] - svkCmdBindDescriptorSets(commandBuffer, descriptorSets, pipeline.layout) - static: - assert not hasBoundDescriptorSets, "Cannot call withBind nested" - hasBoundDescriptorSets = true - body - static: - hasBoundDescriptorSets = false -template withBind*[A, B, C, TShader](commandBuffer: VkCommandBuffer, sets: (DescriptorSet[A], DescriptorSet[B], DescriptorSet[C]), pipeline: Pipeline[TShader], body: untyped): untyped = - static: assertAllDescriptorsBound(A, B, C, EMPTY, TShader) - block: - var descriptorSets: seq[VkDescriptorSet] - for dSet in sets.fields: - assert dSet.vk[currentFiF()].Valid, "DescriptorSet not initialized, maybe forgot to call initDescriptorSet" - descriptorSets.add dSet.vk[currentFiF()] - svkCmdBindDescriptorSets(commandBuffer, descriptorSets, pipeline.layout) - static: - assert not hasBoundDescriptorSets, "Cannot call withBind nested" - hasBoundDescriptorSets = true - body - static: - hasBoundDescriptorSets = false -template withBind*[A, B, TShader](commandBuffer: VkCommandBuffer, sets: (DescriptorSet[A], DescriptorSet[B]), pipeline: Pipeline[TShader], body: untyped): untyped = - static: assertAllDescriptorsBound(A, B, EMPTY, EMPTY, TShader) - block: - var descriptorSets: seq[VkDescriptorSet] - for dSet in sets.fields: - assert dSet.vk[currentFiF()].Valid, "DescriptorSet not initialized, maybe forgot to call initDescriptorSet" - descriptorSets.add dSet.vk[currentFiF()] - svkCmdBindDescriptorSets(commandBuffer, descriptorSets, pipeline.layout) - static: - assert not hasBoundDescriptorSets, "Cannot call withBind nested" - hasBoundDescriptorSets = true - body - static: - hasBoundDescriptorSets = false -template withBind*[A, TShader](commandBuffer: VkCommandBuffer, sets: (DescriptorSet[A], ), pipeline: Pipeline[TShader], body: untyped): untyped = - static: assertAllDescriptorsBound(A, EMPTY, EMPTY, EMPTY, TShader) - block: - var descriptorSets: seq[VkDescriptorSet] - for dSet in sets.fields: - assert dSet.vk[currentFiF()].Valid, "DescriptorSet not initialized, maybe forgot to call initDescriptorSet" - descriptorSets.add dSet.vk[currentFiF()] - svkCmdBindDescriptorSets(commandBuffer, descriptorSets, pipeline.layout) - static: - assert not hasBoundDescriptorSets, "Cannot call withBind nested" - hasBoundDescriptorSets = true - body - static: - hasBoundDescriptorSets = false + +proc bindDescriptorSet*[TDescriptorSet, TShader](commandBuffer: VkCommandBuffer, descriptorSet: DescriptorSetData[TDescriptorSet], index: static DescriptorSetIndex, pipeline: Pipeline[TShader]) = + assert descriptorSet.vk[currentFiF()].Valid, "DescriptorSetData not initialized, maybe forgot to call initDescriptorSet" + static: assertCompatibleDescriptorSet(TDescriptorSet, TShader, index) + svkCmdBindDescriptorSet(commandBuffer, descriptorSet.vk[currentFiF()], index, pipeline.layout) proc assertCanRenderMesh(TShader, TMesh, TInstance: typedesc) = for attrName, attrValue in default(TShader).fieldPairs: @@ -629,14 +571,6 @@ ) = static: assertCanRenderMesh(TShader, TMesh, TInstance) - static: - hasDescriptorSets = false - for attrName, attrValue in default(TShader).fieldPairs(): - if attrValue.hasCustomPragma(DescriptorSets): - hasDescriptorSets = true - # TODO: fix this, not working as intended, seems to depend on scope - # if hasDescriptorSets: - # assert hasBoundDescriptorSets, "Shader uses descriptor sets, but none are bound" var vertexBuffers: seq[VkBuffer] var vertexBuffersOffsets: seq[uint64] @@ -722,7 +656,7 @@ assert sizeof(TPushConstant) <= PUSH_CONSTANT_SIZE, "Push constant values must be <= 128 bytes" var foundPushConstant = false for fieldname, fieldvalue in default(TShader).fieldPairs(): - when hasCustomPragma(fieldvalue, PushConstantAttribute): + when hasCustomPragma(fieldvalue, PushConstant): assert typeof(fieldvalue) is TPushConstant, "Provided push constant has not same type as declared in shader" assert foundPushConstant == false, "More than on push constant found in shader" foundPushConstant = true @@ -768,5 +702,5 @@ proc asGPUValue*[T](data: sink T, bufferType: static BufferType): auto = GPUValue[T, bufferType](data: data) -proc asDescriptorSet*[T](data: sink T): auto = - DescriptorSet[T](data: data) +proc asDescriptorSetData*[T](data: sink T): auto = + DescriptorSetData[T](data: data) diff -r 385dbd68a947 -r 4a1c2b1128bc semicongine/rendering/shaders.nim --- a/semicongine/rendering/shaders.nim Thu Aug 15 12:12:27 2024 +0700 +++ b/semicongine/rendering/shaders.nim Thu Aug 15 18:30:00 2024 +0700 @@ -137,7 +137,7 @@ var passLocation {.hint[XDeclaredButNotUsed]: off.} = 0 var fsOutputLocation = 0 - var sawDescriptorSets = false + var sawDescriptorSets: array[MAX_DESCRIPTORSETS, bool] for fieldname, value in fieldPairs(shader): # vertex shader inputs when hasCustomPragma(value, VertexAttribute) or hasCustomPragma(value, InstanceAttribute): @@ -160,61 +160,56 @@ # descriptor sets # need to consider 4 cases: uniform block, texture, uniform block array, texture array - elif hasCustomPragma(value, DescriptorSets): - assert not sawDescriptorSets, "Only one field with pragma DescriptorSets allowed per shader" - assert typeof(value) is tuple, "Descriptor field '" & fieldname & "' must be of type tuple" - assert tupleLen(value) <= MAX_DESCRIPTORSETS, typetraits.name(TShader) & ": maximum " & $MAX_DESCRIPTORSETS & " allowed" - sawDescriptorSets = true - var descriptorSetIndex = 0 - for descriptor in value.fields: + elif hasCustomPragma(value, DescriptorSet): + let setIndex = value.getCustomPragmaVal(DescriptorSet) + assert not sawDescriptorSets[setIndex], "Only one DescriptorSet per index is allowed per shader" + assert typeof(value) is object, "Descriptor field '" & fieldname & "' must be of type object" + assert setIndex < MAX_DESCRIPTORSETS, typetraits.name(TShader) & ": maximum " & $MAX_DESCRIPTORSETS & " descriptor sets allowed" + sawDescriptorSets[setIndex] = true + + var descriptorBinding = 0 + for descriptorName, descriptorValue in fieldPairs(value): + when typeof(descriptorValue) is Image: + samplers.add "layout(set=" & $setIndex & ", binding = " & $descriptorBinding & ") uniform " & glslType(descriptorValue) & " " & descriptorName & ";" + descriptorBinding.inc + + elif typeof(descriptorValue) is GPUValue: - var descriptorBinding = 0 + uniforms.add "layout(set=" & $setIndex & ", binding = " & $descriptorBinding & ") uniform T" & descriptorName & " {" + when typeof(descriptorValue.data) is object: + + for blockFieldName, blockFieldValue in descriptorValue.data.fieldPairs(): + assert typeof(blockFieldValue) is SupportedGPUType, "uniform block field '" & blockFieldName & "' is not a SupportedGPUType" + uniforms.add " " & glslType(blockFieldValue) & " " & blockFieldName & ";" + uniforms.add "} " & descriptorName & ";" - for descriptorName, descriptorValue in fieldPairs(descriptor): + else: + {.error: "Unsupported shader descriptor field " & descriptorName & " (must be object)".} + descriptorBinding.inc - when typeof(descriptorValue) is Image: - samplers.add "layout(set=" & $descriptorSetIndex & ", binding = " & $descriptorBinding & ") uniform " & glslType(descriptorValue) & " " & descriptorName & ";" + elif typeof(descriptorValue) is array: + + when elementType(descriptorValue) is Image: + + let arrayDecl = "[" & $typeof(descriptorValue).len & "]" + samplers.add "layout(set=" & $setIndex & ", binding = " & $descriptorBinding & ") uniform " & glslType(default(elementType(descriptorValue))) & " " & descriptorName & "" & arrayDecl & ";" descriptorBinding.inc - elif typeof(descriptorValue) is GPUValue: + elif elementType(descriptorValue) is GPUValue: - uniforms.add "layout(set=" & $descriptorSetIndex & ", binding = " & $descriptorBinding & ") uniform T" & descriptorName & " {" - when typeof(descriptorValue.data) is object: + uniforms.add "layout(set=" & $setIndex & ", binding = " & $descriptorBinding & ") uniform T" & descriptorName & " {" - for blockFieldName, blockFieldValue in descriptorValue.data.fieldPairs(): - assert typeof(blockFieldValue) is SupportedGPUType, "uniform block field '" & blockFieldName & "' is not a SupportedGPUType" - uniforms.add " " & glslType(blockFieldValue) & " " & blockFieldName & ";" - uniforms.add "} " & descriptorName & ";" - - else: - {.error: "Unsupported shader descriptor field " & descriptorName & " (must be object)".} + for blockFieldName, blockFieldValue in default(elementType(descriptorValue)).data.fieldPairs(): + assert typeof(blockFieldValue) is SupportedGPUType, "uniform block field '" & blockFieldName & "' is not a SupportedGPUType" + uniforms.add " " & glslType(blockFieldValue) & " " & blockFieldName & ";" + uniforms.add "} " & descriptorName & "[" & $descriptorValue.len & "];" descriptorBinding.inc - elif typeof(descriptorValue) is array: - - when elementType(descriptorValue) is Image: - - let arrayDecl = "[" & $typeof(descriptorValue).len & "]" - samplers.add "layout(set=" & $descriptorSetIndex & ", binding = " & $descriptorBinding & ") uniform " & glslType(default(elementType(descriptorValue))) & " " & descriptorName & "" & arrayDecl & ";" - descriptorBinding.inc - - elif elementType(descriptorValue) is GPUValue: - - uniforms.add "layout(set=" & $descriptorSetIndex & ", binding = " & $descriptorBinding & ") uniform T" & descriptorName & " {" - - for blockFieldName, blockFieldValue in default(elementType(descriptorValue)).data.fieldPairs(): - assert typeof(blockFieldValue) is SupportedGPUType, "uniform block field '" & blockFieldName & "' is not a SupportedGPUType" - uniforms.add " " & glslType(blockFieldValue) & " " & blockFieldName & ";" - uniforms.add "} " & descriptorName & "[" & $descriptorValue.len & "];" - descriptorBinding.inc - - else: - {.error: "Unsupported shader descriptor field " & descriptorName.} - - descriptorSetIndex.inc + else: + {.error: "Unsupported shader descriptor field " & descriptorName.} elif fieldname in ["vertexCode", "fragmentCode"]: discard - elif hasCustomPragma(value, PushConstantAttribute): + elif hasCustomPragma(value, PushConstant): assert pushConstants.len == 0, "Only one push constant value allowed" assert value is object, "push constants need to be objects" pushConstants.add "layout( push_constant ) uniform constants" @@ -327,37 +322,29 @@ const `isinstancename` {.inject.} = hasCustomPragma(value, InstanceAttribute) body -proc getDescriptorSetCount[TShader](): uint32 = - for _, value in fieldPairs(default(TShader)): - when hasCustomPragma(value, DescriptorSets): - return tupleLen(typeof(value)).uint32 - proc createDescriptorSetLayouts[TShader](): array[MAX_DESCRIPTORSETS, VkDescriptorSetLayout] = - var setNumber: int for _, value in fieldPairs(default(TShader)): - when hasCustomPragma(value, DescriptorSets): - for descriptorSet in value.fields: - var layoutbindings: seq[VkDescriptorSetLayoutBinding] - forDescriptorFields(descriptorSet, fieldValue, descriptorType, descriptorCount, descriptorBindingNumber): - layoutbindings.add VkDescriptorSetLayoutBinding( - binding: descriptorBindingNumber, - descriptorType: descriptorType, - descriptorCount: descriptorCount, - stageFlags: VkShaderStageFlags(VK_SHADER_STAGE_ALL_GRAPHICS), - pImmutableSamplers: nil, - ) - var layoutCreateInfo = VkDescriptorSetLayoutCreateInfo( - sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, - bindingCount: layoutbindings.len.uint32, - pBindings: layoutbindings.ToCPointer + when hasCustomPragma(value, DescriptorSet): + var layoutbindings: seq[VkDescriptorSetLayoutBinding] + forDescriptorFields(value, fieldValue, descriptorType, descriptorCount, descriptorBindingNumber): + layoutbindings.add VkDescriptorSetLayoutBinding( + binding: descriptorBindingNumber, + descriptorType: descriptorType, + descriptorCount: descriptorCount, + stageFlags: VkShaderStageFlags(VK_SHADER_STAGE_ALL_GRAPHICS), + pImmutableSamplers: nil, ) - checkVkResult vkCreateDescriptorSetLayout( - vulkan.device, - addr(layoutCreateInfo), - nil, - addr(result[setNumber]) - ) - inc setNumber + var layoutCreateInfo = VkDescriptorSetLayoutCreateInfo( + sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + bindingCount: layoutbindings.len.uint32, + pBindings: layoutbindings.ToCPointer + ) + checkVkResult vkCreateDescriptorSetLayout( + vulkan.device, + addr(layoutCreateInfo), + nil, + addr(result[value.getCustomPragmaVal(DescriptorSet)]) + ) proc createPipeline*[TShader]( renderPass: RenderPass, @@ -373,8 +360,11 @@ const shader = default(TShader) (result.vertexShaderModule, result.fragmentShaderModule) = compileShader(shader) - var nSets = getDescriptorSetCount[TShader]() result.descriptorSetLayouts = createDescriptorSetLayouts[TShader]() + var layouts: seq[VkDescriptorSetLayout] + for l in result.descriptorSetLayouts: + if l.Valid: + layouts.add l let pushConstant = VkPushConstantRange( stageFlags: VkShaderStageFlags(VK_SHADER_STAGE_ALL_GRAPHICS), @@ -384,8 +374,8 @@ let pipelineLayoutInfo = VkPipelineLayoutCreateInfo( sType: VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, - setLayoutCount: nSets, - pSetLayouts: if nSets == 0: nil else: result.descriptorSetLayouts.ToCPointer, + setLayoutCount: layouts.len.uint32, + pSetLayouts: layouts.ToCPointer, pushConstantRangeCount: 1, pPushConstantRanges: addr(pushConstant), ) diff -r 385dbd68a947 -r 4a1c2b1128bc semicongine/rendering/vulkan_wrappers.nim --- a/semicongine/rendering/vulkan_wrappers.nim Thu Aug 15 12:12:27 2024 +0700 +++ b/semicongine/rendering/vulkan_wrappers.nim Thu Aug 15 18:30:00 2024 +0700 @@ -215,6 +215,18 @@ pDynamicOffsets = nil ) +proc svkCmdBindDescriptorSet(commandBuffer: VkCommandBuffer, descriptorSet: VkDescriptorSet, index: DescriptorSetIndex, layout: VkPipelineLayout) = + vkCmdBindDescriptorSets( + commandBuffer = commandBuffer, + pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + layout = layout, + firstSet = index.uint32, + descriptorSetCount = 1, + pDescriptorSets = addr(descriptorSet), + dynamicOffsetCount = 0, + pDynamicOffsets = nil + ) + proc svkCreateRenderPass( attachments: openArray[VkAttachmentDescription], diff -r 385dbd68a947 -r 4a1c2b1128bc semicongine/text.nim --- a/semicongine/text.nim Thu Aug 15 12:12:27 2024 +0700 +++ b/semicongine/text.nim Thu Aug 15 18:30:00 2024 +0700 @@ -53,7 +53,7 @@ uv {.VertexAttribute.}: Vec2f # TODO: maybe we can keep the uvs in a uniform buffer and just pass an index fragmentUv {.Pass.}: Vec2f color {.ShaderOutput.}: Vec4f - descriptorSets {.DescriptorSets.}: (TextboxDescriptorSet, ) + descriptorSets {.DescriptorSet: 0.}: TextboxDescriptorSet vertexCode* = """void main() { gl_Position = vec4(position * vec3(1 / textbox.aspectratio, 1, 1) * textbox.scale + textbox.position, 1.0); fragmentUv = uv; diff -r 385dbd68a947 -r 4a1c2b1128bc semicongine/text/textbox.nim --- a/semicongine/text/textbox.nim Thu Aug 15 12:12:27 2024 +0700 +++ b/semicongine/text/textbox.nim Thu Aug 15 18:30:00 2024 +0700 @@ -17,7 +17,7 @@ position: GPUArray[Vec3f, VertexBuffer] uv: GPUArray[Vec2f, VertexBuffer] indices: GPUArray[uint16, IndexBuffer] - shaderdata: DescriptorSet[TextboxDescriptorSet] + shaderdata: DescriptorSetData[TextboxDescriptorSet] proc `=copy`(dest: var Textbox; source: Textbox) {.error.} @@ -176,8 +176,8 @@ textbox.dirtyGeometry = false proc render*(commandbuffer: VkCommandBuffer, pipeline: Pipeline, textbox: Textbox) = - withBind(commandbuffer, (textbox.shaderdata, ), pipeline): - render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = textbox) + bindDescriptorSet(commandbuffer, textbox.shaderdata, 0, pipeline) + render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = textbox) proc initTextbox*[T: string | seq[Rune]]( renderdata: var RenderData, @@ -204,7 +204,7 @@ position: asGPUArray(newSeq[Vec3f](int(maxLen * 4)), VertexBuffer), uv: asGPUArray(newSeq[Vec2f](int(maxLen * 4)), VertexBuffer), indices: asGPUArray(newSeq[uint16](int(maxLen * 6)), IndexBuffer), - shaderdata: asDescriptorSet( + shaderdata: asDescriptorSetData( TextboxDescriptorSet( textbox: asGPUValue(TextboxData( scale: scale, diff -r 385dbd68a947 -r 4a1c2b1128bc tests/test_rendering.nim --- a/tests/test_rendering.nim Thu Aug 15 12:12:27 2024 +0700 +++ b/tests/test_rendering.nim Thu Aug 15 18:30:00 2024 +0700 @@ -17,7 +17,7 @@ Shader = object position {.VertexAttribute.}: Vec3f color {.VertexAttribute.}: Vec3f - pushConstant {.PushConstantAttribute.}: PushConstant + pushConstant {.PushConstant.}: PushConstant fragmentColor {.Pass.}: Vec3f outColor {.ShaderOutput.}: Vec4f # code @@ -144,7 +144,7 @@ fragmentColor {.Pass.}: Vec3f uv {.Pass.}: Vec2f outColor {.ShaderOutput.}: Vec4f - descriptorSets {.DescriptorSets.}: (Uniforms, ) + descriptorSets {.DescriptorSet: 0.}: Uniforms # code vertexCode: string = """void main() { fragmentColor = material.baseColor; @@ -167,13 +167,13 @@ position: asGPUArray([vec3(-0.5, -0.5, 0), vec3(-0.5, 0.5, 0), vec3(0.5, 0.5, 0), vec3(0.5, -0.5, 0)], VertexBuffer), indices: asGPUArray([0'u16, 1'u16, 2'u16, 2'u16, 3'u16, 0'u16], IndexBuffer), ) - uniforms1 = asDescriptorSet( + uniforms1 = asDescriptorSetData( Uniforms( material: asGPUValue(Material(baseColor: vec3(1, 1, 1)), UniformBuffer), texture1: Image[BGRA](width: 3, height: 3, data: @[R, G, B, G, B, R, B, R, G], minInterpolation: VK_FILTER_NEAREST, magInterpolation: VK_FILTER_NEAREST), ) ) - uniforms2 = asDescriptorSet( + uniforms2 = asDescriptorSetData( Uniforms( material: asGPUValue(Material(baseColor: vec3(0.5, 0.5, 0.5)), UniformBuffer), texture1: Image[BGRA](width: 2, height: 2, data: @[R, G, B, W]), @@ -201,11 +201,11 @@ withPipeline(commandbuffer, pipeline): - withBind(commandbuffer, (uniforms1, ), pipeline): - render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = quad) + bindDescriptorSet(commandbuffer, uniforms1, 0, pipeline) + render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = quad) - withBind(commandbuffer, (uniforms2, ), pipeline): - render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = quad) + bindDescriptorSet(commandbuffer, uniforms2, 0, pipeline) + render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = quad) # cleanup checkVkResult vkDeviceWaitIdle(vulkan.device) @@ -240,7 +240,9 @@ fragmentColor {.Pass.}: Vec3f uv {.Pass.}: Vec2f outColor {.ShaderOutput.}: Vec4f - descriptorSets {.DescriptorSets.}: (ConstSet, MainSet, OtherSet) + descriptorSets0 {.DescriptorSet: 0.}: ConstSet + descriptorSets1 {.DescriptorSet: 1.}: MainSet + descriptorSets2 {.DescriptorSet: 2.}: OtherSet # code vertexCode: string = """void main() { fragmentColor = material[objectSettings.materialIndex].baseColor * renderSettings.brigthness; @@ -260,14 +262,14 @@ position: asGPUArray([vec3(-0.5, -0.5), vec3(-0.5, 0.5), vec3(0.5, 0.5), vec3(0.5, -0.5)], VertexBuffer), indices: asGPUArray([0'u16, 1'u16, 2'u16, 2'u16, 3'u16, 0'u16], IndexBuffer), ) - var constset = asDescriptorSet( + var constset = asDescriptorSetData( ConstSet( constants: asGPUValue(Constants(offset: vec2(-0.3, 0.2)), UniformBuffer), ) ) let G = Gray([50'u8]) let W = Gray([255'u8]) - var mainset = asDescriptorSet( + var mainset = asDescriptorSetData( MainSet( renderSettings: asGPUValue(RenderSettings(brigthness: 0), UniformBufferMapped), material: [ @@ -280,12 +282,12 @@ ], ), ) - var otherset1 = asDescriptorSet( + var otherset1 = asDescriptorSetData( OtherSet( objectSettings: asGPUValue(ObjectSettings(scale: 1.0, materialIndex: 0), UniformBufferMapped), ) ) - var otherset2 = asDescriptorSet( + var otherset2 = asDescriptorSetData( OtherSet( objectSettings: asGPUValue(ObjectSettings(scale: 1.0, materialIndex: 1), UniformBufferMapped), ) @@ -310,16 +312,18 @@ while ((getMonoTime() - start).inMilliseconds().int / 1000) < time: withNextFrame(framebuffer, commandbuffer): + bindDescriptorSet(commandbuffer, constset, 0, pipeline) + bindDescriptorSet(commandbuffer, mainset, 1, pipeline) withRenderPass(vulkan.swapchain.renderPass, framebuffer, commandbuffer, vulkan.swapchain.width, vulkan.swapchain.height, vec4(0, 0, 0, 0)): withPipeline(commandbuffer, pipeline): - withBind(commandbuffer, (constset, mainset, otherset1), pipeline): - render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = quad) + bindDescriptorSet(commandbuffer, otherset1, 2, pipeline) + render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = quad) - withBind(commandbuffer, (constset, mainset, otherset2), pipeline): - render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = quad) + bindDescriptorSet(commandbuffer, otherset2, 2, pipeline) + render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = quad) mainset.data.renderSettings.data.brigthness = ((getMonoTime() - start).inMilliseconds().int / 1000) / time otherset1.data.objectSettings.data.scale = 0.5 + ((getMonoTime() - start).inMilliseconds().int / 1000) / time @@ -344,7 +348,7 @@ color {.VertexAttribute.}: Vec4f fragmentColor {.Pass.}: Vec4f outColor {.ShaderOutput.}: Vec4f - descriptorSets {.DescriptorSets.}: (Uniforms, ) + descriptorSets {.DescriptorSet: 0.}: Uniforms # code vertexCode = """void main() { fragmentColor = color; @@ -417,7 +421,7 @@ ) assignBuffers(renderdata, floor) - var uniforms1 = asDescriptorSet( + var uniforms1 = asDescriptorSetData( Uniforms( data: asGPUValue(UniformData(mvp: Unit4), UniformBufferMapped) ) @@ -449,9 +453,9 @@ withRenderPass(vulkan.swapchain.renderPass, framebuffer, commandbuffer, vulkan.swapchain.width, vulkan.swapchain.height, vec4(0, 0, 0, 0)): withPipeline(commandbuffer, pipeline): - withBind(commandbuffer, (uniforms1, ), pipeline): - render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = mesh) - render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = floor) + bindDescriptorSet(commandbuffer, uniforms1, 0, pipeline) + render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = mesh) + render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = floor) let tEndLoop = getMonoTime() - tStart let looptime = tEndLoop - tStartLoop @@ -532,7 +536,7 @@ uv {.VertexAttribute.}: Vec2f fragmentUv {.Pass.}: Vec2f outColor {.ShaderOutput.}: Vec4f - descriptorSets {.DescriptorSets.}: (Uniforms, ) + descriptorSets {.DescriptorSet: 0.}: Uniforms # code vertexCode: string = """ void main() { @@ -560,7 +564,7 @@ renderdata.flushAllMemory() var pipeline = createPipeline[Shader](renderPass = vulkan.swapchain.renderPass) - var uniforms1 = asDescriptorSet( + var uniforms1 = asDescriptorSetData( Uniforms( texture1: loadImage[BGRA]("art.png"), ) @@ -577,8 +581,8 @@ withPipeline(commandbuffer, pipeline): - withBind(commandbuffer, (uniforms1, ), pipeline): - render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = mesh) + bindDescriptorSet(commandbuffer, uniforms1, 0, pipeline) + render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = mesh) # cleanup checkVkResult vkDeviceWaitIdle(vulkan.device) @@ -610,7 +614,7 @@ position {.VertexAttribute.}: Vec2f uv {.Pass.}: Vec2f outColor {.ShaderOutput.}: Vec4f - descriptorSets {.DescriptorSets.}: (Uniforms, ) + descriptorSets {.DescriptorSet: 0.}: Uniforms # code vertexCode: string = """void main() { uv = ((position + 1) * 0.5) * vec2(1, -1); @@ -641,7 +645,7 @@ position: asGPUArray([vec2(-1, -1), vec2(-1, 1), vec2(1, 1), vec2(1, -1)], VertexBuffer), indices: asGPUArray([0'u16, 1'u16, 2'u16, 2'u16, 3'u16, 0'u16], IndexBuffer), ) - var uniforms1 = asDescriptorSet( + var uniforms1 = asDescriptorSetData( Uniforms( frameTexture: Image[BGRA](width: vulkan.swapchain.width, height: vulkan.swapchain.height, isRenderTarget: true), ) @@ -744,8 +748,8 @@ withPipeline(commandbuffer, presentPipeline): - withBind(commandbuffer, (uniforms1, ), presentPipeline): - render(commandbuffer = commandbuffer, pipeline = presentPipeline, mesh = quad) + bindDescriptorSet(commandbuffer, uniforms1, 0, presentPipeline) + render(commandbuffer = commandbuffer, pipeline = presentPipeline, mesh = quad) # cleanup checkVkResult vkDeviceWaitIdle(vulkan.device)