changeset 1:bb2a7d3a7003

add: more steps in setup
author Sam <sam@basx.dev>
date Fri, 16 Dec 2022 00:05:41 +0700
parents 5daf3f236d87
children 213fdf8d31dd
files Makefile src/engine.nim src/glslang/glslang.nim src/glslang/glslang_c_interface.nim src/glslang/glslang_c_shader_types.nim src/vulkan.nim src/vulkan_helpers.nim
diffstat 7 files changed, 217 insertions(+), 158 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Wed Dec 14 00:49:35 2022 +0700
+++ b/Makefile	Fri Dec 16 00:05:41 2022 +0700
@@ -3,9 +3,9 @@
 build/debug/linux:
 	mkdir -p $@
 build/debug/linux/test: build/debug/linux ${SOURCES}
-	nim c -o:$@ --checks:on --assertions:on src/test.nim
+	nim c -o:$@ --gc:orc --debugger:native --checks:on --assertions:on src/test.nim
 
 build/release/linux:
 	mkdir -p $@
 build/release/linux/test: build/release/linux ${SOURCES}
-	nim c -d:release -o:$@ --checks:off --assertions:off src/test.nim
+	nim c -d:release --gc:orc -o:$@ --checks:off --assertions:off src/test.nim
--- a/src/engine.nim	Wed Dec 14 00:49:35 2022 +0700
+++ b/src/engine.nim	Fri Dec 16 00:05:41 2022 +0700
@@ -5,8 +5,30 @@
 import ./xlib_helpers
 
 import ./glslang/glslang
-import ./glslang/glslang_c_shader_types
 
+var vertexShaderCode: string = """#version 450
+layout(location = 0) out vec3 fragColor;
+vec3 colors[3] = vec3[](
+    vec3(1.0, 0.0, 0.0),
+    vec3(0.0, 1.0, 0.0),
+    vec3(0.0, 0.0, 1.0)
+);
+vec2 positions[3] = vec2[](
+  vec2(0.0, -0.5),
+  vec2(0.5, 0.5),
+  vec2(-0.5, 0.5)
+);
+void main() {
+  gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
+  fragColor = colors[gl_VertexIndex];
+}"""
+
+var fragmentShaderCode: string = """#version 450
+layout(location = 0) out vec4 outColor;
+layout(location = 0) in vec3 fragColor;
+void main() {
+  outColor = vec4(fragColor, 1.0);
+}"""
 
 import
   x11/xlib,
@@ -15,6 +37,8 @@
 const VULKAN_VERSION = VK_MAKE_API_VERSION(0'u32, 1'u32, 2'u32, 0'u32)
 
 type
+  GraphicsPipeline = object
+    shaderStages*: seq[VkPipelineShaderStageCreateInfo]
   QueueFamily = object
     properties*: VkQueueFamilyProperties
     hasSurfaceSupport*: bool
@@ -45,6 +69,7 @@
     display*: PDisplay
     window*: x.Window
     vulkan*: Vulkan
+    pipeline*: GraphicsPipeline
 
 
 proc getAllPhysicalDevices(instance: VkInstance, surface: VkSurfaceKHR): seq[PhyscialDevice] =
@@ -57,7 +82,7 @@
     device.presentModes = getDeviceSurfacePresentModes(vulkanPhysicalDevice, surface)
 
     for i, queueFamilyProperty in enumerate(getQueueFamilies(vulkanPhysicalDevice)):
-      var hasSurfaceSupport: VkBool32 = VkBool32(false)
+      var hasSurfaceSupport: VkBool32 = VK_FALSE
       checkVkResult vkGetPhysicalDeviceSurfaceSupportKHR(vulkanPhysicalDevice, uint32(i), surface, addr(hasSurfaceSupport))
       device.queueFamilies.add(QueueFamily(properties: queueFamilyProperty, hasSurfaceSupport: bool(hasSurfaceSupport)))
 
@@ -146,7 +171,7 @@
     preTransform: result.vulkan.activePhysicalDevice.surfaceCapabilities.currentTransform,
     compositeAlpha: VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
     presentMode: result.vulkan.selectedPresentationMode,
-    clipped: VkBool32(true),
+    clipped: VK_TRUE,
     oldSwapchain: VkSwapchainKHR(0),
   )
   checkVkResult vkCreateSwapchainKHR(result.vulkan.device, addr(swapchainCreateInfo), nil, addr(result.vulkan.swapChain))
