@ -109,8 +109,7 @@ typedef struct MeshStruct {
typedef struct GraphicsPipelineInfoStruct {
typedef struct GraphicsPipelineInfoStruct {
VkDescriptorSetLayout scene_layout ;
VkDescriptorSetLayout scene_layout ;
VkDescriptorSetLayoutBinding * descriptor_bindings ;
VkDescriptorSetLayoutCreateInfo descriptor_info ;
uint32_t descriptor_bindings_count ;
uint32_t input_bindings_count ;
uint32_t input_bindings_count ;
VkVertexInputBindingDescription * input_bindings ;
VkVertexInputBindingDescription * input_bindings ;
@ -426,6 +425,7 @@ VkResult get_best_physical_device(VkInstance instance, VkPhysicalDevice* device)
VkPhysicalDeviceProperties properties ;
VkPhysicalDeviceProperties properties ;
vkGetPhysicalDeviceProperties ( devices [ i ] , & properties ) ;
vkGetPhysicalDeviceProperties ( devices [ i ] , & properties ) ;
fprintf ( stderr , " %d \n " , properties . limits . maxPerStageResources ) ;
VkPhysicalDeviceFeatures features ;
VkPhysicalDeviceFeatures features ;
vkGetPhysicalDeviceFeatures ( devices [ i ] , & features ) ;
vkGetPhysicalDeviceFeatures ( devices [ i ] , & features ) ;
@ -580,7 +580,7 @@ VkResult create_instance(VkInstance* instance) {
VkResult result = vkCreateInstance ( & instance_info , 0 , instance ) ;
VkResult result = vkCreateInstance ( & instance_info , 0 , instance ) ;
if ( result ! = VK_SUCCESS ) {
if ( result ! = VK_SUCCESS ) {
fprintf ( stderr , " vkCreateInstance: 0x%02x\n " , result ) ;
fprintf ( stderr , " vkCreateInstance: %s\n " , string_VkResult ( result ) ) ;
return result ;
return result ;
}
}
@ -635,6 +635,7 @@ VkResult create_logical_device(VkPhysicalDevice physical_device, QueueIndices qu
. descriptorBindingVariableDescriptorCount = VK_TRUE ,
. descriptorBindingVariableDescriptorCount = VK_TRUE ,
. descriptorBindingUniformBufferUpdateAfterBind = VK_TRUE ,
. descriptorBindingUniformBufferUpdateAfterBind = VK_TRUE ,
. descriptorBindingStorageBufferUpdateAfterBind = VK_TRUE ,
. descriptorBindingStorageBufferUpdateAfterBind = VK_TRUE ,
. descriptorBindingSampledImageUpdateAfterBind = VK_TRUE ,
} ;
} ;
VkPhysicalDeviceFeatures device_features = {
VkPhysicalDeviceFeatures device_features = {
@ -1586,34 +1587,28 @@ VkResult create_graphics_pipeline(
out - > max_frames_in_flight = max_frames_in_flight ;
out - > max_frames_in_flight = max_frames_in_flight ;
VkDescriptorSetLayoutCreateInfo descriptor_layout_info = {
VkResult result = vkCreateDescriptorSetLayout ( device , & pipeline_info . descriptor_info , 0 , & out - > descriptors_layout ) ;
. sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO ,
. bindingCount = pipeline_info . descriptor_bindings_count ,
. pBindings = pipeline_info . descriptor_bindings ,
} ;
VkResult result = vkCreateDescriptorSetLayout ( device , & descriptor_layout_info , 0 , & out - > descriptors_layout ) ;
if ( result ! = VK_SUCCESS ) {
if ( result ! = VK_SUCCESS ) {
return result ;
return result ;
}
}
if ( pipeline_info . descriptor_ bindings_c ount > 0 ) {
if ( pipeline_info . descriptor_info . bindingCount > 0 ) {
VkDescriptorPoolSize * pool_sizes = malloc ( sizeof ( VkDescriptorPool ) * ( 1 + pipeline_info . descriptor_ bindings_c ount) ) ;
VkDescriptorPoolSize * pool_sizes = malloc ( sizeof ( VkDescriptorPool ) * ( 1 + pipeline_info . descriptor_info . bindingCount ) ) ;
if ( pool_sizes = = 0 ) {
if ( pool_sizes = = 0 ) {
return VK_ERROR_OUT_OF_HOST_MEMORY ;
return VK_ERROR_OUT_OF_HOST_MEMORY ;
}
}
for ( uint32_t i = 0 ; i < pipeline_info . descriptor_ bindings_c ount; i + + ) {
for ( uint32_t i = 0 ; i < pipeline_info . descriptor_ info. bindingC ount; i + + ) {
VkDescriptorPoolSize pool_size = {
VkDescriptorPoolSize pool_size = {
. type = pipeline_info . descriptor_ b indings[ i ] . descriptorType ,
. type = pipeline_info . descriptor_ info. pB indings[ i ] . descriptorType ,
. descriptorCount = pipeline_info . descriptor_ b indings[ i ] . descriptorCount * max_frames_in_flight ,
. descriptorCount = pipeline_info . descriptor_ info. pB indings[ i ] . descriptorCount * max_frames_in_flight ,
} ;
} ;
pool_sizes [ i ] = pool_size ;
pool_sizes [ i ] = pool_size ;
}
}
VkDescriptorPoolCreateInfo pool_info = {
VkDescriptorPoolCreateInfo pool_info = {
. sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO ,
. sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO ,
. poolSizeCount = pipeline_info . descriptor_ bindings_c ount,
. poolSizeCount = pipeline_info . descriptor_ info. bindingC ount,
. maxSets = max_frames_in_flight ,
. maxSets = max_frames_in_flight ,
. pPoolSizes = pool_sizes ,
. pPoolSizes = pool_sizes ,
. flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT ,
. flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT ,
@ -1816,7 +1811,7 @@ VkResult create_graphics_pipeline(
return VK_SUCCESS ;
return VK_SUCCESS ;
}
}
VkResult create_simple_mesh_pipeline ( VkDevice device , Vk PhysicalDeviceMemoryProperties memories , Vk Extent2D extent , VkRenderPass render_pass , VkDescriptorSetLayout scene_layout , uint32_t max_frames_in_flight , GraphicsPipeline * out ) {
VkResult create_simple_mesh_pipeline ( VkDevice device , Vk Extent2D extent , VkRenderPass render_pass , VkDescriptorSetLayout scene_layout , uint32_t max_frames_in_flight , GraphicsPipeline * out ) {
if ( out = = NULL ) {
if ( out = = NULL ) {
return VK_ERROR_VALIDATION_FAILED_EXT ;
return VK_ERROR_VALIDATION_FAILED_EXT ;
}
}
@ -1861,7 +1856,7 @@ VkResult create_simple_mesh_pipeline(VkDevice device, VkPhysicalDeviceMemoryProp
} ,
} ,
} ;
} ;
VkDescriptorSetLayoutBinding descriptor _bindings[ ] = {
VkDescriptorSetLayoutBinding set _bindings[ ] = {
{
{
. binding = 0 ,
. binding = 0 ,
. descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ,
. descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ,
@ -1871,9 +1866,15 @@ VkResult create_simple_mesh_pipeline(VkDevice device, VkPhysicalDeviceMemoryProp
} ,
} ,
} ;
} ;
VkDescriptorSetLayoutCreateInfo set_info = {
. sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO ,
. pBindings = set_bindings ,
. bindingCount = sizeof ( set_bindings ) / sizeof ( VkDescriptorSetLayoutBinding ) ,
. pNext = NULL ,
} ;
GraphicsPipelineInfo pipeline_info = {
GraphicsPipelineInfo pipeline_info = {
. descriptor_bindings_count = sizeof ( descriptor_bindings ) / sizeof ( VkDescriptorSetLayoutBinding ) ,
. descriptor_info = set_info ,
. descriptor_bindings = descriptor_bindings ,
. shader_stages_count = sizeof ( shader_stages ) / sizeof ( VkPipelineShaderStageCreateInfo ) ,
. shader_stages_count = sizeof ( shader_stages ) / sizeof ( VkPipelineShaderStageCreateInfo ) ,
. shader_stages = shader_stages ,
. shader_stages = shader_stages ,
. scene_layout = scene_layout ,
. scene_layout = scene_layout ,
@ -1883,16 +1884,10 @@ VkResult create_simple_mesh_pipeline(VkDevice device, VkPhysicalDeviceMemoryProp
. input_attributes_count = sizeof ( attributes ) / sizeof ( VkVertexInputAttributeDescription ) ,
. input_attributes_count = sizeof ( attributes ) / sizeof ( VkVertexInputAttributeDescription ) ,
} ;
} ;
GPUPage * memory = NULL ;
VkResult result = gpu_page_allocate ( device , memories , 100000 , 0xFFFFFFFF , VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT , VK_MEMORY_PROPERTY_HOST_COHERENT_BIT , 0 , & memory ) ;
if ( result ! = VK_SUCCESS ) {
return result ;
}
return create_graphics_pipeline ( device , extent , render_pass , pipeline_info , max_frames_in_flight , out ) ;
return create_graphics_pipeline ( device , extent , render_pass , pipeline_info , max_frames_in_flight , out ) ;
}
}
VkResult create_texture_mesh_pipeline ( VkDevice device , VkPhysicalDeviceMemoryProperties memories , VkExtent2D extent , VkRenderPass render_pass , VkDescriptorSetLayout scene_layout , uint32_t max_frames_in_flight , GraphicsPipeline* out ) {
VkResult create_texture_mesh_pipeline ( VkDevice device , VkPhysicalDeviceMemoryProperties memories , VkExtent2D extent , VkRenderPass render_pass , VkDescriptorSetLayout scene_layout , uint32_t max_frames_in_flight , VkCommandPool transfer_pool , VkQueue transfer_queue , VkQueue graphics_queue , VkCommandPool graphics_pool , uint32_t transfer_family , uint32_t graphics_family , GraphicsPipeline * out ) {
if ( out = = NULL ) {
if ( out = = NULL ) {
return VK_ERROR_VALIDATION_FAILED_EXT ;
return VK_ERROR_VALIDATION_FAILED_EXT ;
}
}
@ -1945,18 +1940,36 @@ VkResult create_texture_mesh_pipeline(VkDevice device, VkPhysicalDeviceMemoryPro
} ;
} ;
// TODO: use bindless descriptors for textures, so each draw command will bind a large buffer that is indexed by object ID to get the address of the texture in GPU memory
// TODO: use bindless descriptors for textures, so each draw command will bind a large buffer that is indexed by object ID to get the address of the texture in GPU memory
VkDescriptorSetLayoutBinding mesh_ set_bindings[ ] = {
VkDescriptorSetLayoutBinding set_bindings[ ] = {
{
{
. binding = 0 ,
. binding = 0 ,
. descriptorCount = 1 ,
. descriptorCount = 1 000 ,
. descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ,
. descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ,
. pImmutableSamplers = 0 ,
. pImmutableSamplers = 0 ,
. stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT ,
. stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT ,
} ,
} ,
} ;
} ;
( void ) mesh_set_bindings ;
VkDescriptorBindingFlags set_binding_flags [ ] = {
VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT ,
} ;
VkDescriptorSetLayoutBindingFlagsCreateInfo set_flags_info = {
. sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO ,
. bindingCount = sizeof ( set_bindings ) / sizeof ( VkDescriptorSetLayoutBinding ) ,
. pBindingFlags = set_binding_flags ,
} ;
VkDescriptorSetLayoutCreateInfo set_info = {
. sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO ,
. pBindings = set_bindings ,
. bindingCount = sizeof ( set_bindings ) / sizeof ( VkDescriptorSetLayoutBinding ) ,
. flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT ,
. pNext = & set_flags_info ,
} ;
GraphicsPipelineInfo pipeline_info = {
GraphicsPipelineInfo pipeline_info = {
. descriptor_info = set_info ,
. shader_stages_count = sizeof ( shader_stages ) / sizeof ( VkPipelineShaderStageCreateInfo ) ,
. shader_stages_count = sizeof ( shader_stages ) / sizeof ( VkPipelineShaderStageCreateInfo ) ,
. shader_stages = shader_stages ,
. shader_stages = shader_stages ,
. scene_layout = scene_layout ,
. scene_layout = scene_layout ,
@ -1972,7 +1985,92 @@ VkResult create_texture_mesh_pipeline(VkDevice device, VkPhysicalDeviceMemoryPro
return result ;
return result ;
}
}
return create_graphics_pipeline ( device , extent , render_pass , pipeline_info , max_frames_in_flight , out ) ;
result = create_graphics_pipeline ( device , extent , render_pass , pipeline_info , max_frames_in_flight , out ) ;
if ( result ! = VK_SUCCESS ) {
return result ;
}
GPUPage * tex_memory = NULL ;
result = gpu_page_allocate ( device , memories , 100000 , 0xFFFFFFFF , VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT , VK_MEMORY_PROPERTY_HOST_COHERENT_BIT , 0 , & tex_memory ) ;
if ( result ! = VK_SUCCESS ) {
return result ;
}
VkExtent2D texture_size = {
. width = 10 ,
. height = 10 ,
} ;
( void ) texture_size ;
struct __attribute__ ( ( __packed__ ) ) texel {
uint8_t r ;
uint8_t g ;
uint8_t b ;
uint8_t a ;
} ;
struct texel WHT = { 255 , 255 , 255 , 255 } ;
struct texel BLK = { 0 , 0 , 0 , 255 } ;
struct texel RED = { 255 , 0 , 0 , 255 } ;
struct texel GRN = { 0 , 255 , 0 , 255 } ;
struct texel BLU = { 0 , 0 , 255 , 255 } ;
struct texel texture_data [ 100 ] = {
RED , WHT , GRN , WHT , BLU , WHT , RED , WHT , GRN , BLK ,
RED , WHT , GRN , WHT , BLU , WHT , RED , WHT , GRN , BLK ,
RED , WHT , GRN , WHT , BLU , WHT , RED , WHT , GRN , WHT ,
RED , WHT , GRN , WHT , BLU , WHT , RED , WHT , GRN , WHT ,
RED , WHT , GRN , WHT , BLU , WHT , RED , WHT , GRN , BLK ,
RED , WHT , GRN , WHT , BLU , WHT , RED , WHT , GRN , BLK ,
RED , WHT , GRN , WHT , BLU , WHT , RED , WHT , GRN , WHT ,
RED , WHT , GRN , WHT , BLU , WHT , RED , WHT , GRN , WHT ,
RED , WHT , GRN , WHT , BLU , WHT , RED , WHT , GRN , BLK ,
RED , WHT , GRN , WHT , BLU , WHT , RED , WHT , GRN , BLK ,
} ;
( void ) texture_data ;
GPUPage * texture_memory = NULL ;
result = gpu_page_allocate ( device , memories , 100000 , 0xFFFFFFFF , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT , VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT , 0 , & texture_memory ) ;
if ( result ! = VK_SUCCESS ) {
return result ;
}
GPUPage * staging_memory = NULL ;
result = gpu_page_allocate ( device , memories , 100000 , 0xFFFFFFFF , VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT , VK_MEMORY_PROPERTY_HOST_COHERENT_BIT , 0 , & staging_memory ) ;
if ( result ! = VK_SUCCESS ) {
return result ;
}
GPUBuffer staging = { 0 } ;
result = gpu_buffer_malloc ( device , staging_memory , 100000 , VK_BUFFER_USAGE_TRANSFER_SRC_BIT , & staging ) ;
if ( result ! = VK_SUCCESS ) {
return result ;
}
Texture test_texture = load_texture ( device , texture_memory , staging , transfer_pool , transfer_queue , graphics_pool , graphics_queue , texture_size , VK_FORMAT_R8G8B8A8_SRGB , texture_data , transfer_family , graphics_family ) ;
for ( uint32_t i = 0 ; i < out - > max_frames_in_flight ; i + + ) {
VkDescriptorImageInfo image_info = {
. sampler = test_texture . sampler ,
. imageView = test_texture . view ,
. imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ,
} ;
VkWriteDescriptorSet descriptor_write = {
. sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET ,
. dstSet = out - > descriptors [ i ] ,
. dstBinding = 0 ,
. dstArrayElement = 0 ,
. descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ,
. descriptorCount = 1 ,
. pBufferInfo = 0 ,
. pImageInfo = & image_info ,
. pTexelBufferView = 0 ,
} ;
vkUpdateDescriptorSets ( device , 1 , & descriptor_write , 0 , 0 ) ;
}
return VK_SUCCESS ;
}
}
VkResult command_copy_to_buffer ( VkDevice device , GPUBuffer staging , VkBuffer destination , void * data , VkDeviceSize size , VkDeviceSize offset , VkCommandPool pool , VkQueue queue ) {
VkResult command_copy_to_buffer ( VkDevice device , GPUBuffer staging , VkBuffer destination , void * data , VkDeviceSize size , VkDeviceSize offset , VkCommandPool pool , VkQueue queue ) {
@ -2809,64 +2907,6 @@ Object create_texture_mesh_object(GraphicsPipeline* texture_mesh_pipeline, VkPhy
return zero ;
return zero ;
}
}
VkExtent2D texture_size = {
. width = 10 ,
. height = 10 ,
} ;
( void ) texture_size ;
struct __attribute__ ( ( __packed__ ) ) texel {
uint8_t r ;
uint8_t g ;
uint8_t b ;
uint8_t a ;
} ;
struct texel WHT = { 255 , 255 , 255 , 255 } ;
struct texel BLK = { 0 , 0 , 0 , 255 } ;
struct texel RED = { 255 , 0 , 0 , 255 } ;
struct texel GRN = { 0 , 255 , 0 , 255 } ;
struct texel BLU = { 0 , 0 , 255 , 255 } ;
struct texel texture_data [ 100 ] = {
RED , WHT , GRN , WHT , BLU , WHT , RED , WHT , GRN , BLK ,
RED , WHT , GRN , WHT , BLU , WHT , RED , WHT , GRN , BLK ,
RED , WHT , GRN , WHT , BLU , WHT , RED , WHT , GRN , WHT ,
RED , WHT , GRN , WHT , BLU , WHT , RED , WHT , GRN , WHT ,
RED , WHT , GRN , WHT , BLU , WHT , RED , WHT , GRN , BLK ,
RED , WHT , GRN , WHT , BLU , WHT , RED , WHT , GRN , BLK ,
RED , WHT , GRN , WHT , BLU , WHT , RED , WHT , GRN , WHT ,
RED , WHT , GRN , WHT , BLU , WHT , RED , WHT , GRN , WHT ,
RED , WHT , GRN , WHT , BLU , WHT , RED , WHT , GRN , BLK ,
RED , WHT , GRN , WHT , BLU , WHT , RED , WHT , GRN , BLK ,
} ;
( void ) texture_data ;
/*
Texture test_texture = load_texture ( device , mesh_memory , transfer_buffer , transfer_pool , transfer_queue , graphics_pool , graphics_queue , texture_size , VK_FORMAT_R8G8B8A8_SRGB , texture_data , transfer_family , graphics_family ) ;
for ( uint32_t i = 0 ; i < max_frames_in_flight ; i + + ) {
VkDescriptorImageInfo image_info = {
. sampler = test_texture . sampler ,
. imageView = test_texture . view ,
. imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ,
} ;
VkWriteDescriptorSet descriptor_write = {
. sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET ,
. dstSet = sets [ i ] ,
. dstBinding = 0 ,
. dstArrayElement = 0 ,
. descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ,
. descriptorCount = 1 ,
. pBufferInfo = 0 ,
. pImageInfo = & image_info ,
. pTexelBufferView = 0 ,
} ;
vkUpdateDescriptorSets ( device , 1 , & descriptor_write , 0 , 0 ) ;
} */ // TODO: bindless textures
return object ;
return object ;
}
}
@ -2878,7 +2918,7 @@ void main_loop(PlyMesh ply_mesh, GLFWwindow* window, VulkanContext* context) {
GraphicsPipeline simple_mesh_pipeline = { 0 } ;
GraphicsPipeline simple_mesh_pipeline = { 0 } ;
GraphicsPipeline texture_mesh_pipeline = { 0 } ;
GraphicsPipeline texture_mesh_pipeline = { 0 } ;
VkResult result = create_simple_mesh_pipeline ( context - > device , context - > memories, context - > swapchain_extent, context - > render_pass , scene . descriptor_layout , context - > max_frames_in_flight , & simple_mesh_pipeline ) ;
VkResult result = create_simple_mesh_pipeline ( context - > device , context - > swapchain_extent, context - > render_pass , scene . descriptor_layout , context - > max_frames_in_flight , & simple_mesh_pipeline ) ;
if ( result ! = VK_SUCCESS ) {
if ( result ! = VK_SUCCESS ) {
fprintf ( stderr , " failed to create simple mesh material: %s \n " , string_VkResult ( result ) ) ;
fprintf ( stderr , " failed to create simple mesh material: %s \n " , string_VkResult ( result ) ) ;
return ;
return ;
@ -2890,7 +2930,7 @@ void main_loop(PlyMesh ply_mesh, GLFWwindow* window, VulkanContext* context) {
return ;
return ;
}
}
result = create_texture_mesh_pipeline ( context - > device , context - > memories , context - > swapchain_extent , context - > render_pass , scene . descriptor_layout , context - > max_frames_in_flight , & texture_mesh_pipeline ) ;
result = create_texture_mesh_pipeline ( context - > device , context - > memories , context - > swapchain_extent , context - > render_pass , scene . descriptor_layout , context - > max_frames_in_flight , context - > transfer_command_pool , context - > queues . transfer , context - > queues . graphics , context - > extra_graphics_pool , context - > queue_indices . transfer_family , context - > queue_indices . graphics_index , & texture_mesh_pipeline ) ;
if ( result ! = VK_SUCCESS ) {
if ( result ! = VK_SUCCESS ) {
fprintf ( stderr , " failed to create texture mesh material \n " ) ;
fprintf ( stderr , " failed to create texture mesh material \n " ) ;
return ;
return ;
@ -2918,10 +2958,12 @@ void main_loop(PlyMesh ply_mesh, GLFWwindow* window, VulkanContext* context) {
return ;
return ;
}
}
mat4 * tmp = memory - > ptr + buffer . memory - > offset ;
mat4 * model_1 = memory - > ptr + buffer . memory - > offset ;
glm_mat4_identity ( * tmp ) ;
mat4 * model_2 = memory - > ptr + buffer . memory - > offset + sizeof ( mat4 ) ;
vec3 scale = { 2.0f , 2.0f , 2.0f } ;
glm_mat4_identity ( * model_1 ) ;
glm_scale ( * tmp , scale ) ;
glm_translate_x ( * model_1 , 1.0f ) ;
glm_mat4_identity ( * model_2 ) ;
glm_translate_x ( * model_2 , - 1.0f ) ;
VkBufferDeviceAddressInfo addr_info = {
VkBufferDeviceAddressInfo addr_info = {
. sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO ,
. sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO ,