view src/semicongine/gpu_data.nim @ 650:be6e0f89645a

add: initial code for texture support, not finished, had to completely refactor how to handle material-data (ie scene-wide data, sorry if you ever read this
author Sam <sam@basx.dev>
date Fri, 05 May 2023 23:45:50 +0700
parents f7e7af33e9ee
children 8f2eaf0d2808
line wrap: on
line source

import std/typetraits
import std/strformat
import std/tables

import ./vulkan/api
import ./math

type
  Sampler2DType* = object
  GPUType* = 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] | Sampler2DType
  DataType* = enum
    Float32
    Float64
    Int8
    Int16
    Int32
    Int64
    UInt8
    UInt16
    UInt32
    UInt64
    Vec2I32
    Vec2I64
    Vec3I32
    Vec3I64
    Vec4I32
    Vec4I64
    Vec2U32
    Vec2U64
    Vec3U32
    Vec3U64
    Vec4U32
    Vec4U64
    Vec2F32
    Vec2F64
    Vec3F32
    Vec3F64
    Vec4F32
    Vec4F64
    Mat2F32
    Mat2F64
    Mat23F32
    Mat23F64
    Mat32F32
    Mat32F64
    Mat3F32
    Mat3F64
    Mat34F32
    Mat34F64
    Mat43F32
    Mat43F64
    Mat4F32
    Mat4F64
    Sampler2D
  DataValue* = object
    case thetype*: DataType
    of Float32: float32: float32
    of Float64: float64: float64
    of Int8: int8: int8
    of Int16: int16: int16
    of Int32: int32: int32
    of Int64: int64: int64
    of UInt8: uint8: uint8
    of UInt16: uint16: uint16
    of UInt32: uint32: uint32
    of UInt64: uint64: uint64
    of Vec2I32: vec2i32: TVec2[int32]
    of Vec2I64: vec2i64: TVec2[int64]
    of Vec3I32: vec3i32: TVec3[int32]
    of Vec3I64: vec3i64: TVec3[int64]
    of Vec4I32: vec4i32: TVec4[int32]
    of Vec4I64: vec4i64: TVec4[int64]
    of Vec2U32: vec2u32: TVec2[uint32]
    of Vec2U64: vec2u64: TVec2[uint64]
    of Vec3U32: vec3u32: TVec3[uint32]
    of Vec3U64: vec3u64: TVec3[uint64]
    of Vec4U32: vec4u32: TVec4[uint32]
    of Vec4U64: vec4u64: TVec4[uint64]
    of Vec2F32: vec2f32: TVec2[float32]
    of Vec2F64: vec2f64: TVec2[float64]
    of Vec3F32: vec3f32: TVec3[float32]
    of Vec3F64: vec3f64: TVec3[float64]
    of Vec4F32: vec4f32: TVec4[float32]
    of Vec4F64: vec4f64: TVec4[float64]
    of Mat2F32: mat2f32: TMat2[float32]
    of Mat2F64: mat2f64: TMat2[float64]
    of Mat23F32: mat23f32: TMat23[float32]
    of Mat23F64: mat23f64: TMat23[float64]
    of Mat32F32: mat32f32: TMat32[float32]
    of Mat32F64: mat32f64: TMat32[float64]
    of Mat3F32: mat3f32: TMat3[float32]
    of Mat3F64: mat3f64: TMat3[float64]
    of Mat34F32: mat34f32: TMat34[float32]
    of Mat34F64: mat34f64: TMat34[float64]
    of Mat43F32: mat43f32: TMat43[float32]
    of Mat43F64: mat43f64: TMat43[float64]
    of Mat4F32: mat4f32: TMat4[float32]
    of Mat4F64: mat4f64: TMat4[float64]
    of Sampler2D: discard
  DataList* = object
    len*: uint32
    case thetype*: DataType
    of Float32: float32: seq[float32]
    of Float64: float64: seq[float64]
    of Int8: int8: seq[int8]
    of Int16: int16: seq[int16]
    of Int32: int32: seq[int32]
    of Int64: int64: seq[int64]
    of UInt8: uint8: seq[uint8]
    of UInt16: uint16: seq[uint16]
    of UInt32: uint32: seq[uint32]
    of UInt64: uint64: seq[uint64]
    of Vec2I32: vec2i32: seq[TVec2[int32]]
    of Vec2I64: vec2i64: seq[TVec2[int64]]
    of Vec3I32: vec3i32: seq[TVec3[int32]]
    of Vec3I64: vec3i64: seq[TVec3[int64]]
    of Vec4I32: vec4i32: seq[TVec4[int32]]
    of Vec4I64: vec4i64: seq[TVec4[int64]]
    of Vec2U32: vec2u32: seq[TVec2[uint32]]
    of Vec2U64: vec2u64: seq[TVec2[uint64]]
    of Vec3U32: vec3u32: seq[TVec3[uint32]]
    of Vec3U64: vec3u64: seq[TVec3[uint64]]
    of Vec4U32: vec4u32: seq[TVec4[uint32]]
    of Vec4U64: vec4u64: seq[TVec4[uint64]]
    of Vec2F32: vec2f32: seq[TVec2[float32]]
    of Vec2F64: vec2f64: seq[TVec2[float64]]
    of Vec3F32: vec3f32: seq[TVec3[float32]]
    of Vec3F64: vec3f64: seq[TVec3[float64]]
    of Vec4F32: vec4f32: seq[TVec4[float32]]
    of Vec4F64: vec4f64: seq[TVec4[float64]]
    of Mat2F32: mat2f32: seq[TMat2[float32]]
    of Mat2F64: mat2f64: seq[TMat2[float64]]
    of Mat23F32: mat23f32: seq[TMat23[float32]]
    of Mat23F64: mat23f64: seq[TMat23[float64]]
    of Mat32F32: mat32f32: seq[TMat32[float32]]
    of Mat32F64: mat32f64: seq[TMat32[float64]]
    of Mat3F32: mat3f32: seq[TMat3[float32]]
    of Mat3F64: mat3f64: seq[TMat3[float64]]
    of Mat34F32: mat34f32: seq[TMat34[float32]]
    of Mat34F64: mat34f64: seq[TMat34[float64]]
    of Mat43F32: mat43f32: seq[TMat43[float32]]
    of Mat43F64: mat43f64: seq[TMat43[float64]]
    of Mat4F32: mat4f32*: seq[TMat4[float32]]
    of Mat4F64: mat4f64: seq[TMat4[float64]]
    of Sampler2D: discard
  MemoryPerformanceHint* = enum
    PreferFastRead, PreferFastWrite
  ShaderAttribute* = object
    name*: string
    thetype*: DataType
    perInstance*: bool
    memoryPerformanceHint*: MemoryPerformanceHint

