xolatilization/xulkan.h

2352 lines
109 KiB
C
Executable File

/// _ _
/// __ ___ _| | | ____ _ _ __
/// \ \/ / | | | | |/ / _` | '_ \
/// > <| |_| | | < (_| | | | |
/// /_/\_\\__,_|_|_|\_\__,_|_| |_|
///
/// 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 <vulkan/vulkan.h>
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);
}