/// _ _ /// __ ___ _| | | ____ _ _ __ /// \ \/ / | | | | |/ / _` | '_ \ /// > <| |_| | | < (_| | | | | /// /_/\_\\__,_|_|_|\_\__,_|_| |_| /// /// Copyright (c) 1997 - Ognjen 'xolatile' Milan Robovic /// /// xolatile@chud.cyou - xulkan - Tiny and elegant Vulkan wrapper library so I don't have to write 40k lines of code for a triangle... /// /// This program is free software, free as in freedom and as in free beer, you can redistribute it and/or modify it under the terms of the GNU /// General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version if you wish... /// /// This program is distributed in the hope that it will be useful, but it is probably not, and without any warranty, without even the implied /// warranty of merchantability or fitness for a particular purpose, because it is pointless. Please see the GNU (Geenoo) General Public License /// for more details, if you dare, it is a lot of text that nobody wants to read... /// DO NOT USE THIS CRAP... #define VK_USE_PLATFORM_XCB_KHR #include typedef struct { boolean active; boolean reconfigure_active; boolean validation_layers; boolean hide_cursor_full; boolean hide_cursor; natural time; natural cursor; /// TODO: PROPER INPUT integer cursor_x; integer cursor_y; boolean signal [signal_count]; real pixel_width; real pixel_height; natural frame; natural width; natural height; natural sprite_count; natural * * sprite_data; natural * sprite_width; natural * sprite_height; real * sprite_u; real * sprite_v; natural font_count; natural * * font_index; natural * * font_width; natural * * font_height; character * font_begin; character * font_end; xcb_connection_t * connection; xcb_screen_t * screen; xcb_window_t window; natural global_time; natural gameplay_time; natural animation_time; natural framerate; natural gameplay_framerate; natural animation_framerate; natural_64 frame_time_in_ns; VkInstance instance; VkSurfaceKHR surface; VkPhysicalDevice physical_device; VkQueue queue; natural queue_index; VkDevice boolean_device; natural image_count; VkExtent2D extent; VkFormat format; VkPresentModeKHR present_mode; VkSurfaceTransformFlagBitsKHR transform; VkCompositeAlphaFlagBitsKHR composite_alpha; VkSwapchainKHR swapchain; VkImage * images; VkImageView * image_views; VkSemaphore * semaphore_set_1; VkSemaphore * semaphore_set_2; VkFence * fence_set_1; VkDescriptorSetLayout descriptor_set_layout; VkDescriptorSetLayout * descriptor_set_layouts; VkDescriptorPool descriptor_pool; VkDescriptorSet * descriptor_sets; VkRenderPass render_pass; VkShaderModule vertex_shader; VkShaderModule fragment_shader; VkPipelineLayout pipeline_layout; VkPipeline pipeline; VkFramebuffer * framebuffers; VkCommandPool command_pool; VkCommandBuffer * command_buffers; VkCommandBuffer transfer_buffer; VkBuffer vertex_buffer; VkDeviceMemory vertex_memory; real * vertex_data; VkDeviceSize vertex_size; natural vertex_count; natural vertex_limit; VkBuffer index_buffer; VkDeviceMemory index_memory; natural * index_data; VkDeviceSize index_size; natural index_count; natural index_limit; VkSampler sampler; VkImage layout_image; VkDeviceMemory layout_memory; VkImageView layout_image_view; natural * layout_data; natural layout_size; natural layout_width; natural layout_height; } vulkan_structure; static character * vulkan_continue_execution [] = { "/s Commands successfully completed.\n", "/w Fence or query hasn't yet completed.\n", "/w Wait operation hasn't completed in the specified time.\n", "/w Event is signaled.\n", "/w Event isn't signaled.\n", "/w Return array was too small for the result.\n" }; static character * vulkan_break_execution [] = { "/f Host memory allocation has failed.\n", "/f Device memory allocation has failed.\n", "/f Initialization of an object couldn't be completed.\n", "/f Logical or physical device has been lost.\n", "/f Mapping of a memory object has failed.\n", "/f Requested layer isn't present or couln't be loaded.\n", "/f Requested extension isn't supported.\n", "/f Requested feature isn't supported.\n", "/f Requested version of Vulkan isn't suported.\n", "/f Too many objects of the type have alrady been created.\n", "/f Requested format isn't supported.\n", "/f Pool allocation has failed due to framentation.\n", "/f Unknown error has occurred.\n", "/f Undefined error has occured.\n" }; static procedure vulkan_result (VkResult result) { if (result == 0) { return; } else if (result > 0) { print (vulkan_continue_execution [result]); } else { print (vulkan_break_execution [- result - 1]); //~exit (log_failure); } } static vulkan_structure * vulkan_initialize (caliber quad_memory, caliber layout_side, natural gameplay_framerate, natural animation_framerate) { vulkan_structure * vulkan = allocate (sizeof (* vulkan)); vulkan->vertex_limit = quad_memory * 32; vulkan->index_limit = quad_memory * 6; vulkan->gameplay_framerate = gameplay_framerate; vulkan->animation_framerate = animation_framerate; vulkan->layout_width = layout_side; vulkan->layout_height = layout_side; return (vulkan); } static vulkan_structure * vulkan_deinitialize (vulkan_structure * vulkan) { print ("/c Destroying and deallocating all the bullshit used so far...\n"); vulkan_result (vkQueueWaitIdle (vulkan->queue)); vulkan_result (vkDeviceWaitIdle (vulkan->boolean_device)); vulkan->sprite_width = deallocate (vulkan->sprite_width); vulkan->sprite_height = deallocate (vulkan->sprite_height); vulkan->sprite_u = deallocate (vulkan->sprite_u); vulkan->sprite_v = deallocate (vulkan->sprite_v); if (vulkan->font_count > 0) { for (natural index = 0; index < vulkan->font_count; ++index) { vulkan->font_index [index] = deallocate (vulkan->font_index [index]); vulkan->font_width [index] = deallocate (vulkan->font_width [index]); vulkan->font_height [index] = deallocate (vulkan->font_height [index]); } vulkan->font_index = deallocate (vulkan->font_index); vulkan->font_width = deallocate (vulkan->font_width); vulkan->font_height = deallocate (vulkan->font_height); vulkan->font_begin = deallocate (vulkan->font_begin); vulkan->font_end = deallocate (vulkan->font_end); } vkFreeDescriptorSets (vulkan->boolean_device, vulkan->descriptor_pool, vulkan->image_count, vulkan->descriptor_sets); vulkan->descriptor_set_layouts = deallocate (vulkan->descriptor_set_layouts); vulkan->descriptor_sets = deallocate (vulkan->descriptor_sets); vkDestroyDescriptorPool (vulkan->boolean_device, vulkan->descriptor_pool, null); vkDestroySampler (vulkan->boolean_device, vulkan->sampler, null); vkDestroyImageView (vulkan->boolean_device, vulkan->layout_image_view, null); vkDestroyImage (vulkan->boolean_device, vulkan->layout_image, null); vkFreeMemory (vulkan->boolean_device, vulkan->layout_memory, null); vulkan->layout_data = deallocate (vulkan->layout_data); vulkan->index_data = deallocate (vulkan->index_data); vulkan->vertex_data = deallocate (vulkan->vertex_data); /* vkFreeCommandBuffers (vulkan->boolean_device, vulkan->command_pool, vulkan->image_count, vulkan->command_buffers); */ vulkan->command_buffers = deallocate (vulkan->command_buffers); vkDestroyCommandPool (vulkan->boolean_device, vulkan->command_pool, null); for (natural index = 0; index < vulkan->image_count; ++index) { vkDestroyFramebuffer (vulkan->boolean_device, vulkan->framebuffers [index], null); } vulkan->framebuffers = deallocate (vulkan->framebuffers); vkDestroyPipeline (vulkan->boolean_device, vulkan->pipeline, null); vkDestroyPipelineLayout (vulkan->boolean_device, vulkan->pipeline_layout, null); vkDestroyShaderModule (vulkan->boolean_device, vulkan->fragment_shader, null); vkDestroyShaderModule (vulkan->boolean_device, vulkan->vertex_shader, null); vkDestroyDescriptorSetLayout (vulkan->boolean_device, vulkan->descriptor_set_layout, null); vkDestroyRenderPass (vulkan->boolean_device, vulkan->render_pass, null); for (natural index = 0; index < vulkan->image_count; ++index) { vkDestroySemaphore (vulkan->boolean_device, vulkan->semaphore_set_1 [index], null); vkDestroySemaphore (vulkan->boolean_device, vulkan->semaphore_set_2 [index], null); vkDestroyFence (vulkan->boolean_device, vulkan->fence_set_1 [index], null); } vulkan->semaphore_set_1 = deallocate (vulkan->semaphore_set_1); vulkan->semaphore_set_2 = deallocate (vulkan->semaphore_set_2); vulkan->fence_set_1 = deallocate (vulkan->fence_set_1); for (natural index = 0; index < vulkan->image_count; ++index) { vkDestroyImageView (vulkan->boolean_device, vulkan->image_views [index], null); } vulkan->image_views = deallocate (vulkan->image_views); vkDestroySwapchainKHR (vulkan->boolean_device, vulkan->swapchain, null); vulkan->images = deallocate (vulkan->images); vkDestroySurfaceKHR (vulkan->instance, vulkan->surface, null); vkDestroyDevice (vulkan->boolean_device, null); vkDestroyInstance (vulkan->instance, null); xcb_destroy_window (vulkan->connection, vulkan->window); xcb_disconnect (vulkan->connection); print ("/c Destroyed and deallocated all resources.\n"); return (deallocate (vulkan)); } static natural vulkan_choose_memory_property (vulkan_structure * vulkan, natural wanted) { natural index = 0; natural usable = 0; VkPhysicalDeviceMemoryProperties memory_properties = { 0 }; vkGetPhysicalDeviceMemoryProperties (vulkan->physical_device, & memory_properties); for (index = 0; index < memory_properties.memoryTypeCount; ++index) { if ((memory_properties.memoryTypes [index].propertyFlags & wanted) == wanted) { usable &= (1 << index); } } if (usable != wanted) { print ("/w Can't set this memory property bit: usable = %i, wanted = %i.\n", usable, wanted); } return (usable); } static procedure vulkan_create_buffer (vulkan_structure * vulkan, VkBuffer * buffer, VkDeviceMemory * memory, VkDeviceSize size, VkMemoryPropertyFlags usage) { natural wanted_memory_index = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; VkBufferCreateInfo buffer_information = { 0 }; VkMemoryRequirements memory_requirements = { 0 }; VkMemoryAllocateInfo memory_allocation_information = { 0 }; buffer_information.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; buffer_information.size = size; buffer_information.usage = usage; buffer_information.sharingMode = VK_SHARING_MODE_EXCLUSIVE; vulkan_result (vkCreateBuffer (vulkan->boolean_device, & buffer_information, null, buffer)); vkGetBufferMemoryRequirements (vulkan->boolean_device, * buffer, & memory_requirements); memory_allocation_information.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; memory_allocation_information.allocationSize = memory_requirements.size; memory_allocation_information.memoryTypeIndex = vulkan_choose_memory_property (vulkan, wanted_memory_index); vulkan_result (vkAllocateMemory (vulkan->boolean_device, & memory_allocation_information, null, memory)); vulkan_result (vkBindBufferMemory (vulkan->boolean_device, * buffer, * memory, 0)); } static procedure vulkan_begin_command_buffer (vulkan_structure * vulkan) { VkCommandBufferAllocateInfo command_buffer_allocation_information = { 0 }; VkCommandBufferBeginInfo command_buffer_begin_information = { 0 }; command_buffer_allocation_information.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; command_buffer_allocation_information.commandPool = vulkan->command_pool; command_buffer_allocation_information.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; command_buffer_allocation_information.commandBufferCount = 1; command_buffer_begin_information.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; command_buffer_begin_information.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; vulkan_result (vkAllocateCommandBuffers (vulkan->boolean_device, & command_buffer_allocation_information, & vulkan->transfer_buffer)); vulkan_result (vkBeginCommandBuffer (vulkan->transfer_buffer, & command_buffer_begin_information)); } static procedure vulkan_end_command_buffer (vulkan_structure * vulkan) { VkSubmitInfo submit_information = { 0 }; vkEndCommandBuffer (vulkan->transfer_buffer); submit_information.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_information.commandBufferCount = 1; submit_information.pCommandBuffers = & vulkan->transfer_buffer; vkQueueSubmit (vulkan->queue, 1, & submit_information, VK_NULL_HANDLE); vkQueueWaitIdle (vulkan->queue); vkFreeCommandBuffers (vulkan->boolean_device, vulkan->command_pool, 1, & vulkan->transfer_buffer); vulkan->transfer_buffer = VK_NULL_HANDLE; } static procedure vulkan_create_window (vulkan_structure * vulkan, character * application) { natural window_flags [2] = { 0 }; vulkan->time = tick_tock (); vulkan->connection = xcb_connect (null, null); print ("Connected to /3X11 server/-.\n"); vulkan->screen = xcb_setup_roots_iterator (xcb_get_setup (vulkan->connection)).data; vulkan->window = xcb_generate_id (vulkan->connection); window_flags [0] = vulkan->screen->black_pixel; window_flags [1] = XCB_EVENT_MASK_NO_EVENT | XCB_EVENT_MASK_EXPOSURE | /*XCB_EVENT_MASK_STRUCTURE_NOTIFY |*/ XCB_EVENT_MASK_RESIZE_REDIRECT | XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_KEY_PRESS | /*XCB_EVENT_MASK_POINTER_MOTION |*/ XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_PRESS; xcb_create_window (vulkan->connection, vulkan->screen->root_depth, vulkan->window, vulkan->screen->root, 0, 0, (natural_16) vulkan->width, (natural_16) vulkan->height, 10, XCB_WINDOW_CLASS_INPUT_OUTPUT, vulkan->screen->root_visual, XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK, window_flags); print ("/c Created /3XCB window/-.\n"); xcb_map_window (vulkan->connection, vulkan->window); xcb_change_property (vulkan->connection, XCB_PROP_MODE_REPLACE, vulkan->window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, string_length (application), application); xcb_flush (vulkan->connection); print ("Mapped /3XCB window/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time); } static procedure vulkan_create_instance (vulkan_structure * vulkan, character * application) { natural current = 0; natural general = 0; VkApplicationInfo application_information = { 0 }; VkInstanceCreateInfo instance_information = { 0 }; natural instance_layer_count = 0; natural * instance_layer_index = null; VkLayerProperties * instance_layer_array = null; natural instance_extension_count = 0; natural * instance_extension_index = null; VkExtensionProperties * instance_extension_array = null; natural default_instance_layer_count = (natural) (vulkan->validation_layers == true); natural default_instance_extension_count = 2; character * default_instance_layer_array [VK_MAX_EXTENSION_NAME_SIZE] = { "VK_LAYER_KHRONOS_validation" //~"VK_LAYER_LUNARG_parameter_validation", //~"VK_LAYER_LUNARG_core_validation", //~"VK_LAYER_LUNARG_standard_validation" }; character * default_instance_extension_array [VK_MAX_EXTENSION_NAME_SIZE] = { VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XCB_SURFACE_EXTENSION_NAME }; vulkan->time = tick_tock (); vulkan_result (vkEnumerateInstanceLayerProperties (& instance_layer_count, null)); print ("Instance layer count: /2%i/-\n", instance_layer_count); instance_layer_index = allocate (instance_layer_count * sizeof (* instance_layer_index)); instance_layer_array = allocate (instance_layer_count * sizeof (* instance_layer_array)); vulkan_result (vkEnumerateInstanceLayerProperties (& instance_layer_count, instance_layer_array)); for (current = 0; current < instance_layer_count; ++current) { for (general = 0; general < default_instance_layer_count; ++general) { if (string_compare (instance_layer_array [current].layerName, (character *) default_instance_layer_array [general])) { instance_layer_index [current] = true; } } } for (current = 0; current < instance_layer_count; ++current) { print ("\t[%t] %s\n", instance_layer_index [current], instance_layer_array [current].layerName); } instance_layer_index = deallocate (instance_layer_index); instance_layer_array = deallocate (instance_layer_array); print ("Enumerated /2instance layer properties/-.\n"); vulkan_result (vkEnumerateInstanceExtensionProperties (null, & instance_extension_count, null)); print ("Instance extension count: /2%i/-\n", instance_extension_count); instance_extension_index = allocate (instance_extension_count * sizeof (* instance_extension_index)); instance_extension_array = allocate (instance_extension_count * sizeof (* instance_extension_array)); vulkan_result (vkEnumerateInstanceExtensionProperties (null, & instance_extension_count, instance_extension_array)); for (current = 0; current < instance_extension_count; ++current) { for (general = 0; general < default_instance_extension_count; ++general) { if (string_compare (instance_extension_array [current].extensionName, (character *) default_instance_extension_array [general])) { instance_extension_index [current] = true; } } } for (current = 0; current < instance_extension_count; ++current) { print ("\t[%t] %s\n", instance_extension_index [current], instance_extension_array [current].extensionName); } instance_extension_index = deallocate (instance_extension_index); instance_extension_array = deallocate (instance_extension_array); print ("Enumerated /2instance extension properties/-.\n"); application_information.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; application_information.pApplicationName = application; application_information.applicationVersion = VK_MAKE_VERSION (1, 0, 0); application_information.pEngineName = "xulkan"; application_information.engineVersion = VK_MAKE_VERSION (1, 0, 0); application_information.apiVersion = VK_API_VERSION_1_0; instance_information.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; instance_information.pApplicationInfo = & application_information; instance_information.enabledLayerCount = default_instance_layer_count; instance_information.ppEnabledLayerNames = default_instance_layer_array; instance_information.enabledExtensionCount = default_instance_extension_count; instance_information.ppEnabledExtensionNames = default_instance_extension_array; vulkan_result (vkCreateInstance (& instance_information, null, & vulkan->instance)); print ("/c Created /2Vulkan instance/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time); } static procedure vulkan_create_surface (vulkan_structure * vulkan) { VkXcbSurfaceCreateInfoKHR surface_information = { 0 }; vulkan->time = tick_tock (); surface_information.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; surface_information.connection = vulkan->connection; surface_information.window = vulkan->window; vulkan_result (vkCreateXcbSurfaceKHR (vulkan->instance, & surface_information, null, & vulkan->surface)); print ("/c Created /2Vulkan-XCB surface/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time); } static procedure vulkan_create_device (vulkan_structure * vulkan) { VkDeviceQueueCreateInfo queues = { 0 }; VkDeviceCreateInfo device_information = { 0 }; VkPhysicalDeviceMemoryProperties memory_properties = { 0 }; natural queue_count = 0; natural physical_device_count = 0; VkPhysicalDevice * physical_device_array = null; VkBool32 * support = null; real queue_priorities [1] = { 1 }; natural default_device_extension_count = 1; character * default_device_extension_array [VK_MAX_EXTENSION_NAME_SIZE] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME }; vulkan->time = tick_tock (); vulkan_result (vkEnumeratePhysicalDevices (vulkan->instance, & physical_device_count, null)); print ("Device count: /2%i/-\n", physical_device_count); physical_device_array = allocate (physical_device_count * sizeof (VkPhysicalDevice)); vulkan_result (vkEnumeratePhysicalDevices (vulkan->instance, & physical_device_count, physical_device_array)); print ("Enumerated available physical devices.\n"); for (natural index = 0; index < physical_device_count; ++index) { natural general = 0; natural current = 0; natural device_extension_count = 0; natural * device_extension_index = null; VkExtensionProperties * device_extension_array = null; VkPhysicalDeviceProperties physical_device_properties = { 0 }; VkPhysicalDeviceFeatures physical_device_features = { 0 }; VkQueueFamilyProperties * queue_properties = null; vkGetPhysicalDeviceProperties (physical_device_array [index], & physical_device_properties); vkGetPhysicalDeviceFeatures (physical_device_array [index], & physical_device_features); #define get_fucking_version(i) \ VK_VERSION_MAJOR(i), \ VK_VERSION_MINOR(i), \ VK_VERSION_PATCH(i) print ("Physical device: /2%s/-\n", physical_device_properties.deviceName); print ("Device ID: /2%i/-\n", physical_device_properties.deviceID); print ("API version: /2%i.%i.%i/-\n", get_fucking_version (physical_device_properties.apiVersion)); print ("Driver version: /2%i.%i.%i/-\n", get_fucking_version (physical_device_properties.driverVersion)); #undef get_fucking_version switch (physical_device_properties.deviceType) { case (VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU): print ("Device type: /2Integrated GPU/-\n"); break; case (VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU): print ("Device type: /2Discrete GPU/-\n"); break; case (VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU): print ("Device type: /2Virtual GPU/-\n"); break; case (VK_PHYSICAL_DEVICE_TYPE_CPU): print ("Device type: /2CPU/-\n"); break; default: print ("Device type: /2Other/-\n"); break; } switch (physical_device_properties.vendorID) { case (VK_VENDOR_ID_VIV): print ("Vendor: /2VIV/-\n"); break; case (VK_VENDOR_ID_VSI): print ("Vendor: /2VSI/-\n"); break; case (VK_VENDOR_ID_KAZAN): print ("Vendor: /2Kazan/-\n"); break; case (VK_VENDOR_ID_CODEPLAY): print ("Vendor: /2Codeplay/-\n"); break; case (VK_VENDOR_ID_MESA): print ("Vendor: /2MESA/-\n"); break; case (VK_VENDOR_ID_POCL): print ("Vendor: /2POCL/-\n"); break; default: print ("Vendor: /2Other/-\n"); break; } vulkan_result (vkEnumerateDeviceExtensionProperties (physical_device_array [index], null, & device_extension_count, null)); print ("Device extensions available: %i\n", device_extension_count); device_extension_index = allocate (device_extension_count * sizeof (* device_extension_index)); device_extension_array = allocate (device_extension_count * sizeof (* device_extension_array)); vulkan_result (vkEnumerateDeviceExtensionProperties (physical_device_array [index], null, & device_extension_count, device_extension_array)); for (current = 0; current < device_extension_count; ++current) { for (general = 0; general < default_device_extension_count; ++general) { if (string_compare (device_extension_array [current].extensionName, (character *) default_device_extension_array [general])) { device_extension_index [current] = true; } } } for (current = 0; current < device_extension_count; ++current) { print ("\t[%t] %s\n", device_extension_index [current], device_extension_array [current].extensionName); } device_extension_index = deallocate (device_extension_index); device_extension_array = deallocate (device_extension_array); vkGetPhysicalDeviceQueueFamilyProperties (physical_device_array [index], & queue_count, null); queue_properties = allocate (queue_count * sizeof (VkQueueFamilyProperties)); vkGetPhysicalDeviceQueueFamilyProperties (physical_device_array [index], & queue_count, queue_properties); vulkan->queue_index = 0; if ((physical_device_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) || (physical_device_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)) { vulkan->physical_device = physical_device_array [index]; } queue_properties = deallocate (queue_properties); print ("Enumerated device layer properties.\n"); print ("Enumerated device extension properties.\n"); } vulkan->physical_device = physical_device_array [1]; /// THIS SHIT SUCKS. VkPhysicalDeviceProperties selected_physical_device_properties = { 0 }; vkGetPhysicalDeviceProperties (vulkan->physical_device, & selected_physical_device_properties); print ("/c Selecting physical device '/2%s/-'.\n", selected_physical_device_properties.deviceName); physical_device_array = deallocate (physical_device_array); queues.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queues.queueFamilyIndex = vulkan->queue_index; queues.queueCount = 1; queues.pQueuePriorities = queue_priorities; device_information.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; device_information.queueCreateInfoCount = 1; device_information.pQueueCreateInfos = & queues; device_information.enabledExtensionCount = default_device_extension_count; device_information.ppEnabledExtensionNames = default_device_extension_array; device_information.pEnabledFeatures = null; vulkan_result (vkCreateDevice (vulkan->physical_device, & device_information, null, & vulkan->boolean_device)); print ("/c Created Vulkan boolean device.\n"); vkGetDeviceQueue (vulkan->boolean_device, vulkan->queue_index, 0, & vulkan->queue); vkGetPhysicalDeviceQueueFamilyProperties (vulkan->physical_device, & queue_count, null); support = allocate (queue_count * sizeof (VkBool32)); for (natural index = 0; index < queue_count; ++index) { vulkan_result (vkGetPhysicalDeviceSurfaceSupportKHR (vulkan->physical_device, index, vulkan->surface, & support [index])); } for (natural index = 0; (index != queue_count) && (! (vulkan->queue_index = support [index] ? (index++) : 0)); ); support = deallocate (support); vkGetPhysicalDeviceMemoryProperties (vulkan->physical_device, & memory_properties); print ("Found /2Vulkan physical device/- memory properties.\n"); for (natural index = 0; index < memory_properties.memoryTypeCount; ++index) { print ("> %i\n", memory_properties.memoryTypes [index].propertyFlags); } print ("Found /2Vulkan surface support/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time); } static procedure vulkan_choose_extent (vulkan_structure * vulkan) { VkSurfaceCapabilitiesKHR capabilities = { 0 }; vulkan->time = tick_tock (); vulkan_result (vkGetPhysicalDeviceSurfaceCapabilitiesKHR (vulkan->physical_device, vulkan->surface, & capabilities)); vulkan->image_count = capabilities.minImageCount + 1; vulkan->extent.width = vulkan->width; vulkan->extent.height = vulkan->height; vulkan->extent.width = (vulkan->extent.width < capabilities.minImageExtent.width) ? capabilities.minImageExtent.width : vulkan->extent.width; vulkan->extent.height = (vulkan->extent.height < capabilities.minImageExtent.height) ? capabilities.minImageExtent.height : vulkan->extent.height; vulkan->extent.width = (vulkan->extent.width > capabilities.maxImageExtent.width) ? capabilities.maxImageExtent.width : vulkan->extent.width; vulkan->extent.height = (vulkan->extent.height > capabilities.maxImageExtent.height) ? capabilities.maxImageExtent.height : vulkan->extent.height; vulkan->transform = capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; vulkan->composite_alpha = capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; print ("Found /2Vulkan-XCB surface capabilities/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time); } static procedure vulkan_choose_format (vulkan_structure * vulkan) { natural format_count = 0; VkSurfaceFormatKHR * format_array = null; vulkan->time = tick_tock (); vulkan_result (vkGetPhysicalDeviceSurfaceFormatsKHR (vulkan->physical_device, vulkan->surface, & format_count, null)); format_array = allocate (format_count * sizeof (VkSurfaceFormatKHR)); vulkan_result (vkGetPhysicalDeviceSurfaceFormatsKHR (vulkan->physical_device, vulkan->surface, & format_count, format_array)); print ("Available surface format count: /2%i/-\n", format_count); vulkan->format = VK_FORMAT_B8G8R8A8_UNORM; format_array = deallocate (format_array); print ("Choosing default /2Vulkan surface formats/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time); } static procedure vulkan_choose_present_mode (vulkan_structure * vulkan) { natural present_mode_count = 0; VkPresentModeKHR * present_mode_array = null; vulkan->time = tick_tock (); vulkan_result (vkGetPhysicalDeviceSurfacePresentModesKHR (vulkan->physical_device, vulkan->surface, & present_mode_count, null)); present_mode_array = allocate (present_mode_count * sizeof (VkPresentModeKHR)); vulkan_result (vkGetPhysicalDeviceSurfacePresentModesKHR (vulkan->physical_device, vulkan->surface, & present_mode_count, present_mode_array)); vulkan->present_mode = VK_PRESENT_MODE_FIFO_KHR; present_mode_array = deallocate (present_mode_array); print ("Choosing FIFO /2Vulkan surface present mode/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time); } static procedure vulkan_create_swapchain (vulkan_structure * vulkan) { VkSwapchainCreateInfoKHR swapchain_information = { 0 }; vulkan->time = tick_tock (); swapchain_information.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapchain_information.surface = vulkan->surface; swapchain_information.minImageCount = vulkan->image_count; swapchain_information.imageFormat = vulkan->format; swapchain_information.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; swapchain_information.imageExtent = vulkan->extent; swapchain_information.imageArrayLayers = 1; swapchain_information.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; swapchain_information.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swapchain_information.queueFamilyIndexCount = 0; swapchain_information.pQueueFamilyIndices = null; swapchain_information.preTransform = vulkan->transform; swapchain_information.compositeAlpha = vulkan->composite_alpha; swapchain_information.presentMode = vulkan->present_mode; swapchain_information.clipped = VK_TRUE; swapchain_information.oldSwapchain = VK_NULL_HANDLE; vulkan_result (vkCreateSwapchainKHR (vulkan->boolean_device, & swapchain_information, null, & vulkan->swapchain)); print ("/c Created /2Vulkan swapchain/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time); } static procedure vulkan_create_images (vulkan_structure * vulkan) { natural temporary = vulkan->image_count; vulkan->time = tick_tock (); vulkan_result (vkGetSwapchainImagesKHR (vulkan->boolean_device, vulkan->swapchain, & temporary, null)); vulkan->images = allocate (vulkan->image_count * sizeof (VkImage)); vulkan_result (vkGetSwapchainImagesKHR (vulkan->boolean_device, vulkan->swapchain, & temporary, vulkan->images)); print ("/c Created /2Vulkan swapchain images/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time); } static procedure vulkan_create_image_views (vulkan_structure * vulkan) { VkComponentMapping component_mapping = { 0 }; VkImageSubresourceRange image_subresource_range = { 0 }; VkImageViewCreateInfo image_view_information = { 0 }; vulkan->time = tick_tock (); vulkan->image_views = allocate (vulkan->image_count * sizeof (VkImageView)); component_mapping.r = VK_COMPONENT_SWIZZLE_R; component_mapping.g = VK_COMPONENT_SWIZZLE_G; component_mapping.b = VK_COMPONENT_SWIZZLE_B; component_mapping.a = VK_COMPONENT_SWIZZLE_A; image_subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; image_subresource_range.baseMipLevel = 0; image_subresource_range.levelCount = 1; image_subresource_range.baseArrayLayer = 0; image_subresource_range.layerCount = 1; image_view_information.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; image_view_information.viewType = VK_IMAGE_VIEW_TYPE_2D; image_view_information.format = vulkan->format; image_view_information.components = component_mapping; image_view_information.subresourceRange = image_subresource_range; for (natural index = 0; index < vulkan->image_count; ++index) { image_view_information.image = vulkan->images [index]; vulkan_result (vkCreateImageView (vulkan->boolean_device, & image_view_information, null, & vulkan->image_views [index])); } print ("/c Created /2Vulkan swapchain image views/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time); } static procedure vulkan_create_semaphores (vulkan_structure * vulkan) { VkSemaphoreCreateInfo semaphore_information = { 0 }; vulkan->time = tick_tock (); vulkan->semaphore_set_1 = allocate (vulkan->image_count * sizeof (VkSemaphore)); vulkan->semaphore_set_2 = allocate (vulkan->image_count * sizeof (VkSemaphore)); semaphore_information.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; for (natural index = 0; index < vulkan->image_count; ++index) { vulkan_result (vkCreateSemaphore (vulkan->boolean_device, & semaphore_information, null, & vulkan->semaphore_set_1 [index])); vulkan_result (vkCreateSemaphore (vulkan->boolean_device, & semaphore_information, null, & vulkan->semaphore_set_2 [index])); } print ("/c Created /2Vulkan synchronization semaphores/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time); } static procedure vulkan_create_fences (vulkan_structure * vulkan) { natural index = 0; VkFenceCreateInfo fence_information = { 0 }; vulkan->time = tick_tock (); vulkan->fence_set_1 = allocate (vulkan->image_count * sizeof (VkFence)); fence_information.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fence_information.flags = VK_FENCE_CREATE_SIGNALED_BIT; for (index = 0; index < vulkan->image_count; ++index) { vulkan_result (vkCreateFence (vulkan->boolean_device, & fence_information, null, & vulkan->fence_set_1 [index])); } print ("/c Created /2Vulkan synchronization fences/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time); } static procedure vulkan_create_render_pass (vulkan_structure * vulkan) { VkAttachmentDescription attachment_description = { 0 }; VkAttachmentReference attachment_reference = { 0 }; VkSubpassDescription subpass_description = { 0 }; VkSubpassDependency subpass_dependencies [2] = { { 0 } }; VkRenderPassCreateInfo render_pass_information = { 0 }; vulkan->time = tick_tock (); attachment_description.flags = 0; attachment_description.format = vulkan->format; attachment_description.samples = VK_SAMPLE_COUNT_1_BIT; attachment_description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; attachment_description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; attachment_description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; attachment_description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; attachment_description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; attachment_description.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; attachment_reference.attachment = 0; attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; subpass_description.flags = 0; subpass_description.pipelineBindPointeger = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass_description.inputAttachmentCount = 0; subpass_description.pInputAttachments = null; subpass_description.colorAttachmentCount = 1; subpass_description.pColorAttachments = & attachment_reference; subpass_description.pResolveAttachments = null; subpass_description.pDepthStencilAttachment = null; subpass_description.preserveAttachmentCount = 0; subpass_description.pPreserveAttachments = null; subpass_dependencies [0].srcSubpass = VK_SUBPASS_EXTERNAL; subpass_dependencies [0].dstSubpass = 0; subpass_dependencies [0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; subpass_dependencies [0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; subpass_dependencies [0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; subpass_dependencies [0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; subpass_dependencies [0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; subpass_dependencies [1].srcSubpass = 0; subpass_dependencies [1].dstSubpass = VK_SUBPASS_EXTERNAL; subpass_dependencies [1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; subpass_dependencies [1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; subpass_dependencies [1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; subpass_dependencies [1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; subpass_dependencies [1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; render_pass_information.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; render_pass_information.attachmentCount = 1; render_pass_information.pAttachments = & attachment_description; render_pass_information.subpassCount = 1; render_pass_information.pSubpasses = & subpass_description; render_pass_information.dependencyCount = 2; render_pass_information.pDependencies = subpass_dependencies; vulkan_result (vkCreateRenderPass (vulkan->boolean_device, & render_pass_information, null, & vulkan->render_pass)); print ("/c Created /2Vulkan render pass/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time); } static procedure vulkan_create_descriptor_set_layout (vulkan_structure * vulkan) { VkDescriptorSetLayoutBinding descriptor_set_layout_bindings [2] = { { 0 } }; VkDescriptorSetLayoutCreateInfo descriptor_set_layout_information = { 0 }; vulkan->time = tick_tock (); descriptor_set_layout_bindings [0].binding = 0; descriptor_set_layout_bindings [0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; descriptor_set_layout_bindings [0].descriptorCount = 1; descriptor_set_layout_bindings [0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; descriptor_set_layout_bindings [0].pImmutableSamplers = null; descriptor_set_layout_bindings [1].binding = 1; descriptor_set_layout_bindings [1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; descriptor_set_layout_bindings [1].descriptorCount = 1; descriptor_set_layout_bindings [1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; descriptor_set_layout_bindings [1].pImmutableSamplers = null; descriptor_set_layout_information.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; descriptor_set_layout_information.bindingCount = 2; descriptor_set_layout_information.pBindings = descriptor_set_layout_bindings; vulkan_result (vkCreateDescriptorSetLayout (vulkan->boolean_device, & descriptor_set_layout_information, null, & vulkan->descriptor_set_layout)); print ("/c Created /2 Vulkan descriptor layout/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time); } static procedure vulkan_create_vertex_shader (vulkan_structure * vulkan) { natural vertex_shader_code [] = { 0x07230203, 0x00010000, 0x000d000b, 0x00000028, 0x00000000, 0x00020011, 0x00000001, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x000b000f, 0x00000000, 0x00000004, 0x6e69616d, 0x00000000, 0x0000000d, 0x00000012, 0x00000021, 0x00000022, 0x00000024, 0x00000026, 0x00030003, 0x00000002, 0x000001c2, 0x000a0004, 0x475f4c47, 0x4c474f4f, 0x70635f45, 0x74735f70, 0x5f656c79, 0x656e696c, 0x7269645f, 0x69746365, 0x00006576, 0x00080004, 0x475f4c47, 0x4c474f4f, 0x6e695f45, 0x64756c63, 0x69645f65, 0x74636572, 0x00657669, 0x00040005, 0x00000004, 0x6e69616d, 0x00000000, 0x00060005, 0x0000000b, 0x505f6c67, 0x65567265, 0x78657472, 0x00000000, 0x00060006, 0x0000000b, 0x00000000, 0x505f6c67, 0x7469736f, 0x006e6f69, 0x00070006, 0x0000000b, 0x00000001, 0x505f6c67, 0x746e696f, 0x657a6953, 0x00000000, 0x00070006, 0x0000000b, 0x00000002, 0x435f6c67, 0x4470696c, 0x61747369, 0x0065636e, 0x00070006, 0x0000000b, 0x00000003, 0x435f6c67, 0x446c6c75, 0x61747369, 0x0065636e, 0x00030005, 0x0000000d, 0x00000000, 0x00030005, 0x00000012, 0x00797869, 0x00030005, 0x00000021, 0x0076756f, 0x00030005, 0x00000022, 0x00767569, 0x00030005, 0x00000024, 0x0000636f, 0x00030005, 0x00000026, 0x00006369, 0x00050048, 0x0000000b, 0x00000000, 0x0000000b, 0x00000000, 0x00050048, 0x0000000b, 0x00000001, 0x0000000b, 0x00000001, 0x00050048, 0x0000000b, 0x00000002, 0x0000000b, 0x00000003, 0x00050048, 0x0000000b, 0x00000003, 0x0000000b, 0x00000004, 0x00030047, 0x0000000b, 0x00000002, 0x00040047, 0x00000012, 0x0000001e, 0x00000000, 0x00040047, 0x00000021, 0x0000001e, 0x00000000, 0x00040047, 0x00000022, 0x0000001e, 0x00000001, 0x00040047, 0x00000024, 0x0000001e, 0x00000001, 0x00040047, 0x00000026, 0x0000001e, 0x00000002, 0x00020013, 0x00000002, 0x00030021, 0x00000003, 0x00000002, 0x00030016, 0x00000006, 0x00000020, 0x00040017, 0x00000007, 0x00000006, 0x00000004, 0x00040015, 0x00000008, 0x00000020, 0x00000000, 0x0004002b, 0x00000008, 0x00000009, 0x00000001, 0x0004001c, 0x0000000a, 0x00000006, 0x00000009, 0x0006001e, 0x0000000b, 0x00000007, 0x00000006, 0x0000000a, 0x0000000a, 0x00040020, 0x0000000c, 0x00000003, 0x0000000b, 0x0004003b, 0x0000000c, 0x0000000d, 0x00000003, 0x00040015, 0x0000000e, 0x00000020, 0x00000001, 0x0004002b, 0x0000000e, 0x0000000f, 0x00000000, 0x00040017, 0x00000010, 0x00000006, 0x00000002, 0x00040020, 0x00000011, 0x00000001, 0x00000010, 0x0004003b, 0x00000011, 0x00000012, 0x00000001, 0x0004002b, 0x00000008, 0x00000013, 0x00000000, 0x00040020, 0x00000014, 0x00000001, 0x00000006, 0x0004002b, 0x00000006, 0x00000017, 0x3f800000, 0x0004002b, 0x00000006, 0x0000001c, 0x00000000, 0x00040020, 0x0000001e, 0x00000003, 0x00000007, 0x00040020, 0x00000020, 0x00000003, 0x00000010, 0x0004003b, 0x00000020, 0x00000021, 0x00000003, 0x0004003b, 0x00000011, 0x00000022, 0x00000001, 0x0004003b, 0x0000001e, 0x00000024, 0x00000003, 0x00040020, 0x00000025, 0x00000001, 0x00000007, 0x0004003b, 0x00000025, 0x00000026, 0x00000001, 0x00050036, 0x00000002, 0x00000004, 0x00000000, 0x00000003, 0x000200f8, 0x00000005, 0x00050041, 0x00000014, 0x00000015, 0x00000012, 0x00000013, 0x0004003d, 0x00000006, 0x00000016, 0x00000015, 0x00050083, 0x00000006, 0x00000018, 0x00000016, 0x00000017, 0x00050041, 0x00000014, 0x00000019, 0x00000012, 0x00000009, 0x0004003d, 0x00000006, 0x0000001a, 0x00000019, 0x00050083, 0x00000006, 0x0000001b, 0x0000001a, 0x00000017, 0x00070050, 0x00000007, 0x0000001d, 0x00000018, 0x0000001b, 0x0000001c, 0x00000017, 0x00050041, 0x0000001e, 0x0000001f, 0x0000000d, 0x0000000f, 0x0003003e, 0x0000001f, 0x0000001d, 0x0004003d, 0x00000010, 0x00000023, 0x00000022, 0x0003003e, 0x00000021, 0x00000023, 0x0004003d, 0x00000007, 0x00000027, 0x00000026, 0x0003003e, 0x00000024, 0x00000027, 0x000100fd, 0x00010038 }; VkShaderModuleCreateInfo vertex_shader_information = { 0 }; vulkan->time = tick_tock (); vertex_shader_information.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; vertex_shader_information.codeSize = sizeof (vertex_shader_code); vertex_shader_information.pCode = vertex_shader_code; vulkan_result (vkCreateShaderModule (vulkan->boolean_device, & vertex_shader_information, null, & vulkan->vertex_shader)); print ("/c Created /2Vulkan vertex shader module/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time); } static procedure vulkan_create_fragment_shader (vulkan_structure * vulkan) { natural fragment_shader_code [] = { 0x07230203, 0x00010000, 0x000d000b, 0x00000018, 0x00000000, 0x00020011, 0x00000001, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x0008000f, 0x00000004, 0x00000004, 0x6e69616d, 0x00000000, 0x00000009, 0x00000011, 0x00000015, 0x00030010, 0x00000004, 0x00000007, 0x00030003, 0x00000002, 0x000001c2, 0x000a0004, 0x475f4c47, 0x4c474f4f, 0x70635f45, 0x74735f70, 0x5f656c79, 0x656e696c, 0x7269645f, 0x69746365, 0x00006576, 0x00080004, 0x475f4c47, 0x4c474f4f, 0x6e695f45, 0x64756c63, 0x69645f65, 0x74636572, 0x00657669, 0x00040005, 0x00000004, 0x6e69616d, 0x00000000, 0x00040005, 0x00000009, 0x69727073, 0x00006574, 0x00060005, 0x0000000d, 0x74786574, 0x5f657275, 0x706d6173, 0x0072656c, 0x00030005, 0x00000011, 0x00007675, 0x00030005, 0x00000015, 0x0000636f, 0x00040047, 0x00000009, 0x0000001e, 0x00000000, 0x00040047, 0x0000000d, 0x00000022, 0x00000000, 0x00040047, 0x0000000d, 0x00000021, 0x00000001, 0x00040047, 0x00000011, 0x0000001e, 0x00000000, 0x00040047, 0x00000015, 0x0000001e, 0x00000001, 0x00020013, 0x00000002, 0x00030021, 0x00000003, 0x00000002, 0x00030016, 0x00000006, 0x00000020, 0x00040017, 0x00000007, 0x00000006, 0x00000004, 0x00040020, 0x00000008, 0x00000003, 0x00000007, 0x0004003b, 0x00000008, 0x00000009, 0x00000003, 0x00090019, 0x0000000a, 0x00000006, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x0003001b, 0x0000000b, 0x0000000a, 0x00040020, 0x0000000c, 0x00000000, 0x0000000b, 0x0004003b, 0x0000000c, 0x0000000d, 0x00000000, 0x00040017, 0x0000000f, 0x00000006, 0x00000002, 0x00040020, 0x00000010, 0x00000001, 0x0000000f, 0x0004003b, 0x00000010, 0x00000011, 0x00000001, 0x00040020, 0x00000014, 0x00000001, 0x00000007, 0x0004003b, 0x00000014, 0x00000015, 0x00000001, 0x00050036, 0x00000002, 0x00000004, 0x00000000, 0x00000003, 0x000200f8, 0x00000005, 0x0004003d, 0x0000000b, 0x0000000e, 0x0000000d, 0x0004003d, 0x0000000f, 0x00000012, 0x00000011, 0x00050057, 0x00000007, 0x00000013, 0x0000000e, 0x00000012, 0x0004003d, 0x00000007, 0x00000016, 0x00000015, 0x00050085, 0x00000007, 0x00000017, 0x00000013, 0x00000016, 0x0003003e, 0x00000009, 0x00000017, 0x000100fd, 0x00010038 }; VkShaderModuleCreateInfo fragment_shader_information = { 0 }; vulkan->time = tick_tock (); fragment_shader_information.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; fragment_shader_information.codeSize = sizeof (fragment_shader_code); fragment_shader_information.pCode = fragment_shader_code; vulkan_result (vkCreateShaderModule (vulkan->boolean_device, & fragment_shader_information, null, & vulkan->fragment_shader)); print ("/c Created /2Vulkan fragment shader module/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time); } static procedure vulkan_create_pipeline_layout (vulkan_structure * vulkan) { VkPipelineLayoutCreateInfo pipeline_layout_information = { 0 }; vulkan->time = tick_tock (); pipeline_layout_information.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipeline_layout_information.setLayoutCount = 1; pipeline_layout_information.pSetLayouts = & vulkan->descriptor_set_layout; vulkan_result (vkCreatePipelineLayout (vulkan->boolean_device, & pipeline_layout_information, VK_NULL_HANDLE, & vulkan->pipeline_layout)); print ("/c Created /2Vulkan graphics pipeline layout/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time); } static procedure vulkan_create_pipeline (vulkan_structure * vulkan) { VkPipelineShaderStageCreateInfo pipeline_shader_stage_information [2] = { { 0 } }; VkPipelineInputAssemblyStateCreateInfo pipeline_input_assembly_state_information = { 0 }; VkVertexInputBindingDescription vertex_input_binding_description [1] = { { 0 } }; VkVertexInputAttributeDescription vertex_input_attribute_description [4] = { { 0 } }; VkPipelineVertexInputStateCreateInfo pipeline_vertex_input_state_information = { 0 }; VkViewport viewport = { 0 }; VkOffset2D scissor_offset = { 0 }; VkExtent2D scissor_extent = { 0 }; VkRect2D scissor = { 0 }; VkPipelineViewportStateCreateInfo pipeline_viewport_state_information = { 0 }; VkPipelineRasterizationStateCreateInfo pipeline_rasterization_state_information = { 0 }; VkPipelineMultisampleStateCreateInfo pipeline_multisample_state_information = { 0 }; VkPipelineColorBlendAttachmentState pipeline_colour_blend_attachment_state = { 0 }; VkPipelineColorBlendStateCreateInfo pipeline_colour_blend_state_information = { 0 }; VkGraphicsPipelineCreateInfo pipeline_information = { 0 }; vulkan->time = tick_tock (); pipeline_shader_stage_information [0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; pipeline_shader_stage_information [0].stage = VK_SHADER_STAGE_VERTEX_BIT; pipeline_shader_stage_information [0].module = vulkan->vertex_shader; pipeline_shader_stage_information [0].pName = "main"; pipeline_shader_stage_information [0].pSpecializationInfo = null; pipeline_shader_stage_information [1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; pipeline_shader_stage_information [1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; pipeline_shader_stage_information [1].module = vulkan->fragment_shader; pipeline_shader_stage_information [1].pName = "main"; pipeline_shader_stage_information [1].pSpecializationInfo = null; pipeline_input_assembly_state_information.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; pipeline_input_assembly_state_information.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; pipeline_input_assembly_state_information.primitiveRestartEnable = VK_FALSE; vertex_input_binding_description [0].binding = 0; vertex_input_binding_description [0].stride = 32; vertex_input_binding_description [0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; vertex_input_attribute_description [0].binding = vertex_input_binding_description [0].binding; vertex_input_attribute_description [0].location = 0; vertex_input_attribute_description [0].format = VK_FORMAT_R32G32_SFLOAT; vertex_input_attribute_description [0].offset = 0; vertex_input_attribute_description [1].binding = vertex_input_binding_description [0].binding; vertex_input_attribute_description [1].location = 1; vertex_input_attribute_description [1].format = VK_FORMAT_R32G32_SFLOAT; vertex_input_attribute_description [1].offset = 8; vertex_input_attribute_description [2].binding = vertex_input_binding_description [0].binding; vertex_input_attribute_description [2].location = 2; vertex_input_attribute_description [2].format = VK_FORMAT_R32G32B32A32_SFLOAT; vertex_input_attribute_description [2].offset = 16; pipeline_vertex_input_state_information.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; pipeline_vertex_input_state_information.vertexBindingDescriptionCount = 1; pipeline_vertex_input_state_information.pVertexBindingDescriptions = vertex_input_binding_description; pipeline_vertex_input_state_information.vertexAttributeDescriptionCount = 3; pipeline_vertex_input_state_information.pVertexAttributeDescriptions = vertex_input_attribute_description; viewport.x = 0; viewport.y = 0; viewport.width = vulkan->width; viewport.height = vulkan->height; viewport.minDepth = 0; viewport.maxDepth = 1; scissor_offset.x = 0; scissor_offset.y = 0; scissor_extent.width = vulkan->width; scissor_extent.height = vulkan->height; scissor.offset = scissor_offset; scissor.extent = scissor_extent; pipeline_viewport_state_information.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; pipeline_viewport_state_information.viewportCount = 1; pipeline_viewport_state_information.pViewports = & viewport; pipeline_viewport_state_information.scissorCount = 1; pipeline_viewport_state_information.pScissors = & scissor; pipeline_rasterization_state_information.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; pipeline_rasterization_state_information.depthClampEnable = VK_FALSE; pipeline_rasterization_state_information.rasterizerDiscardEnable = VK_FALSE; pipeline_rasterization_state_information.polygonMode = VK_POLYGON_MODE_FILL; pipeline_rasterization_state_information.cullMode = VK_CULL_MODE_BACK_BIT; pipeline_rasterization_state_information.frontFace = VK_FRONT_FACE_CLOCKWISE; pipeline_rasterization_state_information.depthBiasEnable = VK_FALSE; pipeline_rasterization_state_information.depthBiasConstantFactor = 0; pipeline_rasterization_state_information.depthBiasClamp = 0; pipeline_rasterization_state_information.depthBiasSlopeFactor = 0; pipeline_rasterization_state_information.lineWidth = 1; pipeline_multisample_state_information.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; pipeline_multisample_state_information.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; pipeline_multisample_state_information.sampleShadingEnable = VK_FALSE; pipeline_multisample_state_information.minSampleShading = 1; pipeline_multisample_state_information.pSampleMask = null; pipeline_multisample_state_information.alphaToCoverageEnable = VK_FALSE; pipeline_multisample_state_information.alphaToOneEnable = VK_FALSE; pipeline_colour_blend_attachment_state.blendEnable = VK_TRUE; pipeline_colour_blend_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; pipeline_colour_blend_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; pipeline_colour_blend_attachment_state.colorBlendOp = VK_BLEND_OP_ADD; pipeline_colour_blend_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; pipeline_colour_blend_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; pipeline_colour_blend_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD; pipeline_colour_blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; pipeline_colour_blend_state_information.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; pipeline_colour_blend_state_information.logicOpEnable = VK_FALSE; pipeline_colour_blend_state_information.logicOp = VK_LOGIC_OP_COPY; pipeline_colour_blend_state_information.attachmentCount = 1; pipeline_colour_blend_state_information.pAttachments = & pipeline_colour_blend_attachment_state; pipeline_information.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; pipeline_information.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT; pipeline_information.stageCount = 2; pipeline_information.pStages = pipeline_shader_stage_information; pipeline_information.pVertexInputState = & pipeline_vertex_input_state_information; pipeline_information.pInputAssemblyState = & pipeline_input_assembly_state_information; pipeline_information.pTessellationState = null; pipeline_information.pViewportState = & pipeline_viewport_state_information; pipeline_information.pRasterizationState = & pipeline_rasterization_state_information; pipeline_information.pMultisampleState = & pipeline_multisample_state_information; pipeline_information.pDepthStencilState = null; pipeline_information.pColorBlendState = & pipeline_colour_blend_state_information; pipeline_information.pDynamicState = null; pipeline_information.layout = vulkan->pipeline_layout; pipeline_information.renderPass = vulkan->render_pass; pipeline_information.subpass = 0; pipeline_information.basePipelineHandle = VK_NULL_HANDLE; pipeline_information.basePipelineIndex = -1; vulkan_result (vkCreateGraphicsPipelines (vulkan->boolean_device, VK_NULL_HANDLE, 1, & pipeline_information, null, & vulkan->pipeline)); print ("/c Created /2Vulkan graphics pipeline/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time); } static procedure vulkan_create_framebuffers (vulkan_structure * vulkan) { VkFramebufferCreateInfo framebuffer_information = { 0 }; vulkan->time = tick_tock (); vulkan->framebuffers = allocate (vulkan->image_count * sizeof (VkFramebuffer)); framebuffer_information.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; framebuffer_information.renderPass = vulkan->render_pass; framebuffer_information.attachmentCount = 1; framebuffer_information.width = vulkan->extent.width; framebuffer_information.height = vulkan->extent.height; framebuffer_information.layers = 1; for (natural index = 0; index < vulkan->image_count; ++index) { framebuffer_information.pAttachments = & vulkan->image_views [index]; vulkan_result (vkCreateFramebuffer (vulkan->boolean_device, & framebuffer_information, null, & vulkan->framebuffers [index])); } print ("/c Created /2Vulkan framebuffers/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time); } static procedure vulkan_create_command_pool (vulkan_structure * vulkan) { VkCommandPoolCreateInfo command_pool_information = { 0 }; vulkan->time = tick_tock (); command_pool_information.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; command_pool_information.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; command_pool_information.queueFamilyIndex = vulkan->queue_index; vulkan_result (vkCreateCommandPool (vulkan->boolean_device, & command_pool_information, null, & vulkan->command_pool)); print ("/c Created /2Vulkan command pool/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time); } static procedure vulkan_create_command_buffers (vulkan_structure * vulkan) { VkCommandBufferAllocateInfo command_buffer_information = { 0 }; vulkan->time = tick_tock (); vulkan->command_buffers = allocate (vulkan->image_count * sizeof (VkCommandBuffer)); command_buffer_information.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; command_buffer_information.commandPool = vulkan->command_pool; command_buffer_information.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; command_buffer_information.commandBufferCount = vulkan->image_count; vulkan_result (vkAllocateCommandBuffers (vulkan->boolean_device, & command_buffer_information, vulkan->command_buffers)); print ("/c Allocated /2Vulkan command buffers/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time); } static procedure vulkan_create_vertex_buffer (vulkan_structure * vulkan) { VkBuffer transfer_buffer = VK_NULL_HANDLE; VkDeviceMemory transfer_memory = VK_NULL_HANDLE; procedure * transfer_procedure = null; VkBufferCopy copy_information = { 0 }; /* vulkan->time = tick_tock (); */ vulkan->vertex_size = vulkan->vertex_count * sizeof (* vulkan->vertex_data); vulkan_create_buffer (vulkan, & transfer_buffer, & transfer_memory, vulkan->vertex_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT); vulkan_result (vkMapMemory (vulkan->boolean_device, transfer_memory, 0, vulkan->vertex_size, 0, & transfer_v0)); memory_copy (transfer_v0, vulkan->vertex_data, vulkan->vertex_size); vulkan_create_buffer (vulkan, & vulkan->vertex_buffer, & vulkan->vertex_memory, vulkan->vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); vulkan_begin_command_buffer (vulkan); copy_information.srcOffset = 0; copy_information.dstOffset = 0; copy_information.size = vulkan->vertex_size; vkCmdCopyBuffer (vulkan->transfer_buffer, transfer_buffer, vulkan->vertex_buffer, 1, & copy_information); vulkan_end_command_buffer (vulkan); vkDestroyBuffer (vulkan->boolean_device, transfer_buffer, null); vkFreeMemory (vulkan->boolean_device, transfer_memory, null); /*print ("/c Created /2Vulkan vertex buffer/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time);*/ } static procedure vulkan_create_index_buffer (vulkan_structure * vulkan) { VkBuffer transfer_buffer = VK_NULL_HANDLE; VkDeviceMemory transfer_memory = VK_NULL_HANDLE; procedure * transfer_procedure = null; VkBufferCopy copy_information = { 0 }; /* vulkan->time = tick_tock (); */ vulkan->index_size = vulkan->index_count * sizeof (* vulkan->index_data); vulkan_create_buffer (vulkan, & transfer_buffer, & transfer_memory, vulkan->index_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT); vulkan_result (vkMapMemory (vulkan->boolean_device, transfer_memory, 0, vulkan->index_size, 0, & transfer_v0)); memory_copy (transfer_v0, vulkan->index_data, vulkan->index_size); vulkan_create_buffer (vulkan, & vulkan->index_buffer, & vulkan->index_memory, vulkan->index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); vulkan_begin_command_buffer (vulkan); copy_information.srcOffset = 0; copy_information.dstOffset = 0; copy_information.size = vulkan->index_size; vkCmdCopyBuffer (vulkan->transfer_buffer, transfer_buffer, vulkan->index_buffer, 1, & copy_information); vulkan_end_command_buffer (vulkan); vkDestroyBuffer (vulkan->boolean_device, transfer_buffer, null); vkFreeMemory (vulkan->boolean_device, transfer_memory, null); /* print ("/c Created /2Vulkan index buffer/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time);*/ } static procedure vulkan_create_image_buffer (vulkan_structure * vulkan) { VkBuffer transfer_buffer = VK_NULL_HANDLE; VkDeviceMemory transfer_memory = VK_NULL_HANDLE; procedure * transfer_procedure = null; VkExtent3D image_extent = { 0 }; VkImageCreateInfo image_information = { 0 }; VkMemoryRequirements memory_requirements = { 0 }; VkMemoryAllocateInfo memory_allocation_information = { 0 }; VkImageSubresourceLayers region_subresource_layers = { 0 }; VkOffset3D region_offset = { 0 }; VkExtent3D region_extent = { 0 }; VkBufferImageCopy region_copying_information = { 0 }; VkComponentMapping component_mapping = { 0 }; VkImageSubresourceRange image_subresource_range = { 0 }; VkImageViewCreateInfo image_view_information = { 0 }; VkImageMemoryBarrier image_memory_barrier = { 0 }; vulkan->time = tick_tock (); vulkan_create_buffer (vulkan, & transfer_buffer, & transfer_memory, vulkan->layout_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT); vulkan_result (vkMapMemory (vulkan->boolean_device, transfer_memory, 0, vulkan->layout_size, 0, & transfer_v0)); memory_copy (transfer_v0, vulkan->layout_data, vulkan->layout_size); image_extent.width = vulkan->layout_width; image_extent.height = vulkan->layout_height; image_extent.depth = 1; image_information.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image_information.imageType = VK_IMAGE_TYPE_2D; image_information.format = vulkan->format; image_information.extent = image_extent; image_information.mipLevels = 1; image_information.arrayLayers = 1; image_information.samples = VK_SAMPLE_COUNT_1_BIT; image_information.tiling = VK_IMAGE_TILING_OPTIMAL; image_information.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; image_information.sharingMode = VK_SHARING_MODE_EXCLUSIVE; image_information.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; image_subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; image_subresource_range.baseMipLevel = 0; image_subresource_range.levelCount = 1; image_subresource_range.baseArrayLayer = 0; image_subresource_range.layerCount = 1; vulkan_result (vkCreateImage (vulkan->boolean_device, & image_information, null, & vulkan->layout_image)); vkGetImageMemoryRequirements (vulkan->boolean_device, vulkan->layout_image, & memory_requirements); memory_allocation_information.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; memory_allocation_information.allocationSize = memory_requirements.size; memory_allocation_information.memoryTypeIndex = vulkan_choose_memory_property (vulkan, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); vulkan_result (vkAllocateMemory (vulkan->boolean_device, & memory_allocation_information, null, & vulkan->layout_memory)); vulkan_result (vkBindImageMemory (vulkan->boolean_device, vulkan->layout_image, vulkan->layout_memory, 0)); vulkan_begin_command_buffer (vulkan); image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; image_memory_barrier.pNext = null; image_memory_barrier.srcAccessMask = 0; image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = vulkan->layout_image; image_memory_barrier.subresourceRange = image_subresource_range; vkCmdPipelineBarrier (vulkan->transfer_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, null, 0, null, 1, & image_memory_barrier); vulkan_end_command_buffer (vulkan); vulkan_begin_command_buffer (vulkan); region_subresource_layers.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; region_subresource_layers.mipLevel = 0; region_subresource_layers.baseArrayLayer = 0; region_subresource_layers.layerCount = 1; region_offset.x = 0; region_offset.y = 0; region_offset.z = 0; region_extent.width = vulkan->layout_width; region_extent.height = vulkan->layout_height; region_extent.depth = 1; region_copying_information.bufferOffset = 0; region_copying_information.bufferRowLength = 0; region_copying_information.bufferImageHeight = 0; region_copying_information.imageSubresource = region_subresource_layers; region_copying_information.imageOffset = region_offset; region_copying_information.imageExtent = region_extent; vkCmdCopyBufferToImage (vulkan->transfer_buffer, transfer_buffer, vulkan->layout_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, & region_copying_information); vulkan_end_command_buffer (vulkan); vulkan_begin_command_buffer (vulkan); image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; image_memory_barrier.pNext = null; image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = vulkan->layout_image; image_memory_barrier.subresourceRange = image_subresource_range; vkCmdPipelineBarrier (vulkan->transfer_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, null, 0, null, 1, & image_memory_barrier); vulkan_end_command_buffer (vulkan); component_mapping.r = VK_COMPONENT_SWIZZLE_R; component_mapping.g = VK_COMPONENT_SWIZZLE_G; component_mapping.b = VK_COMPONENT_SWIZZLE_B; component_mapping.a = VK_COMPONENT_SWIZZLE_A; image_view_information.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; image_view_information.viewType = VK_IMAGE_VIEW_TYPE_2D; image_view_information.format = vulkan->format; image_view_information.components = component_mapping; image_view_information.subresourceRange = image_subresource_range; image_view_information.image = vulkan->layout_image; vulkan_result (vkCreateImageView (vulkan->boolean_device, & image_view_information, null, & vulkan->layout_image_view)); vkDestroyBuffer (vulkan->boolean_device, transfer_buffer, null); vkFreeMemory (vulkan->boolean_device, transfer_memory, null); print ("/c Created /2Vulkan image layout buffer/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time); } static procedure vulkan_create_sampler (vulkan_structure * vulkan) { VkSamplerCreateInfo sampler_information = { 0 }; vulkan->time = tick_tock (); sampler_information.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; sampler_information.magFilter = VK_FILTER_NEAREST; sampler_information.minFilter = VK_FILTER_NEAREST; sampler_information.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; sampler_information.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; sampler_information.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; sampler_information.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; sampler_information.mipLodBias = 0; sampler_information.anisotropyEnable = VK_FALSE; sampler_information.maxAnisotropy = 1; sampler_information.compareEnable = VK_FALSE; sampler_information.compareOp = VK_COMPARE_OP_ALWAYS; sampler_information.minLod = 0; sampler_information.maxLod = 0; sampler_information.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; sampler_information.unnormalizedCoordinates = VK_FALSE; vulkan_result (vkCreateSampler (vulkan->boolean_device, & sampler_information, null, & vulkan->sampler)); print ("/c Created /2Vulkan sampler/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time); } static procedure vulkan_create_descriptor_pool (vulkan_structure * vulkan) { VkDescriptorPoolSize descriptor_pool_sizes [2] = { { 0 } }; VkDescriptorPoolCreateInfo descriptor_pool_information = { 0 }; vulkan->time = tick_tock (); descriptor_pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; descriptor_pool_sizes[0].descriptorCount = vulkan->image_count; descriptor_pool_sizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; descriptor_pool_sizes[1].descriptorCount = vulkan->image_count; descriptor_pool_information.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; descriptor_pool_information.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; descriptor_pool_information.maxSets = vulkan->image_count; descriptor_pool_information.poolSizeCount = 2; descriptor_pool_information.pPoolSizes = descriptor_pool_sizes; vulkan_result (vkCreateDescriptorPool (vulkan->boolean_device, & descriptor_pool_information, null, & vulkan->descriptor_pool)); print ("/c Created /2Vulkan descriptor pool/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time); } static procedure vulkan_create_descriptor_sets (vulkan_structure * vulkan) { VkDescriptorSetAllocateInfo descriptor_set_allocation_information = { 0 }; vulkan->time = tick_tock (); vulkan->descriptor_set_layouts = allocate (vulkan->image_count * sizeof (VkDescriptorSetLayout)); for (natural index = 0; index < vulkan->image_count; ++index) { vulkan->descriptor_set_layouts [index] = vulkan->descriptor_set_layout; } descriptor_set_allocation_information.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; descriptor_set_allocation_information.descriptorPool = vulkan->descriptor_pool; descriptor_set_allocation_information.descriptorSetCount = vulkan->image_count; descriptor_set_allocation_information.pSetLayouts = vulkan->descriptor_set_layouts; vulkan->descriptor_sets = allocate (vulkan->image_count * sizeof (VkDescriptorSet)); vulkan_result (vkAllocateDescriptorSets (vulkan->boolean_device, & descriptor_set_allocation_information, vulkan->descriptor_sets)); print ("/c Allocated /2Vulkan descriptor sets/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time); } static procedure vulkan_record_descriptor_sets (vulkan_structure * vulkan) { VkDescriptorBufferInfo descriptor_buffer_information = { 0 }; VkDescriptorImageInfo descriptor_image_information = { 0 }; VkWriteDescriptorSet write_descriptor_set = { 0 }; vulkan->time = tick_tock (); descriptor_image_information.sampler = vulkan->sampler; descriptor_image_information.imageView = vulkan->layout_image_view; descriptor_image_information.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; write_descriptor_set.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; write_descriptor_set.dstBinding = 1; write_descriptor_set.dstArrayElement = 0; write_descriptor_set.descriptorCount = 1; write_descriptor_set.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; write_descriptor_set.pImageInfo = & descriptor_image_information; write_descriptor_set.pBufferInfo = null; for (natural index = 0; index < vulkan->image_count; ++index) { write_descriptor_set.dstSet = vulkan->descriptor_sets [index]; vkUpdateDescriptorSets (vulkan->boolean_device, 1, & write_descriptor_set, 0, null); } print ("/c Recorded /2Vulkan descriptor sets/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time); } static procedure vulkan_record_command_buffers (vulkan_structure * vulkan, integer clear_colour, integer frame) { natural index = 0; VkCommandBufferBeginInfo command_buffer_begin_information = { 0 }; //~VkImageSubresourceRange image_subresource_range = { 0 }; VkClearValue clear_value = { 0 }; VkOffset2D render_area_offset = { 0 }; VkExtent2D render_area_extent = { 0 }; VkRect2D render_area = { 0 }; VkRenderPassBeginInfo render_pass_begin_information = { 0 }; VkDeviceSize vertex_offset = 0; VkClearColorValue clear_colour_value = { { (real) ((clear_colour & 0xff000000) >> 24) / 255, (real) ((clear_colour & 0x00ff0000) >> 16) / 255, (real) ((clear_colour & 0x0000ff00) >> 8) / 255, (real) ((clear_colour & 0x000000ff) >> 0) / 255 } }; (none) frame; /* vulkan->time = tick_tock (); */ command_buffer_begin_information.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; command_buffer_begin_information.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; //~image_subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; //~image_subresource_range.baseMipLevel = 0; //~image_subresource_range.levelCount = 1; //~image_subresource_range.baseArrayLayer = 0; //~image_subresource_range.layerCount = 1; clear_value.color = clear_colour_value; render_area_offset.x = 0; render_area_offset.y = 0; render_area_extent.width = vulkan->extent.width; render_area_extent.height = vulkan->extent.height; render_area.offset = render_area_offset; render_area.extent = render_area_extent; render_pass_begin_information.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; render_pass_begin_information.pNext = null; render_pass_begin_information.renderPass = vulkan->render_pass; render_pass_begin_information.renderArea = render_area; render_pass_begin_information.clearValueCount = 1; render_pass_begin_information.pClearValues = & clear_value; for (index = 0; index < vulkan->image_count; ++index) { render_pass_begin_information.framebuffer = vulkan->framebuffers [index]; vulkan_result (vkBeginCommandBuffer (vulkan->command_buffers [index], & command_buffer_begin_information)); vkCmdBeginRenderPass (vulkan->command_buffers [index], & render_pass_begin_information, VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline (vulkan->command_buffers [index], VK_PIPELINE_BIND_POINT_GRAPHICS, vulkan->pipeline); vkCmdBindVertexBuffers (vulkan->command_buffers [index], 0, 1, & vulkan->vertex_buffer, & vertex_offset); vkCmdBindIndexBuffer (vulkan->command_buffers [index], vulkan->index_buffer, 0, VK_INDEX_TYPE_UINT32); vkCmdBindDescriptorSets (vulkan->command_buffers [index], VK_PIPELINE_BIND_POINT_GRAPHICS, vulkan->pipeline_layout, 0, 1, vulkan->descriptor_sets, 0, null); vkCmdDrawIndexed (vulkan->command_buffers [index], vulkan->index_count, 1, 0, 0, 0); vkCmdEndRenderPass (vulkan->command_buffers [index]); vulkan_result (vkEndCommandBuffer (vulkan->command_buffers [index])); } /* render_pass_begin_information.framebuffer = vulkan_framebuffers [frame]; vulkan_result (vkBeginCommandBuffer (vulkan_command_buffers [frame], & command_buffer_begin_information)); vkCmdBeginRenderPass (vulkan_command_buffers [frame], & render_pass_begin_information, VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline (vulkan_command_buffers [frame], VK_PIPELINE_BIND_POINT_GRAPHICS, vulkan_pipeline); vkCmdBindVertexBuffers (vulkan_command_buffers [frame], 0, 1, & vulkan_vertex_buffer, & vertex_offset); vkCmdBindIndexBuffer (vulkan_command_buffers [frame], vulkan_index_buffer, 0, VK_INDEX_TYPE_UINT32); vkCmdBindDescriptorSets (vulkan_command_buffers [frame], VK_PIPELINE_BIND_POINT_GRAPHICS, vulkan_pipeline_layout, 0, 1, vulkan_descriptor_sets, 0, null); vkCmdDrawIndexed (vulkan_command_buffers [frame], vulkan_index_count, 1, 0, 0, 0); vkCmdEndRenderPass (vulkan_command_buffers [frame]); vulkan_result (vkEndCommandBuffer (vulkan_command_buffers [frame])); */ vulkan_result (vkQueueWaitIdle (vulkan->queue)); vulkan_result (vkDeviceWaitIdle (vulkan->boolean_device)); /*print ("/c Recorded /2Vulkan command buffers/-.\n"); print ("/c Time approximation: /6%i/-\n", tick_tock () - vulkan->time);*/ } static natural vulkan_import_sprite (vulkan_structure * vulkan, natural * data, natural width, natural height) { fatal_failure (vulkan->active == true, "vulkan_import_sprite: Failed to import sprite, engine was already configured."); fatal_failure (data == null, "vulkan_import_sprite: Failed to import sprite, data is null pointer."); fatal_failure (width <= 0, "vulkan_import_sprite: Failed to import sprite, width is equal or below zero."); fatal_failure (height <= 0, "vulkan_import_sprite: Failed to import sprite, height is equal or below zero."); ++vulkan->sprite_count; vulkan->sprite_data = reallocate (vulkan->sprite_data, vulkan->sprite_count * sizeof (* vulkan->sprite_data)); vulkan->sprite_width = reallocate (vulkan->sprite_width, vulkan->sprite_count * sizeof (* vulkan->sprite_width)); vulkan->sprite_height = reallocate (vulkan->sprite_height, vulkan->sprite_count * sizeof (* vulkan->sprite_height)); vulkan->sprite_u = reallocate (vulkan->sprite_u, vulkan->sprite_count * sizeof (* vulkan->sprite_u)); vulkan->sprite_v = reallocate (vulkan->sprite_v, vulkan->sprite_count * sizeof (* vulkan->sprite_v)); vulkan->sprite_data [vulkan->sprite_count - 1] = data; vulkan->sprite_width [vulkan->sprite_count - 1] = width; vulkan->sprite_height [vulkan->sprite_count - 1] = height; vulkan->sprite_u [vulkan->sprite_count - 1] = 0; vulkan->sprite_v [vulkan->sprite_count - 1] = 0; return (vulkan->sprite_count - 1); } static natural vulkan_import_font (vulkan_structure * vulkan, natural * data, natural image_width, natural image_height, character begin, character end, natural empty) { natural pointer = 0; character index = 0; natural width = 0; natural height = 0; natural x = 0; natural y = 0; natural * buffer = null; ++vulkan->font_count; vulkan->font_index = reallocate (vulkan->font_index, vulkan->font_count * sizeof (* vulkan->font_index)); vulkan->font_width = reallocate (vulkan->font_width, vulkan->font_count * sizeof (* vulkan->font_width)); vulkan->font_height = reallocate (vulkan->font_height, vulkan->font_count * sizeof (* vulkan->font_height)); vulkan->font_begin = reallocate (vulkan->font_begin, vulkan->font_count * sizeof (* vulkan->font_begin)); vulkan->font_end = reallocate (vulkan->font_end, vulkan->font_count * sizeof (* vulkan->font_end)); vulkan->font_begin [vulkan->font_count - 1] = begin; vulkan->font_end [vulkan->font_count - 1] = end; vulkan->font_index [vulkan->font_count - 1] = allocate ((end - begin + 1) * sizeof (* * vulkan->font_index)); vulkan->font_width [vulkan->font_count - 1] = allocate ((end - begin + 1) * sizeof (* * vulkan->font_width)); vulkan->font_height [vulkan->font_count - 1] = allocate ((end - begin + 1) * sizeof (* * vulkan->font_height)); for (index = begin; index <= end; ++index) { for ( ; data [pointer] == empty; ++pointer); for (width = 0; data [pointer + width] != empty; ++width); for (height = 0; data [pointer + height * image_width] != empty; ++height); buffer = allocate (width * height * sizeof (* buffer)); for (y = 0; y < height; ++y) { for (x = 0; x < width; ++x) { buffer [y * width + x] = data [pointer + (y * image_width) + x]; } } vulkan->font_index [vulkan->font_count - 1] [index - begin] = vulkan_import_sprite (vulkan, buffer, width, height); vulkan->font_width [vulkan->font_count - 1] [index - begin] = width; vulkan->font_height [vulkan->font_count - 1] [index - begin] = height; pointer += width; for (; data [pointer] == empty; ++pointer); if (pointer % image_width == 2) { pointer += height * image_width; } } return (vulkan->font_count - 1); } static procedure vulkan_bundle_layout (vulkan_structure * vulkan) { natural * order = null; vulkan->layout_size = vulkan->layout_width * vulkan->layout_height * (natural) sizeof (* vulkan->layout_data); vulkan->layout_data = allocate (vulkan->layout_size); order = allocate (vulkan->sprite_count * sizeof (* order)); for (natural index = 0; index < vulkan->sprite_count; ++index) { order [index] = index; } for (natural index = 0; index < vulkan->sprite_count; ++index) { for (natural subindex = 0; subindex < vulkan->sprite_count; ++subindex) { if (vulkan->sprite_height [order [index]] < vulkan->sprite_height [order [subindex]]) { integer temporary = order [index]; order [index] = order [subindex]; order [subindex] = temporary; } } } for (natural index = 0; index < vulkan->sprite_count; ++index) { natural x = 0; natural y = 0; natural u = 0; natural v = 0; if (u + vulkan->sprite_width [order [index]] >= vulkan->layout_width) { u *= 0; v += vulkan->sprite_height [order [index]]; } vulkan->sprite_u [order [index]] = (real) u / (real) vulkan->layout_width; vulkan->sprite_v [order [index]] = (real) v / (real) vulkan->layout_height; for (natural y = 0; y < vulkan->sprite_height [order [index]]; ++y) { for (natural x = 0; x < vulkan->sprite_width [order [index]]; ++x) { natural destination = (v + y) * vulkan->layout_width + (u + x); natural source = y * vulkan->sprite_width [order [index]] + x; vulkan->layout_data [destination] = vulkan->sprite_data [order [index]] [source]; } } u += vulkan->sprite_width [order [index]]; vulkan->sprite_data [order [index]] = deallocate (vulkan->sprite_data [order [index]]); } vulkan->sprite_data = deallocate (vulkan->sprite_data); order = deallocate (order); } static procedure vulkan_configure (vulkan_structure * vulkan, integer width, integer height, character * application) { integer index = 0; natural * dumb_buffer = null; if (vulkan->active == true) { return; } vulkan->width = width; vulkan->height = height; vulkan->pixel_width = (real) 2 / (real) width; vulkan->pixel_height = (real) 2 / (real) height; dumb_buffer = allocate (256 * sizeof (* dumb_buffer)); for (index = 0; index < 256; ++index) { dumb_buffer [index] = ~0; } vulkan_import_sprite (vulkan, dumb_buffer, 16, 16); vulkan_bundle_layout (vulkan); vulkan->vertex_data = allocate (vulkan->vertex_limit * sizeof (* vulkan->vertex_data)); vulkan->index_data = allocate (vulkan->index_limit * sizeof (* vulkan->index_data)); vulkan_create_window (vulkan, application); vulkan_create_instance (vulkan, application); print ("/c Variable : width = %i\n", vulkan->width); print ("/c Variable : height = %i\n", vulkan->height); print ("/c Variable : sprite_count = %i\n", vulkan->sprite_count); print ("/c Variable : font_count = %i\n", vulkan->font_count); print ("/c Variable : gameplay_framerate = %i\n", vulkan->gameplay_framerate); print ("/c Variable : animation_framerate = %i\n", vulkan->animation_framerate); print ("/c Variable : vertex_limit = %i\n", vulkan->vertex_limit); print ("/c Variable : index_limit = %i\n", vulkan->index_limit); print ("/c Variable : layout_size = %i\n", vulkan->layout_size); print ("/c Variable : layout_width = %i\n", vulkan->layout_width); print ("/c Variable : layout_height = %i\n", vulkan->layout_height); vulkan_create_surface (vulkan); vulkan_create_device (vulkan); vulkan_choose_extent (vulkan); vulkan_choose_format (vulkan); vulkan_choose_present_mode (vulkan); vulkan_create_swapchain (vulkan); vulkan_create_images (vulkan); vulkan_create_image_views (vulkan); vulkan_create_semaphores (vulkan); vulkan_create_fences (vulkan); vulkan_create_render_pass (vulkan); vulkan_create_descriptor_set_layout (vulkan); vulkan_create_vertex_shader (vulkan); vulkan_create_fragment_shader (vulkan); vulkan_create_pipeline_layout (vulkan); vulkan_create_pipeline (vulkan); vulkan_create_framebuffers (vulkan); vulkan_create_command_pool (vulkan); vulkan_create_command_buffers (vulkan); vulkan_create_image_buffer (vulkan); vulkan_create_sampler (vulkan); vulkan_create_descriptor_pool (vulkan); vulkan_create_descriptor_sets (vulkan); vulkan_record_descriptor_sets (vulkan); vulkan->active = true; } /* static procedure vulkan_reconfigure (none) { integer index; vulkan_result (vkQueueWaitIdle (vulkan_queue)); vulkan_result (vkDeviceWaitIdle (vulkan_boolean_device)); for (index = 0; index < vulkan_image_count; ++index) { vkDestroyFramebuffer (vulkan_boolean_device, vulkan_framebuffers [index], null); } vulkan_framebuffers = deallocate (vulkan_framebuffers); for (index = 0; index < vulkan_image_count; ++index) { vkDestroyImageView (vulkan_boolean_device, vulkan_image_views [index], null); } vulkan_image_views = deallocate (vulkan_image_views); vkDestroySwapchainKHR (vulkan_boolean_device, vulkan_swapchain, null); vulkan_images = deallocate (vulkan_images); vulkan_choose_extent (); vulkan_choose_format (); vulkan_choose_present_mode (); vulkan_create_swapchain (); vulkan_create_images (); vulkan_create_image_views (); vulkan_create_framebuffers (); vulkan_result (vkQueueWaitIdle (vulkan_queue)); vulkan_result (vkDeviceWaitIdle (vulkan_boolean_device)); vulkan_reconfigure_active = false; } */ static procedure vulkan_render_core (vulkan_structure * vulkan, integer sprite, integer x, integer y, integer u, integer v, integer width, integer height, real scale_x, real scale_y, integer flip_x, integer flip_y, integer colour_0, natural colour_1, natural colour_2, natural colour_3) { real screen_x = x * vulkan->pixel_width; real screen_y = y * vulkan->pixel_height; real unwrap_x = vulkan->sprite_u [sprite] + (real) u / vulkan->layout_width; real unwrap_y = vulkan->sprite_v [sprite] + (real) v / vulkan->layout_height; real screen_width = (real) width * vulkan->pixel_width * scale_x; real screen_height = (real) height * vulkan->pixel_height * scale_y; real unwrap_width = (real) width / vulkan->layout_width; real unwrap_height = (real) height / vulkan->layout_height; fatal_failure (vulkan->vertex_count + 32 >= vulkan->vertex_limit, "Reached vertex limit."); fatal_failure (vulkan->index_count + 6 >= vulkan->index_limit, "Reached index limit."); vulkan->vertex_data [vulkan->vertex_count + 0] = screen_x; vulkan->vertex_data [vulkan->vertex_count + 1] = screen_y; vulkan->vertex_data [vulkan->vertex_count + 2] = unwrap_x + unwrap_width * (flip_y != 0); vulkan->vertex_data [vulkan->vertex_count + 3] = unwrap_y + unwrap_height * (flip_x != 0); vulkan->vertex_data [vulkan->vertex_count + 4] = (real) ((colour_0 >> 24) & 0xff) / 255; vulkan->vertex_data [vulkan->vertex_count + 5] = (real) ((colour_0 >> 16) & 0xff) / 255; vulkan->vertex_data [vulkan->vertex_count + 6] = (real) ((colour_0 >> 8) & 0xff) / 255; vulkan->vertex_data [vulkan->vertex_count + 7] = (real) ((colour_0 >> 0) & 0xff) / 255; vulkan->vertex_data [vulkan->vertex_count + 8] = screen_x + screen_width; vulkan->vertex_data [vulkan->vertex_count + 9] = screen_y; vulkan->vertex_data [vulkan->vertex_count + 10] = unwrap_x + unwrap_width * (flip_y == 0); vulkan->vertex_data [vulkan->vertex_count + 11] = unwrap_y + unwrap_height * (flip_x != 0); vulkan->vertex_data [vulkan->vertex_count + 12] = (real) ((colour_1 >> 24) & 0xff) / 255; vulkan->vertex_data [vulkan->vertex_count + 13] = (real) ((colour_1 >> 16) & 0xff) / 255; vulkan->vertex_data [vulkan->vertex_count + 14] = (real) ((colour_1 >> 8) & 0xff) / 255; vulkan->vertex_data [vulkan->vertex_count + 15] = (real) ((colour_1 >> 0) & 0xff) / 255; vulkan->vertex_data [vulkan->vertex_count + 16] = screen_x; vulkan->vertex_data [vulkan->vertex_count + 17] = screen_y + screen_height; vulkan->vertex_data [vulkan->vertex_count + 18] = unwrap_x + unwrap_width * (flip_y != 0); vulkan->vertex_data [vulkan->vertex_count + 19] = unwrap_y + unwrap_height * (flip_x == 0); vulkan->vertex_data [vulkan->vertex_count + 20] = (real) ((colour_2 >> 24) & 0xff) / 255; vulkan->vertex_data [vulkan->vertex_count + 21] = (real) ((colour_2 >> 16) & 0xff) / 255; vulkan->vertex_data [vulkan->vertex_count + 22] = (real) ((colour_2 >> 8) & 0xff) / 255; vulkan->vertex_data [vulkan->vertex_count + 23] = (real) ((colour_2 >> 0) & 0xff) / 255; vulkan->vertex_data [vulkan->vertex_count + 24] = screen_x + screen_width; vulkan->vertex_data [vulkan->vertex_count + 25] = screen_y + screen_height; vulkan->vertex_data [vulkan->vertex_count + 26] = unwrap_x + unwrap_width * (flip_y == 0); vulkan->vertex_data [vulkan->vertex_count + 27] = unwrap_y + unwrap_height * (flip_x == 0); vulkan->vertex_data [vulkan->vertex_count + 28] = (real) ((colour_3 >> 24) & 0xff) / 255; vulkan->vertex_data [vulkan->vertex_count + 29] = (real) ((colour_3 >> 16) & 0xff) / 255; vulkan->vertex_data [vulkan->vertex_count + 30] = (real) ((colour_3 >> 8) & 0xff) / 255; vulkan->vertex_data [vulkan->vertex_count + 31] = (real) ((colour_3 >> 0) & 0xff) / 255; vulkan->index_data [vulkan->index_count + 0] = (vulkan->vertex_count >> 3) + 0; vulkan->index_data [vulkan->index_count + 1] = (vulkan->vertex_count >> 3) + 1; vulkan->index_data [vulkan->index_count + 2] = (vulkan->vertex_count >> 3) + 2; vulkan->index_data [vulkan->index_count + 3] = (vulkan->vertex_count >> 3) + 1; vulkan->index_data [vulkan->index_count + 4] = (vulkan->vertex_count >> 3) + 3; vulkan->index_data [vulkan->index_count + 5] = (vulkan->vertex_count >> 3) + 2; vulkan->vertex_count += 32; vulkan->index_count += 6; } static procedure vulkan_render_sprite (vulkan_structure * vulkan, integer sprite, integer x, integer y, natural colour) { vulkan_render_core (vulkan, sprite, x, y, 0, 0, vulkan->sprite_width [sprite], vulkan->sprite_height [sprite], 1.0, 1.0, 0, 0, colour, colour, colour,colour); } static procedure vulkan_render_sprite_scale (vulkan_structure * vulkan, integer sprite, integer x, integer y, real scale, natural colour) { vulkan_render_core (vulkan, sprite, x, y, 0, 0, vulkan->sprite_width [sprite], vulkan->sprite_height [sprite], scale, scale, 0, 0, colour, colour, colour,colour); } static procedure vulkan_render_sprite_crop (vulkan_structure * vulkan, integer sprite, integer x, integer y, integer u, integer v, integer width, integer height, natural colour) { vulkan_render_core (vulkan, sprite, x, y, u, v, width, height, 1.0, 1.0, 0, 0, colour, colour, colour, colour); } static procedure vulkan_render_rectangle (vulkan_structure * vulkan, integer x, integer y, integer width, integer height, natural colour) { vulkan_render_core (vulkan, vulkan->sprite_count - 1, x, y, 0, 0, 16, 16, (real) width / 16, (real) height / 16, 0, 0, colour, colour, colour, colour); } static procedure vulkan_render_rectangle_gradient_v (vulkan_structure * vulkan, integer x, integer y, integer width, integer height, natural colour_up, natural colour_down) { vulkan_render_core (vulkan, vulkan->sprite_count - 1, x, y, 0, 0, 16, 16, (real) width / 16, (real) height / 16, 0, 0, colour_up, colour_up, colour_down, colour_down); } static procedure vulkan_render_rectangle_gradient_h (vulkan_structure * vulkan, integer x, integer y, integer width, integer height, natural colour_left, natural colour_right) { vulkan_render_core (vulkan, vulkan->sprite_count - 1, x, y, 0, 0, 16, 16, (real) width / 16, (real) height / 16, 0, 0, colour_left, colour_right, colour_left, colour_right); } static integer vulkan_string_width (vulkan_structure * vulkan, character * string, integer font, real scale) { integer length = 0; for (natural index = 0; string [index] != '\0'; ++index) { integer character = vulkan->font_index [font] [string [index] - vulkan->font_begin [font]]; /* if (string [index] == '\t') { length += 8 * vulkan->sprite_width [vulkan->font_index [font] [' ' - vulkan->font_begin [font]]]; continue; } if (string [index] == '\n') { continue; } */ length += vulkan->sprite_width [character] * scale; } return (length); } static procedure vulkan_render_string (vulkan_structure * vulkan, character * string, integer font, integer x, integer y, natural colour) { integer offset = x; for (natural index = 0; string [index] != '\0'; ++index) { integer character = vulkan->font_index [font] [string [index] - vulkan->font_begin [font]]; if (string [index] == '\t') { x += 8 * vulkan->sprite_width [vulkan->font_index [font] [' ' - vulkan->font_begin [font]]]; continue; } if (string [index] == '\n') { x = offset; y += vulkan->sprite_height [vulkan->font_index [font] [' ' - vulkan->font_begin [font]]]; continue; } vulkan_render_sprite (vulkan, character, x, y, colour); x += vulkan->sprite_width [character]; } } static procedure vulkan_render_string_scale (vulkan_structure * vulkan, character * string, integer font, integer x, integer y, real scale, natural colour) { integer offset = x; for (natural index = 0; string [index] != '\0'; ++index) { integer character = vulkan->font_index [font] [string [index] - vulkan->font_begin [font]]; if (string [index] == '\t') { x += 8 * vulkan->sprite_width [vulkan->font_index [font] [' ' - vulkan->font_begin [font]]]; continue; } if (string [index] == '\n') { x = offset; y += vulkan->sprite_height [vulkan->font_index [font] [' ' - vulkan->font_begin [font]]]; continue; } vulkan_render_core (vulkan, character, x, y, 0, 0, vulkan->sprite_width [character], vulkan->sprite_height [character], scale, scale, 0, 0, colour, colour, colour, colour); x += vulkan->sprite_width [character]; } } static procedure vulkan_render_string_offset (vulkan_structure * vulkan, character * string, natural length, natural font, natural offset, integer * x, integer * y, natural colour) { for (natural index = 0; (string [index] != '\0') && (index < length); ++index) { natural character = vulkan->font_index [font] [string [index] - vulkan->font_begin [font]]; if (string [index] == '\t') { * x += 8 * vulkan->sprite_width [vulkan->font_index [font] [' ' - vulkan->font_begin [font]]]; continue; } if (string [index] == '\n') { * x = offset; * y += vulkan->sprite_height [vulkan->font_index [font] [' ' - vulkan->font_begin [font]]]; continue; } vulkan_render_sprite (vulkan, character, * x, * y, colour); * x += vulkan->sprite_width [character]; } } static procedure vulkan_render_string_gradient_v (vulkan_structure * vulkan, character * string, integer font, integer x, integer y, real scale, natural colour_up, natural colour_down) { integer offset = x; for (natural index = 0; string [index] != '\0'; ++index) { natural character = vulkan->font_index [font] [string [index] - vulkan->font_begin [font]]; if (string [index] == '\t') { x += 8 * vulkan->sprite_width [vulkan->font_index [font] [' ' - vulkan->font_begin [font]]] * scale; continue; } if (string [index] == '\n') { x = offset; y += vulkan->sprite_height [vulkan->font_index [font] [' ' - vulkan->font_begin [font]]] * scale; continue; } vulkan_render_core (vulkan, character, x, y, 0, 0, vulkan->sprite_width [character], vulkan->sprite_height [character], scale, scale, 0, 0, colour_up, colour_up, colour_down, colour_down); x += vulkan->sprite_width [character] * scale; } } static procedure vulkan_render_string_gradient_h (vulkan_structure * vulkan, character * string, integer font, integer x, integer y, real scale, natural colour_left, natural colour_right) { integer offset = x; for (natural index = 0; string [index] != '\0'; ++index) { natural character = vulkan->font_index [font] [string [index] - vulkan->font_begin [font]]; if (string [index] == '\t') { x += 8 * vulkan->sprite_width [vulkan->font_index [font] [' ' - vulkan->font_begin [font]]] * scale; continue; } if (string [index] == '\n') { x = offset; y += vulkan->sprite_height [vulkan->font_index [font] [' ' - vulkan->font_begin [font]]] * scale; continue; } vulkan_render_core (vulkan, character, x, y, 0, 0, vulkan->sprite_width [character], vulkan->sprite_height [character], scale, scale, 0, 0, colour_left, colour_right, colour_left, colour_right); x += vulkan->sprite_width [character] * scale; } } static procedure vulkan_handle_events (vulkan_structure * vulkan) { static integer signal_code [signal_count] = { 0, 38, 56, 54, 40, 26, 41, 42, 43, 31, 44, 45, 46, 58, 57, 32, 33, 24, 27, 39, 28, 30, 55, 25, 53, 29, 52, 19, 10, 11, 12, 13, 14, 15, 16, 17, 18, 9, 23, 36, 36, 61, 51, 47, 49, 65, 22, 60, 59, 48, 66, 20, 21, 34, 35, 37, 105, 50, 62, 64, 108, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 95, 96, 111, 116, 113, 114, 77, 127, 118, 110, 112, 119, 115, 117, 86, 82, 63, 106, 104, 91, 90, 87, 88, 89, 83, 84, 85, 79, 80, 81 }; integer index, key_code; xcb_generic_event_t * generic_event; /*generic_event = xcb_wait_for_event (vulkan_connection);*/ generic_event = xcb_poll_for_event (vulkan->connection); if (generic_event == null) { return; } switch (generic_event->response_type & 127) { case (XCB_EXPOSE): { xcb_flush (vulkan->connection); } break; /*case (XCB_CONFIGURE_NOTIFY): { xcb_configure_notify_event_t * reconfigure = (xcb_configure_notify_event_t *) generic_event; if ((reconfigure->width != vulkan->width) || (reconfigure->height != vulkan->height)) { vulkan->width = reconfigure->width; vulkan->height = reconfigure->height; if ((vulkan->width > 0) && (vulkan->height > 0)) { vulkan->reconfigure_active = true; vulkan->reconfigure (); } } } break;*/ case (XCB_BUTTON_PRESS): { vulkan->cursor = (integer) ((xcb_button_press_event_t *) generic_event)->detail; vulkan->cursor_x = (integer) ((xcb_button_press_event_t *) generic_event)->event_x; vulkan->cursor_y = (integer) ((xcb_button_press_event_t *) generic_event)->event_y; } break; case (XCB_BUTTON_RELEASE): { vulkan->cursor = cursor_none; vulkan->cursor_x = (integer) ((xcb_button_release_event_t *) generic_event)->event_x; vulkan->cursor_y = (integer) ((xcb_button_release_event_t *) generic_event)->event_y; } break; case (XCB_KEY_PRESS): { key_code = (integer) ((xcb_key_press_event_t *) generic_event)->detail; for (index = 0; index < signal_count; ++index) { if (key_code == signal_code [index]) { vulkan->signal [index] = true; break; } } } break; case (XCB_KEY_RELEASE): { key_code = (integer) ((xcb_key_release_event_t *) generic_event)->detail; for (index = 0; index < signal_count; ++index) { if (key_code == signal_code [index]) { vulkan->signal [index] = false; break; } } } break; /*case (XCB_MOTION_NOTIFY): { vulkan->cursor_x = (integer) ((xcb_motion_notify_event_t *) generic_event)->event_x; vulkan->cursor_y = (integer) ((xcb_motion_notify_event_t *) generic_event)->event_y; } break;*/ default: { } break; } generic_event = deallocate (generic_event); } static procedure vulkan_synchronize (vulkan_structure * vulkan, natural clear_colour) { natural index = 0; natural frame = 0; VkResult result = VK_SUCCESS; generic * ubo_procedure = null; VkPipelineStageFlags wait_stages [1] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT} ; VkSubmitInfo submit_information = { 0 }; VkPresentInfoKHR present_information = { 0 }; VkSwapchainKHR * swapchain_pointer = & vulkan->swapchain; struct timespec frame_begin = { 0 }; struct timespec frame_end = { 0 }; clock_gettime (CLOCK_REALTIME, & frame_begin); vulkan_handle_events (vulkan); if ((vulkan->active == false) || (vulkan->reconfigure_active == true)) { return; } if (vulkan->signal [signal_q] == true) { vulkan->active = false; } vulkan_render_core (vulkan, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); vulkan_create_vertex_buffer (vulkan); vulkan_create_index_buffer (vulkan); vulkan_record_command_buffers (vulkan, clear_colour, frame); vulkan_result (vkWaitForFences (vulkan->boolean_device, 1, & vulkan->fence_set_1 [vulkan->frame], VK_TRUE, ~0)); vulkan_result (vkAcquireNextImageKHR (vulkan->boolean_device, vulkan->swapchain, ~0, vulkan->semaphore_set_1 [vulkan->frame], VK_NULL_HANDLE, & frame)); /* result = vkAcquireNextImageKHR (vulkan->boolean_device, vulkan->swapchain, ~0, vulkan->semaphore_set_1 [vulkan->frame], VK_NULL_HANDLE, & frame); print ("vkAcquireNextImageKHR : /5%i/-\n", result); if (result == VK_ERROR_OUT_OF_DATE_KHR) { vulkan->reconfigure_active = true; return; } */ vulkan_result (vkResetFences (vulkan->boolean_device, 1, & vulkan->fence_set_1 [vulkan->frame])); submit_information.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_information.waitSemaphoreCount = 1; submit_information.pWaitSemaphores = & vulkan->semaphore_set_1 [vulkan->frame]; submit_information.pWaitDstStageMask = wait_stages; submit_information.commandBufferCount = 1; submit_information.pCommandBuffers = & vulkan->command_buffers [vulkan->frame]; //~submit_information.pCommandBuffers = & vulkan->command_buffers [frame]; submit_information.signalSemaphoreCount = 1; submit_information.pSignalSemaphores = & vulkan->semaphore_set_2 [vulkan->frame]; vulkan_result (vkQueueSubmit (vulkan->queue, 1, & submit_information, vulkan->fence_set_1 [vulkan->frame])); present_information.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; present_information.waitSemaphoreCount = 1; present_information.pWaitSemaphores = & vulkan->semaphore_set_2 [vulkan->frame]; present_information.swapchainCount = 1; present_information.pSwapchains = swapchain_pointer; present_information.pImageIndices = & frame; vulkan_result (vkQueuePresentKHR (vulkan->queue, & present_information)); /* result = vkQueuePresentKHR (vulkan->queue, & present_information); print ("vkQueuePresentKHR : /5%i/-\n", result); if ((result == VK_ERROR_OUT_OF_DATE_KHR) || (result == VK_SUBOPTIMAL_KHR)) { vulkan->reconfigure_active = true; return; } */ vulkan->frame = (vulkan->frame + 1) % vulkan->image_count; vulkan_result (vkQueueWaitIdle (vulkan->queue)); vulkan_result (vkDeviceWaitIdle (vulkan->boolean_device)); vkDestroyBuffer (vulkan->boolean_device, vulkan->index_buffer, null); vkFreeMemory (vulkan->boolean_device, vulkan->index_memory, null); vkDestroyBuffer (vulkan->boolean_device, vulkan->vertex_buffer, null); vkFreeMemory (vulkan->boolean_device, vulkan->vertex_memory, null); vulkan->vertex_count = 0; vulkan->index_count = 0; vulkan_result (vkQueueWaitIdle (vulkan->queue)); vulkan_result (vkDeviceWaitIdle (vulkan->boolean_device)); clock_gettime (CLOCK_REALTIME, & frame_end); if (vulkan->gameplay_time % (vulkan->gameplay_framerate / 10) == 0) { vulkan->frame_time_in_ns = (frame_end.tv_sec - frame_begin.tv_sec) * 1000000000 + frame_end.tv_nsec - frame_begin.tv_nsec; vulkan->framerate = (integer) (1000000000 / vulkan->frame_time_in_ns); } if (vulkan->framerate > vulkan->gameplay_framerate) { struct timespec wait = { 0, 0 }; wait.tv_nsec = 1000000000 / vulkan->gameplay_framerate - vulkan->frame_time_in_ns; while (nanosleep (& wait, null) == -1) continue; } ++vulkan->global_time; vulkan->global_time = vulkan->global_time % (vulkan->gameplay_framerate * vulkan->animation_framerate); vulkan->gameplay_time = vulkan->global_time % (vulkan->gameplay_framerate); vulkan->animation_time = vulkan->global_time / (vulkan->gameplay_framerate / vulkan->animation_framerate); }