func vertexInputs*(attributes: seq[ShaderAttribute]): seq[ShaderAttribute] =
  for attr in attributes:
    if attr.perInstance == false:
      result.add attr

func instanceInputs*(attributes: seq[ShaderAttribute]): seq[ShaderAttribute] =
  for attr in attributes:
    if attr.perInstance == false:
      result.add attr

func numberOfVertexInputAttributeDescriptors*(thetype: DataType): uint32 =
  case thetype:
    of Mat2F32, Mat2F64, Mat23F32, Mat23F64: 2
    of Mat32F32, Mat32F64, Mat3F32, Mat3F64, Mat34F32, Mat34F64: 3
    of Mat43F32, Mat43F64, Mat4F32, Mat4F64: 4
    else: 1

func size*(thetype: DataType): uint32 =
  case thetype:
    of Float32: 4
    of Float64: 8
    of Int8: 1
    of Int16: 2
    of Int32: 4
    of Int64: 8
    of UInt8: 1
    of UInt16: 2
    of UInt32: 4
    of UInt64: 8
    of Vec2I32: 8
    of Vec2I64: 16
    of Vec3I32: 12
    of Vec3I64: 24
    of Vec4I32: 16
    of Vec4I64: 32
    of Vec2U32: 8
    of Vec2U64: 16
    of Vec3U32: 12
    of Vec3U64: 24
    of Vec4U32: 16
    of Vec4U64: 32
    of Vec2F32: 8
    of Vec2F64: 16
    of Vec3F32: 12
    of Vec3F64: 24
    of Vec4F32: 16
    of Vec4F64: 32
    of Mat2F32: 16
    of Mat2F64: 32
    of Mat23F32: 24
    of Mat23F64: 48
    of Mat32F32: 24
    of Mat32F64: 48
    of Mat3F32: 36
    of Mat3F64: 72
    of Mat34F32: 48
    of Mat34F64: 92
    of Mat43F32: 48
    of Mat43F64: 92
    of Mat4F32: 64
    of Mat4F64: 128
    of Sampler2D: 0

func size*(attribute: ShaderAttribute, perDescriptor=false): uint32 =
  if perDescriptor: attribute.thetype.size div attribute.thetype.numberOfVertexInputAttributeDescriptors
  else:      attribute.thetype.size

func size*(thetype: seq[ShaderAttribute]): uint32 =
  for attribute in thetype:
    result += attribute.size

func size*(value: DataValue): uint32 =
  value.thetype.size

func size*(value: DataList): uint32 =
  value.thetype.size * value.len

func getDataType*[T: GPUType|int|uint|float](): DataType =
  when T is float32: Float32
  elif T is float64: Float64
  elif T is int8: Int8
  elif T is int16: Int16
  elif T is int32: Int32
  elif T is int64: Int64
  elif T is uint8: UInt8
  elif T is uint16: UInt16
  elif T is uint32: UInt32
  elif T is uint64: UInt64
  elif T is int and sizeof(int) == sizeof(int64): Int64
  elif T is int and sizeof(int) == sizeof(int32): Int32
  elif T is uint and sizeof(uint) == sizeof(uint64): UInt64
  elif T is uint and sizeof(uint) == sizeof(uint32): UInt32
  elif T is float and sizeof(float) == sizeof(float32): Float32
  elif T is float and sizeof(float) == sizeof(float64): Float64
  elif T is TVec2[int32]: Vec2I32
  elif T is TVec2[int64]: Vec2I64
  elif T is TVec3[int32]: Vec3I32
  elif T is TVec3[int64]: Vec3I64
  elif T is TVec4[int32]: Vec4I32
  elif T is TVec4[int64]: Vec4I64
  elif T is TVec2[uint32]: Vec2U32
  elif T is TVec2[uint64]: Vec2U64
  elif T is TVec3[uint32]: Vec3U32
  elif T is TVec3[uint64]: Vec3U64
  elif T is TVec4[uint32]: Vec4U32
  elif T is TVec4[uint64]: Vec4U64
  elif T is TVec2[float32]: Vec2F32
  elif T is TVec2[float64]: Vec2F64
  elif T is TVec3[float32]: Vec3F32
  elif T is TVec3[float64]: Vec3F64
  elif T is TVec4[float32]: Vec4F32
  elif T is TVec4[float64]: Vec4F64
  elif T is TMat2[float32]: Mat2F32
  elif T is TMat2[float64]: Mat2F64
  elif T is TMat23[float32]: Mat23F32
  elif T is TMat23[float64]: Mat23F64
  elif T is TMat32[float32]: Mat32F32
  elif T is TMat32[float64]: Mat32F64
  elif T is TMat3[float32]: Mat3F32
  elif T is TMat3[float64]: Mat3F64
  elif T is TMat34[float32]: Mat34F32
  elif T is TMat34[float64]: Mat34F64
  elif T is TMat43[float32]: Mat43F32
  elif T is TMat43[float64]: Mat43F64
  elif T is TMat4[float32]: Mat4F32
  elif T is TMat4[float64]: Mat4F64
  elif T is Sampler2DType: Sampler2D
  else:
    static:
      raise newException(Exception, &"Unsupported data type for GPU data: {name(T)}" )

func attr*[T: GPUType](
  name: string,
  perInstance=false,
  memoryPerformanceHint=PreferFastRead,
): auto =
  ShaderAttribute(
    name: name,
    thetype: getDataType[T](),
    perInstance: perInstance,
    memoryPerformanceHint: memoryPerformanceHint,
  )

func get*[T: GPUType|int|uint|float](value: DataValue): T =
  when T is float32: value.float32
  elif T is float64: value.float64
  elif T is int8: value.int8
  elif T is int16: value.int16
  elif T is int32: value.int32
  elif T is int64: value.int64
  elif T is uint8: value.uint8
  elif T is uint16: value.uint16
  elif T is uint32: value.uint32
  elif T is uint64: value.uint64
  elif T is int and sizeof(int) == sizeof(int32): value.int32
  elif T is int and sizeof(int) == sizeof(int64): value.int64
  elif T is uint and sizeof(uint) == sizeof(uint32): value.uint32
  elif T is uint and sizeof(uint) == sizeof(uint64): value.uint64
  elif T is float and sizeof(float) == sizeof(float32): value.float32
  elif T is float and sizeof(float) == sizeof(float64): value.float64
  elif T is TVec2[int32]: value.vec2i32
  elif T is TVec2[int64]: value.vec2i64
  elif T is TVec3[int32]: value.vec3i32
  elif T is TVec3[int64]: value.vec3i64
  elif T is TVec4[int32]: value.vec4i32
  elif T is TVec4[int64]: value.vec4i64
  elif T is TVec2[uint32]: value.vec2u32
  elif T is TVec2[uint64]: value.vec2u64
  elif T is TVec3[uint32]: value.vec3u32
  elif T is TVec3[uint64]: value.vec3u64
  elif T is TVec4[uint32]: value.vec4u32
  elif T is TVec4[uint64]: value.vec4u64
  elif T is TVec2[float32]: value.vec2f32
  elif T is TVec2[float64]: value.vec2f64
  elif T is TVec3[float32]: value.vec3f32
  elif T is TVec3[float64]: value.vec3f64
  elif T is TVec4[float32]: value.vec4f32
  elif T is TVec4[float64]: value.vec4f64
  elif T is TMat2[float32]: value.mat2f32
  elif T is TMat2[float64]: value.mat2f64
  elif T is TMat23[float32]: value.mat23f
  elif T is TMat23[float64]: value.mat23f64
  elif T is TMat32[float32]: value.mat32f32
  elif T is TMat32[float64]: value.mat32f64
  elif T is TMat3[float32]: value.mat3f32
  elif T is TMat3[float64]: value.mat3f64
  elif T is TMat34[float32]: value.mat34f32
  elif T is TMat34[float64]: value.mat34f64
  elif T is TMat43[float32]: value.mat43f32
  elif T is TMat43[float64]: value.mat43f64
  elif T is TMat4[float32]: value.mat4f32
  elif T is TMat4[float64]: value.mat4f64
  else: {.error: "Virtual datatype has no value" .}

