Mercurial > games > semicongine
changeset 1210:570ac1620fb6 compiletime-tests
fix: make uniform-block-arrays working
author | sam <sam@basx.dev> |
---|---|
date | Wed, 17 Jul 2024 00:30:49 +0700 |
parents | e177336cac3f |
children | d9799f74f5a7 |
files | semicongine/rendering.nim semicongine/rendering/renderer.nim semicongine/rendering/shaders.nim tests/test_rendering tests/test_rendering.nim |
diffstat | 5 files changed, 255 insertions(+), 145 deletions(-) [+] |
line wrap: on
line diff
--- a/semicongine/rendering.nim Tue Jul 16 20:39:35 2024 +0700 +++ b/semicongine/rendering.nim Wed Jul 17 00:30:49 2024 +0700 @@ -104,17 +104,18 @@ rawPointer: pointer # if not nil, buffer is using mapped memory offsetNextFree: uint64 Texture*[T: TextureType] = object + width*: uint32 + height*: uint32 + interpolation*: VkFilter = VK_FILTER_LINEAR + data*: seq[T] vk: VkImage imageview: VkImageView sampler: VkSampler - width*: uint32 - height*: uint32 - data*: seq[T] GPUArray*[T: SupportedGPUType, TBuffer: static BufferType] = object data*: seq[T] buffer*: Buffer offset*: uint64 - GPUValue*[T: object|array, TBuffer: static BufferType] = object + GPUValue*[T: object, TBuffer: static BufferType] = object data*: T buffer: Buffer offset: uint64 @@ -139,7 +140,7 @@ let `valuename` {.inject.} = value body `bindingNumber`.inc - elif typeof(value) is object: + elif typeof(value) is GPUValue: block: const `fieldname` {.inject.} = theFieldname const `typename` {.inject.} = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER @@ -156,16 +157,18 @@ let `valuename` {.inject.} = value body `bindingNumber`.inc - elif elementType(value) is object: + elif elementType(value) is GPUValue: block: const `fieldname` {.inject.} = theFieldname const `typename` {.inject.} = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER - const `countname` {.inject.} = uint32(typeof(value).len) + const `countname` {.inject.} = len(value).uint32 let `valuename` {.inject.} = value body `bindingNumber`.inc else: {.error: "Unsupported descriptor type: " & typetraits.name(typeof(value)).} + else: + {.error: "Unsupported descriptor type: " & typetraits.name(typeof(value)).} include ./rendering/vulkan_wrappers include ./rendering/renderpasses
--- a/semicongine/rendering/renderer.nim Tue Jul 16 20:39:35 2024 +0700 +++ b/semicongine/rendering/renderer.nim Wed Jul 17 00:30:49 2024 +0700 @@ -88,13 +88,26 @@ ) = # santization checks - for name, value in descriptorSet.data.fieldPairs: + for theName, value in descriptorSet.data.fieldPairs: when typeof(value) is GPUValue: assert value.buffer.vk.Valid elif typeof(value) is Texture: assert value.vk.Valid assert value.imageview.Valid assert value.sampler.Valid + elif typeof(value) is array: + when elementType(value) is Texture: + for t in value: + assert t.vk.Valid + assert t.imageview.Valid + assert t.sampler.Valid + elif elementType(value) is GPUValue: + for t in value: + assert t.buffer.vk.Valid + else: + {.error: "Unsupported descriptor set field: '" & theName & "'".} + else: + {.error: "Unsupported descriptor set field: '" & theName & "'".} # allocate var layouts = newSeqWith(descriptorSet.vk.len, layout) @@ -147,12 +160,11 @@ pBufferInfo: nil, ) elif typeof(fieldValue) is array: - discard when elementType(fieldValue) is Texture: - for textureIndex in 0 ..< descriptorCount: + for texture in fieldValue: imageWrites.add VkDescriptorImageInfo( - sampler: fieldValue[textureIndex].sampler, - imageView: fieldValue[textureIndex].imageView, + sampler: texture.sampler, + imageView: texture.imageView, imageLayout: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, ) descriptorSetWrites.add VkWriteDescriptorSet( @@ -165,6 +177,23 @@ pImageInfo: addr(imageWrites[^descriptorCount.int]), pBufferInfo: nil, ) + elif elementType(fieldValue) is GPUValue: + for entry in fieldValue: + 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], + 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: @@ -260,35 +289,48 @@ for name, fieldvalue in value.fieldPairs(): when typeof(fieldvalue) is GPUData: UpdateGPUBuffer(fieldvalue) + when typeof(fieldvalue) is array: + when elementType(fieldvalue) is GPUData: + for entry in fieldvalue: + UpdateGPUBuffer(entry) + +proc AssignGPUData(renderdata: var RenderData, value: var GPUData) = + # find buffer that has space + var selectedBufferI = -1 + + for i in 0 ..< renderData.buffers[value.bufferType].len: + let buffer = renderData.buffers[value.bufferType][i] + if buffer.size - alignedTo(buffer.offsetNextFree, BUFFER_ALIGNMENT) >= value.size: + selectedBufferI = i + + # otherwise create new buffer + if selectedBufferI < 0: + selectedBufferI = renderdata.buffers[value.bufferType].len + renderdata.buffers[value.bufferType].add renderdata.AllocateNewBuffer( + size = max(value.size, BUFFER_ALLOCATION_SIZE), + bufferType = value.bufferType, + ) + + # assigne value + let selectedBuffer = renderdata.buffers[value.bufferType][selectedBufferI] + renderdata.buffers[value.bufferType][selectedBufferI].offsetNextFree = alignedTo( + selectedBuffer.offsetNextFree, + BUFFER_ALIGNMENT + ) + value.buffer = selectedBuffer + value.offset = renderdata.buffers[value.bufferType][selectedBufferI].offsetNextFree + renderdata.buffers[value.bufferType][selectedBufferI].offsetNextFree += value.size proc AssignBuffers*[T](renderdata: var RenderData, data: var T, uploadData = true) = for name, value in fieldPairs(data): - when typeof(value) is GPUData: - - # find buffer that has space - var selectedBufferI = -1 - for i in 0 ..< renderData.buffers[value.bufferType].len: - let buffer = renderData.buffers[value.bufferType][i] - if buffer.size - alignedTo(buffer.offsetNextFree, BUFFER_ALIGNMENT) >= value.size: - selectedBufferI = i - # otherwise create new buffer - if selectedBufferI < 0: - selectedBufferI = renderdata.buffers[value.bufferType].len - renderdata.buffers[value.bufferType].add renderdata.AllocateNewBuffer( - size = max(value.size, BUFFER_ALLOCATION_SIZE), - bufferType = value.bufferType, - ) + when typeof(value) is GPUData: + AssignGPUData(renderdata, value) + elif typeof(value) is array: + when elementType(value) is GPUValue: + for v in value.mitems: + AssignGPUData(renderdata, v) - # assigne value - let selectedBuffer = renderdata.buffers[value.bufferType][selectedBufferI] - renderdata.buffers[value.bufferType][selectedBufferI].offsetNextFree = alignedTo( - selectedBuffer.offsetNextFree, - BUFFER_ALIGNMENT - ) - value.buffer = selectedBuffer - value.offset = renderdata.buffers[value.bufferType][selectedBufferI].offsetNextFree - renderdata.buffers[value.bufferType][selectedBufferI].offsetNextFree += value.size if uploadData: UpdateAllGPUBuffers(data) @@ -410,7 +452,7 @@ texture.vk = svkCreate2DImage(texture.width, texture.height, format, usage) renderData.images.add texture.vk - texture.sampler = createSampler() + texture.sampler = createSampler(magFilter = texture.interpolation, minFilter = texture.interpolation) renderData.samplers.add texture.sampler let memoryRequirements = texture.vk.svkGetImageMemoryRequirements() @@ -480,48 +522,6 @@ let `fieldvalue` {.inject.} = value body -proc AssertCompatible(TShader, TMesh, TInstance, TFirstDescriptorSet, TSecondDescriptorSet: typedesc) = - var descriptorSetCount = 0 - - for shaderAttributeName, shaderAttribute in default(TShader).fieldPairs: - var foundField = false - - # Vertex input data - when hasCustomPragma(shaderAttribute, VertexAttribute): - assert typeof(shaderAttribute) is SupportedGPUType - for meshName, meshValue in default(TMesh).fieldPairs: - when meshName == shaderAttributeName: - assert meshValue is GPUArray, "Mesh attribute '" & meshName & "' must be of type 'GPUArray' but is of type " & typetraits.name(typeof(meshValue)) - assert foundField == false, "Shader input '" & typetraits.name(TShader) & "." & shaderAttributeName & "' has been found more than once" - assert elementType(meshValue.data) is typeof(shaderAttribute), "Shader input " & typetraits.name(TShader) & "." & shaderAttributeName & " is of type '" & typetraits.name(typeof(shaderAttribute)) & "' but mesh attribute is of type '" & typetraits.name(elementType(meshValue.data)) & "'" - foundField = true - assert foundField, "Shader input '" & typetraits.name(TShader) & "." & shaderAttributeName & ": " & typetraits.name(typeof(shaderAttribute)) & "' not found in '" & typetraits.name(TMesh) & "'" - - # Instance input data - elif hasCustomPragma(shaderAttribute, InstanceAttribute): - assert typeof(shaderAttribute) is SupportedGPUType - for instanceName, instanceValue in default(TInstance).fieldPairs: - when instanceName == shaderAttributeName: - assert instanceValue is GPUArray, "Instance attribute '" & instanceName & "' must be of type 'GPUArray' but is of type " & typetraits.name(typeof(instanceName)) - assert foundField == false, "Shader input '" & typetraits.name(TShader) & "." & shaderAttributeName & "' has been found more than once" - assert elementType(instanceValue.data) is typeof(shaderAttribute), "Shader input " & typetraits.name(TShader) & "." & shaderAttributeName & " is of type '" & typetraits.name(typeof(shaderAttribute)) & "' but instance attribute is of type '" & typetraits.name(elementType(instanceValue.data)) & "'" - foundField = true - assert foundField, "Shader input '" & typetraits.name(TShader) & "." & shaderAttributeName & ": " & typetraits.name(typeof(shaderAttribute)) & "' not found in '" & typetraits.name(TInstance) & "'" - - # descriptors - elif typeof(shaderAttribute) is DescriptorSet: - assert descriptorSetCount <= MAX_DESCRIPTORSETS.int, typetraits.name(TShader) & ": maximum " & $MAX_DESCRIPTORSETS & " allowed" - descriptorSetCount.inc - - - when shaderAttribute.sType == First: - assert shaderAttribute.sType == default(TFirstDescriptorSet).sType, "Shader has first descriptor set of type '" & $shaderAttribute.sType & "' but matching provided type is '" & $default(TFirstDescriptorSet).sType & "'" - assert typeof(shaderAttribute) is TFirstDescriptorSet, "Shader has first descriptor set type '" & typetraits.name(get(genericParams(typeof(shaderAttribute)), 0)) & "' but provided type is " & typetraits.name(TFirstDescriptorSet) - elif shaderAttribute.sType == Second: - assert shaderAttribute.sType == default(TSecondDescriptorSet).sType, "Shader has second descriptor set of type '" & $shaderAttribute.sType & "' but matching provided type is '" & $default(TSecondDescriptorSet).sType & "'" - assert typeof(shaderAttribute) is TSecondDescriptorSet, "Shader has seconddescriptor type '" & typetraits.name(get(genericParams(typeof(shaderAttribute)), 0)) & "' but provided type is " & typetraits.name(TSecondDescriptorSet) - - template WithBind*[A, B, C, D](commandBuffer: VkCommandBuffer, sets: (DescriptorSet[A], DescriptorSet[B], DescriptorSet[C], DescriptorSet[D]), pipeline: Pipeline, currentFiF: int, body: untyped): untyped = block: var descriptorSets: seq[VkDescriptorSet] @@ -555,17 +555,12 @@ svkCmdBindDescriptorSets(commandBuffer, descriptorSets, pipeline.layout) body - -proc Render*[TFirstDescriptorSet, TSecondDescriptorSet: DescriptorSet, TShader, TMesh, TInstance]( +proc Render*[TShader, TMesh, TInstance]( commandBuffer: VkCommandBuffer, pipeline: Pipeline[TShader], - firstSet: TFirstDescriptorSet, - secondSet: TSecondDescriptorSet, mesh: TMesh, instances: TInstance, ) = - when not defined(release): - static: AssertCompatible(TShader, TMesh, TInstance, TFirstDescriptorSet, TSecondDescriptorSet) var vertexBuffers: seq[VkBuffer] var vertexBuffersOffsets: seq[uint64] @@ -643,44 +638,13 @@ ) type EMPTY = object -type EMPTY_DESCRIPTORSET = DescriptorSet[EMPTY] -proc Render*[TFirstDescriptorSet, TSecondDescriptorSet: DescriptorSet, TShader, TMesh]( - commandBuffer: VkCommandBuffer, - pipeline: Pipeline[TShader], - firstSet: TFirstDescriptorSet, - secondSet: TSecondDescriptorSet, - mesh: TMesh, -) = - Render(commandBuffer, pipeline, firstSet, secondSet, mesh, EMPTY()) -proc Render*[TFirstDescriptorSet: DescriptorSet, TMesh, TShader]( - commandBuffer: VkCommandBuffer, - pipeline: Pipeline[TShader], - firstSet: TFirstDescriptorSet, - mesh: TMesh, -) = - Render(commandBuffer, pipeline, firstSet, EMPTY_DESCRIPTORSET(), mesh, EMPTY()) proc Render*[TShader, TMesh]( commandBuffer: VkCommandBuffer, pipeline: Pipeline[TShader], mesh: TMesh, ) = - Render(commandBuffer, pipeline, EMPTY_DESCRIPTORSET(), EMPTY_DESCRIPTORSET(), mesh, EMPTY()) -proc Render*[TFirstDescriptorSet: DescriptorSet, TMesh, TShader, TInstance]( - commandBuffer: VkCommandBuffer, - pipeline: Pipeline[TShader], - firstSet: TFirstDescriptorSet, - mesh: TMesh, - instances: TInstance, -) = - Render(commandBuffer, pipeline, firstSet, EMPTY_DESCRIPTORSET(), mesh, instances) -proc Render*[TShader, TMesh, TInstance]( - commandBuffer: VkCommandBuffer, - pipeline: Pipeline[TShader], - mesh: TMesh, - instances: TInstance, -) = - Render(commandBuffer, pipeline, EMPTY_DESCRIPTORSET(), EMPTY_DESCRIPTORSET(), mesh, instances) + Render(commandBuffer, pipeline, mesh, EMPTY()) proc asGPUArray*[T](data: openArray[T], bufferType: static BufferType): auto = GPUArray[T, bufferType](data: @data)
--- a/semicongine/rendering/shaders.nim Tue Jul 16 20:39:35 2024 +0700 +++ b/semicongine/rendering/shaders.nim Wed Jul 17 00:30:49 2024 +0700 @@ -166,6 +166,7 @@ for descriptor in value.fields: var descriptorBinding = 0 + for descriptorName, descriptorValue in fieldPairs(descriptor): when typeof(descriptorValue) is Texture: @@ -173,25 +174,40 @@ descriptorBinding.inc elif typeof(descriptorValue) is GPUValue: + uniforms.add "layout(set=" & $descriptorSetIndex & ", 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 & ";" - elif typeof(descriptorValue.data) is array: - 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.data.len & "];" + + else: + {.error: "Unsupported shader descriptor field " & descriptorName & " (must be object)".} descriptorBinding.inc + elif typeof(descriptorValue) is array: + when elementType(descriptorValue) is Texture: + 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 elif fieldname in ["vertexCode", "fragmentCode"]: discard @@ -304,9 +320,9 @@ var setNumber: int for _, value in fieldPairs(default(TShader)): when hasCustomPragma(value, DescriptorSets): - for descriptor in value.fields: + for descriptorSet in value.fields: var layoutbindings: seq[VkDescriptorSetLayoutBinding] - ForDescriptorFields(descriptor, fieldName, fieldValue, descriptorType, descriptorCount, descriptorBindingNumber): + ForDescriptorFields(descriptorSet, fieldName, fieldValue, descriptorType, descriptorCount, descriptorBindingNumber): layoutbindings.add VkDescriptorSetLayoutBinding( binding: descriptorBindingNumber, descriptorType: descriptorType,
--- a/tests/test_rendering.nim Tue Jul 16 20:39:35 2024 +0700 +++ b/tests/test_rendering.nim Wed Jul 17 00:30:49 2024 +0700 @@ -119,31 +119,126 @@ DestroyPipeline(pipeline) DestroyRenderData(renderdata) -proc test_03_global_descriptorset(nFrames: int) = +proc test_03_simple_descriptorset(nFrames: int) = + var renderdata = InitRenderData() + + type + Material = object + baseColor: Vec3f + + Uniforms = object + material: GPUValue[Material, UniformBuffer] + texture1: Texture[TVec3[uint8]] + + QuadShader = object + position {.VertexAttribute.}: Vec3f + fragmentColor {.Pass.}: Vec3f + uv {.Pass.}: Vec2f + outColor {.ShaderOutput.}: Vec4f + descriptorSets {.DescriptorSets.}: (Uniforms, ) + # code + vertexCode: string = """void main() { + fragmentColor = material.baseColor; + gl_Position = vec4(position, 1); + gl_Position.x += ((material.baseColor.b - 0.5) * 2) - 0.5; + uv = position.xy + 0.5; + }""" + fragmentCode: string = """void main() { + outColor = vec4(fragmentColor, 1) * texture(texture1, uv);}""" + QuadMesh = object + position: GPUArray[Vec3f, VertexBuffer] + indices: GPUArray[uint16, IndexBuffer] + + let R = TVec3[uint8]([255'u8, 0'u8, 0'u8]) + let G = TVec3[uint8]([0'u8, 255'u8, 0'u8]) + let B = TVec3[uint8]([0'u8, 0'u8, 255'u8]) + let W = TVec3[uint8]([255'u8, 255'u8, 255'u8]) + var + quad = QuadMesh( + position: asGPUArray([NewVec3f(-0.5, -0.5), NewVec3f(-0.5, 0.5), NewVec3f(0.5, 0.5), NewVec3f(0.5, -0.5)], VertexBuffer), + indices: asGPUArray([0'u16, 1'u16, 2'u16, 2'u16, 3'u16, 0'u16], IndexBuffer), + ) + uniforms1 = asDescriptorSet( + Uniforms( + material: asGPUValue(Material(baseColor: NewVec3f(1, 1, 1)), UniformBuffer), + texture1: Texture[TVec3[uint8]](width: 3, height: 3, data: @[R, G, B, G, B, R, B, R, G], interpolation: VK_FILTER_NEAREST), + ) + ) + uniforms2 = asDescriptorSet( + Uniforms( + material: asGPUValue(Material(baseColor: NewVec3f(0.5, 0.5, 0.5)), UniformBuffer), + texture1: Texture[TVec3[uint8]](width: 2, height: 2, data: @[R, G, B, W]), + ) + ) + + AssignBuffers(renderdata, quad) + AssignBuffers(renderdata, uniforms1) + AssignBuffers(renderdata, uniforms2) + UploadTextures(renderdata, uniforms1) + UploadTextures(renderdata, uniforms2) + renderdata.FlushAllMemory() + + var pipeline = CreatePipeline[QuadShader](renderPass = mainRenderpass, samples = swapchain.samples) + + InitDescriptorSet(renderdata, pipeline.descriptorSetLayouts[0], uniforms1) + InitDescriptorSet(renderdata, pipeline.descriptorSetLayouts[0], uniforms2) + + var c = 0 + while UpdateInputs() and c < nFrames: + WithNextFrame(swapchain, framebuffer, commandbuffer): + WithRenderPass(mainRenderpass, framebuffer, commandbuffer, swapchain.width, swapchain.height, NewVec4f(0, 0, 0, 0)): + WithPipeline(commandbuffer, pipeline): + WithBind(commandbuffer, (uniforms1, ), pipeline, swapchain.currentFiF): + Render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = quad) + WithBind(commandbuffer, (uniforms2, ), pipeline, swapchain.currentFiF): + Render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = quad) + inc c + + # cleanup + checkVkResult vkDeviceWaitIdle(vulkan.device) + DestroyPipeline(pipeline) + DestroyRenderData(renderdata) + +proc test_04_multiple_descriptorsets(nFrames: int) = var renderdata = InitRenderData() type RenderSettings = object brigthness: float32 + Material = object + baseColor: Vec3f ObjectSettings = object - baseColor: Vec3f + scale: float32 + materialIndex: uint32 + Constants = object + offset: Vec2f + + ConstSet = object + constants: GPUValue[Constants, UniformBuffer] MainSet = object renderSettings: GPUValue[RenderSettings, UniformBufferMapped] - materialSettings: GPUValue[ObjectSettings, UniformBuffer] + material: array[2, GPUValue[Material, UniformBuffer]] + texture1: array[2, Texture[TVec1[uint8]]] OtherSet = object - # TODO + objectSettings: GPUValue[ObjectSettings, UniformBufferMapped] QuadShader = object position {.VertexAttribute.}: Vec3f fragmentColor {.Pass.}: Vec3f + uv {.Pass.}: Vec2f outColor {.ShaderOutput.}: Vec4f - descriptorSets {.DescriptorSets.}: (MainSet, OtherSet) + descriptorSets {.DescriptorSets.}: (ConstSet, MainSet, OtherSet) # code vertexCode: string = """void main() { - fragmentColor = materialSettings.baseColor * renderSettings.brigthness; - gl_Position = vec4(position, 1);}""" + fragmentColor = material[objectSettings.materialIndex].baseColor * renderSettings.brigthness; + gl_Position = vec4(position * objectSettings.scale, 1); + gl_Position.xy += constants.offset.xy; + gl_Position.x += material[objectSettings.materialIndex].baseColor.b - 0.5; + uv = position.xy + 0.5; + }""" fragmentCode: string = """void main() { - outColor = vec4(fragmentColor, 1);}""" + outColor = vec4(fragmentColor * texture(texture1[objectSettings.materialIndex], uv).rrr, 1); + }""" QuadMesh = object position: GPUArray[Vec3f, VertexBuffer] indices: GPUArray[uint16, IndexBuffer] @@ -152,35 +247,65 @@ position: asGPUArray([NewVec3f(-0.5, -0.5), NewVec3f(-0.5, 0.5), NewVec3f(0.5, 0.5), NewVec3f(0.5, -0.5)], VertexBuffer), indices: asGPUArray([0'u16, 1'u16, 2'u16, 2'u16, 3'u16, 0'u16], IndexBuffer), ) - var mainSet = asDescriptorSet( + var constset = asDescriptorSet( + ConstSet( + constants: asGPUValue(Constants(offset: NewVec2f(-0.3, 0.2)), UniformBuffer), + ) + ) + let G = TVec1[uint8]([50'u8]) + let W = TVec1[uint8]([255'u8]) + var mainset = asDescriptorSet( MainSet( renderSettings: asGPUValue(RenderSettings(brigthness: 0), UniformBufferMapped), - materialSettings: asGPUValue(ObjectSettings(baseColor: NewVec3f(1, 1, 0)), UniformBuffer), + material: [ + asGPUValue(Material(baseColor: NewVec3f(1, 1, 0)), UniformBuffer), + asGPUValue(Material(baseColor: NewVec3f(1, 0, 1)), UniformBuffer), + ], + texture1: [ + Texture[TVec1[uint8]](width: 2, height: 2, data: @[W, G, G, W], interpolation: VK_FILTER_NEAREST), + Texture[TVec1[uint8]](width: 3, height: 3, data: @[W, G, W, G, W, G, W, G, W], interpolation: VK_FILTER_NEAREST), + ], + ), + ) + var otherset1 = asDescriptorSet( + OtherSet( + objectSettings: asGPUValue(ObjectSettings(scale: 1.0, materialIndex: 0), UniformBufferMapped), ) ) - var settings = asDescriptorSet( + var otherset2 = asDescriptorSet( OtherSet( - # TODO + objectSettings: asGPUValue(ObjectSettings(scale: 1.0, materialIndex: 1), UniformBufferMapped), ) ) AssignBuffers(renderdata, quad) - AssignBuffers(renderdata, mainSet) + AssignBuffers(renderdata, constset) + AssignBuffers(renderdata, mainset) + AssignBuffers(renderdata, otherset1) + AssignBuffers(renderdata, otherset2) + UploadTextures(renderdata, mainset) renderdata.FlushAllMemory() var pipeline = CreatePipeline[QuadShader](renderPass = mainRenderpass, samples = swapchain.samples) - InitDescriptorSet(renderdata, pipeline.descriptorSetLayouts[0], mainSet) + InitDescriptorSet(renderdata, pipeline.descriptorSetLayouts[0], constset) + InitDescriptorSet(renderdata, pipeline.descriptorSetLayouts[1], mainset) + InitDescriptorSet(renderdata, pipeline.descriptorSetLayouts[2], otherset1) + InitDescriptorSet(renderdata, pipeline.descriptorSetLayouts[2], otherset2) var c = 0 while UpdateInputs() and c < nFrames: WithNextFrame(swapchain, framebuffer, commandbuffer): - WithBind(commandbuffer, (mainSet, ), pipeline, swapchain.currentFiF): - WithRenderPass(mainRenderpass, framebuffer, commandbuffer, swapchain.width, swapchain.height, NewVec4f(0, 0, 0, 0)): - WithPipeline(commandbuffer, pipeline): - Render(commandbuffer = commandbuffer, pipeline = pipeline, firstSet = mainSet, mesh = quad) - mainSet.data.renderSettings.data.brigthness = (c.float32 / nFrames.float32) - UpdateGPUBuffer(mainSet.data.renderSettings) + WithRenderPass(mainRenderpass, framebuffer, commandbuffer, swapchain.width, swapchain.height, NewVec4f(0, 0, 0, 0)): + WithPipeline(commandbuffer, pipeline): + WithBind(commandbuffer, (constset, mainset, otherset1), pipeline, swapchain.currentFiF): + Render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = quad) + WithBind(commandbuffer, (constset, mainset, otherset2), pipeline, swapchain.currentFiF): + Render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = quad) + mainset.data.renderSettings.data.brigthness = (c.float32 / nFrames.float32) + otherset1.data.objectSettings.data.scale = 0.5 + (c.float32 / nFrames.float32) + UpdateGPUBuffer(mainset.data.renderSettings) + UpdateGPUBuffer(otherset1.data.objectSettings) renderdata.FlushAllMemory() inc c @@ -204,8 +329,10 @@ # tests instanced triangles and quads, mixing meshes and instances # test_02_triangle_quad_instanced(nFrames) + # test_03_simple_descriptorset(nFrames) + # tests - test_03_global_descriptorset(nFrames) + test_04_multiple_descriptorsets(nFrames) checkVkResult vkDeviceWaitIdle(vulkan.device) vkDestroyRenderPass(vulkan.device, mainRenderpass, nil)