@@ -175,15 +200,47 @@
       ),
     )
     checkVkResult vkCreateImageView(result.vulkan.device, addr(imageViewCreateInfo), nil, addr(result.vulkan.swapImageViews[i]))
-    echo compileShaderToSPIRV_Vulkan(GLSLANG_STAGE_VERTEX, """#version 450
-vec2 positions[3] = vec2[](
-    vec2(0.0, -0.5),
-    vec2(0.5, 0.5),
-    vec2(-0.5, 0.5)
-);
-void main() {
-    gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
-}""", "<memory-shader>")
+
+  # init shader system
+  checkGlslangResult glslang_initialize_process()
+
+  # load shaders
+  result.pipeline.shaderStages.add(createShaderStage(result.vulkan.device, VK_SHADER_STAGE_VERTEX_BIT, vertexShaderCode))
+  result.pipeline.shaderStages.add(createShaderStage(result.vulkan.device, VK_SHADER_STAGE_FRAGMENT_BIT, fragmentShaderCode))
+
+  # create graphis pipeline
+  var dynamicStates = [VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR]
+  var dynamicState = VkPipelineDynamicStateCreateInfo(
+    sType: VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
+    dynamicStateCount: uint32(dynamicStates.len),
+    pDynamicStates: addr(dynamicStates[0]),
+  )
+  var vertexInputInfo = VkPipelineVertexInputStateCreateInfo(
+    sType: VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+    vertexBindingDescriptionCount: 0,
+    pVertexBindingDescriptions: nil,
+    vertexAttributeDescriptionCount: 0,
+    pVertexAttributeDescriptions: nil,
+  )
+  var inputAssembly = VkPipelineInputAssemblyStateCreateInfo(
+    sType: VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
+    topology: VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
+    primitiveRestartEnable: VK_FALSE,
+  )
+
+  # setup viewport
+  var viewport = VkViewport(
+    x: 0.0,
+    y: 0.0,
+    width: (float) result.vulkan.selectedExtent.width,
+    height: (float) result.vulkan.selectedExtent.height,
+    minDepth: 0.0,
+    maxDepth: 1.0,
+  )
+  var scissor = VkRect2D(
+    offset: VkOffset2D(x: 0, y: 0),
+    extent: result.vulkan.selectedExtent
+  )
 
 
 proc fullThrottle*(engine: Engine) =
@@ -207,6 +264,9 @@
       discard
 
 proc trash*(engine: Engine) =
+  for shaderStage in engine.pipeline.shaderStages:
+    vkDestroyShaderModule(engine.vulkan.device, shaderStage.module, nil);
+  glslang_finalize_process()
   vkDestroySwapchainKHR(engine.vulkan.device, engine.vulkan.swapChain, nil);
   vkDestroySurfaceKHR(engine.vulkan.instance, engine.vulkan.surface, nil);
   vkDestroyDevice(engine.vulkan.device, nil)
--- a/src/glslang/glslang.nim	Wed Dec 14 00:49:35 2022 +0700
+++ b/src/glslang/glslang.nim	Fri Dec 16 00:05:41 2022 +0700
@@ -1,86 +1,75 @@
-# required to link the GLSL compiler
-{.passl: "-Lthirdparty/glslang/lib/" .}
-{.passl: "-Lthirdparty/spirv-tools/lib/" .}
-
-{.passl: "-lglslang" .}
-{.passl: "-lglslang-default-resource-limits" .}
-{.passl: "-lHLSL" .}
-{.passl: "-lMachineIndependent" .}
-{.passl: "-lGenericCodeGen" .}
-{.passl: "-lOSDependent" .}
-{.passl: "-lOGLCompiler" .}
-{.passl: "-lSPIRV" .}
-{.passl: "-lSPIRV-Tools-opt" .}
-
-{.passl: "-lSPIRV-Tools" .}
-{.passl: "-lSPIRV-Tools-diff" .}
-{.passl: "-lSPIRV-Tools-fuzz" .}
-{.passl: "-lSPIRV-Tools-link" .}
-{.passl: "-lSPIRV-Tools-lint" .}
-{.passl: "-lSPIRV-Tools-opt" .}
-{.passl: "-lSPIRV-Tools-reduce" .}
-
-{.passl: "-lstdc++" .}
-{.passl: "-lm" .}
-
 import glslang_c_interface
 import glslang_c_shader_types
 
+export
+  glslang_stage_t,
+  glslang_initialize_process,
+  glslang_finalize_process
 
-proc compileShaderToSPIRV_Vulkan*(stage: glslang_stage_t , shaderSource: string, fileName: string): seq[uint32] =
-    var input = glslang_input_t(
-        language: GLSLANG_SOURCE_GLSL,
-        stage: stage,
-        client: GLSLANG_CLIENT_VULKAN,
-        client_version: GLSLANG_TARGET_VULKAN_1_2,
-        target_language: GLSLANG_TARGET_SPV,
-        target_language_version: GLSLANG_TARGET_SPV_1_5,
-        code: shaderSource,
-        default_version: 100,
-        default_profile: GLSLANG_NO_PROFILE,
-        force_default_version_and_profile: false.cint,
-        forward_compatible: false.cint,
-        messages: GLSLANG_MSG_DEFAULT_BIT,
-        resource: glslang_default_resource(),
-    )
+type
+  ShaderVersion = enum
+    ES_VERSION = 100
+    DESKTOP_VERSION = 110
 
-    let shader = glslang_shader_create(addr(input))
+proc compileGLSLToSPIRV*(stage: glslang_stage_t, shaderSource: string, fileName: string): seq[uint32] =
+  var input = glslang_input_t(
+    stage: stage,
+    language: GLSLANG_SOURCE_GLSL,
+    client: GLSLANG_CLIENT_VULKAN,
+    client_version: GLSLANG_TARGET_VULKAN_1_2,
+    target_language: GLSLANG_TARGET_SPV,
+    target_language_version: GLSLANG_TARGET_SPV_1_5,
+    code: cstring(shaderSource),
+    default_version: ord(DESKTOP_VERSION),
+    default_profile: GLSLANG_CORE_PROFILE,
+    force_default_version_and_profile: false.cint,
+    forward_compatible: false.cint,
+    messages: GLSLANG_MSG_DEBUG_INFO_BIT,
+    resource: glslang_default_resource(),
+  )
 
-    if not bool(glslang_shader_preprocess(shader, addr(input))):
-        echo "GLSL preprocessing failed " & fileName
-        echo glslang_shader_get_info_log(shader)
-        echo glslang_shader_get_info_debug_log(shader)
-        echo input.code
-        glslang_shader_delete(shader)
-        return
+  var shader = glslang_shader_create(addr(input))
 
-    if not bool(glslang_shader_parse(shader, addr(input))):
-        echo "GLSL parsing failed " & fileName
-        echo glslang_shader_get_info_log(shader)
-        echo glslang_shader_get_info_debug_log(shader)
-        echo glslang_shader_get_preprocessed_code(shader)
-        glslang_shader_delete(shader)
-        return
+  if not bool(glslang_shader_preprocess(shader, addr(input))):
+      echo "GLSL preprocessing failed " & fileName
+      echo glslang_shader_get_info_log(shader)
+      echo glslang_shader_get_info_debug_log(shader)
+      echo input.code
+      glslang_shader_delete(shader)
+      return
 
-    let program: ptr glslang_program_t = glslang_program_create()
-    glslang_program_add_shader(program, shader)
+  if not bool(glslang_shader_parse(shader, addr(input))):
+      echo "GLSL parsing failed " & fileName
+      echo glslang_shader_get_info_log(shader)
+      echo glslang_shader_get_info_debug_log(shader)
+      echo glslang_shader_get_preprocessed_code(shader)
+      glslang_shader_delete(shader)
+      return
+
+  var program: ptr glslang_program_t = glslang_program_create()
+  glslang_program_add_shader(program, shader)
 
-    if not bool(glslang_program_link(program, ord(GLSLANG_MSG_SPV_RULES_BIT) or ord(GLSLANG_MSG_VULKAN_RULES_BIT))):
-        echo "GLSL linking failed " & fileName
-        echo glslang_program_get_info_log(program)
-        echo glslang_program_get_info_debug_log(program)
-        glslang_program_delete(program)
-        glslang_shader_delete(shader)
-        return
+  if not bool(glslang_program_link(program, ord(GLSLANG_MSG_SPV_RULES_BIT) or ord(GLSLANG_MSG_VULKAN_RULES_BIT))):
+      echo "GLSL linking failed " & fileName
+      echo glslang_program_get_info_log(program)
+      echo glslang_program_get_info_debug_log(program)
+      glslang_program_delete(program)
+      glslang_shader_delete(shader)
+      return
 
