changeset 1176:511c9f7cd1da compiletime-tests

sync to notebook in bedroom
author sam <sam@basx.dev>
date Sat, 29 Jun 2024 21:04:04 +0700
parents a94732d98cc6
children 4ef959278451
files static_utils.nim
diffstat 1 files changed, 242 insertions(+), 58 deletions(-) [+]
line wrap: on
line diff
--- a/static_utils.nim	Sat Jun 29 11:13:35 2024 +0700
+++ b/static_utils.nim	Sat Jun 29 21:04:04 2024 +0700
@@ -21,6 +21,7 @@
 template ShaderOutput* {.pragma.}
 
 const INFLIGHTFRAMES = 2'u32
+
 type
   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]
   ShaderObject*[TShader] = object
@@ -125,9 +126,10 @@
         let `isinstancename` {.inject.} = hasCustomPragma(value, InstanceAttribute)
         body
 
-template ForDescriptorFields*(inputData: typed, typename, countname, bindingNumber, body: untyped): untyped =
+template ForDescriptorFields*(inputData: typed, fieldname, typename, countname, bindingNumber, body: untyped): untyped =
   var `bindingNumber` {.inject.} = 1'u32
   for theFieldname, value in fieldPairs(inputData):
+    let `fieldname` {.inject.} = theFieldname
     when typeof(value) is Texture:
       block:
         let `typename` {.inject.} = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
@@ -195,9 +197,31 @@
 type
   IndexType = enum
     None, UInt8, UInt16, UInt32
-  RenderBuffers = object
-    deviceBuffers: seq[Buffer]      # for fast reads
-    hostVisibleBuffers: seq[Buffer] # for fast writes
+
+  IndirectGPUMemory = object
+    vk: VkDeviceMemory
+    size: uint64
+  DirectGPUMemory = object
+    vk: VkDeviceMemory
+    size: uint64
+    data: pointer
+  GPUMemory = IndirectGPUMemory | DirectGPUMemory
+
+  Buffer[TMemory: GPUMemory] = object
+    vk: VkBuffer
+    memory*: TMemory
+    offset: uint64
+    size: uint64
+
+  GPUArray[T: SupportedGPUType, TMemory: GPUMemory] = object
+    data: seq[T]
+    buffer: Buffer[TMemory]
+    offset: uint64
+  GPUValue[T: object|array, TMemory: GPUMemory] = object
+    data: T
+    buffer: Buffer[TMemory]
+    offset: uint64
+
   Renderable[TMesh, TInstance] = object
     vertexBuffers: seq[VkBuffer]
     bufferOffsets: seq[VkDeviceSize]
@@ -209,10 +233,19 @@
         indexBuffer: VkBuffer
         indexCount: uint32
         indexBufferOffset: VkDeviceSize
+
   Pipeline[TShader] = object
     pipeline: VkPipeline
     layout: VkPipelineLayout
-    descriptorSets: array[INFLIGHTFRAMES.int, VkDescriptorSet]
+    descriptorSetLayout: VkDescriptorSetLayout
+  RenderData = object
+    descriptorPool: VkDescriptorPool
+    indirectMemory: seq[IndirectGPUMemory]
+    nextFreeIndirectMemoryOffset: seq[uint64]
+    indirectBuffers: seq[Buffer[IndirectGPUMemory]]
+    directMemory: seq[DirectGPUMemory]
+    nextFreeDirectMemoryOffset: seq[uint64]
+    directBuffers: seq[Buffer[DirectGPUMemory]]
 
 converter toVkIndexType(indexType: IndexType): VkIndexType =
   case indexType:
@@ -424,15 +457,11 @@
   polygonMode: VkPolygonMode = VK_POLYGON_MODE_FILL,
   cullMode: VkCullModeFlagBits = VK_CULL_MODE_BACK_BIT,
   frontFace: VkFrontFace = VK_FRONT_FACE_CLOCKWISE,
+  descriptorPoolLimit = 1024
 ): Pipeline[TShader] =
-  # assumptions/limitations:
-  # - we are only using vertex and fragment shaders (2 stages)
-  # - we only support one subpass
-  # = we only support one Uniform-Block
-
   # create pipeline
   var layoutbindings: seq[VkDescriptorSetLayoutBinding]
-  ForDescriptorFields(default(TShader), descriptorType, descriptorCount, descriptorBindingNumber):
+  ForDescriptorFields(default(TShader), fieldName, descriptorType, descriptorCount, descriptorBindingNumber):
     layoutbindings.add VkDescriptorSetLayoutBinding(
       binding: descriptorBindingNumber,
       descriptorType: descriptorType,
@@ -445,12 +474,12 @@
     bindingCount: uint32(layoutbindings.len),
     pBindings: layoutbindings.ToCPointer
   )