func get*[T: GPUType|int|uint|float](value: DataList): seq[T] =
  when T is float32: value.float32
  elif T is float64: value.float64
  elif T is int8: value.int8
  elif T is int16: value.int16
  elif T is int32: value.int32
  elif T is int64: value.int64
  elif T is uint8: value.uint8
  elif T is uint16: value.uint16
  elif T is uint32: value.uint32
  elif T is uint64: value.uint64
  elif T is int and sizeof(int) == sizeof(int32): value.int32
  elif T is int and sizeof(int) == sizeof(int64): value.int64
  elif T is uint and sizeof(uint) == sizeof(uint32): value.uint32
  elif T is uint and sizeof(uint) == sizeof(uint64): value.uint64
  elif T is float and sizeof(float) == sizeof(float32): value.float32
  elif T is float and sizeof(float) == sizeof(float64): value.float64
  elif T is TVec2[int32]: value.vec2i32
  elif T is TVec2[int64]: value.vec2i64
  elif T is TVec3[int32]: value.vec3i32
  elif T is TVec3[int64]: value.vec3i64
  elif T is TVec4[int32]: value.vec4i32
  elif T is TVec4[int64]: value.vec4i64
  elif T is TVec2[uint32]: value.vec2u32
  elif T is TVec2[uint64]: value.vec2u64
  elif T is TVec3[uint32]: value.vec3u32
  elif T is TVec3[uint64]: value.vec3u64
  elif T is TVec4[uint32]: value.vec4u32
  elif T is TVec4[uint64]: value.vec4u64
  elif T is TVec2[float32]: value.vec2f32
  elif T is TVec2[float64]: value.vec2f64
  elif T is TVec3[float32]: value.vec3f32
  elif T is TVec3[float64]: value.vec3f64
  elif T is TVec4[float32]: value.vec4f32
  elif T is TVec4[float64]: value.vec4f64
  elif T is TMat2[float32]: value.mat2f32
  elif T is TMat2[float64]: value.mat2f64
  elif T is TMat23[float32]: value.mat23f
  elif T is TMat23[float64]: value.mat23f64
  elif T is TMat32[float32]: value.mat32f32
  elif T is TMat32[float64]: value.mat32f64
  elif T is TMat3[float32]: value.mat3f32
  elif T is TMat3[float64]: value.mat3f64
  elif T is TMat34[float32]: value.mat34f32
  elif T is TMat34[float64]: value.mat34f64
  elif T is TMat43[float32]: value.mat43f32
  elif T is TMat43[float64]: value.mat43f64
  elif T is TMat4[float32]: value.mat4f32
  elif T is TMat4[float64]: value.mat4f64
  else: {. error: "Virtual datatype has no values" .}

func getRawData*(value: var DataValue): (pointer, uint32) =
  result[1] = value.thetype.size
  case value.thetype
    of Float32: result[0] = addr value.float32
    of Float64: result[0] = addr value.float64
    of Int8: result[0] = addr value.int8
    of Int16: result[0] = addr value.int16
    of Int32: result[0] = addr value.int32
    of Int64: result[0] = addr value.int64
    of UInt8: result[0] = addr value.uint8
    of UInt16: result[0] = addr value.uint16
    of UInt32: result[0] = addr value.uint32
    of UInt64: result[0] = addr value.uint64
    of Vec2I32: result[0] = addr value.vec2i32
    of Vec2I64: result[0] = addr value.vec2i64
    of Vec3I32: result[0] = addr value.vec3i32
    of Vec3I64: result[0] = addr value.vec3i64
    of Vec4I32: result[0] = addr value.vec4i32
    of Vec4I64: result[0] = addr value.vec4i64
    of Vec2U32: result[0] = addr value.vec2u32
    of Vec2U64: result[0] = addr value.vec2u64
    of Vec3U32: result[0] = addr value.vec3u32
    of Vec3U64: result[0] = addr value.vec3u64
    of Vec4U32: result[0] = addr value.vec4u32
    of Vec4U64: result[0] = addr value.vec4u64
    of Vec2F32: result[0] = addr value.vec2f32
    of Vec2F64: result[0] = addr value.vec2f64
    of Vec3F32: result[0] = addr value.vec3f32
    of Vec3F64: result[0] = addr value.vec3f64
    of Vec4F32: result[0] = addr value.vec4f32
    of Vec4F64: result[0] = addr value.vec4f64
    of Mat2F32: result[0] = addr value.mat2f32
    of Mat2F64: result[0] = addr value.mat2f64
    of Mat23F32: result[0] = addr value.mat23f32
    of Mat23F64: result[0] = addr value.mat23f64
    of Mat32F32: result[0] = addr value.mat32f32
    of Mat32F64: result[0] = addr value.mat32f64
    of Mat3F32: result[0] = addr value.mat3f32
    of Mat3F64: result[0] = addr value.mat3f64
    of Mat34F32: result[0] = addr value.mat34f32
    of Mat34F64: result[0] = addr value.mat34f64
    of Mat43F32: result[0] = addr value.mat43f32
    of Mat43F64: result[0] = addr value.mat43f64
    of Mat4F32: result[0] = addr value.mat4f32
    of Mat4F64: result[0] = addr value.mat4f64
    of Sampler2D: result[0] = nil

