comparison src/zamikongine/shader.nim @ 24:71bbe11d8de8

did: change shader compilation to run during program compilation, maybe add dynamic version later
author Sam <sam@basx.dev>
date Wed, 11 Jan 2023 11:15:02 +0700
parents b45a5d338cd0
children 8f290112718a
comparison
equal deleted inserted replaced
23:0ffdf1f4ecf4 24:71bbe11d8de8
1 import std/osproc 1 import std/tempfiles
2 import std/strformat 2 import std/strformat
3 import std/strutils 3 import std/strutils
4 import std/tables 4 import std/tables
5 import std/compilesettings
6
5 7
6 import ./vulkan_helpers 8 import ./vulkan_helpers
7 import ./vulkan 9 import ./vulkan
8 import ./vertex 10 import ./vertex
9 11
11 ShaderProgram* = object 13 ShaderProgram* = object
12 entryPoint*: string 14 entryPoint*: string
13 programType*: VkShaderStageFlagBits 15 programType*: VkShaderStageFlagBits
14 shader*: VkPipelineShaderStageCreateInfo 16 shader*: VkPipelineShaderStageCreateInfo
15 17
16 func stage2string(stage: VkShaderStageFlagBits): string = 18 func stage2string(stage: VkShaderStageFlagBits): string {.compileTime.} =
17 case stage 19 case stage
18 of VK_SHADER_STAGE_VERTEX_BIT: "vert" 20 of VK_SHADER_STAGE_VERTEX_BIT: "vert"
19 of VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: "tesc" 21 of VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: "tesc"
20 of VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: "tese" 22 of VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: "tese"
21 of VK_SHADER_STAGE_GEOMETRY_BIT: "geom" 23 of VK_SHADER_STAGE_GEOMETRY_BIT: "geom"
22 of VK_SHADER_STAGE_FRAGMENT_BIT: "frag" 24 of VK_SHADER_STAGE_FRAGMENT_BIT: "frag"
23 of VK_SHADER_STAGE_ALL_GRAPHICS: "" 25 of VK_SHADER_STAGE_ALL_GRAPHICS: ""
24 of VK_SHADER_STAGE_COMPUTE_BIT: "comp" 26 of VK_SHADER_STAGE_COMPUTE_BIT: "comp"
25 of VK_SHADER_STAGE_ALL: "" 27 of VK_SHADER_STAGE_ALL: ""
26 28
27 proc compileGLSLToSPIRV(stage: VkShaderStageFlagBits, shaderSource: string, entrypoint: string): seq[uint32] = 29 proc compileGLSLToSPIRV(stage: VkShaderStageFlagBits, shaderSource: string, entrypoint: string): seq[uint32] {.compileTime.} =
28 let stagename = stage2string(stage) 30 let stagename = stage2string(stage)
29 let (output, exitCode) = execCmdEx(command=fmt"./glslangValidator --entry-point {entrypoint} -V --stdin -S {stagename}", input=shaderSource) 31 let (tmpfile, tmpfilename) = createTempFile("shader", stage2string(stage))
32 tmpfile.close()
33 let (output, exitCode) = gorgeEx(command=fmt"{querySetting(projectPath)}/glslangValidator --entry-point {entrypoint} -V --stdin -S {stagename} -o {tmpfilename}", input=shaderSource)
30 if exitCode != 0: 34 if exitCode != 0:
31 raise newException(Exception, output) 35 raise newException(Exception, output)
32 let shaderbinary = readFile fmt"{stagename}.spv" 36 let shaderbinary = staticRead tmpfilename
33 var i = 0 37 var i = 0
34 while i < shaderbinary.len: 38 while i < shaderbinary.len:
35 result.add( 39 result.add(
36 (uint32(shaderbinary[i + 0]) shl 0) or 40 (uint32(shaderbinary[i + 0]) shl 0) or
37 (uint32(shaderbinary[i + 1]) shl 8) or 41 (uint32(shaderbinary[i + 1]) shl 8) or
38 (uint32(shaderbinary[i + 2]) shl 16) or 42 (uint32(shaderbinary[i + 2]) shl 16) or
39 (uint32(shaderbinary[i + 3]) shl 24) 43 (uint32(shaderbinary[i + 3]) shl 24)
40 ) 44 )
41 i += 4 45 i += 4
42 46
43 proc initShaderProgram*(device: VkDevice, programType: VkShaderStageFlagBits, shader: string, entryPoint: string="main"): ShaderProgram = 47 proc initShaderProgram*(device: VkDevice, programType: static VkShaderStageFlagBits, shader: static string, entryPoint: static string="main"): ShaderProgram =
44 result.entryPoint = entryPoint 48 result.entryPoint = entryPoint
45 result.programType = programType 49 result.programType = programType
46 50
47 var code = compileGLSLToSPIRV(result.programType, shader, result.entryPoint) 51 const constcode = compileGLSLToSPIRV(programType, shader, entryPoint)
52 var code = constcode
48 var createInfo = VkShaderModuleCreateInfo( 53 var createInfo = VkShaderModuleCreateInfo(
49 sType: VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, 54 sType: VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
50 codeSize: uint(code.len * sizeof(uint32)), 55 codeSize: uint(code.len * sizeof(uint32)),
51 pCode: if code.len > 0: addr(code[0]) else: nil, 56 pCode: if code.len > 0: addr(code[0]) else: nil,
52 ) 57 )
58 stage: programType, 63 stage: programType,
59 module: shaderModule, 64 module: shaderModule,
60 pName: cstring(result.entryPoint), # entry point for shader 65 pName: cstring(result.entryPoint), # entry point for shader
61 ) 66 )
62 67
63 func generateVertexShaderCode*[T](entryPoint, positionAttrName, colorAttrName: static string): string = 68 func generateVertexShaderCode*[T](entryPoint, positionAttrName, colorAttrName: static string): string {.compileTime.} =
64 var lines: seq[string] 69 var lines: seq[string]
65 lines.add "#version 450" 70 lines.add "#version 450"
66 lines.add generateGLSLDeclarations[T]() 71 lines.add generateGLSLDeclarations[T]()
67 lines.add "layout(location = 0) out vec3 fragColor;" 72 lines.add "layout(location = 0) out vec3 fragColor;"
68 lines.add "void " & entryPoint & "() {" 73 lines.add "void " & entryPoint & "() {"
73 when typeof(value) is VertexAttribute and name == colorAttrName: 78 when typeof(value) is VertexAttribute and name == colorAttrName:
74 lines.add " fragColor = " & name & ";" 79 lines.add " fragColor = " & name & ";"
75 lines.add "}" 80 lines.add "}"
76 return lines.join("\n") 81 return lines.join("\n")
77 82
78 func generateFragmentShaderCode*[T](entryPoint: static string): string = 83 func generateFragmentShaderCode*[T](entryPoint: static string): string {.compileTime.} =
79 var lines: seq[string] 84 var lines: seq[string]
80 lines.add "#version 450" 85 lines.add "#version 450"
81 lines.add "layout(location = 0) in vec3 fragColor;" 86 lines.add "layout(location = 0) in vec3 fragColor;"
82 lines.add "layout(location = 0) out vec4 outColor;" 87 lines.add "layout(location = 0) out vec4 outColor;"
83 lines.add "void " & entryPoint & "() {" 88 lines.add "void " & entryPoint & "() {"