-  var descriptorSetLayout: VkDescriptorSetLayout
-  checkVkResult vkCreateDescriptorSetLayout(device, addr(layoutCreateInfo), nil, addr(descriptorSetLayout))
+  result.descriptorSetLayout: VkDescriptorSetLayout
+  checkVkResult vkCreateDescriptorSetLayout(device, addr(layoutCreateInfo), nil, addr(result.descriptorSetLayout))
   let pipelineLayoutInfo = VkPipelineLayoutCreateInfo(
     sType: VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
     setLayoutCount: 1,
-    pSetLayouts: addr(descriptorSetLayout),
+    pSetLayouts: addr(result.descriptorSetLayout),
     # pushConstantRangeCount: uint32(pushConstants.len),
       # pPushConstantRanges: pushConstants.ToCPointer,
   )
@@ -582,37 +611,108 @@
     addr(result.pipeline)
   )
 
-  # create descriptors, one per frame-in-flight
-  let nSamplers = 0'u32
-  let nUniformBuffers = 0'u32
+proc AllocateIndirectMemory(device: VkDevice, pDevice: VkPhysicalDevice, allocationSize: uint64): IndirectGPUMemory =
+  # chooses biggest memory type that has NOT VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
+  result.size = allocationSize
+
+  # find a good memory type
+  var physicalProperties: VkPhysicalDeviceMemoryProperties
+  vkGetPhysicalDeviceMemoryProperties(pDevice, addr physicalProperties)
+
+  var biggestHeap: uint64 = -1
+  var memoryTypeIndex = -1
+  # try to find non-host-visible type
+  for i in 0 ..< physicalProperties.memoryTypeCount:
+    if VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT not in toEnums(physicalProperties.memoryTypes[i].propertyFlags)
+      let size = physicalProperties.memoryHeaps[physicalProperties.memoryTypes[i].heapIndex].size
+      if size > biggestHeap:
+        biggest = size
+        memoryTypeIndex = i
+
+  # If we did not found a device-only memory type, let's just take the biggest overall
+  if memoryTypeIndex < 0:
+    for i in 0 ..< physicalProperties.memoryTypeCount:
+        let size = physicalProperties.memoryHeaps[physicalProperties.memoryTypes[i].heapIndex].size
+        if size > biggestHeap:
+          biggest = size
+          memoryTypeIndex = i
+
+  assert memoryTypeIndex >= 0, "Unable to find indirect memory type"
+  var allocationInfo = VkMemoryAllocateInfo(
+    sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+    allocationSize: initialAllocationSize,
+    memoryTypeIndex: memoryTypeIndex,
+  )
+  checkVkResult vkAllocateMemory(
+    device,
+    addr allocationInfo,
+    nil,
+    addr result.vk
+  )
+
+proc AllocateDirectMemory(device: VkDevice, allocationSize: uint64): DirectGPUMemory =
+  result.size = allocationSize
+
+  # find a good memory type
+  var physicalProperties: VkPhysicalDeviceMemoryProperties
+  vkGetPhysicalDeviceMemoryProperties(pDevice, addr physicalProperties)
 
-  if nSamplers + nUniformBuffers > 0:
-    var poolSizes: seq[VkDescriptorPoolSize]
-    if nUniformBuffers > 0:
-      poolSizes.add VkDescriptorPoolSize(thetype: VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, descriptorCount: nSamplers * INFLIGHTFRAMES)
-    if nSamplers > 0:
-      poolSizes.add VkDescriptorPoolSize(thetype: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: nUniformBuffers * INFLIGHTFRAMES)
-    var poolInfo = VkDescriptorPoolCreateInfo(
-      sType: VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
-      poolSizeCount: uint32(poolSizes.len),
-      pPoolSizes: poolSizes.ToCPointer,
-      maxSets: (nUniformBuffers + nSamplers) * INFLIGHTFRAMES * 2, # good formula? no idea...
-    )
-    var pool: VkDescriptorPool
-    checkVkResult vkCreateDescriptorPool(device, addr(poolInfo), nil, addr(pool))
+  var biggestHeap: uint64 = -1
+  var memoryTypeIndex = -1
+  # try to find host-visible type
+  for i in 0 ..< physicalProperties.memoryTypeCount:
+    if VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT in toEnums(physicalProperties.memoryTypes[i].propertyFlags)
+      let size = physicalProperties.memoryHeaps[physicalProperties.memoryTypes[i].heapIndex].size
+      if size > biggestHeap:
+        biggest = size
+        memoryTypeIndex = i
 