func getRawData*(value: var DataList): (pointer, uint32) =
  result[1] = value.thetype.size * value.len
  case value.thetype
    of Float32: result[0] = addr value.float32[0]
    of Float64: result[0] = addr value.float64[0]
    of Int8: result[0] = addr value.int8[0]
    of Int16: result[0] = addr value.int16[0]
    of Int32: result[0] = addr value.int32[0]
    of Int64: result[0] = addr value.int64[0]
    of UInt8: result[0] = addr value.uint8[0]
    of UInt16: result[0] = addr value.uint16[0]
    of UInt32: result[0] = addr value.uint32[0]
    of UInt64: result[0] = addr value.uint64[0]
    of Vec2I32: result[0] = addr value.vec2i32[0]
    of Vec2I64: result[0] = addr value.vec2i64[0]
    of Vec3I32: result[0] = addr value.vec3i32[0]
    of Vec3I64: result[0] = addr value.vec3i64[0]
    of Vec4I32: result[0] = addr value.vec4i32[0]
    of Vec4I64: result[0] = addr value.vec4i64[0]
    of Vec2U32: result[0] = addr value.vec2u32[0]
    of Vec2U64: result[0] = addr value.vec2u64[0]
    of Vec3U32: result[0] = addr value.vec3u32[0]
    of Vec3U64: result[0] = addr value.vec3u64[0]
    of Vec4U32: result[0] = addr value.vec4u32[0]
    of Vec4U64: result[0] = addr value.vec4u64[0]
    of Vec2F32: result[0] = addr value.vec2f32[0]
    of Vec2F64: result[0] = addr value.vec2f64[0]
    of Vec3F32: result[0] = addr value.vec3f32[0]
    of Vec3F64: result[0] = addr value.vec3f64[0]
    of Vec4F32: result[0] = addr value.vec4f32[0]
    of Vec4F64: result[0] = addr value.vec4f64[0]
    of Mat2F32: result[0] = addr value.mat2f32[0]
    of Mat2F64: result[0] = addr value.mat2f64[0]
    of Mat23F32: result[0] = addr value.mat23f32[0]
    of Mat23F64: result[0] = addr value.mat23f64[0]
    of Mat32F32: result[0] = addr value.mat32f32[0]
    of Mat32F64: result[0] = addr value.mat32f64[0]
    of Mat3F32: result[0] = addr value.mat3f32[0]
    of Mat3F64: result[0] = addr value.mat3f64[0]
    of Mat34F32: result[0] = addr value.mat34f32[0]
    of Mat34F64: result[0] = addr value.mat34f64[0]
    of Mat43F32: result[0] = addr value.mat43f32[0]
    of Mat43F64: result[0] = addr value.mat43f64[0]
    of Mat4F32: result[0] = addr value.mat4f32[0]
    of Mat4F64: result[0] = addr value.mat4f64[0]
    of Sampler2D: result[0] = nil

func initData*(value: var DataList, len: uint32) =
  value.len = len
  case value.thetype
    of Float32: value.float32.setLen(len)
    of Float64: value.float64.setLen(len)
    of Int8: value.int8.setLen(len)
    of Int16: value.int16.setLen(len)
    of Int32: value.int32.setLen(len)
    of Int64: value.int64.setLen(len)
    of UInt8: value.uint8.setLen(len)
    of UInt16: value.uint16.setLen(len)
    of UInt32: value.uint32.setLen(len)
    of UInt64: value.uint64.setLen(len)
    of Vec2I32: value.vec2i32.setLen(len)
    of Vec2I64: value.vec2i64.setLen(len)
    of Vec3I32: value.vec3i32.setLen(len)
    of Vec3I64: value.vec3i64.setLen(len)
    of Vec4I32: value.vec4i32.setLen(len)
    of Vec4I64: value.vec4i64.setLen(len)
    of Vec2U32: value.vec2u32.setLen(len)
    of Vec2U64: value.vec2u64.setLen(len)
    of Vec3U32: value.vec3u32.setLen(len)
    of Vec3U64: value.vec3u64.setLen(len)
    of Vec4U32: value.vec4u32.setLen(len)
    of Vec4U64: value.vec4u64.setLen(len)
    of Vec2F32: value.vec2f32.setLen(len)
    of Vec2F64: value.vec2f64.setLen(len)
    of Vec3F32: value.vec3f32.setLen(len)
    of Vec3F64: value.vec3f64.setLen(len)
    of Vec4F32: value.vec4f32.setLen(len)
    of Vec4F64: value.vec4f64.setLen(len)
    of Mat2F32: value.mat2f32.setLen(len)
    of Mat2F64: value.mat2f64.setLen(len)
    of Mat23F32: value.mat23f32.setLen(len)
    of Mat23F64: value.mat23f64.setLen(len)
    of Mat32F32: value.mat32f32.setLen(len)
    of Mat32F64: value.mat32f64.setLen(len)
    of Mat3F32: value.mat3f32.setLen(len)
    of Mat3F64: value.mat3f64.setLen(len)
    of Mat34F32: value.mat34f32.setLen(len)
    of Mat34F64: value.mat34f64.setLen(len)
    of Mat43F32: value.mat43f32.setLen(len)
    of Mat43F64: value.mat43f64.setLen(len)
    of Mat4F32: value.mat4f32.setLen(len)
    of Mat4F64: value.mat4f64.setLen(len)
    of Sampler2D: discard