-    glslang_program_SPIRV_generate(program, stage)
+  glslang_program_SPIRV_generate(program, stage)
 
-    result = newSeq[uint32](glslang_program_SPIRV_get_size(program))
-    glslang_program_SPIRV_get(program, addr(result[0]))
+  result = newSeq[uint32](glslang_program_SPIRV_get_size(program))
+  glslang_program_SPIRV_get(program, addr(result[0]))
+
+  var spirv_messages: cstring = glslang_program_SPIRV_get_messages(program)
+  if spirv_messages != nil:
+      echo "(%s) %s\b", fileName, spirv_messages
 
-    var spirv_messages: cstring = glslang_program_SPIRV_get_messages(program)
-    if spirv_messages != nil:
-        echo "(%s) %s\b", fileName, spirv_messages
+  glslang_program_delete(program)
+  glslang_shader_delete(shader)
 
-    glslang_program_delete(program)
-    glslang_shader_delete(shader)
+template checkGlslangResult*(call: untyped) =
+  let value = call
+  if value != 1:
+    raise newException(Exception, "glgslang error: " & astToStr(call) & " returned " & $value)
--- a/src/glslang/glslang_c_interface.nim	Wed Dec 14 00:49:35 2022 +0700
+++ b/src/glslang/glslang_c_interface.nim	Fri Dec 16 00:05:41 2022 +0700
@@ -1,15 +1,37 @@
+# required to link the GLSL compiler
+when defined(release):
+  {.passl: "-Lthirdparty/glslang/lib/release" .}
+else:
+  {.passl: "-Lthirdparty/glslang/lib/debug" .}
+{.passl: "-Lthirdparty/spirv-tools/lib/" .}
+
+{.passl: "-lglslang" .}
+{.passl: "-lglslang-default-resource-limits" .}
+{.passl: "-lHLSL" .}
+{.passl: "-lMachineIndependent" .}
+{.passl: "-lGenericCodeGen" .}
+{.passl: "-lOSDependent" .}
+{.passl: "-lOGLCompiler" .}
+{.passl: "-lSPIRV" .}
+{.passl: "-lSPIRV-Tools-opt" .}
+
+{.passl: "-lSPIRV-Tools" .}
+{.passl: "-lSPIRV-Tools-diff" .}
+{.passl: "-lSPIRV-Tools-fuzz" .}
+{.passl: "-lSPIRV-Tools-link" .}
+{.passl: "-lSPIRV-Tools-lint" .}
+{.passl: "-lSPIRV-Tools-opt" .}
+{.passl: "-lSPIRV-Tools-reduce" .}
+
+{.passl: "-lstdc++" .}
+{.passl: "-lm" .}
+
 import
   glslang_c_shader_types
 
-type
-  glslang_shader_s = object
-  glslang_program_s = object
-  glslang_shader_t* = glslang_shader_s
-  glslang_program_t* = glslang_program_s
-
-##  TLimits counterpart
-
-type
+type 
+  glslang_shader_t* {.nodecl incompleteStruct.} = object
+  glslang_program_t* {.nodecl incompleteStruct.} = object
   glslang_limits_t* {.bycopy.} = object
     non_inductive_for_loops*: bool
     while_loops*: bool
@@ -20,11 +42,6 @@
     general_sampler_indexing*: bool
     general_variable_indexing*: bool
     general_constant_matrix_vector_indexing*: bool
-
-
-##  TBuiltInResource counterpart
-
-type
   glslang_resource_t* {.bycopy.} = object
     max_lights*: cint
     max_clip_planes*: cint
@@ -129,7 +146,6 @@
     max_mesh_view_count_ext*: cint
     maxDualSourceDrawBuffersEXT*: cint
     limits*: glslang_limits_t
-
   glslang_input_t* {.bycopy.} = object
     language*: glslang_source_t
     stage*: glslang_stage_t
@@ -137,7 +153,6 @@
     client_version*: glslang_target_client_version_t
     target_language*: glslang_target_language_t
     target_language_version*: glslang_target_language_version_t
-    ##  Shader source code
     code*: cstring
     default_version*: cint
     default_profile*: glslang_profile_t
@@ -145,49 +160,19 @@
     forward_compatible*: cint
     messages*: glslang_messages_t
     resource*: ptr glslang_resource_t