-    var layouts = newSeqWith(result.descriptorSets.len, descriptorSetLayout)
-    var allocInfo = VkDescriptorSetAllocateInfo(
-      sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
-      descriptorPool: pool,
-      descriptorSetCount: uint32(layouts.len),
-      pSetLayouts: layouts.ToCPointer,
-    )
-    checkVkResult vkAllocateDescriptorSets(device, addr(allocInfo), result.descriptorSets.ToCPointer)
+  assert memoryTypeIndex >= 0, "Unable to find direct (aka host-visible) memory type"
+  var allocationInfo = VkMemoryAllocateInfo(
+    sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+    allocationSize: initialAllocationSize,
+    memoryTypeIndex: memoryTypeIndex,
+  )
+  checkVkResult vkAllocateMemory(
+    device,
+    addr allocationInfo,
+    nil,
+    addr result.vk
+  )
+  checkVkResult result.device.vk.vkMapMemory(
+    memory = result.vk,
+    offset = 0'u64,
+    size = result.size,
+    flags = VkMemoryMapFlags(0),
+    ppData = addr(result.data)
+  )
+
+proc InitRenderData(device: VkDevice, descriptorPoolLimit = 1024): RenderData =
+  # allocate descriptor pools
+  var poolSizes = [
+    VkDescriptorPoolSize(thetype: VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, descriptorCount: descriptorPoolLimit)
+    VkDescriptorPoolSize(thetype: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: descriptorPoolLimit)
+  ]
+  var poolInfo = VkDescriptorPoolCreateInfo(
+    sType: VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
+    poolSizeCount: poolSizes.len.uint32,
+    pPoolSizes: poolSizes.ToCPointer,
+    maxSets: descriptorPoolLimit,
+  )
+  checkVkResult vkCreateDescriptorPool(device, addr(poolInfo), nil, addr(result.descriptorPool))
+
+  # allocate some memory
+  var initialAllocationSize: 1_000_000_000 # TODO: make this more dynamic or something
+  result.indirectMemory = @[AllocateIndirectMemory(device, size=initialAllocationSize)]
+  result.nextFreeIndirectMemoryOffset = @[0'u64]
+  result.directMemory = @[AllocateDirectMemory(device, size=initialAllocationSize)]
+  result.nextFreeDirectMemoryOffset = @[0'u64]
 
 proc WriteDescriptors[TShader](device: VkDevice, pipeline: Pipeline[TShader]) =
   var descriptorSetWrites: seq[VkWriteDescriptorSet]
-  ForDescriptorFields(default(TShader), descriptorType, descriptorCount, descriptorBindingNumber):
+  # map (buffer + offset + range) to descriptor
+  # map (texture) to descriptor
+  ForDescriptorFields(default(TShader), fieldName, descriptorType, descriptorCount, descriptorBindingNumber):
     for frameInFlight in 0 ..< pipeline.descriptorSets.len:
       if descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
         # TODO
@@ -653,7 +753,6 @@
 proc CreateRenderable[TMesh, TInstance](
   mesh: TMesh,
   instance: TInstance,
-  buffers: RenderBuffers,
 ): Renderable[TMesh, TInstance] =
   result.indexType = None
 
@@ -676,23 +775,31 @@
   # assert normal fields of TMesh|Globals == normal fields of TShaderDescriptors
   for inputName, inputValue in default(TShader).fieldPairs:
     var foundField = false
+
+    # Vertex input data
     when hasCustomPragma(inputValue, VertexAttribute):
       assert typeof(inputValue) is SupportedGPUType
       for meshName, meshValue in default(TMesh).fieldPairs:
         when meshName == inputName:
+          assert meshValue is GPUArray, "Mesh attribute '" & meshName & "' must be of type 'GPUArray' but is of type " & tt.name(typeof(meshValue))
           assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once"
-          assert elementType(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(elementType(meshValue)) & "'"
+          assert elementType(meshValue.data) is typeof(inputValue), "Shader input " & tt.name(TShader) & "." & inputName & " is of type '" & tt.name(typeof(inputValue)) & "' but mesh attribute is of type '" & tt.name(elementType(meshValue.data)) & "'"
           foundField = true
       assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TMesh) & "'"
+
+    # Instance input data
     elif hasCustomPragma(inputValue, InstanceAttribute):
       assert typeof(inputValue) is SupportedGPUType
       for instanceName, instanceValue in default(TInstance).fieldPairs:
         when instanceName == inputName:
+          assert instanceValue is GPUArray, "Instance attribute '" & instanceName & "' must be of type 'GPUArray' but is of type " & tt.name(typeof(instanceName))
           assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once"
-          assert elementType(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(elementType(instanceValue)) & "'"
+          assert elementType(instanceValue.data) is typeof(inputValue), "Shader input " & tt.name(TShader) & "." & inputName & " is of type '" & tt.name(typeof(inputValue)) & "' but instance attribute is of type '" & tt.name(elementType(instanceValue.data)) & "'"
           foundField = true
       assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TInstance) & "'"
-    elif typeof(inputValue) is Texture or typeof(inputValue) is object:
+
+    # Texture
+    elif typeof(inputValue) is Texture:
       for meshName, meshValue in default(TMesh).fieldPairs:
         when meshName == inputName:
           assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once"
@@ -704,8 +811,28 @@
           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)) & "'"
           foundField = true
       assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TMesh) & "|" & tt.name(TGlobals) & "'"