func setValue*[T: GPUType|int|uint|float](value: var DataValue, data: T) =
  when T is float32: value.float32 = data
  elif T is float64: value.float64 = data
  elif T is int8: value.int8 = data
  elif T is int16: value.int16 = data
  elif T is int32: value.int32 = data
  elif T is int64: value.int64 = data
  elif T is uint8: value.uint8 = data
  elif T is uint16: value.uint16 = data
  elif T is uint32: value.uint32 = data
  elif T is uint64: value.uint64 = data
  elif T is int and sizeof(int) == sizeof(int32): value.int32 = data
  elif T is int and sizeof(int) == sizeof(int64): value.int64 = data
  elif T is uint and sizeof(uint) == sizeof(uint32): value.uint32 = data
  elif T is uint and sizeof(uint) == sizeof(uint64): value.uint64 = data
  elif T is float and sizeof(float) == sizeof(float32): value.float32 = data
  elif T is float and sizeof(float) == sizeof(float64): value.float64 = data
  elif T is TVec2[int32]: value.vec2i32 = data
  elif T is TVec2[int64]: value.vec2i64 = data
  elif T is TVec3[int32]: value.vec3i32 = data
  elif T is TVec3[int64]: value.vec3i64 = data
  elif T is TVec4[int32]: value.vec4i32 = data
  elif T is TVec4[int64]: value.vec4i64 = data
  elif T is TVec2[uint32]: value.vec2u32 = data
  elif T is TVec2[uint64]: value.vec2u64 = data
  elif T is TVec3[uint32]: value.vec3u32 = data
  elif T is TVec3[uint64]: value.vec3u64 = data
  elif T is TVec4[uint32]: value.vec4u32 = data
  elif T is TVec4[uint64]: value.vec4u64 = data
  elif T is TVec2[float32]: value.vec2f32 = data
  elif T is TVec2[float64]: value.vec2f64 = data
  elif T is TVec3[float32]: value.vec3f32 = data
  elif T is TVec3[float64]: value.vec3f64 = data
  elif T is TVec4[float32]: value.vec4f32 = data
  elif T is TVec4[float64]: value.vec4f64 = data
  elif T is TMat2[float32]: value.mat2f32 = data
  elif T is TMat2[float64]: value.mat2f64 = data
  elif T is TMat23[float32]: value.mat23f32 = data
  elif T is TMat23[float64]: value.mat23f64 = data
  elif T is TMat32[float32]: value.mat32f32 = data
  elif T is TMat32[float64]: value.mat32f64 = data
  elif T is TMat3[float32]: value.mat3f32 = data
  elif T is TMat3[float64]: value.mat3f64 = data
  elif T is TMat34[float32]: value.mat34f32 = data
  elif T is TMat34[float64]: value.mat34f64 = data
  elif T is TMat43[float32]: value.mat43f32 = data
  elif T is TMat43[float64]: value.mat43f64 = data
  elif T is TMat4[float32]: value.mat4f32 = data
  elif T is TMat4[float64]: value.mat4f64 = data
  else: {.error: "Virtual datatype has no value" .}

func setValues*[T: GPUType|int|uint|float](value: var DataList, data: seq[T]) =
  value.len = uint32(data.len)
  when T is float32: value.float32 = data
  elif T is float64: value.float64 = data
  elif T is int8: value.int8 = data
  elif T is int16: value.int16 = data
  elif T is int32: value.int32 = data
  elif T is int64: value.int64 = data
  elif T is uint8: value.uint8 = data
  elif T is uint16: value.uint16 = data
  elif T is uint32: value.uint32 = data
  elif T is uint64: value.uint64 = data
  elif T is int and sizeof(int) == sizeof(int32): value.int32 = data
  elif T is int and sizeof(int) == sizeof(int64): value.int64 = data
  elif T is uint and sizeof(uint) == sizeof(uint32): value.uint32 = data
  elif T is uint and sizeof(uint) == sizeof(uint64): value.uint64 = data
  elif T is float and sizeof(float) == sizeof(float32): value.float32 = data
  elif T is float and sizeof(float) == sizeof(float64): value.float64 = data
  elif T is TVec2[int32]: value.vec2i32 = data
  elif T is TVec2[int64]: value.vec2i64 = data
  elif T is TVec3[int32]: value.vec3i32 = data
  elif T is TVec3[int64]: value.vec3i64 = data
  elif T is TVec4[int32]: value.vec4i32 = data
  elif T is TVec4[int64]: value.vec4i64 = data
  elif T is TVec2[uint32]: value.vec2u32 = data
  elif T is TVec2[uint64]: value.vec2u64 = data
  elif T is TVec3[uint32]: value.vec3u32 = data
  elif T is TVec3[uint64]: value.vec3u64 = data
  elif T is TVec4[uint32]: value.vec4u32 = data
  elif T is TVec4[uint64]: value.vec4u64 = data
  elif T is TVec2[float32]: value.vec2f32 = data
  elif T is TVec2[float64]: value.vec2f64 = data
  elif T is TVec3[float32]: value.vec3f32 = data
  elif T is TVec3[float64]: value.vec3f64 = data
  elif T is TVec4[float32]: value.vec4f32 = data
  elif T is TVec4[float64]: value.vec4f64 = data
  elif T is TMat2[float32]: value.mat2f32 = data
  elif T is TMat2[float64]: value.mat2f64 = data
  elif T is TMat23[float32]: value.mat23f32 = data
  elif T is TMat23[float64]: value.mat23f64 = data
  elif T is TMat32[float32]: value.mat32f32 = data
  elif T is TMat32[float64]: value.mat32f64 = data
  elif T is TMat3[float32]: value.mat3f32 = data
  elif T is TMat3[float64]: value.mat3f64 = data
  elif T is TMat34[float32]: value.mat34f32 = data
  elif T is TMat34[float64]: value.mat34f64 = data
  elif T is TMat43[float32]: value.mat43f32 = data
  elif T is TMat43[float64]: value.mat43f64 = data
  elif T is TMat4[float32]: value.mat4f32 = data
  elif T is TMat4[float64]: value.mat4f64 = data
  else: {. error: "Virtual datatype has no values" .}