-
-
-##  Inclusion result structure allocated by C include_local/include_system callbacks
-
-type
   glsl_include_result_t* {.bycopy.} = object
     ##  Header file name or NULL if inclusion failed
     header_name*: cstring
     ##  Header contents or NULL
     header_data*: cstring
     header_length*: csize_t
-
-
-##  Callback for local file inclusion
-
-type
-  glsl_include_local_func* = proc (ctx: pointer; header_name: cstring;
-                                includer_name: cstring; include_depth: csize_t): ptr glsl_include_result_t
-
-##  Callback for system file inclusion
-
-type
-  glsl_include_system_func* = proc (ctx: pointer; header_name: cstring;
-                                 includer_name: cstring; include_depth: csize_t): ptr glsl_include_result_t
-
-##  Callback for include result destruction
-
-type
-  glsl_free_include_result_func* = proc (ctx: pointer;
-                                      result: ptr glsl_include_result_t): cint
-
-##  Collection of callbacks for GLSL preprocessor
-
-type
+  glsl_include_local_func* = proc (ctx: pointer; header_name: cstring; includer_name: cstring; include_depth: csize_t): ptr glsl_include_result_t
+  glsl_include_system_func* = proc (ctx: pointer; header_name: cstring; includer_name: cstring; include_depth: csize_t): ptr glsl_include_result_t
+  glsl_free_include_result_func* = proc (ctx: pointer; result: ptr glsl_include_result_t): cint
   glsl_include_callbacks_t* {.bycopy.} = object
     include_system*: glsl_include_system_func
     include_local*: glsl_include_local_func
     free_include_result*: glsl_free_include_result_func
-
-
-##  SpvOptions counterpart
-
-type
   glslang_spv_options_t* {.bycopy.} = object
     generate_debug_info*: bool
     strip_debug_info*: bool
@@ -198,7 +183,6 @@
     emit_nonsemantic_shader_debug_info*: bool
     emit_nonsemantic_shader_debug_source*: bool
 
-
 proc glslang_initialize_process*(): cint {.importc.}
 proc glslang_finalize_process*() {.importc.}
 proc glslang_shader_create*(input: ptr glslang_input_t): ptr glslang_shader_t {.importc.}
--- a/src/glslang/glslang_c_shader_types.nim	Wed Dec 14 00:49:35 2022 +0700
+++ b/src/glslang/glslang_c_shader_types.nim	Fri Dec 16 00:05:41 2022 +0700
@@ -1,7 +1,7 @@
+type
 
-type
   # EShLanguage counterpart
-  glslang_stage_t* = enum
+  glslang_stage_t* {.size: sizeof(cint).} = enum
     GLSLANG_STAGE_VERTEX
     GLSLANG_STAGE_TESSCONTROL
     GLSLANG_STAGE_TESSEVALUATION
@@ -19,7 +19,7 @@
     GLSLANG_STAGE_COUNT
 
   # EShLanguageMask counterpart
-  glslang_stage_mask_t* = enum
+  glslang_stage_mask_t* {.size: sizeof(cint).} = enum
     GLSLANG_STAGE_VERTEX_MASK = (1 shl ord(GLSLANG_STAGE_VERTEX))
     GLSLANG_STAGE_TESSCONTROL_MASK = (1 shl ord(GLSLANG_STAGE_TESSCONTROL))
     GLSLANG_STAGE_TESSEVALUATION_MASK = (1 shl ord(GLSLANG_STAGE_TESSEVALUATION))
@@ -37,27 +37,27 @@
     GLSLANG_STAGE_MASK_COUNT
 
   # EShSource counterpart
-  glslang_source_t* = enum
+  glslang_source_t* {.size: sizeof(cint).} = enum
     GLSLANG_SOURCE_NONE
     GLSLANG_SOURCE_GLSL
     GLSLANG_SOURCE_HLSL
     GLSLANG_SOURCE_COUNT
 
   # EShClient counterpart
-  glslang_client_t* = enum
+  glslang_client_t* {.size: sizeof(cint).} = enum
     GLSLANG_CLIENT_NONE
     GLSLANG_CLIENT_VULKAN
     GLSLANG_CLIENT_OPENGL
     GLSLANG_CLIENT_COUNT
 
   # EShTargetLanguage counterpart