+
+    # Uniform block
+    elif typeof(inputValue) is object:
+      for meshName, meshValue in default(TMesh).fieldPairs:
+        when meshName == inputName:
+          assert meshValue is GPUValue, "Mesh attribute '" & meshName & "' must be of type 'GPUValue' but is of type " & tt.name(typeof(meshValue))
+          assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once"
+          assert typeof(meshValue.data) is typeof(inputValue), "Shader input " & tt.name(TShader) & "." & inputName & " is of type '" & tt.name(typeof(inputValue)) & "' but mesh attribute is of type '" & tt.name(elementType(meshValue.data)) & "'"
+          foundField = true
+      for globalName, globalValue in default(TGlobals).fieldPairs:
+        when globalName == inputName:
+          assert globalValue is GPUValue, "global attribute '" & globalName & "' must be of type 'GPUValue' but is of type " & tt.name(typeof(globalValue))
+          assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once"
+          assert typeof(globalValue.data) 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.data)) & "'"
+          foundField = true
+      assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TMesh) & "|" & tt.name(TGlobals) & "'"
+
+    # array
     elif typeof(inputValue) is array:
-      when (elementType(inputValue) is Texture or elementType(inputValue) is object):
+
+      # texture-array
+      when elementType(inputValue) is Texture:
         for meshName, meshValue in default(TMesh).fieldPairs:
           when meshName == inputName:
             assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once"
@@ -718,6 +845,22 @@
             foundField = true
         assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TMesh) & "|" & tt.name(TGlobals) & "'"
 
+      # uniform-block array
+      elif elementType(inputValue) is object:
+        for meshName, meshValue in default(TMesh).fieldPairs:
+          when meshName == inputName:
+            assert meshValue is GPUValue, "Mesh attribute '" & meshName & "' must be of type 'GPUValue' but is of type " & tt.name(typeof(meshValue))
+            assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once"
+            assert typeof(meshValue.data) is typeof(inputValue), "Shader input " & tt.name(TShader) & "." & inputName & " is of type '" & tt.name(typeof(inputValue)) & "' but mesh attribute is of type '" & tt.name(elementType(meshValue.data)) & "'"
+            foundField = true
+        for globalName, globalValue in default(TGlobals).fieldPairs:
+          when globalName == inputName:
+            assert globalValue is GPUValue, "global attribute '" & globalName & "' must be of type 'GPUValue' but is of type " & tt.name(typeof(globalValue))
+            assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once"
+            assert typeof(globalValue.data) 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.data)) & "'"
+            foundField = true
+        assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TMesh) & "|" & tt.name(TGlobals) & "'"
+
 
 proc Render[TShader, TMesh, TInstance, TGlobals](
   pipeline: Pipeline[TShader],
@@ -768,28 +911,29 @@
     ShaderSettings = object
       brightness: float32
     MeshA = object
-      position: seq[Vec3f]
-      transparency: float
-      material: array[3, MaterialA]
-      materialTextures: array[3, Texture]
+      position: GPUArray[Vec3f, IndirectGPUMemory]
     InstanceA = object
-      transform: seq[Mat4]
-      position: seq[Vec3f]
-    Globals = object
+      rotation: GPUArray[Vec4f, IndirectGPUMemory]
+      objPosition: GPUArray[Vec3f, IndirectGPUMemory]
+    UniformsA = object
+      materials: GPUValue[array[3, MaterialA], IndirectGPUMemory]
+      materialTextures: array[3, Texture]
+    GlobalsA = object
       fontAtlas: Texture
-      settings: ShaderSettings
+      settings: GPUValue[ShaderSettings, IndirectGPUMemory]
 
     ShaderA = object
       # vertex input
       position {.VertexAttribute.}: Vec3f
-      transform {.InstanceAttribute.}: Mat4
+      objPosition {.InstanceAttribute.}: Vec3f
+      rotation {.InstanceAttribute.}: Vec4f
       # intermediate
       test {.Pass.}: float32
       test1 {.PassFlat.}: Vec3f
       # output
       color {.ShaderOutput.}: Vec4f
       # uniforms
-      material: array[3, MaterialA]
+      materials: array[3, MaterialA]
       settings: ShaderSettings
       # textures
       fontAtlas: Texture
@@ -806,7 +950,6 @@
     layers = @["VK_LAYER_KHRONOS_validation"],
   )
 