func setValue*[T: GPUType|int|uint|float](value: var DataList, i: uint32, data: T) =
  assert i < value.len
  when T is float32: value.float32[i] = data
  elif T is float64: value.float64[i] = data
  elif T is int8: value.int8[i] = data
  elif T is int16: value.int16[i] = data
  elif T is int32: value.int32[i] = data
  elif T is int64: value.int64[i] = data
  elif T is uint8: value.uint8[i] = data
  elif T is uint16: value.uint16[i] = data
  elif T is uint32: value.uint32[i] = data
  elif T is uint64: value.uint64[i] = data
  elif T is int and sizeof(int) == sizeof(int32): value.int32[i] = data
  elif T is int and sizeof(int) == sizeof(int64): value.int64[i] = data
  elif T is uint and sizeof(uint) == sizeof(uint32): value.uint32[i] = data
  elif T is uint and sizeof(uint) == sizeof(uint64): value.uint64[i] = data
  elif T is float and sizeof(float) == sizeof(float32): value.float32[i] = data
  elif T is float and sizeof(float) == sizeof(float64): value.float64[i] = data
  elif T is TVec2[int32]: value.vec2i32[i] = data
  elif T is TVec2[int64]: value.vec2i64[i] = data
  elif T is TVec3[int32]: value.vec3i32[i] = data
  elif T is TVec3[int64]: value.vec3i64[i] = data
  elif T is TVec4[int32]: value.vec4i32[i] = data
  elif T is TVec4[int64]: value.vec4i64[i] = data
  elif T is TVec2[uint32]: value.vec2u32[i] = data
  elif T is TVec2[uint64]: value.vec2u64[i] = data
  elif T is TVec3[uint32]: value.vec3u32[i] = data
  elif T is TVec3[uint64]: value.vec3u64[i] = data
  elif T is TVec4[uint32]: value.vec4u32[i] = data
  elif T is TVec4[uint64]: value.vec4u64[i] = data
  elif T is TVec2[float32]: value.vec2f32[i] = data
  elif T is TVec2[float64]: value.vec2f64[i] = data
  elif T is TVec3[float32]: value.vec3f32[i] = data
  elif T is TVec3[float64]: value.vec3f64[i] = data
  elif T is TVec4[float32]: value.vec4f32[i] = data
  elif T is TVec4[float64]: value.vec4f64[i] = data
  elif T is TMat2[float32]: value.mat2f32[i] = data
  elif T is TMat2[float64]: value.mat2f64[i] = data
  elif T is TMat23[float32]: value.mat23f32[i] = data
  elif T is TMat23[float64]: value.mat23f64[i] = data
  elif T is TMat32[float32]: value.mat32f32[i] = data
  elif T is TMat32[float64]: value.mat32f64[i] = data
  elif T is TMat3[float32]: value.mat3f32[i] = data
  elif T is TMat3[float64]: value.mat3f64[i] = data
  elif T is TMat34[float32]: value.mat34f32[i] = data
  elif T is TMat34[float64]: value.mat34f64[i] = data
  elif T is TMat43[float32]: value.mat43f32[i] = data
  elif T is TMat43[float64]: value.mat43f64[i] = data
  elif T is TMat4[float32]: value.mat4f32[i] = data
  elif T is TMat4[float64]: value.mat4f64[i] = data
  else: {. error: "Virtual datatype has no values" .}

const TYPEMAP = {
    Float32: VK_FORMAT_R32_SFLOAT,
    Float64: VK_FORMAT_R64_SFLOAT,
    Int8: VK_FORMAT_R8_SINT,
    Int16: VK_FORMAT_R16_SINT,
    Int32: VK_FORMAT_R32_SINT,
    Int64: VK_FORMAT_R64_SINT,
    UInt8: VK_FORMAT_R8_UINT,
    UInt16: VK_FORMAT_R16_UINT,
    UInt32: VK_FORMAT_R32_UINT,
    UInt64: VK_FORMAT_R64_UINT,
    Vec2I32: VK_FORMAT_R32G32_SINT,
    Vec2I64: VK_FORMAT_R64G64_SINT,
    Vec3I32: VK_FORMAT_R32G32B32_SINT,
    Vec3I64: VK_FORMAT_R64G64B64_SINT,
    Vec4I32: VK_FORMAT_R32G32B32A32_SINT,
    Vec4I64: VK_FORMAT_R64G64B64A64_SINT,
    Vec2U32: VK_FORMAT_R32G32_UINT,
    Vec2U64: VK_FORMAT_R64G64_UINT,
    Vec3U32: VK_FORMAT_R32G32B32_UINT,
    Vec3U64: VK_FORMAT_R64G64B64_UINT,
    Vec4U32: VK_FORMAT_R32G32B32A32_UINT,
    Vec4U64: VK_FORMAT_R64G64B64A64_UINT,
    Vec2F32: VK_FORMAT_R32G32_SFLOAT,
    Vec2F64: VK_FORMAT_R64G64_SFLOAT,
    Vec3F32: VK_FORMAT_R32G32B32_SFLOAT,
    Vec3F64: VK_FORMAT_R64G64B64_SFLOAT,
    Vec4F32: VK_FORMAT_R32G32B32A32_SFLOAT,
    Vec4F64: VK_FORMAT_R64G64B64A64_SFLOAT,
    Mat2F32: VK_FORMAT_R32G32_SFLOAT,
    Mat2F64: VK_FORMAT_R64G64_SFLOAT,
    Mat23F32: VK_FORMAT_R32G32B32_SFLOAT,
    Mat23F64: VK_FORMAT_R64G64B64_SFLOAT,
    Mat32F32: VK_FORMAT_R32G32_SFLOAT,
    Mat32F64: VK_FORMAT_R64G64_SFLOAT,
    Mat3F32: VK_FORMAT_R32G32B32_SFLOAT,
    Mat3F64: VK_FORMAT_R64G64B64_SFLOAT,
    Mat34F32: VK_FORMAT_R32G32B32A32_SFLOAT,
    Mat34F64: VK_FORMAT_R64G64B64A64_SFLOAT,
    Mat43F32: VK_FORMAT_R32G32B32_SFLOAT,
    Mat43F64: VK_FORMAT_R64G64B64_SFLOAT,
    Mat4F32: VK_FORMAT_R32G32B32A32_SFLOAT,
    Mat4F64: VK_FORMAT_R64G64B64A64_SFLOAT,
}.toTable