-  glslang_target_language_t* = enum
+  glslang_target_language_t* {.size: sizeof(cint).} = enum
     GLSLANG_TARGET_NONE
     GLSLANG_TARGET_SPV
     GLSLANG_TARGET_COUNT
 
   # SH_TARGET_ClientVersion counterpart
-  glslang_target_client_version_t* = enum
+  glslang_target_client_version_t* {.size: sizeof(cint).} = enum
     GLSLANG_TARGET_CLIENT_VERSION_COUNT = 5
     GLSLANG_TARGET_OPENGL_450 = 450
     GLSLANG_TARGET_VULKAN_1_0 = (1 shl 22)
@@ -66,7 +66,7 @@
     GLSLANG_TARGET_VULKAN_1_3 = (1 shl 22) or (3 shl 12)
 
   # SH_TARGET_LanguageVersion counterpart
-  glslang_target_language_version_t* = enum
+  glslang_target_language_version_t* {.size: sizeof(cint).} = enum
       GLSLANG_TARGET_LANGUAGE_VERSION_COUNT = 7
       GLSLANG_TARGET_SPV_1_0 = (1 shl 16)
       GLSLANG_TARGET_SPV_1_1 = (1 shl 16) or (1 shl 8)
@@ -77,14 +77,14 @@
       GLSLANG_TARGET_SPV_1_6 = (1 shl 16) or (6 shl 8)
 
   # EShExecutable counterpart
-  glslang_executable_t* = enum
+  glslang_executable_t* {.size: sizeof(cint).} = enum
     GLSLANG_EX_VERTEX_FRAGMENT
     GLSLANG_EX_FRAGMENT
 
   # EShOptimizationLevel counterpart
   # This enum is not used in the current C interface, but could be added at a later date.
   # GLSLANG_OPT_NONE is the current default.
-  glslang_optimization_level_t* = enum
+  glslang_optimization_level_t* {.size: sizeof(cint).} = enum
     GLSLANG_OPT_NO_GENERATION
     GLSLANG_OPT_NONE
     GLSLANG_OPT_SIMPLE
@@ -92,13 +92,13 @@
     GLSLANG_OPT_LEVEL_COUNT
 
   # EShTextureSamplerTransformMode counterpart
-  glslang_texture_sampler_transform_mode_t* = enum
+  glslang_texture_sampler_transform_mode_t* {.size: sizeof(cint).} = enum
     GLSLANG_TEX_SAMP_TRANS_KEEP
     GLSLANG_TEX_SAMP_TRANS_UPGRADE_TEXTURE_REMOVE_SAMPLER
     GLSLANG_TEX_SAMP_TRANS_COUNT
 
   # EShMessages counterpart
-  glslang_messages_t* = enum
+  glslang_messages_t* {.size: sizeof(cint).} = enum
     GLSLANG_MSG_DEFAULT_BIT = 0
     GLSLANG_MSG_RELAXED_ERRORS_BIT = (1 shl 0)
     GLSLANG_MSG_SUPPRESS_WARNINGS_BIT = (1 shl 1)
@@ -119,7 +119,7 @@
     GLSLANG_MSG_COUNT
 
   # EShReflectionOptions counterpart
-  glslang_reflection_options_t* = enum
+  glslang_reflection_options_t* {.size: sizeof(cint).} = enum
     GLSLANG_REFLECTION_DEFAULT_BIT = 0
     GLSLANG_REFLECTION_STRICT_ARRAY_SUFFIX_BIT = (1 shl 0)
     GLSLANG_REFLECTION_BASIC_ARRAY_SUFFIX_BIT = (1 shl 1)
@@ -133,7 +133,7 @@
     GLSLANG_REFLECTION_COUNT
 
   # EProfile counterpart (from Versions.h)
-  glslang_profile_t* = enum
+  glslang_profile_t* {.size: sizeof(cint).} = enum
     GLSLANG_BAD_PROFILE = 0
     GLSLANG_NO_PROFILE = (1 shl 0)
     GLSLANG_CORE_PROFILE = (1 shl 1)
@@ -142,7 +142,7 @@
     GLSLANG_PROFILE_COUNT
 
   # Shader options
-  glslang_shader_options_t* = enum
+  glslang_shader_options_t* {.size: sizeof(cint).} = enum
     GLSLANG_SHADER_DEFAULT_BIT = 0
     GLSLANG_SHADER_AUTO_MAP_BINDINGS = (1 shl 0)
     GLSLANG_SHADER_AUTO_MAP_LOCATIONS = (1 shl 1)