-
   let selectedPhysicalDevice = i.GetPhysicalDevices().FilterBestGraphics()
   let dev = i.CreateDevice(
     selectedPhysicalDevice,
@@ -816,8 +959,26 @@
   let frameWidth = 100'u32
   let frameHeight = 100'u32
 
-  var myRenderable: Renderable[MeshA, InstanceA]
-  var myGlobals: Globals
+  var myMesh1 = MeshA(
+    position: GPUArray[Vec3f, IndirectGPUMemory](data: @[NewVec3f(0, 0, ), NewVec3f(0, 0, ), NewVec3f(0, 0, )]),
+  )
+  var uniforms1 = UniformsA(
+    materials: GPUValue[array[3, MaterialA], IndirectGPUMemory](data: [
+      MaterialA(reflection: 0, baseColor: NewVec3f(1, 0, 0)),
+      MaterialA(reflection: 0.1, baseColor: NewVec3f(0, 1, 0)),
+      MaterialA(reflection: 0.5, baseColor: NewVec3f(0, 0, 1)),
+    ]),
+    materialTextures: [
+      Texture(isGrayscale: false, colorImage: Image[RGBAPixel](width: 1, height: 1, imagedata: @[[255'u8, 0'u8, 0'u8, 255'u8]])),
+      Texture(isGrayscale: false, colorImage: Image[RGBAPixel](width: 1, height: 1, imagedata: @[[0'u8, 255'u8, 0'u8, 255'u8]])),
+      Texture(isGrayscale: false, colorImage: Image[RGBAPixel](width: 1, height: 1, imagedata: @[[0'u8, 0'u8, 255'u8, 255'u8]])),
+    ]
+  )
+  var instances1 = InstanceA(
+    rotation: GPUArray[Vec4f, IndirectGPUMemory](data: @[NewVec4f(1, 0, 0, 0.1), NewVec4f(0, 1, 0, 0.1)]),
+    objPosition: GPUArray[Vec3f, IndirectGPUMemory](data: @[NewVec3f(0, 0, 0), NewVec3f(1, 1, 1)]),
+  )
+  var myGlobals: GlobalsA
 
   # setup for rendering (TODO: swapchain & framebuffers)
 
@@ -829,7 +990,30 @@
   let shaderObject = dev.vk.CompileShader(shader)
   var pipeline1 = CreatePipeline(dev.vk, renderPass = renderpass, shaderObject)
 
+  var renderdata = InitRenderData(dev.vk)
+
+  # create descriptor sets
+  var descriptorSets: array[INFLIGHTFRAMES.int, VkDescriptorSet]
+  var layouts = newSeqWith(descriptorSets.len, pipeline.descriptorSetLayout)
+  var allocInfo = VkDescriptorSetAllocateInfo(
+    sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
+    descriptorPool: pool,
+    descriptorSetCount: uint32(layouts.len),
+    pSetLayouts: layouts.ToCPointer,
+  )
+  checkVkResult vkAllocateDescriptorSets(device, addr(allocInfo), descriptorSets.ToCPointer)
+
+
+  #[
   # TODO: probably here: allocate renderables, uniform buffers & textures
+  let meshBuffers: seq[(bool, uint64)] = GetBufferSizes[MeshA](item = myMesh1)
+  let instanceBuffers: seq[(bool, uint64)] = GetBufferSizes[InstanceA](item = instances1)
+  let globalBuffers: seq[(bool, uint64)] = GetBufferSizes[Globals](item = myGlobals)
+  var myRenderable = CreateRenderable()
+  UploadTextures[MeshA]()
+  UploadTextures[Globals]()
+  ]#
+  var myRenderable: Renderable[MeshA, InstanceA]
 
   # descriptors
   WriteDescriptors(dev.vk, pipeline1)