comparison static_utils.nim @ 1162:46fae89cffb0 compiletime-tests

advance evenmore!
author sam <sam@basx.dev>
date Thu, 20 Jun 2024 09:37:44 +0700
parents dbca0528c714
children 438d32d8b14f
comparison
equal deleted inserted replaced
1161:dbca0528c714 1162:46fae89cffb0
1 import std/os
1 import std/macros 2 import std/macros
2 import std/strformat 3 import std/strformat
3 import std/typetraits 4 import std/typetraits as tt
4 5
5 import semicongine/core/utils 6 import semicongine/core/utils
6 import semicongine/core/imagetypes 7 import semicongine/core/imagetypes
7 import semicongine/core/vector 8 import semicongine/core/vector
8 import semicongine/core/matrix 9 import semicongine/core/matrix
9 import semicongine/core/vulkanapi 10 import semicongine/core/vulkanapi
10 import semicongine/vulkan/buffer 11 import semicongine/vulkan/buffer
11 12
12 template VertexAttribute* {.pragma.} 13 template VertexAttribute* {.pragma.}
13 template InstanceAttribute* {.pragma.} 14 template InstanceAttribute* {.pragma.}
14 template DescriptorAttribute* {.pragma.} 15 template Descriptor* {.pragma.}
15 16 template Pass* {.pragma.}
17 template PassFlat* {.pragma.}
18 template ShaderOutput* {.pragma.}
16 19
17 type 20 type
18 SupportedGPUType* = float32 | float64 | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64 | TVec2[int32] | TVec2[int64] | TVec3[int32] | TVec3[int64] | TVec4[int32] | TVec4[int64] | TVec2[uint32] | TVec2[uint64] | TVec3[uint32] | TVec3[uint64] | TVec4[uint32] | TVec4[uint64] | TVec2[float32] | TVec2[float64] | TVec3[float32] | TVec3[float64] | TVec4[float32] | TVec4[float64] | TMat2[float32] | TMat2[float64] | TMat23[float32] | TMat23[float64] | TMat32[float32] | TMat32[float64] | TMat3[float32] | TMat3[float64] | TMat34[float32] | TMat34[float64] | TMat43[float32] | TMat43[float64] | TMat4[float32] | TMat4[float64] 21 SupportedGPUType* = float32 | float64 | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64 | TVec2[int32] | TVec2[int64] | TVec3[int32] | TVec3[int64] | TVec4[int32] | TVec4[int64] | TVec2[uint32] | TVec2[uint64] | TVec3[uint32] | TVec3[uint64] | TVec4[uint32] | TVec4[uint64] | TVec2[float32] | TVec2[float64] | TVec3[float32] | TVec3[float64] | TVec4[float32] | TVec4[float64] | TMat2[float32] | TMat2[float64] | TMat23[float32] | TMat23[float64] | TMat32[float32] | TMat32[float64] | TMat3[float32] | TMat3[float64] | TMat34[float32] | TMat34[float64] | TMat43[float32] | TMat43[float64] | TMat4[float32] | TMat4[float64]
19 22
20 func VkType[T: SupportedGPUType](value: T): VkFormat = 23 func VkType[T: SupportedGPUType](value: T): VkFormat =
44 elif T is TVec2[float64]: VK_FORMAT_R64G64_SFLOAT 47 elif T is TVec2[float64]: VK_FORMAT_R64G64_SFLOAT
45 elif T is TVec3[float32]: VK_FORMAT_R32G32B32_SFLOAT 48 elif T is TVec3[float32]: VK_FORMAT_R32G32B32_SFLOAT
46 elif T is TVec3[float64]: VK_FORMAT_R64G64B64_SFLOAT 49 elif T is TVec3[float64]: VK_FORMAT_R64G64B64_SFLOAT
47 elif T is TVec4[float32]: VK_FORMAT_R32G32B32A32_SFLOAT 50 elif T is TVec4[float32]: VK_FORMAT_R32G32B32A32_SFLOAT
48 elif T is TVec4[float64]: VK_FORMAT_R64G64B64A64_SFLOAT 51 elif T is TVec4[float64]: VK_FORMAT_R64G64B64A64_SFLOAT
49 elif T is Mat2[float32]: VK_FORMAT_R32G32_SFLOAT 52 elif T is TMat2[float32]: VK_FORMAT_R32G32_SFLOAT
50 elif T is Mat2[float64]: VK_FORMAT_R64G64_SFLOAT 53 elif T is TMat2[float64]: VK_FORMAT_R64G64_SFLOAT
51 elif T is Mat23[float32]: VK_FORMAT_R32G32B32_SFLOAT 54 elif T is TMat23[float32]: VK_FORMAT_R32G32B32_SFLOAT
52 elif T is Mat23[float64]: VK_FORMAT_R64G64B64_SFLOAT 55 elif T is TMat23[float64]: VK_FORMAT_R64G64B64_SFLOAT
53 elif T is Mat32[float32]: VK_FORMAT_R32G32_SFLOAT 56 elif T is TMat32[float32]: VK_FORMAT_R32G32_SFLOAT
54 elif T is Mat32[float64]: VK_FORMAT_R64G64_SFLOAT 57 elif T is TMat32[float64]: VK_FORMAT_R64G64_SFLOAT
55 elif T is Mat3[float32]: VK_FORMAT_R32G32B32_SFLOAT 58 elif T is TMat3[float32]: VK_FORMAT_R32G32B32_SFLOAT
56 elif T is Mat3[float64]: VK_FORMAT_R64G64B64_SFLOAT 59 elif T is TMat3[float64]: VK_FORMAT_R64G64B64_SFLOAT
57 elif T is Mat34[float32]: VK_FORMAT_R32G32B32A32_SFLOAT 60 elif T is TMat34[float32]: VK_FORMAT_R32G32B32A32_SFLOAT
58 elif T is Mat34[float64]: VK_FORMAT_R64G64B64A64_SFLOAT 61 elif T is TMat34[float64]: VK_FORMAT_R64G64B64A64_SFLOAT
59 elif T is Mat43[float32]: VK_FORMAT_R32G32B32_SFLOAT 62 elif T is TMat43[float32]: VK_FORMAT_R32G32B32_SFLOAT
60 elif T is Mat43[float64]: VK_FORMAT_R64G64B64_SFLOAT 63 elif T is TMat43[float64]: VK_FORMAT_R64G64B64_SFLOAT
61 elif T is Mat4[float32]: VK_FORMAT_R32G32B32A32_SFLOAT 64 elif T is TMat4[float32]: VK_FORMAT_R32G32B32A32_SFLOAT
62 elif T is Mat4[float64]: VK_FORMAT_R64G64B64A64_SFLOAT 65 elif T is TMat4[float64]: VK_FORMAT_R64G64B64A64_SFLOAT
66 else: {.error: "Unsupported data type on GPU".}
67
68 func GlslType[T: SupportedGPUType](value: T): string =
69 when T is float32: "float"
70 elif T is float64: "double"
71 elif T is int8, int16, int32, int64: "int"
72 elif T is uint8, uint16, uint32, uint64: "uint"
73 elif T is TVec2[int32]: "ivec2"
74 elif T is TVec2[int64]: "ivec2"
75 elif T is TVec3[int32]: "ivec3"
76 elif T is TVec3[int64]: "ivec3"
77 elif T is TVec4[int32]: "ivec4"
78 elif T is TVec4[int64]: "ivec4"
79 elif T is TVec2[uint32]: "uvec2"
80 elif T is TVec2[uint64]: "uvec2"
81 elif T is TVec3[uint32]: "uvec3"
82 elif T is TVec3[uint64]: "uvec3"
83 elif T is TVec4[uint32]: "uvec4"
84 elif T is TVec4[uint64]: "uvec4"
85 elif T is TVec2[float32]: "vec2"
86 elif T is TVec2[float64]: "dvec2"
87 elif T is TVec3[float32]: "vec3"
88 elif T is TVec3[float64]: "dvec3"
89 elif T is TVec4[float32]: "vec4"
90 elif T is TVec4[float64]: "dvec4"
91 elif T is TMat2[float32]: "mat2"
92 elif T is TMat2[float64]: "dmat2"
93 elif T is TMat23F32]: "mat23"
94 elif T is TMat23[float64]: "dmat23"
95 elif T is TMat32[float32]: "mat32"
96 elif T is TMat32[float64]: "dmat32"
97 elif T is TMat3[float32]: "mat3"
98 elif T is TMat3[float64]: "dmat3"
99 elif T is TMat34[float32]: "mat34"
100 elif T is TMat34[float64]: "dmat34"
101 elif T is TMat43[float32]: "mat43"
102 elif T is TMat43[float64]: "dmat43"
103 elif T is TMat4[float32]: "mat4"
104 elif T is TMat4[float64]: "dmat4"
105 elif T is Texture: "sampler2D"
63 else: {.error: "Unsupported data type on GPU".} 106 else: {.error: "Unsupported data type on GPU".}
64 107
65 template getElementType(field: typed): untyped = 108 template getElementType(field: typed): untyped =
66 when not (typeof(field) is seq or typeof(field) is array): 109 when not (typeof(field) is seq or typeof(field) is array):
67 {.error: "getElementType can only be used with seq or array".} 110 typeof(field)
68 genericParams(typeof(field)).get(0) 111 # {.error: "getElementType can only be used with seq or array".}
112 else:
113 genericParams(typeof(field)).get(0)
69 114
70 template ForVertexDataFields*(inputData: typed, fieldname, valuename, isinstancename, body: untyped): untyped = 115 template ForVertexDataFields*(inputData: typed, fieldname, valuename, isinstancename, body: untyped): untyped =
71 for theFieldname, value in fieldPairs(inputData): 116 for theFieldname, value in fieldPairs(inputData):
72 when hasCustomPragma(value, VertexAttribute) or hasCustomPragma(value, InstanceAttribute): 117 when hasCustomPragma(value, VertexAttribute) or hasCustomPragma(value, InstanceAttribute):
73 when not typeof(value) is seq: 118 when not typeof(value) is seq:
74 {.error: "field '" & theFieldname & "' needs to be a seq".} 119 {.error: "field '" & theFieldname & "' needs to be a seq".}
75 when not typeof(value) is SupportedGPUType: 120 when not typeof(value) is SupportedGPUType:
76 {.error: "field '" & theFieldname & "' is not a supported GPU type".} 121 {.error: "field '" & theFieldname & "' is not a supported GPU type".}
77 block: 122 block:
78 let `fieldname` {.inject.} = theFieldname 123 let `fieldname` {.inject.} = theFieldname
79 let `valuename` {.inject.} = default(getElementType(value)) 124 let `valuename` {.inject.} = value
80 let `isinstancename` {.inject.} = value.isInstanceAttribute() 125 let `isinstancename` {.inject.} = hasCustomPragma(value, InstanceAttribute)
81 body 126 body
82 127
83 template ForDescriptorFields*(inputData: typed, fieldname, valuename, typename, countname, body: untyped): untyped = 128 template ForDescriptorFields*(inputData: typed, fieldname, valuename, typename, countname, body: untyped): untyped =
84 for theFieldname, value in fieldPairs(inputData): 129 for theFieldname, value in fieldPairs(inputData):
85 when hasCustomPragma(value, DescriptorAttribute): 130 when hasCustomPragma(value, Descriptor):
86 when not ( 131 when not (
87 typeof(value) is SupportedGPUType 132 typeof(value) is SupportedGPUType or
88 or (typeof(value) is array and elementType(value) is SupportedGPUType) 133 typeof(value) is Texture or
89 or typeof(value) is Texture 134 (typeof(value) is array and getElementType(value) is SupportedGPUType)
90 ): 135 ):
91 {.error: "field '" & theFieldname & "' needs to be a SupportedGPUType or an array of SupportedGPUType".} 136 {.error: "field '" & theFieldname & "' needs to be a SupportedGPUType or an array of SupportedGPUType or a Texture".}
92 block: 137 block:
93 let `fieldname` {.inject.} = theFieldname 138 let `fieldname` {.inject.} = theFieldname
94 let `valuename` {.inject.} = default(getElementType(value)) 139 let `valuename` {.inject.} = default(getElementType(value))
95 140
96 # TODO 141 when typeof(value) is Texture or (typeof(value) is array and getElementType(value) is Texture):
97 let `typename` {.inject.} = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER 142 let `typename` {.inject.} = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
98 let `typename` {.inject.} = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
99
100 when typeof(value) is array:
101 let `countname` {.inject.} = genericParams(typeof(value)).get(0)
102 else: 143 else:
103 let `countname` {.inject.} = 1 144 let `typename` {.inject.} = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
145
146 when typeof(value) is SupportedGPUType or typeof(value) is Texture:
147 let `countname` {.inject.} = 1'u32
148 else:
149 assert typeof(value) is array
150 let `countname` {.inject.} = uint32(genericParams(typeof(value)).get(0))
104 body 151 body
105 152
106 func NumberOfVertexInputAttributeDescriptors[T: SupportedGPUType](value: T): uint32 = 153 func NumberOfVertexInputAttributeDescriptors[T: SupportedGPUType](value: T): uint32 =
107 when T is TMat2[float32] or T is TMat2[float64] or T is TMat23[float32] or T is TMat23[float64]: 154 when T is TMat2[float32] or T is TMat2[float64] or T is TMat23[float32] or T is TMat23[float64]:
108 2 155 2
111 elif T is TMat43[float32] or T is TMat43[float64] or T is TMat4[float32] or T is TMat4[float64]: 158 elif T is TMat43[float32] or T is TMat43[float64] or T is TMat4[float32] or T is TMat4[float64]:
112 4 159 4
113 else: 160 else:
114 1 161 1
115 162
116 func NLocationSlots[T: SupportedGPUType](value: T): uint32 = 163 func NLocationSlots[T: SupportedGPUType|Texture](value: T): uint32 =
117 #[ 164 #[
118 single location: 165 single location:
166 - any scalar
167 - any 16-bit vector
168 - any 32-bit vector
169 - any 64-bit vector that has max. 2 components
119 16-bit scalar and vector types, and 170 16-bit scalar and vector types, and
120 32-bit scalar and vector types, and 171 32-bit scalar and vector types, and
121 64-bit scalar and 2-component vector types. 172 64-bit scalar and 2-component vector types.
122 two locations 173 two locations
123 64-bit three- and four-component vectors 174 64-bit three- and four-component vectors
124 ]# 175 ]#
125 when typeof(value) is TVec3 and sizeof(getElementType(value)) == 8: 176 when T is TVec3[int64] or
126 return 2 177 T is TVec4[int64] or
127 elif typeof(value) is TVec4 and sizeof(getElementType(value)) == 8: 178 T is TVec3[uint64] or
179 T is TVec4[uint64] or
180 T is TVec3[float64] or
181 T is TVec4[float64] or
182 T is TMat23[float64] or
183 T is TMat3[float64] or
184 T is TMat34[float64] or
185 T is TMat43[float64] or
186 T is TMat4[float64]:
128 return 2 187 return 2
129 else: 188 else:
130 return 1 189 return 1
131 190
132 type 191 type
144 vertexCount: uint32 203 vertexCount: uint32
145 else: 204 else:
146 indexBuffer: VkBuffer 205 indexBuffer: VkBuffer
147 indexCount: uint32 206 indexCount: uint32
148 indexBufferOffset: VkDeviceSize 207 indexBufferOffset: VkDeviceSize
149 Pipeline[TShaderInputs] = object 208 Pipeline[TShader] = object
150 pipeline: VkPipeline 209 pipeline: VkPipeline
151 layout: VkPipelineLayout 210 layout: VkPipelineLayout
152 descriptorSets: array[2, seq[VkDescriptorSet]] 211 descriptorSets: array[2, seq[VkDescriptorSet]]
153 ShaderSet[TShaderInputs] = object 212
154 vertexShader: VkShaderModule
155 fragmentShader: VkShaderModule
156 converter toVkIndexType(indexType: IndexType): VkIndexType = 213 converter toVkIndexType(indexType: IndexType): VkIndexType =
157 case indexType: 214 case indexType:
158 of None: VK_INDEX_TYPE_NONE_KHR 215 of None: VK_INDEX_TYPE_NONE_KHR
159 of UInt8: VK_INDEX_TYPE_UINT8_EXT 216 of UInt8: VK_INDEX_TYPE_UINT8_EXT
160 of UInt16: VK_INDEX_TYPE_UINT16 217 of UInt16: VK_INDEX_TYPE_UINT16
161 of UInt32: VK_INDEX_TYPE_UINT32 218 of UInt32: VK_INDEX_TYPE_UINT32
162 219
163 220 proc compileGlslToSPIRV(stage: VkShaderStageFlagBits, shaderSource: string): seq[uint32] {.compileTime.} =
164 proc CreatePipeline*[TShaderInputs]( 221 func stage2string(stage: VkShaderStageFlagBits): string {.compileTime.} =
222 case stage
223 of VK_SHADER_STAGE_VERTEX_BIT: "vert"
224 of VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: "tesc"
225 of VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: "tese"
226 of VK_SHADER_STAGE_GEOMETRY_BIT: "geom"
227 of VK_SHADER_STAGE_FRAGMENT_BIT: "frag"
228 of VK_SHADER_STAGE_COMPUTE_BIT: "comp"
229 else: ""
230
231 when defined(nimcheck): # will not run if nimcheck is running
232 return result
233
234 let
235 stagename = stage2string(stage)
236 shaderHash = hash(shaderSource)
237 shaderfile = getTempDir() / &"shader_{shaderHash}.{stagename}"
238
239
240 if not shaderfile.fileExists:
241 echo "shader of type ", stage, ", entrypoint ", entrypoint
242 for i, line in enumerate(shaderSource.splitlines()):
243 echo " ", i + 1, " ", line
244 var glslExe = currentSourcePath.parentDir.parentDir.parentDir / "tools" / "glslangValidator"
245 when defined(windows):
246 glslExe = glslExe & "." & ExeExt
247 let command = &"{glslExe} --entry-point {entrypoint} -V --stdin -S {stagename} -o {shaderfile}"
248 echo "run: ", command
249 discard StaticExecChecked(
250 command = command,
251 input = shaderSource
252 )
253 else:
254 echo &"shaderfile {shaderfile} is up-to-date"
255
256 when defined(mingw) and defined(linux): # required for crosscompilation, path separators get messed up
257 let shaderbinary = staticRead shaderfile.replace("\\", "/")
258 else:
259 let shaderbinary = staticRead shaderfile
260
261 var i = 0
262 while i < shaderbinary.len:
263 result.add(
264 (uint32(shaderbinary[i + 0]) shl 0) or
265 (uint32(shaderbinary[i + 1]) shl 8) or
266 (uint32(shaderbinary[i + 2]) shl 16) or
267 (uint32(shaderbinary[i + 3]) shl 24)
268 )
269 i += 4
270
271 proc generateShaderSource[TShader](shader: TShader): (string, string) {.compileTime.} =
272 const GLSL_VERSION = "450"
273 var vsInput: seq[string]
274 var vsOutput: seq[string]
275 var fsInput: seq[string]
276 var fsOutput: seq[string]
277 var uniforms: seq[string]
278 var samplers: seq[string]
279 var vsInputLocation = 0
280 var passLocation = 0
281 var fsOutputLocation = 0
282 var binding = 0
283
284 for fieldname, value in fieldPairs(shader):
285 # vertex shader inputs
286 if hasCustomPragma(value, VertexAttribute) or hasCustomPragma(value, InstanceAttribute):
287 assert typeof(value) is SupportedGPUType
288 vsInput.add &"layout(location = {vsInputLocation}) in {GlslType(value)} {fieldname};"
289 for j in 0 ..< NumberOfVertexInputAttributeDescriptors(value):
290 vsInputLocation += NLocationSlots(value)
291 # intermediate values, passed between shaders
292 if hasCustomPragma(value, Pass) or hasCustomPragma(value, PassFlat):
293 let flat = if hasCustomPragma(value, PassFlat): "flat " else ""
294 vsOutput.add &"layout(location = {passLocation}) {flat}out {GlslType(value)} {fieldname};"
295 fsInput.add &"layout(location = {passLocation}) {flat}in {GlslType(value)} {fieldname};"
296 passLocation.inc
297 if hasCustomPragma(value, ShaderOutput):
298 fsOutput.add &"layout(location = {fsOutputLocation}) out {GlslType(value)} {fieldname};"
299 fsOutputLocation.inc
300 if hasCustomPragma(value, Descriptor):
301 # TODO; samplers and uniforms
302 if typeof(value) is Texture:
303 else:
304
305 result[0] = (@[&"#version {GLSL_VERSION}", "#extension GL_EXT_scalar_block_layout : require", ""] &
306 vsInput &
307 uniforms &
308 samplers &
309 vsOutput &
310 @[shader.vertexCode]).join("\n")
311
312 result[1] = (@[&"#version {GLSL_VERSION}", "#extension GL_EXT_scalar_block_layout : require", ""] &
313 fsInput &
314 uniforms &
315 samplers &
316 fsOutput &
317 @[shader.fragmentCode]).join("\n")
318
319 proc CompileShader[TShader](shader: TShader): (seq[uint32], seq[uint32]) {.compileTime.} =
320 let (vertexShaderSource, fragmentShaderSource) = generateShaderSource(shader)
321 (
322 compileGlslToSPIRV(VK_SHADER_STAGE_VERTEX_BIT, vertexShaderSource),
323 compileGlslToSPIRV(VK_SHADER_STAGE_FRAGMENT_BIT, fragmentShaderSource)
324 )
325
326
327 proc CreatePipeline*[TShader](
165 device: VkDevice, 328 device: VkDevice,
166 renderPass: VkRenderPass, 329 renderPass: VkRenderPass,
167 shaderSet: ShaderSet[TShaderInputs], 330 vertexShader: VkShaderModule,
331 fragmentShader: VkShaderModule,
168 topology: VkPrimitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 332 topology: VkPrimitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
169 polygonMode: VkPolygonMode = VK_POLYGON_MODE_FILL, 333 polygonMode: VkPolygonMode = VK_POLYGON_MODE_FILL,
170 cullMode: VkCullModeFlagBits = VK_CULL_MODE_BACK_BIT, 334 cullMode: VkCullModeFlagBits = VK_CULL_MODE_BACK_BIT,
171 frontFace: VkFrontFace = VK_FRONT_FACE_CLOCKWISE, 335 frontFace: VkFrontFace = VK_FRONT_FACE_CLOCKWISE,
172 ): Pipeline[TShaderInputs] = 336 ): Pipeline[TShader] =
173 # assumptions/limitations: 337 # assumptions/limitations:
174 # - we are only using vertex and fragment shaders (2 stages) 338 # - we are only using vertex and fragment shaders (2 stages)
175 # - we only support one subpass 339 # - we only support one subpass
176 340 # = we only support one Uniform-Block
177 # CONTINUE HERE, WITH PIPELINE LAYOUT!!!!
178 # Rely on TShaderInputs
179 341
180 var layoutbindings: seq[VkDescriptorSetLayoutBinding] 342 var layoutbindings: seq[VkDescriptorSetLayoutBinding]
181 let descriptors = [
182 (VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1), # more than 1 for arrays
183 (VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1),
184 ]
185 var descriptorBindingNumber = 0'u32 343 var descriptorBindingNumber = 0'u32
186 ForDescriptorFields(default(TShaderInputs), fieldname, value, descriptorCount): 344 ForDescriptorFields(default(TShader), fieldname, value, descriptorType, descriptorCount):
345 # TODO: Only one binding needed for a Uniforms block
187 layoutbindings.add VkDescriptorSetLayoutBinding( 346 layoutbindings.add VkDescriptorSetLayoutBinding(
188 binding: descriptorBindingNumber, 347 binding: descriptorBindingNumber,
189 descriptorType: descriptorType, 348 descriptorType: descriptorType,
190 descriptorCount: descriptorCount, 349 descriptorCount: descriptorCount,
191 stageFlags: VK_SHADER_STAGE_ALL_GRAPHICS, 350 stageFlags: VkShaderStageFlags(VK_SHADER_STAGE_ALL_GRAPHICS),
192 pImmutableSamplers: nil, 351 pImmutableSamplers: nil,
193 ) 352 )
194 inc descriptorBindingNumber 353 inc descriptorBindingNumber
195 var layoutCreateInfo = VkDescriptorSetLayoutCreateInfo( 354 var layoutCreateInfo = VkDescriptorSetLayoutCreateInfo(
196 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, 355 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
197 bindingCount: uint32(layoutbindings.len), 356 bindingCount: uint32(layoutbindings.len),
198 pBindings: layoutbindings.ToCPointer 357 pBindings: layoutbindings.ToCPointer
199 ) 358 )
200 var descriptorSetLayout: VkDescriptorSetLayout 359 var descriptorSetLayout: VkDescriptorSetLayout
201 checkVkResult vkCreateDescriptorSetLayout(device.vk, addr(layoutCreateInfo), nil, addr(descriptorSetLayout)) 360 checkVkResult vkCreateDescriptorSetLayout(device, addr(layoutCreateInfo), nil, addr(descriptorSetLayout))
202 let pipelineLayoutInfo = VkPipelineLayoutCreateInfo( 361 let pipelineLayoutInfo = VkPipelineLayoutCreateInfo(
203 sType: VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 362 sType: VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
204 setLayoutCount: 1, 363 setLayoutCount: 1,
205 pSetLayouts: addr(descriptorSetLayout), 364 pSetLayouts: addr(descriptorSetLayout),
206 # pushConstantRangeCount: uint32(pushConstants.len), 365 # pushConstantRangeCount: uint32(pushConstants.len),
210 369
211 let stages = [ 370 let stages = [
212 VkPipelineShaderStageCreateInfo( 371 VkPipelineShaderStageCreateInfo(
213 sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 372 sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
214 stage: VK_SHADER_STAGE_VERTEX_BIT, 373 stage: VK_SHADER_STAGE_VERTEX_BIT,
215 module: shaderSet.vertexShader, 374 module: vertexShader,
216 pName: "main", 375 pName: "main",
217 ), 376 ),
218 VkPipelineShaderStageCreateInfo( 377 VkPipelineShaderStageCreateInfo(
219 sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 378 sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
220 stage: VK_SHADER_STAGE_FRAGMENT_BIT, 379 stage: VK_SHADER_STAGE_FRAGMENT_BIT,
221 module: shaderSet.fragmentShader, 380 module: fragmentShader,
222 pName: "main", 381 pName: "main",
223 ), 382 ),
224 ] 383 ]
225 let 384 var
226 bindings: var seq[VkVertexInputBindingDescription] 385 bindings: seq[VkVertexInputBindingDescription]
227 attributes: var seq[VkVertexInputAttributeDescription] 386 attributes: seq[VkVertexInputAttributeDescription]
228 var inputBindingNumber = 0'u32 387 var inputBindingNumber = 0'u32
229 var inputLocationNumber = 0'u32 388 var location = 0'u32
230 ForVertexDataFields(default(TShaderInputs), fieldname, value, isInstanceAttr): 389 ForVertexDataFields(default(TShader), fieldname, value, isInstanceAttr):
231 bindings.add VkVertexInputBindingDescription( 390 bindings.add VkVertexInputBindingDescription(
232 binding: inputBindingNumber, 391 binding: inputBindingNumber,
233 stride: sizeof(value).uint32, 392 stride: sizeof(value).uint32,
234 inputRate: if isInstanceAttr: VK_VERTEX_INPUT_RATE_INSTANCE else: VK_VERTEX_INPUT_RATE_VERTEX, 393 inputRate: if isInstanceAttr: VK_VERTEX_INPUT_RATE_INSTANCE else: VK_VERTEX_INPUT_RATE_VERTEX,
235 ) 394 )
236 # allows to submit larger data structures like Mat44, for most other types will be 1 395 # allows to submit larger data structures like Mat44, for most other types will be 1
237 let perDescriptorSize = sizeof(value).uint32 div NumberOfVertexInputAttributeDescriptors(value) 396 let perDescriptorSize = sizeof(value).uint32 div NumberOfVertexInputAttributeDescriptors(value)
238 for i in 0'u32 ..< NumberOfVertexInputAttributeDescriptors(value): 397 for i in 0'u32 ..< NumberOfVertexInputAttributeDescriptors(value):
239 attributes.add VkVertexInputAttributeDescription( 398 attributes.add VkVertexInputAttributeDescription(
240 binding: inputBindingNumber, 399 binding: inputBindingNumber,
241 inputLocationNumber: inputLocationNumber, 400 location: location,
242 format: VkType(value), 401 format: VkType(value),
243 offset: i * perDescriptorSize, 402 offset: i * perDescriptorSize,
244 ) 403 )
245 inputLocationNumber += NLocationSlots(value) 404 location += NLocationSlots(value)
246 inc inputBindingNumber 405 inc inputBindingNumber
247 406
248 let 407 let
249 vertexInputInfo = VkPipelineVertexInputStateCreateInfo( 408 vertexInputInfo = VkPipelineVertexInputStateCreateInfo(
250 sType: VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, 409 sType: VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
308 pDynamicStates: dynamicStates.ToCPointer, 467 pDynamicStates: dynamicStates.ToCPointer,
309 ) 468 )
310 let createInfo = VkGraphicsPipelineCreateInfo( 469 let createInfo = VkGraphicsPipelineCreateInfo(
311 sType: VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, 470 sType: VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
312 stageCount: 2, 471 stageCount: 2,
313 pStages: addr(stages), 472 pStages: stages.ToCPointer,
314 pVertexInputState: addr(vertexInputInfo), 473 pVertexInputState: addr(vertexInputInfo),
315 pInputAssemblyState: addr(inputAssembly), 474 pInputAssemblyState: addr(inputAssembly),
316 pViewportState: addr(viewportState), 475 pViewportState: addr(viewportState),
317 pRasterizationState: addr(rasterizer), 476 pRasterizationState: addr(rasterizer),
318 pMultisampleState: addr(multisampling), 477 pMultisampleState: addr(multisampling),
351 pipeline.descriptorSets[currentFrameInFlight], 510 pipeline.descriptorSets[currentFrameInFlight],
352 0, 511 0,
353 nil, 512 nil,
354 ) 513 )
355 514
356 proc AssertCompatible(TShaderInputs, TMesh, TInstance, TGlobals: typedesc) = 515 proc AssertCompatible(TShader, TMesh, TInstance, TGlobals: typedesc) =
357 # assert seq-fields of TMesh|TInstance == seq-fields of TShaderInputs 516 # assert seq-fields of TMesh|TInstance == seq-fields of TShader
358 # assert normal fields of TMesh|Globals == normal fields of TShaderDescriptors 517 # assert normal fields of TMesh|Globals == normal fields of TShaderDescriptors
359 for inputName, inputValue in default(TShaderInputs).fieldPairs: 518 for inputName, inputValue in default(TShader).fieldPairs:
360 echo "checking shader input '" & inputName & "'" 519 echo "checking shader input '" & inputName & "'"
361 var foundField = false 520 var foundField = false
362 when hasCustomPragma(inputValue, VertexAttribute): 521 when hasCustomPragma(inputValue, VertexAttribute):
363 echo " is vertex attribute" 522 echo " is vertex attribute"
364 for meshName, meshValue in default(TMesh).fieldPairs: 523 for meshName, meshValue in default(TMesh).fieldPairs:
365 when meshName == inputName: 524 when meshName == inputName:
366 assert foundField == false, "Shader input '" & TShaderInputs.name & "." & inputName & "' has been found more than once" 525 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once"
367 assert getElementType(meshValue) is typeof(inputValue), "Shader input " & TShaderInputs.name & "." & inputName & " is of type '" & typeof(inputValue).name & "' but mesh attribute is of type '" & getElementType(meshValue).name & "'" 526 assert getElementType(meshValue) is typeof(inputValue), "Shader input " & tt.name(TShader) & "." & inputName & " is of type '" & tt.name(typeof(inputValue)) & "' but mesh attribute is of type '" & tt.name(getElementType(meshValue)) & "'"
368 foundField = true 527 foundField = true
369 assert foundField, "Shader input '" & TShaderInputs.name & "." & inputName & ": " & typeof(inputValue).name & "' not found in '" & TMesh.name & "'" 528 assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TMesh) & "'"
370 elif hasCustomPragma(inputValue, InstanceAttribute): 529 elif hasCustomPragma(inputValue, InstanceAttribute):
371 echo " is instance attribute" 530 echo " is instance attribute"
372 for instanceName, instanceValue in default(TInstance).fieldPairs: 531 for instanceName, instanceValue in default(TInstance).fieldPairs:
373 when instanceName == inputName: 532 when instanceName == inputName:
374 assert foundField == false, "Shader input '" & TShaderInputs.name & "." & inputName & "' has been found more than once" 533 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once"
375 assert getElementType(instanceValue) is typeof(inputValue), "Shader input " & TShaderInputs.name & "." & inputName & " is of type '" & typeof(inputValue).name & "' but instance attribute is of type '" & getElementType(instanceValue).name & "'" 534 assert getElementType(instanceValue) is typeof(inputValue), "Shader input " & tt.name(TShader) & "." & inputName & " is of type '" & tt.name(typeof(inputValue)) & "' but instance attribute is of type '" & tt.name(getElementType(instanceValue)) & "'"
376 foundField = true 535 foundField = true
377 assert foundField, "Shader input '" & TShaderInputs.name & "." & inputName & ": " & typeof(inputValue).name & "' not found in '" & TInstance.name & "'" 536 assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TInstance) & "'"
378 elif hasCustomPragma(inputValue, DescriptorAttribute): 537 elif hasCustomPragma(inputValue, Descriptor):
379 echo " is descriptor attribute" 538 echo " is descriptor attribute"
380 for meshName, meshValue in default(TMesh).fieldPairs: 539 for meshName, meshValue in default(TMesh).fieldPairs:
381 when meshName == inputName: 540 when meshName == inputName:
382 assert foundField == false, "Shader input '" & TShaderInputs.name & "." & inputName & "' has been found more than once" 541 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once"
383 assert typeof(meshValue) is typeof(inputValue), "Shader input " & TShaderInputs.name & "." & inputName & " is of type '" & typeof(inputValue).name & "' but mesh attribute is of type '" & getElementType(meshValue).name & "'" 542 assert typeof(meshValue) is typeof(inputValue), "Shader input " & tt.name(TShader) & "." & inputName & " is of type '" & tt.name(typeof(inputValue)) & "' but mesh attribute is of type '" & tt.name(getElementType(meshValue)) & "'"
384 foundField = true 543 foundField = true
385 for globalName, globalValue in default(TGlobals).fieldPairs: 544 for globalName, globalValue in default(TGlobals).fieldPairs:
386 when globalName == inputName: 545 when globalName == inputName:
387 assert foundField == false, "Shader input '" & TShaderInputs.name & "." & inputName & "' has been found more than once" 546 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once"
388 assert typeof(globalValue) is typeof(inputValue), "Shader input " & TShaderInputs.name & "." & inputName & " is of type '" & typeof(inputValue).name & "' but global attribute is of type '" & typeof(globalValue).name & "'" 547 assert typeof(globalValue) is typeof(inputValue), "Shader input " & tt.name(TShader) & "." & inputName & " is of type '" & tt.name(typeof(inputValue)) & "' but global attribute is of type '" & tt.name(typeof(globalValue)) & "'"
389 foundField = true 548 foundField = true
390 assert foundField, "Shader input '" & TShaderInputs.name & "." & inputName & ": " & typeof(inputValue).name & "' not found in '" & TMesh.name & "|" & TGlobals.name & "'" 549 assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TMesh) & "|" & tt.name(TGlobals) & "'"
391 echo " found" 550 echo " found"
392 551
393 552
394 proc Render[TShaderInputs, TMesh, TInstance, TGlobals]( 553 proc Render[TShader, TMesh, TInstance, TGlobals](
395 pipeline: Pipeline[TShaderInputs], 554 pipeline: Pipeline[TShader],
396 renderable: Renderable[TMesh, TInstance], 555 renderable: Renderable[TMesh, TInstance],
397 globals: TGlobals, 556 globals: TGlobals,
398 commandBuffer: VkCommandBuffer, 557 commandBuffer: VkCommandBuffer,
399 ) = 558 ) =
400 static: 559 static:
401 AssertCompatible(TShaderInputs, TMesh, TInstance, TGlobals) 560 AssertCompatible(TShader, TMesh, TInstance, TGlobals)
402 commandBuffer.vkCmdBindVertexBuffers( 561 commandBuffer.vkCmdBindVertexBuffers(
403 firstBinding = 0'u32, 562 firstBinding = 0'u32,
404 bindingCount = uint32(renderable.vertexBuffers.len), 563 bindingCount = uint32(renderable.vertexBuffers.len),
405 pBuffers = renderable.vertexBuffers.ToCPointer(), 564 pBuffers = renderable.vertexBuffers.ToCPointer(),
406 pOffsets = renderable.bufferOffsets.ToCPointer() 565 pOffsets = renderable.bufferOffsets.ToCPointer()
425 firstVertex = 0, 584 firstVertex = 0,
426 firstInstance = 0 585 firstInstance = 0
427 ) 586 )
428 587
429 when isMainModule: 588 when isMainModule:
589 import semicongine/platform/window
590 import semicongine/core/vulkanapi
591 import semicongine/vulkan/instance
592 import semicongine/vulkan/device
593 import semicongine/vulkan/physicaldevice
594 import semicongine/vulkan/renderpass
595
430 type 596 type
431 MeshA = object 597 MeshA = object
432 position: seq[Vec3f] 598 position: seq[Vec3f]
433 transparency: float 599 transparency: float
434 InstanceA = object 600 InstanceA = object
435 transform: seq[Mat4] 601 transform: seq[Mat4]
436 position: seq[Vec3f] 602 position: seq[Vec3f]
603 other: seq[array[3, int32]]
437 Globals = object 604 Globals = object
438 color: Vec4f 605 fontAtlas: Texture
439 606
440 ShaderInputsA = object 607 ShaderA = object
441 position {.VertexAttribute.}: Vec3f 608 position {.VertexAttribute.}: Vec3f
442 transform {.InstanceAttribute.}: Mat4 609 transform {.InstanceAttribute.}: Mat4
443 color {.DescriptorAttribute.}: Vec4f 610 fontAtlas {.Descriptor.}: Texture
444 611 other {.InstanceAttribute.}: array[3, int32]
445 var p: Pipeline[ShaderInputsA] 612 test {.Pass.}: float32
613 test1 {.PassFlat.}: Vec3f
614 color {.ShaderOutput.}: Vec4f
615 vertexCode: string = "void main() {}"
616 fragmentCode: string = "void main() {}"
617
618 let w = CreateWindow("test2")
619 putEnv("VK_LAYER_ENABLES", "VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_AMD,VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_NVIDIA,VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXTVK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT,VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT")
620 let i = w.CreateInstance(
621 vulkanVersion = VK_MAKE_API_VERSION(0, 1, 3, 0),
622 instanceExtensions = @[],
623 layers = @["VK_LAYER_KHRONOS_validation"],
624 )
625
626 const (a, b) = CompileShader(Shader(A))
627
628 let selectedPhysicalDevice = i.GetPhysicalDevices().FilterBestGraphics()
629 let d = i.CreateDevice(
630 selectedPhysicalDevice,
631 enabledExtensions = @[],
632 selectedPhysicalDevice.FilterForGraphicsPresentationQueues()
633 )
634
635 var p: Pipeline[ShaderA]
446 var r: Renderable[MeshA, InstanceA] 636 var r: Renderable[MeshA, InstanceA]
447 var g: Globals 637 var g: Globals
448 var s: ShaderSet[ShaderInputsA] 638
449 639 let rp = CreateRenderPass(d.vk, d.physicalDevice.GetSurfaceFormats().FilterSurfaceFormat().format)
450 var p1 = CreatePipeline(device = VkDevice(0), renderPass = VkRenderPass(0), shaderSet = s) 640 var p1 = CreatePipeline[ShaderA](device = d.vk, renderPass = rp, VkShaderModule(0), VkShaderModule(0))
451 Render(p, r, g, VkCommandBuffer(0)) 641 Render(p, r, g, VkCommandBuffer(0))