import vulkan 
, vulkan_utils
type 
 Uniform_Buffer_Object = object of RootObj
  device_memory*: VkDeviceMemory
  vk_buffer*: VkBuffer
  # The descriptor set stores the resources bound to the binding points in a shader
  # It connects the binding points of the different shaders with the buffers and images used for those bindings
  descriptor_buffer_info*: VkDescriptorBufferInfo
  descriptor_set*: VkDescriptorSet
  # We keep a pointer to the mapped buffer, so we can easily update it's contents via a memcpy
  data*: pointer
 
 Uniform_Buffer* = ref object of Uniform_Buffer_Object

proc a_uniform_buffer*( vk_device: VkDevice
                     , gpu_memory_properties: VkPhysicalDeviceMemoryProperties
                     , buffer_usage_flags: VkBufferUsageFlags
                     , memory_flags: VkMemoryPropertyFlags
                     , allocation_size: VkDeviceSize
                     ): Uniform_Buffer = 

 result = Uniform_Buffer()

 var
  allocation_info = VkMemoryAllocateInfo(sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO)
  memory_allocation_flag_info = VkMemoryAllocateFlagsInfo(sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR)
  mem_reqs: VkMemoryRequirements
  buffer_info = VkBufferCreateInfo( sType: VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO
                                  , pNext: nil 
                                  , size: allocation_size
                                  , usage: VkBufferUsageFlags VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT 
                                  )
  
 assert vkCreateBuffer( vk_device
                      , addr buffer_info
                      , nil
                      , addr result.vk_buffer
                      ) == VK_SUCCESS

 vkGetBufferMemoryRequirements( vk_device
                              , result.vk_buffer
                              , addr mem_reqs
                              )
 
 allocation_info.allocationSize = mem_reqs.size
 allocation_info.memoryTypeIndex = gpu_memory_properties.find_memory_with_property( mem_reqs.memoryTypeBits
                                                          , memory_flags
                                                          )

 discard vkAllocateMemory( vk_device
                         , addr allocation_info
                         , nil
                         , addr result.device_memory
                         )
 
 discard vkBindBufferMemory( vk_device
                           , result.vk_buffer
                           , result.device_memory
                           , VkDeviceSize 0
                           )
 
 assert vkMapMemory( vk_device 
             , result.device_memory 
             , VkDeviceSize 0
             , allocation_size
             , VkMemoryMapFlags 0
             , addr result.data
             ) ==  VK_SUCCESS
 
 return result