{.experimental: "codeReordering".}
import vulkan
, vkTypes
, vulkan_utils
, ../utils/[lets
]
, bitops
type
Buffer_Object = object of RootObj
device_memory*: VkDeviceMemory
vk_buffer*: VkBuffer
size*: VkDeviceSize
data*: ptr char
current_data_offset*: Natural
Buffer* = ref object of Buffer_Object
#[
Buffer& result
, VkDevice device
, const VkPhysicalDeviceMemoryProperties& memoryProperties
, size_t size
, VkBufferUsageFlags usage
, VkMemoryPropertyFlags memoryFlags
]#
proc a_vulkan_buffer*( vk_device: VkDevice
, gpu_memory_properties: VkPhysicalDeviceMemoryProperties
, buffer_usage_flags: VkBufferUsageFlags
, memory_flags: VkMemoryPropertyFlags
, allocation_size: VkDeviceSize
): Buffer =
result = Buffer( size: allocation_size
)
var
mem_reqs: VkMemoryRequirements
buffer_info = VkBufferCreateInfo( sType: VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO
, size: allocation_size
)
allocation_info = VkMemoryAllocateInfo(sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO
)
memory_allocation_flag_info =
VkMemoryAllocateFlagsInfo( sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR
)
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
)
if bitand( buffer_usage_flags.int
, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT.ord
) == 1:
allocation_info.pNext = addr memory_allocation_flag_info
memory_allocation_flag_info.flags = VkMemoryAllocateFlags VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT
memory_allocation_flag_info.deviceMask = 1
discard vkAllocateMemory( vk_device
, addr allocation_info
, nil
, addr result.device_memory
)
discard vkBindBufferMemory( vk_device
, result.vk_buffer
, result.device_memory
, VkDeviceSize 0
)
if bitand( memory_flags.int
, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT.ord
) == 1:
assert vkMapMemory( vk_device
, result.device_memory
, VkDeviceSize 0
, allocation_size
, VkMemoryMapFlags 0
, cast[ptr pointer] (result.data)
) == VK_SUCCESS
#[ result.descriptor.buffer = result.vk_buffer
result.descriptor.offset = VkDeviceSize 0
result.descriptor.range = VkDeviceSize VK_WHOLE_SIZE
]#
return result
#[ proc fillDescr*( buffer: Buffer
, size: VkDeviceSize = VkDeviceSize VK_WHOLE_SIZE
, offset: VkDeviceSize = vk0
) =
buffer.descriptor.offset = offset
buffer.descriptor.buffer = buffer.vkbuffer
buffer.descriptor.range = size ]#
# Map a memory range of this buffer. If successful, mapped points to the specified buffer range.
# @param size (Optional) Size of the memory range to map. Pass VK_WHOLE_SIZE to map the complete buffer range.
# @param offset (Optional) Byte offset from beginning
proc map_memory*( vk_device: VkDevice
, memory: VkDeviceMemory
, data: var pointer
, size: VkDeviceSize = vkWholeSize
, offset: VkDeviceSize = vk0
) =
discard vkMapMemory( vk_device
, memory
, vk0
, size
, VkMemoryMapFlags 0
, addr data
)
# vkUnmapMemory can't fail (?)
proc unMapMem*( buffer: var Buffer
, data: var pointer
) =
if not data.isNil: data = nil
# # Copies the specified data to the mapped buffer
# # @param data Pointer to the data to copy
# # @param size Size of the data to copy in machine units
# proc copyTo*( data: pointer
# , buffer: Buffer
# , size: Natural
# ) =
# assert not buffer.mapped.isNil
# copyMem(data, addr buffer.mapped, size)
proc aVkMappedMemoryRange*( memory: VkDeviceMemory
, offset: VkDeviceSize
, size: VkDeviceSize
, pNext: pointer = nil
, sType: VkStructureType = VkStructureTypeMappedMemoryRange
): VkMappedMemoryRange =
result.sType = sType
result.memory = memory
result.offset = offset
result.pNext = pNext
result.size = size
# flush a memory range of the buffer to make it visible to VkDevice
# Only required for non-coherent memory (?)
proc flushMem*( vk_device: VkDevice
, buffer: Buffer
, data: pointer
, offset: VkDeviceSize
, size: VkDeviceSize
) =
var r = aVkMappedMemoryRange( memory = buffer.device_memory
, offset = offset
, size = size
)
discard vkFlushMappedMemoryRanges(vk_device, 1.uint32, addr r)
# Invalidates a memory range of the buffer
# to make it visible to the host
# Only required for non-coherent memory (?)
proc invalidate*( vk_device: VkDevice
, buffer: Buffer
, size: VkDeviceSize
, offset: VkDeviceSize
) =
var r = aVkMappedMemoryRange( memory = buffer.device_memory
, offset = offset
, size = size
)
discard vkInvalidateMappedMemoryRanges(vk_device, 1, addr r)
# Release all Vulkan resources held by this buffer
proc destroy*( vk_device: VkDevice
, buffer: var Buffer
) =
vkDestroyBuffer(vk_device, buffer.vkbuffer, nil)
vkFreeMemory(vk_device, buffer.device_memory, nil)
#[ proc fill_descriptor*( buffer: var Buffer
, size: VkDeviceSize = VkDeviceSize VK_WHOLE_SIZE
, offset: VkDeviceSize = vk0
) =
buffer.descriptor.offset = offset
buffer.descriptor.buffer = buffer.vkbuffer
buffer.descriptor.range = size ]#
proc create_command_buffers*( device: VkDevice
, pool: VkCommandPool
, level: VkCommandBufferLevel = VK_COMMAND_BUFFER_LEVEL_PRIMARY
, amount: uint32 = 2
): seq[VkCommandBuffer] =
result.setLen amount
var allocInfo = VkCommandBufferAllocateInfo( sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO
, commandPool: pool
, level: level
, commandBufferCount: amount
)
discard vkAllocateCommandBuffers( device
, addr allocInfo
, addr result[0]
)