# HG changeset patch # User Sam # Date 1679282750 -25200 # Node ID 20837928dc63cc12e1c7ac6ec36c6e8576eea6df # Parent fb42da98c1aa678d06970b81c41974bb64a50d82 add: finally working initial approach for shader definitions diff -r fb42da98c1aa -r 20837928dc63 src/semicongine/descriptor.nim --- a/src/semicongine/descriptor.nim Fri Mar 17 01:11:58 2023 +0700 +++ b/src/semicongine/descriptor.nim Mon Mar 20 10:25:50 2023 +0700 @@ -50,8 +50,7 @@ template getDescriptorType*(v: Descriptor): auto = get(genericParams(typeof(v)), 0) -func generateGLSLUniformDeclarations*[Uniforms]( - binding: int = 0): string {.compileTime.} = +func generateGLSLUniformDeclarations*[Uniforms](binding: int = 0): string {.compileTime.} = var stmtList: seq[string] when not (Uniforms is void): diff -r fb42da98c1aa -r 20837928dc63 src/semicongine/vulkan/framebuffer.nim --- a/src/semicongine/vulkan/framebuffer.nim Fri Mar 17 01:11:58 2023 +0700 +++ b/src/semicongine/vulkan/framebuffer.nim Mon Mar 20 10:25:50 2023 +0700 @@ -10,7 +10,7 @@ vk*: VkFramebuffer device*: Device -proc createFramebuffer*(device: Device, renderpass: RenderPass, attachments: openArray[ImageView], dimension: TVec2[uint32]): Framebuffer = +proc createFramebuffer*(device: Device, renderPass: RenderPass, attachments: openArray[ImageView], dimension: TVec2[uint32]): Framebuffer = assert device.vk.valid assert renderpass.vk.valid var theattachments: seq[VkImageView] diff -r fb42da98c1aa -r 20837928dc63 src/semicongine/vulkan/glsl.nim --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/semicongine/vulkan/glsl.nim Mon Mar 20 10:25:50 2023 +0700 @@ -0,0 +1,132 @@ +import std/typetraits +import std/strformat +import ../math/vector +import ../math/matrix + + +func getGLSLType*[T](t: T): string {.compileTime.} = + # todo: likely not correct as we would need to enable some + # extensions somewhere (Vulkan/GLSL compiler?) to have + # everything work as intended. Or maybe the GPU driver does + # some automagic conversion stuf.. + when T is uint8: "uint" + elif T is int8: "int" + elif T is uint16: "uint" + elif T is int16: "int" + elif T is uint32: "uint" + elif T is int32: "int" + elif T is uint64: "uint" + elif T is int64: "int" + elif T is float32: "float" + elif T is float64: "double" + + elif T is TVec2[uint8]: "uvec2" + elif T is TVec2[int8]: "ivec2" + elif T is TVec2[uint16]: "uvec2" + elif T is TVec2[int16]: "ivec2" + elif T is TVec2[uint32]: "uvec2" + elif T is TVec2[int32]: "ivec2" + elif T is TVec2[uint64]: "uvec2" + elif T is TVec2[int64]: "ivec2" + elif T is TVec2[float32]: "vec2" + elif T is TVec2[float64]: "dvec2" + + elif T is TVec3[uint8]: "uvec3" + elif T is TVec3[int8]: "ivec3" + elif T is TVec3[uint16]: "uvec3" + elif T is TVec3[int16]: "ivec3" + elif T is TVec3[uint32]: "uvec3" + elif T is TVec3[int32]: "ivec3" + elif T is TVec3[uint64]: "uvec3" + elif T is TVec3[int64]: "ivec3" + elif T is TVec3[float32]: "vec3" + elif T is TVec3[float64]: "dvec3" + + elif T is TVec4[uint8]: "uvec4" + elif T is TVec4[int8]: "ivec4" + elif T is TVec4[uint16]: "uvec4" + elif T is TVec4[int16]: "ivec4" + elif T is TVec4[uint32]: "uvec4" + elif T is TVec4[int32]: "ivec4" + elif T is TVec4[uint64]: "uvec4" + elif T is TVec4[int64]: "ivec4" + elif T is TVec4[float32]: "vec4" + elif T is TVec4[float64]: "dvec4" + + elif T is TMat22[float32]: "mat2" + elif T is TMat23[float32]: "mat32" + elif T is TMat32[float32]: "mat23" + elif T is TMat33[float32]: "mat3" + elif T is TMat34[float32]: "mat43" + elif T is TMat43[float32]: "mat34" + elif T is TMat44[float32]: "mat4" + + elif T is TMat22[float64]: "dmat2" + elif T is TMat23[float64]: "dmat32" + elif T is TMat32[float64]: "dmat23" + elif T is TMat33[float64]: "dmat3" + elif T is TMat34[float64]: "dmat43" + elif T is TMat43[float64]: "dmat34" + elif T is TMat44[float64]: "dmat4" + + +# return the number of elements into which larger types are divided +func compositeAttributesNumber*[T](value: T): int = + when T is TMat33[float32]: + 3 + elif T is TMat44[float32]: + 4 + else: + 1 + + +# from https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap15.html +func nLocationSlots*[T](value: T): uint32 = + when (T is TVec3[float64] or T is TVec3[uint64] or T is TVec4[float64] or T is TVec4[float64]): + return 2 + elif T is SomeNumber or T is TVec: + return 1 + else: + raise newException(Exception, "Unsupported vertex attribute type") + + +# return the type into which larger types are divided +func compositeAttribute*[T](value: T): auto = + when T is TMat33[float32]: + Vec3() + elif T is TMat44[float32]: + Vec4() + else: + value + +func glslInput*[T](): seq[string] {.compileTime.} = + when not (T is void): + var i = 0'u32 + for fieldname, value in default(T).fieldPairs: + let glsltype = getGLSLType(value) + let thename = fieldname + result.add &"layout(location = {i}) in {glsltype} {thename};" + for j in 0 ..< compositeAttributesNumber(value): + i += nLocationSlots(compositeAttribute(value)) + +func glslUniforms*[T](): seq[string] {.compileTime.} = + # currently only a single uniform block supported, therefore binding = 0 + when not (T is void): + let uniformName = name(T) + result.add(&"layout(binding = 0) uniform T{uniformName} {{") + for fieldname, value in default(T).fieldPairs: + let glsltype = getGLSLType(value) + let thename = fieldname + result.add(&" {glsltype} {thename};") + result.add(&"}} {uniformName};") + +func glslOutput*[T](): seq[string] {.compileTime.} = + when not (T is void): + var i = 0'u32 + for fieldname, value in default(T).fieldPairs: + let glsltype = getGLSLType(value) + let thename = fieldname + result.add &"layout(location = {i}) out {glsltype} {thename};" + i += 1 + else: + result diff -r fb42da98c1aa -r 20837928dc63 src/semicongine/vulkan/pipeline.nim --- a/src/semicongine/vulkan/pipeline.nim Fri Mar 17 01:11:58 2023 +0700 +++ b/src/semicongine/vulkan/pipeline.nim Mon Mar 20 10:25:50 2023 +0700 @@ -13,7 +13,7 @@ descriptorLayout: VkDescriptorSetLayout -proc createPipeline*(renderPass: RenderPass, vertexShader: Shader, fragmentShader: Shader): Pipeline = +proc createPipeline*[VertexShader: Shader, FragmentShader: Shader](renderPass: RenderPass, vertexShader: VertexShader, fragmentShader: FragmentShader): Pipeline = assert renderPass.vk.valid assert renderPass.device.vk.valid result.device = renderPass.device diff -r fb42da98c1aa -r 20837928dc63 src/semicongine/vulkan/shader.nim --- a/src/semicongine/vulkan/shader.nim Fri Mar 17 01:11:58 2023 +0700 +++ b/src/semicongine/vulkan/shader.nim Mon Mar 20 10:25:50 2023 +0700 @@ -7,104 +7,39 @@ import std/strutils import std/compilesettings +import ../math import ./api import ./device +import ./vertex +import ./glsl +import ./utils let logger = newConsoleLogger() addHandler(logger) type - Shader*[InputAttributes, Uniforms] = object + Shader*[Inputs, Uniforms, Outputs] = object device: Device vk*: VkShaderModule entrypoint*: string - inputs*: InputAttributes - uniforms*: Uniforms - binary*: seq[uint32] + -# produce ast for: static shader string, inputs, uniforms, entrypoint - -dumpAstGen: - block: - const test = 1 +proc compileGLSLToSPIRV*(stage: VkShaderStageFlagBits, shaderSource: string, entrypoint: string): seq[uint32] {.compileTime.} = -macro shader*(inputattributes: typed, uniforms: typed, device: Device, body: untyped): untyped = - var shadertype: NimNode - var entrypoint: NimNode - var version: NimNode - var code: NimNode - for node in body: - if node.kind == nnkCall and node[0].kind == nnkIdent and node[0].strVal == "shadertype": - expectKind(node[1], nnkStmtList) - expectKind(node[1][0], nnkIdent) - shadertype = node[1][0] - if node.kind == nnkCall and node[0].kind == nnkIdent and node[0].strVal == "entrypoint": - expectKind(node[1], nnkStmtList) - expectKind(node[1][0], nnkStrLit) - entrypoint = node[1][0] - if node.kind == nnkCall and node[0].kind == nnkIdent and node[0].strVal == "version": - expectKind(node[1], nnkStmtList) - expectKind(node[1][0], nnkIntLit) - version = node[1][0] - if node.kind == nnkCall and node[0].kind == nnkIdent and node[0].strVal == "code": - expectKind(node[1], nnkStmtList) - expectKind(node[1][0], {nnkStrLit, nnkTripleStrLit}) - code = node[1][0] - var shadercode: seq[string] - shadercode.add &"#version {version.intVal}" - shadercode.add &"""void {entrypoint.strVal}(){{ -{code} -}}""" - - return nnkBlockStmt.newTree( - newEmptyNode(), - nnkStmtList.newTree( - nnkConstSection.newTree( - nnkConstDef.newTree( - newIdentNode("shaderbinary"), - newEmptyNode(), - newCall("compileGLSLToSPIRV", shadertype, newStrLitNode(shadercode.join("\n")), entrypoint) - ) - ), - nnkObjConstr.newTree( - nnkBracketExpr.newTree( - newIdentNode("Shader"), - inputattributes, - uniforms, - ), - nnkExprColonExpr.newTree(newIdentNode("device"), device), - nnkExprColonExpr.newTree(newIdentNode("entrypoint"), entrypoint), - nnkExprColonExpr.newTree(newIdentNode("binary"), newIdentNode("shaderbinary")), + func stage2string(stage: VkShaderStageFlagBits): string {.compileTime.} = + case stage + of VK_SHADER_STAGE_VERTEX_BIT: "vert" + of VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: "tesc" + of VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: "tese" + of VK_SHADER_STAGE_GEOMETRY_BIT: "geom" + of VK_SHADER_STAGE_FRAGMENT_BIT: "frag" + of VK_SHADER_STAGE_COMPUTE_BIT: "comp" + else: "" - # vk*: VkShaderModule - # inputs*: InputAttributes - # uniforms*: Uniforms - ) - ) - ) - -proc staticExecChecked(command: string, input = ""): string {.compileTime.} = - let (output, exitcode) = gorgeEx( - command = command, - input = input) - if exitcode != 0: - raise newException(Exception, &"Running '{command}' produced exit code: {exitcode}" & output) - return output - -func stage2string(stage: VkShaderStageFlagBits): string {.compileTime.} = - case stage - of VK_SHADER_STAGE_VERTEX_BIT: "vert" - of VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: "tesc" - of VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: "tese" - of VK_SHADER_STAGE_GEOMETRY_BIT: "geom" - of VK_SHADER_STAGE_FRAGMENT_BIT: "frag" - of VK_SHADER_STAGE_COMPUTE_BIT: "comp" - else: "" - -proc compileGLSLToSPIRV*(stage: static VkShaderStageFlagBits, shaderSource: static string, entrypoint: static string): seq[uint32] {.compileTime.} = when defined(nimcheck): # will not run if nimcheck is running return result - const + + let stagename = stage2string(stage) shaderHash = hash(shaderSource) # cross compilation for windows workaround, sorry computer @@ -135,13 +70,35 @@ ) i += 4 -proc loadShaderCode*(device: Device, binary: var seq[uint32]): VkShaderModule = + +proc shaderCode*[Inputs, Uniforms, Outputs](shadertype: VkShaderStageFlagBits, version: int, entrypoint: string, body: seq[string]): seq[uint32] {.compileTime.} = + var code = @[&"#version {version}", ""] & + glslInput[Inputs]() & @[""] & + glslUniforms[Uniforms]() & @[""] & + glslOutput[Outputs]() & @[""] & + @[&"void {entrypoint}(){{"] & + body & + @[&"}}"] + compileGLSLToSPIRV(shadertype, code.join("\n"), entrypoint) + + +proc shaderCode*[Inputs, Uniforms, Outputs](shadertype: VkShaderStageFlagBits, version: int, entrypoint: string, body: string): seq[uint32] {.compileTime.} = + return shaderCode[Inputs, Uniforms, Outputs](shadertype, version, entrypoint, @[body]) + + +proc createShader*[Inputs, Uniforms, Outputs](device: Device, entrypoint: string, binary: seq[uint32]): Shader[Inputs, Uniforms, Outputs] = + assert device.vk.valid + assert len(binary) > 0 + + result.device = device + result.entrypoint = entrypoint + var bin = binary var createInfo = VkShaderModuleCreateInfo( sType: VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, - codeSize: uint(binary.len * sizeof(uint32)), - pCode: if binary.len > 0: addr(binary[0]) else: nil, + codeSize: uint(bin.len * sizeof(uint32)), + pCode: addr(bin[0]), ) - checkVkResult vkCreateShaderModule(device.vk, addr(createInfo), nil, addr(result)) + checkVkResult vkCreateShaderModule(device.vk, addr(createInfo), nil, addr(result.vk)) proc getPipelineInfo*(shader: Shader): VkPipelineShaderStageCreateInfo = VkPipelineShaderStageCreateInfo( @@ -156,3 +113,81 @@ assert shader.vk.valid shader.device.vk.vkDestroyShaderModule(shader.vk, nil) shader.vk.reset + + +func getVkFormat[T](value: T): VkFormat = + when T is uint8: VK_FORMAT_R8_UINT + elif T is int8: VK_FORMAT_R8_SINT + elif T is uint16: VK_FORMAT_R16_UINT + elif T is int16: VK_FORMAT_R16_SINT + elif T is uint32: VK_FORMAT_R32_UINT + elif T is int32: VK_FORMAT_R32_SINT + elif T is uint64: VK_FORMAT_R64_UINT + elif T is int64: VK_FORMAT_R64_SINT + elif T is float32: VK_FORMAT_R32_SFLOAT + elif T is float64: VK_FORMAT_R64_SFLOAT + elif T is TVec2[uint8]: VK_FORMAT_R8G8_UINT + elif T is TVec2[int8]: VK_FORMAT_R8G8_SINT + elif T is TVec2[uint16]: VK_FORMAT_R16G16_UINT + elif T is TVec2[int16]: VK_FORMAT_R16G16_SINT + elif T is TVec2[uint32]: VK_FORMAT_R32G32_UINT + elif T is TVec2[int32]: VK_FORMAT_R32G32_SINT + elif T is TVec2[uint64]: VK_FORMAT_R64G64_UINT + elif T is TVec2[int64]: VK_FORMAT_R64G64_SINT + elif T is TVec2[float32]: VK_FORMAT_R32G32_SFLOAT + elif T is TVec2[float64]: VK_FORMAT_R64G64_SFLOAT + elif T is TVec3[uint8]: VK_FORMAT_R8G8B8_UINT + elif T is TVec3[int8]: VK_FORMAT_R8G8B8_SINT + elif T is TVec3[uint16]: VK_FORMAT_R16G16B16_UINT + elif T is TVec3[int16]: VK_FORMAT_R16G16B16_SINT + elif T is TVec3[uint32]: VK_FORMAT_R32G32B32_UINT + elif T is TVec3[int32]: VK_FORMAT_R32G32B32_SINT + elif T is TVec3[uint64]: VK_FORMAT_R64G64B64_UINT + elif T is TVec3[int64]: VK_FORMAT_R64G64B64_SINT + elif T is TVec3[float32]: VK_FORMAT_R32G32B32_SFLOAT + elif T is TVec3[float64]: VK_FORMAT_R64G64B64_SFLOAT + elif T is TVec4[uint8]: VK_FORMAT_R8G8B8A8_UINT + elif T is TVec4[int8]: VK_FORMAT_R8G8B8A8_SINT + elif T is TVec4[uint16]: VK_FORMAT_R16G16B16A16_UINT + elif T is TVec4[int16]: VK_FORMAT_R16G16B16A16_SINT + elif T is TVec4[uint32]: VK_FORMAT_R32G32B32A32_UINT + elif T is TVec4[int32]: VK_FORMAT_R32G32B32A32_SINT + elif T is TVec4[uint64]: VK_FORMAT_R64G64B64A64_UINT + elif T is TVec4[int64]: VK_FORMAT_R64G64B64A64_SINT + elif T is TVec4[float32]: VK_FORMAT_R32G32B32A32_SFLOAT + elif T is TVec4[float64]: VK_FORMAT_R64G64B64A64_SFLOAT + else: {.error: "Unsupported vertex attribute type".} + + +proc getVertexInputInfo*[Input, Uniforms, Output]( + shader: Shader[Input, Uniforms, Output], + bindings: var seq[VkVertexInputBindingDescription], + attributes: var seq[VkVertexInputAttributeDescription], +): VkPipelineVertexInputStateCreateInfo = + var location = 0'u32 + var binding = 0'u32 + + for name, value in default(Input).fieldPairs: + bindings.add VkVertexInputBindingDescription( + binding: binding, + stride: uint32(sizeof(value)), + inputRate: if value.hasCustomPragma(PerInstance): VK_VERTEX_INPUT_RATE_INSTANCE else: VK_VERTEX_INPUT_RATE_VERTEX, + ) + # allows to submit larger data structures like Mat44, for most other types will be 1 + for i in 0 ..< compositeAttributesNumber(value): + attributes.add VkVertexInputAttributeDescription( + binding: binding, + location: location, + format: getVkFormat(compositeAttribute(value)), + offset: uint32(i * sizeof(compositeAttribute(value))), + ) + location += nLocationSlots(compositeAttribute(value)) + inc binding + + return VkPipelineVertexInputStateCreateInfo( + sType: VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + vertexBindingDescriptionCount: uint32(bindings.len), + pVertexBindingDescriptions: bindings.toCPointer, + vertexAttributeDescriptionCount: uint32(attributes.len), + pVertexAttributeDescriptions: attributes.toCPointer, + ) diff -r fb42da98c1aa -r 20837928dc63 src/semicongine/vulkan/utils.nim --- a/src/semicongine/vulkan/utils.nim Fri Mar 17 01:11:58 2023 +0700 +++ b/src/semicongine/vulkan/utils.nim Mon Mar 20 10:25:50 2023 +0700 @@ -1,4 +1,6 @@ import std/strutils +import std/os +import std/strformat func cleanString*(str: openArray[char]): string = for i in 0 ..< len(str): @@ -8,3 +10,13 @@ func toCPointer*[T](list: var seq[T]): ptr T = if list.len > 0: addr list[0] else: nil + +proc staticExecChecked*(command: string, input = ""): string {.compileTime.} = + let (output, exitcode) = gorgeEx( + command = command, + input = input) + if exitcode != 0: + raise newException(Exception, &"Running '{command}' produced exit code: {exitcode}" & output) + return output + + diff -r fb42da98c1aa -r 20837928dc63 src/semicongine/vulkan/vertex.nim --- a/src/semicongine/vulkan/vertex.nim Fri Mar 17 01:11:58 2023 +0700 +++ b/src/semicongine/vulkan/vertex.nim Mon Mar 20 10:25:50 2023 +0700 @@ -3,112 +3,8 @@ import ../math import ./api -import ./utils -import ./shader # add pragma to fields of the VertexType that represent per instance attributes template PerInstance*() {.pragma.} -# from https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap15.html -func nLocationSlots[T](value: T): uint32 = - when (T is TVec3[float64] or T is TVec3[uint64] or T is TVec4[float64] or T is TVec4[float64]): - return 2 - elif T is SomeNumber or T is TVec: - return 1 - else: - raise newException(Exception, "Unsupported vertex attribute type") - -# return the type into which larger types are divided -func compositeAttribute[T](value: T): auto = - when T is TMat33[float32]: - Vec3() - elif T is TMat44[float32]: - Vec4() - else: - value - -# return the number of elements into which larger types are divided -func compositeAttributesNumber[T](value: T): int = - when T is TMat33[float32]: - 3 - elif T is TMat44[float32]: - 4 - else: - 1 - -func getVkFormat[T](value: T): VkFormat = - when T is uint8: VK_FORMAT_R8_UINT - elif T is int8: VK_FORMAT_R8_SINT - elif T is uint16: VK_FORMAT_R16_UINT - elif T is int16: VK_FORMAT_R16_SINT - elif T is uint32: VK_FORMAT_R32_UINT - elif T is int32: VK_FORMAT_R32_SINT - elif T is uint64: VK_FORMAT_R64_UINT - elif T is int64: VK_FORMAT_R64_SINT - elif T is float32: VK_FORMAT_R32_SFLOAT - elif T is float64: VK_FORMAT_R64_SFLOAT - elif T is TVec2[uint8]: VK_FORMAT_R8G8_UINT - elif T is TVec2[int8]: VK_FORMAT_R8G8_SINT - elif T is TVec2[uint16]: VK_FORMAT_R16G16_UINT - elif T is TVec2[int16]: VK_FORMAT_R16G16_SINT - elif T is TVec2[uint32]: VK_FORMAT_R32G32_UINT - elif T is TVec2[int32]: VK_FORMAT_R32G32_SINT - elif T is TVec2[uint64]: VK_FORMAT_R64G64_UINT - elif T is TVec2[int64]: VK_FORMAT_R64G64_SINT - elif T is TVec2[float32]: VK_FORMAT_R32G32_SFLOAT - elif T is TVec2[float64]: VK_FORMAT_R64G64_SFLOAT - elif T is TVec3[uint8]: VK_FORMAT_R8G8B8_UINT - elif T is TVec3[int8]: VK_FORMAT_R8G8B8_SINT - elif T is TVec3[uint16]: VK_FORMAT_R16G16B16_UINT - elif T is TVec3[int16]: VK_FORMAT_R16G16B16_SINT - elif T is TVec3[uint32]: VK_FORMAT_R32G32B32_UINT - elif T is TVec3[int32]: VK_FORMAT_R32G32B32_SINT - elif T is TVec3[uint64]: VK_FORMAT_R64G64B64_UINT - elif T is TVec3[int64]: VK_FORMAT_R64G64B64_SINT - elif T is TVec3[float32]: VK_FORMAT_R32G32B32_SFLOAT - elif T is TVec3[float64]: VK_FORMAT_R64G64B64_SFLOAT - elif T is TVec4[uint8]: VK_FORMAT_R8G8B8A8_UINT - elif T is TVec4[int8]: VK_FORMAT_R8G8B8A8_SINT - elif T is TVec4[uint16]: VK_FORMAT_R16G16B16A16_UINT - elif T is TVec4[int16]: VK_FORMAT_R16G16B16A16_SINT - elif T is TVec4[uint32]: VK_FORMAT_R32G32B32A32_UINT - elif T is TVec4[int32]: VK_FORMAT_R32G32B32A32_SINT - elif T is TVec4[uint64]: VK_FORMAT_R64G64B64A64_UINT - elif T is TVec4[int64]: VK_FORMAT_R64G64B64A64_SINT - elif T is TVec4[float32]: VK_FORMAT_R32G32B32A32_SFLOAT - elif T is TVec4[float64]: VK_FORMAT_R64G64B64A64_SFLOAT - else: {.error: "Unsupported vertex attribute type".} - -proc getVertexInputInfo*( - shader: Shader, - bindings: var seq[VkVertexInputBindingDescription], - attributes: var seq[VkVertexInputAttributeDescription], -): VkPipelineVertexInputStateCreateInfo = - var location = 0'u32 - var binding = 0'u32 - - for name, value in shader.inputs.fieldPairs: - bindings.add VkVertexInputBindingDescription( - binding: binding, - stride: uint32(sizeof(value)), - inputRate: if value.hasCustomPragma(PerInstance): VK_VERTEX_INPUT_RATE_INSTANCE else: VK_VERTEX_INPUT_RATE_VERTEX, - ) - # allows to submit larger data structures like Mat44, for most other types will be 1 - for i in 0 ..< compositeAttributesNumber(value): - attributes.add VkVertexInputAttributeDescription( - binding: binding, - location: location, - format: getVkFormat(compositeAttribute(value)), - offset: uint32(i * sizeof(compositeAttribute(value))), - ) - location += nLocationSlots(compositeAttribute(value)) - inc binding - - return VkPipelineVertexInputStateCreateInfo( - sType: VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - vertexBindingDescriptionCount: uint32(bindings.len), - pVertexBindingDescriptions: bindings.toCPointer, - vertexAttributeDescriptionCount: uint32(attributes.len), - pVertexAttributeDescriptions: attributes.toCPointer, - ) diff -r fb42da98c1aa -r 20837928dc63 tests/test_vulkan_wrapper.nim --- a/tests/test_vulkan_wrapper.nim Fri Mar 17 01:11:58 2023 +0700 +++ b/tests/test_vulkan_wrapper.nim Mon Mar 20 10:25:50 2023 +0700 @@ -7,8 +7,12 @@ type Vertex = object pos: Vec3 + FragmentInput = object + fragpos: Vec3 Uniforms = object time: float32 + Pixel = object + color: Vec4 when isMainModule: @@ -76,20 +80,12 @@ renderFinished = device.createSemaphore() inflight = device.createFence() - var vertexshader = shader(Vertex, Uniforms, device): - shadertype: VK_SHADER_STAGE_VERTEX_BIT - entrypoint: "main" - version: 450 - code: """""" - var fragmentshader = shader(Vertex, Uniforms, device): - shadertype: VK_SHADER_STAGE_FRAGMENT_BIT - entrypoint: "main" - version: 450 - code: "" + const vertexBinary = shaderCode[Vertex, Uniforms, FragmentInput](shadertype=VK_SHADER_STAGE_VERTEX_BIT, version=450, entrypoint="main", "fragpos = pos;") + const fragmentBinary = shaderCode[FragmentInput, void, Pixel](shadertype=VK_SHADER_STAGE_FRAGMENT_BIT, version=450, entrypoint="main", "color = vec4(1, 1, 1, 0);") + var vertexshader = createShader[Vertex, Uniforms, FragmentInput](device, "main", vertexBinary) + var fragmentshader = createShader[FragmentInput, void, Pixel](device, "main", fragmentBinary) - #var vertexshader = loadShaderCode[Vertex, Uniforms](device, vertexshadercode) - #var fragmentshader = loadShaderCode[Vertex, Uniforms](device, fragmentshadercode) - #var pipeline = renderpass.createPipeline(vertexshaderhandle, fragmentshaderhandle) + var pipeline = renderpass.createPipeline(vertexshader, fragmentshader) echo "All successfull" echo "Start cleanup" @@ -98,6 +94,8 @@ #pipeline.destroy() #vertexshader.destroy() #fragmentshader.destroy() + vertexshader.destroy() + fragmentshader.destroy() inflight.destroy() imageAvailable.destroy() renderFinished.destroy()