func getVkFormat*(thetype: DataType): VkFormat =
  TYPEMAP[thetype]

# from https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap15.html
func nLocationSlots*(thetype: DataType): uint32 =
  #[
  single location:
    16-bit scalar and vector types, and
    32-bit scalar and vector types, and
    64-bit scalar and 2-component vector types.
  two locations
    64-bit three- and four-component vectors
  ]#
  case thetype:
    of Float32: 1
    of Float64: 1
    of Int8: 1
    of Int16: 1
    of Int32: 1
    of Int64: 1
    of UInt8: 1
    of UInt16: 1
    of UInt32: 1
    of UInt64: 1
    of Vec2I32: 1
    of Vec2I64: 1
    of Vec3I32: 1
    of Vec3I64: 2
    of Vec4I32: 1
    of Vec4I64: 2
    of Vec2U32: 1
    of Vec2U64: 1
    of Vec3U32: 1
    of Vec3U64: 2
    of Vec4U32: 1
    of Vec4U64: 2
    of Vec2F32: 1
    of Vec2F64: 1
    of Vec3F32: 1
    of Vec3F64: 2
    of Vec4F32: 1
    of Vec4F64: 2
    of Mat2F32: 1
    of Mat2F64: 1
    of Mat23F32: 1
    of Mat23F64: 2
    of Mat32F32: 1
    of Mat32F64: 1
    of Mat3F32: 1
    of Mat3F64: 2
    of Mat34F32: 1
    of Mat34F64: 2
    of Mat43F32: 1
    of Mat43F64: 2
    of Mat4F32: 1
    of Mat4F64: 2
    of Sampler2D: 1

func glslType*(thetype: DataType): string =
  # 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..
  case thetype:
    of Float32: "float"
    of Float64: "double"
    of Int8, Int16, Int32, Int64: "int"
    of UInt8, UInt16, UInt32, UInt64: "uint"
    of Vec2I32: "ivec2"
    of Vec2I64: "ivec2"
    of Vec3I32: "ivec3"
    of Vec3I64: "ivec3"
    of Vec4I32: "ivec4"
    of Vec4I64: "ivec4"
    of Vec2U32: "uvec2"
    of Vec2U64: "uvec2"
    of Vec3U32: "uvec3"
    of Vec3U64: "uvec3"
    of Vec4U32: "uvec4"
    of Vec4U64: "uvec4"
    of Vec2F32: "vec2"
    of Vec2F64: "dvec2"
    of Vec3F32: "vec3"
    of Vec3F64: "dvec3"
    of Vec4F32: "vec4"
    of Vec4F64: "dvec4"
    of Mat2F32: "mat2"
    of Mat2F64: "dmat2"
    of Mat23F32: "mat23"
    of Mat23F64: "dmat23"
    of Mat32F32: "mat32"
    of Mat32F64: "dmat32"
    of Mat3F32: "mat3"
    of Mat3F64: "dmat3"
    of Mat34F32: "mat34"
    of Mat34F64: "dmat34"
    of Mat43F32: "mat43"
    of Mat43F64: "dmat43"
    of Mat4F32: "mat4"
    of Mat4F64: "dmat4"
    of Sampler2D: "sampler2D"

func glslInput*(group: seq[ShaderAttribute]): seq[string] =
  if group.len == 0:
    return @[]
  var i = 0'u32
  for attribute in group:
      result.add &"layout(location = {i}) in {attribute.thetype.glslType} {attribute.name};"
      for j in 0 ..< attribute.thetype.numberOfVertexInputAttributeDescriptors:
        i += attribute.thetype.nLocationSlots

func glslUniforms*(group: seq[ShaderAttribute], blockName="Uniforms", binding: int): seq[string] =
  if group.len == 0:
    return @[]
  # currently only a single uniform block supported, therefore binding = 0
  result.add(&"layout(binding = {binding}) uniform T{blockName} {{")
  for attribute in group:
    result.add(&"    {attribute.thetype.glslType} {attribute.name};")
  result.add(&"}} {blockName};")

func glslSamplers*(group: seq[ShaderAttribute], basebinding: int): seq[string] =
  if group.len == 0:
    return @[]
  var thebinding = basebinding
  for attribute in group:
    result.add(&"layout(binding = {thebinding}) uniform {attribute.thetype.glslType} {attribute.name};")
    inc thebinding

func glslOutput*(group: seq[ShaderAttribute]): seq[string] =
  if group.len == 0:
    return @[]
  var i = 0'u32
  for attribute in group:
    result.add &"layout(location = {i}) out {attribute.thetype.glslType} {attribute.name};"
    i += 1