@@ -150,7 +150,7 @@
     GLSLANG_SHADER_COUNT
 
   # TResourceType counterpart
-  glslang_resource_type_t* = enum
+  glslang_resource_type_t* {.size: sizeof(cint).} = enum
     GLSLANG_RESOURCE_TYPE_SAMPLER
     GLSLANG_RESOURCE_TYPE_TEXTURE
     GLSLANG_RESOURCE_TYPE_IMAGE
@@ -158,3 +158,4 @@
     GLSLANG_RESOURCE_TYPE_SSBO
     GLSLANG_RESOURCE_TYPE_UAV
     GLSLANG_RESOURCE_TYPE_COUNT
+
--- a/src/vulkan.nim	Wed Dec 14 00:49:35 2022 +0700
+++ b/src/vulkan.nim	Fri Dec 16 00:05:41 2022 +0700
@@ -47,6 +47,7 @@
   ANativeWindow = ptr object
   CAMetalLayer = ptr object
   AHardwareBuffer = ptr object
+  VkBool32* = distinct uint32
 
 # Enums
 const
@@ -63,8 +64,8 @@
   VK_REMAINING_ARRAY_LAYERS* = (not 0'u32)
   VK_WHOLE_SIZE* = (not 0'u64)
   VK_ATTACHMENT_UNUSED* = (not 0'u32)
-  VK_TRUE* = 1
-  VK_FALSE* = 0
+  VK_TRUE* = VkBool32(1)
+  VK_FALSE* = VkBool32(0)
   VK_QUEUE_FAMILY_IGNORED* = (not 0'u32)
   VK_QUEUE_FAMILY_EXTERNAL* = (not 0'u32) - 1
   VK_QUEUE_FAMILY_EXTERNAL_KHR* = VK_QUEUE_FAMILY_EXTERNAL
@@ -1226,7 +1227,6 @@
 
 type
   VkSampleMask* = distinct uint32
-  VkBool32* = distinct uint32
   VkFlags* = distinct uint32
   VkDeviceSize* = distinct uint64
   VkDeviceAddress* = distinct uint64
--- a/src/vulkan_helpers.nim	Wed Dec 14 00:49:35 2022 +0700
+++ b/src/vulkan_helpers.nim	Fri Dec 16 00:05:41 2022 +0700
@@ -1,6 +1,9 @@
+import std/tables
 import std/strutils
-import std/enumerate
-import vulkan
+
+import ./glslang/glslang
+import ./vulkan
+
 
 when defined(release):
   const ENABLEVULKANVALIDATIONLAYERS = false
@@ -17,6 +20,7 @@
 proc VK_MAKE_API_VERSION*(variant: uint32, major: uint32, minor: uint32, patch: uint32): uint32 {.compileTime.} =
   (variant shl 29) or (major shl 22) or (minor shl 12) or patch
 
+
 proc getInstanceExtensions*(): seq[string] =
   var extensionCount: uint32
   checkVkResult vkEnumerateInstanceExtensionProperties(nil, addr(extensionCount), nil)
@@ -167,3 +171,24 @@
   )
   checkVkResult vkCreateDevice(physicalDevice, addr(deviceCreateInfo), nil, addr(result[0]))
   vkGetDeviceQueue(result[0], selectedQueueFamily, 0'u32, addr(result[1]));
+
+proc createShaderStage*(device: VkDevice, stage: VkShaderStageFlagBits, shader: string): VkPipelineShaderStageCreateInfo =
+  const VK_GLSL_MAP = {
+    VK_SHADER_STAGE_VERTEX_BIT: GLSLANG_STAGE_VERTEX,
+    VK_SHADER_STAGE_FRAGMENT_BIT: GLSLANG_STAGE_FRAGMENT,
+  }.toTable()
+  var code = compileGLSLToSPIRV(VK_GLSL_MAP[stage], shader, "<memory-shader>")
+  var createInfo = VkShaderModuleCreateInfo(
+    sType: VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
+    codeSize: code.len.uint,
+    pCode: addr(code[0]),
+  )
+  var shaderModule: VkShaderModule
+  checkVkResult vkCreateShaderModule(device, addr(createInfo), nil, addr(shaderModule))
+
+  var vertShaderStageInfo = VkPipelineShaderStageCreateInfo(
+    sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+    stage: stage,
+    module: shaderModule,
+    pName: "main", # entry point for shader
+  )