diff --git a/CMakeLists.txt b/CMakeLists.txt index b497248..ef8d115 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,9 @@ add_compile_options( -Wall -Wextra -Wpedantic -Wno-nested-anon-types -Wno-keyword-macro -Wno-gnu-auto-type -Wno-auto-decl-extensions -Wno-gnu-empty-initializer -Wno-fixed-enum-extension -Wno-gnu-binary-literal -fno-exceptions -fno-stack-protector - -fdiagnostics-color=always -ferror-limit=1 + -fdiagnostics-color=always + -fansi-escape-codes + -ferror-limit=1 -march=native ${BB_IS_CI_C_FLAG} -DCOMPILER_NAME=\"${COMPILER_NAME}\" -DBUILD_DIR=\"${CMAKE_BINARY_DIR}\" -DBB_DIR=\"${BB_DIR}\" ) @@ -210,8 +212,8 @@ if (NOT BB_IS_CI) add_subdirectory(dependencies/volk-1.3.301 volk) target_link_libraries(${COMPILER_NAME} PRIVATE volk) target_sources(${COMPILER_NAME} PRIVATE - "bootstrap/bloat-buster/shader_compilation.c" - "bootstrap/bloat-buster/image_loader.c" + "bootstrap/std/image_loader.c" + "bootstrap/std/shader_compilation.c" "bootstrap/std/font_cache.c" "bootstrap/std/font_provider.c" "bootstrap/std/graphics.c" diff --git a/bootstrap/bloat-buster/bb_core.c b/bootstrap/bloat-buster/bb_core.c index dd97205..071a6e9 100644 --- a/bootstrap/bloat-buster/bb_core.c +++ b/bootstrap/bloat-buster/bb_core.c @@ -1,14 +1,12 @@ #if BB_CI == 0 #include -#include - #include #include - -#include -#include -#include +#include +#include +#include +#include STRUCT(Vec4) { @@ -25,561 +23,22 @@ STRUCT(Vertex) }; decl_vb(Vertex); -[[noreturn]] [[gnu::cold]] fn void wrong_vulkan_result(VkResult result, String call_string, String file, int line) -{ - unused(result); - unused(call_string); - unused(file); - unused(line); - trap(); -} - -#define vkok(call) do {\ - VkResult _r_e_s_u_l_t_ = call; \ - if (unlikely(_r_e_s_u_l_t_ != VK_SUCCESS)) wrong_vulkan_result(_r_e_s_u_l_t_, strlit(#call), strlit(__FILE__), __LINE__); \ -} while(0) - -#define vkok_swapchain(call) do {\ - VkResult result = call; \ - if (unlikely(result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)) wrong_vulkan_result(result, strlit(#call), strlit(__FILE__), __LINE__); \ -} while(0) - STRUCT(GPUDrawPushConstants) { - VkDeviceAddress vertex_buffer; + u64 vertex_buffer; f32 width; f32 height; }; -fn u8 vk_layer_is_supported(String layer_name) -{ - assert(layer_name.pointer[layer_name.length] == 0); - - VkLayerProperties layers[256]; - u32 layer_count; - - vkok(vkEnumerateInstanceLayerProperties(&layer_count, 0)); - - if (layer_count > array_length(layers)) - { - failed_execution(); - } - - vkok(vkEnumerateInstanceLayerProperties(&layer_count, layers)); - - u8 supported = 0; - for (u32 i = 0; i < layer_count; i += 1) - { - VkLayerProperties* properties = &layers[i]; - - auto candidate_layer_name = cstr(properties->layerName); - if (s_equal(candidate_layer_name, layer_name)) - { - supported = 1; - break; - } - } - - return supported; -} - -fn VkBool32 VKAPI_CALL debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, VkDebugUtilsMessageTypeFlagsEXT message_type, const VkDebugUtilsMessengerCallbackDataEXT* callback_data, void* user_data) -{ - unused(message_severity); - unused(message_type); - unused(user_data); - print("Validation message ({cstr}): {cstr}\n", callback_data->pMessageIdName ? callback_data->pMessageIdName : "ID_NONE", callback_data->pMessage); - if (message_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) - { - failed_execution(); - } - return VK_FALSE; -} - -#define frame_overlap (2) - -fn void vk_image_transition(VkCommandBuffer command_buffer, VkImage image, VkImageLayout old_layout, VkImageLayout new_layout) -{ - VkImageMemoryBarrier2 image_barrier = { - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, - .srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, - .srcAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT, - .dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, - .dstAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT | VK_ACCESS_2_MEMORY_READ_BIT, - .oldLayout = old_layout, - .newLayout = new_layout, - .image = image, - .subresourceRange = { - .aspectMask = (new_layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT, - .baseMipLevel = 0, - .levelCount = VK_REMAINING_MIP_LEVELS, - .baseArrayLayer = 0, - .layerCount = VK_REMAINING_ARRAY_LAYERS, - }, - }; - - VkDependencyInfo dependency_info = { - .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, - .imageMemoryBarrierCount = 1, - .pImageMemoryBarriers = &image_barrier, - }; - - vkCmdPipelineBarrier2(command_buffer, &dependency_info); -} - -fn VkShaderModule vk_shader_module_create(Arena* arena, VkDevice device, const VkAllocationCallbacks* allocator, String path, ShaderStage shader_stage) -{ - auto binary = compile_shader(arena, path, shader_stage); - - VkShaderModuleCreateInfo create_info = { - .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, - .codeSize = binary.length, - .pCode = (u32*)binary.pointer, - }; - - VkShaderModule shader_module; - vkok(vkCreateShaderModule(device, &create_info, allocator, &shader_module)); - - return shader_module; -} - -fn VkDeviceMemory vk_allocate_memory(VkDevice device, const VkAllocationCallbacks* allocation_callbacks, VkPhysicalDeviceMemoryProperties memory_properties, VkMemoryRequirements memory_requirements, VkMemoryPropertyFlags flags, u8 use_device_address_bit) -{ - u32 memory_type_index; - for (memory_type_index = 0; memory_type_index < memory_properties.memoryTypeCount; memory_type_index += 1) - { - auto memory_type = memory_properties.memoryTypes[memory_type_index]; - - if ((memory_requirements.memoryTypeBits & (1 << memory_type_index)) != 0 && (memory_type.propertyFlags & flags) == flags) - { - break; - } - } - - if (memory_type_index == memory_properties.memoryTypeCount) - { - failed_execution(); - } - - VkMemoryAllocateInfo allocate_info = { - .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - .allocationSize = memory_requirements.size, - .memoryTypeIndex = memory_type_index, - }; - - VkMemoryAllocateFlagsInfo flags_info = { - .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO, - .pNext = 0, - .flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT, - .deviceMask = 1, - }; - - if (use_device_address_bit) - { - allocate_info.pNext = &flags_info; - } - - VkDeviceMemory memory = 0; - vkok(vkAllocateMemory(device, &allocate_info, allocation_callbacks, &memory)); - - return memory; -} - -STRUCT(VulkanBuffer) -{ - VkBuffer handle; - VkDeviceMemory gpu_data; - void* cpu_data; - VkDeviceSize size; -}; - -STRUCT(ImmediateContext) -{ - VkDevice device; - VkFence fence; - VkCommandBuffer command_buffer; - VkCommandPool command_pool; - VkQueue queue; -}; - -fn void immediate_start(ImmediateContext context) -{ - VkFence fences[] = { context.fence }; - VkCommandBufferResetFlags reset_flags = 0; - - vkok(vkResetFences(context.device, array_length(fences), fences)); - vkok(vkResetCommandBuffer(context.command_buffer, reset_flags)); - - VkCommandBufferBeginInfo command_buffer_begin_info = { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, - .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, - }; - vkok(vkBeginCommandBuffer(context.command_buffer, &command_buffer_begin_info)); -} - -fn void immediate_end(ImmediateContext context) -{ - VkFence fences[] = { context.fence }; - - vkok(vkEndCommandBuffer(context.command_buffer)); - - VkCommandBufferSubmitInfo command_buffer_submit_infos[] = { - { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO, - .pNext = 0, - .deviceMask = 0, - .commandBuffer = context.command_buffer, - } - }; - - VkSubmitFlags submit_flags = 0; - - VkSubmitInfo2 submit_info[] = { - { - .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, - .pNext = 0, - .flags = submit_flags, - .waitSemaphoreInfoCount = 0, - .pWaitSemaphoreInfos = 0, - .commandBufferInfoCount = array_length(command_buffer_submit_infos), - .pCommandBufferInfos = command_buffer_submit_infos, - .signalSemaphoreInfoCount = 0, - .pSignalSemaphoreInfos = 0, - } - }; - - vkok(vkQueueSubmit2(context.queue, array_length(submit_info), submit_info, context.fence)); - VkBool32 wait_all = 1; - auto timeout = ~(u64)0; - vkok(vkWaitForFences(context.device, array_length(fences), fences, wait_all, timeout)); -} -STRUCT(VulkanCopyImage) -{ - VkImage handle; - VkExtent2D extent; -}; - -STRUCT(VulkanCopyImageArgs) -{ - VulkanCopyImage source; - VulkanCopyImage destination; -}; - -fn void vk_image_copy(VkCommandBuffer command_buffer, VulkanCopyImageArgs args) -{ - VkImageSubresourceLayers subresource_layers = { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .mipLevel = 0, - .baseArrayLayer = 0, - .layerCount = 1, - }; - VkImageBlit2 blit_regions[] = { - { - .sType = VK_STRUCTURE_TYPE_IMAGE_BLIT_2, - .pNext = 0, - .srcSubresource = subresource_layers, - .srcOffsets = { - [1] = { - .x = args.source.extent.width, - .y = args.source.extent.height, - .z = 1, - }, - }, - .dstSubresource = subresource_layers, - .dstOffsets = { - [1] = { - .x = args.destination.extent.width, - .y = args.destination.extent.height, - .z = 1, - }, - }, - }, - }; - - VkBlitImageInfo2 blit_info = { - .sType = VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2, - .pNext = 0, - .srcImage = args.source.handle, - .srcImageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - .dstImage = args.destination.handle, - .dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - .regionCount = array_length(blit_regions), - .pRegions = blit_regions, - .filter = VK_FILTER_LINEAR, - }; - - vkCmdBlitImage2(command_buffer, &blit_info); -} - -fn VulkanBuffer vk_buffer_create(VkDevice device, const VkAllocationCallbacks* allocation_callbacks, VkPhysicalDeviceMemoryProperties physical_device_memory_properties, VkDeviceSize buffer_size, VkBufferUsageFlags usage_flags, VkMemoryPropertyFlags memory_flags) -{ - VkBuffer buffer; - VkBufferCreateInfo create_info = { - .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, - .pNext = 0, - .flags = 0, - .size = buffer_size, - .usage = usage_flags, - .sharingMode = VK_SHARING_MODE_EXCLUSIVE, - .queueFamilyIndexCount = 0, - .pQueueFamilyIndices = 0, - }; - vkok(vkCreateBuffer(device, &create_info, allocation_callbacks, &buffer)); - - VkMemoryRequirements memory_requirements; - vkGetBufferMemoryRequirements(device, buffer, &memory_requirements); - - u8 use_device_address_bit = (create_info.usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) != 0; - VkDeviceMemory memory = vk_allocate_memory(device, allocation_callbacks, physical_device_memory_properties, memory_requirements, memory_flags, use_device_address_bit); - - VkDeviceSize memory_offset = 0; - vkok(vkBindBufferMemory(device, buffer, memory, memory_offset)); - - void* data = 0; - if (memory_flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) - { - VkDeviceSize offset = 0; - VkMemoryMapFlags map_flags = 0; - vkok(vkMapMemory(device, memory, offset, memory_requirements.size, map_flags, &data)); - } - - VulkanBuffer result = { - .handle = buffer, - .cpu_data = data, - .gpu_data = memory, - .size = buffer_size, - }; - - return result; -} - -STRUCT(VulkanImageCreate) -{ - u32 width; - u32 height; - u32 mip_levels; - VkFormat format; - VkImageUsageFlags usage; -}; - -STRUCT(VulkanImage) -{ - VkImage handle; - VkImageView view; - VkDeviceMemory memory; - VkFormat format; -}; - -fn VulkanImage vk_image_create(VkDevice device, const VkAllocationCallbacks* allocation_callbacks, VkPhysicalDeviceMemoryProperties memory_properties, VulkanImageCreate create) -{ - assert(create.width); - assert(create.height); - VulkanImage result = {}; - result.format = create.format; - - VkImageCreateInfo create_info = { - .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, - .pNext = 0, - .flags = 0, - .imageType = VK_IMAGE_TYPE_2D, - .format = create.format, - .extent = { - .width = create.width, - .height = create.height, - .depth = 1, - }, - .mipLevels = create.mip_levels, - .arrayLayers = 1, - .samples = VK_SAMPLE_COUNT_1_BIT, - .tiling = VK_IMAGE_TILING_OPTIMAL, - .usage = create.usage, - .sharingMode = 0, - .queueFamilyIndexCount = 0, - .pQueueFamilyIndices = 0, - .initialLayout = 0, - }; - vkok(vkCreateImage(device, &create_info, allocation_callbacks, &result.handle)); - - VkMemoryRequirements memory_requirements; - vkGetImageMemoryRequirements(device, result.handle, &memory_requirements); - - VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - u8 use_device_address_bit = 0; - result.memory = vk_allocate_memory(device, allocation_callbacks, memory_properties, memory_requirements, flags, use_device_address_bit); - - VkDeviceSize memory_offset = 0; - vkok(vkBindImageMemory(device, result.handle, result.memory, memory_offset)); - - VkImageViewCreateInfo view_create_info = { - .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - .image = result.handle, - .viewType = VK_IMAGE_VIEW_TYPE_2D, - .format = create_info.format, - .subresourceRange = { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .baseMipLevel = 0, - .levelCount = create.mip_levels, - .baseArrayLayer = 0, - .layerCount = 1, - }, - }; - - vkok(vkCreateImageView(device, &view_create_info, allocation_callbacks, &result.view)); - return result; -} - -STRUCT(ImageFromTextureOptions) -{ - VkFormat format; -}; - -fn VulkanImage vk_image_from_texture(VkDevice device, const VkAllocationCallbacks* allocation_callbacks, ImmediateContext immediate_context, VkPhysicalDeviceMemoryProperties memory_properties, TextureMemory texture, VkFormat format) -{ - assert(texture.depth == 1); - - VulkanImage result = vk_image_create(device, allocation_callbacks, memory_properties, (VulkanImageCreate) { - .width = texture.width, - .height = texture.height, - .mip_levels = 1, - .format = format, - .usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, - }); - - auto image_size = (u64)texture.depth * texture.width * texture.height * texture.channel_count; - VkBufferUsageFlags buffer_usage_flags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - VkMemoryPropertyFlags buffer_memory_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - auto transfer_buffer = vk_buffer_create(device, allocation_callbacks, memory_properties, image_size, buffer_usage_flags, buffer_memory_flags); - memcpy(transfer_buffer.cpu_data, texture.pointer, image_size); - - immediate_start(immediate_context); - - vk_image_transition(immediate_context.command_buffer, result.handle, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - - VkBufferImageCopy copy_regions[] = { - { - .bufferOffset = 0, - .bufferRowLength = 0, - .bufferImageHeight = 0, - .imageSubresource = { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .mipLevel = 0, - .baseArrayLayer = 0, - .layerCount = 1, - }, - .imageOffset = { .x = 0, .y = 0, .z = 0 }, - .imageExtent = { - .width = texture.width, - .height = texture.height, - .depth = texture.depth, - }, - } - }; - - vkCmdCopyBufferToImage(immediate_context.command_buffer, transfer_buffer.handle, result.handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, array_length(copy_regions), copy_regions); - - vk_image_transition(immediate_context.command_buffer, result.handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - - immediate_end(immediate_context); - - return result; -} - void run_app(Arena* arena) { u8 use_x11 = 1; graphics_init(use_x11); - vkok(volkInitialize()); - - const VkAllocationCallbacks* allocation_callbacks = 0; - VkInstance instance; - { - auto debug_layer = strlit("VK_LAYER_KHRONOS_validation"); - if (!vk_layer_is_supported(debug_layer)) - { - failed_execution(); - } - const char* layers[] = - { - string_to_c(debug_layer), - }; - - auto api_version = volkGetInstanceVersion(); - if (api_version < VK_API_VERSION_1_3) - { - failed_execution(); - } - - const char* extensions[] = { - VK_EXT_DEBUG_UTILS_EXTENSION_NAME, - VK_KHR_SURFACE_EXTENSION_NAME, -#ifdef VK_USE_PLATFORM_WIN32_KHR - VK_KHR_WIN32_SURFACE_EXTENSION_NAME, -#endif -#ifdef VK_USE_PLATFORM_XLIB_KHR - VK_KHR_XLIB_SURFACE_EXTENSION_NAME, -#endif -#ifdef VK_USE_PLATFORM_WAYLAND_KHR - VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, -#endif -#ifdef VK_USE_PLATFORM_MACOS_MVK - VK_KHR_COCOA_SURFACE_EXTENSION_NAME, -#endif - }; - - - VkValidationFeatureEnableEXT enabled_validation_features[] = - { - VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT, - }; - - VkDebugUtilsMessengerCreateInfoEXT msg_ci = { - .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, - .pNext = 0, - .flags = 0, - .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, - .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_DEVICE_ADDRESS_BINDING_BIT_EXT, - .pfnUserCallback = debug_callback, - .pUserData = 0, - }; - - u8 enable_shader_debug_printf = 0; - - VkValidationFeaturesEXT validation_features = { - .sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT, - .enabledValidationFeatureCount = array_length(enabled_validation_features), - .pEnabledValidationFeatures = enabled_validation_features, - .pNext = &msg_ci, - }; - - VkApplicationInfo app_info = { - .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, - .apiVersion = api_version, - }; - - VkInstanceCreateInfo ci = { - .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, - .pApplicationInfo = &app_info, - .ppEnabledLayerNames = layers, - .enabledLayerCount = array_length(layers), - .ppEnabledExtensionNames = extensions, - .enabledExtensionCount = array_length(extensions), - .pNext = enable_shader_debug_printf ? (const void*)&validation_features : (const void*)&msg_ci, - }; - - vkok(vkCreateInstance(&ci, allocation_callbacks, &instance)); - volkLoadInstance(instance); - - VkDebugUtilsMessengerEXT messenger; - vkok(vkCreateDebugUtilsMessengerEXT(instance, &msg_ci, allocation_callbacks, &messenger)); - } - - int initial_width = 1024; - int initial_height = 768; GraphicsWindow* window = graphics_window_create((GraphicsWindowCreate) { .name = strlit("Bloat Buster"), .size = { - .width = initial_width, - .height= initial_height, + .width = 1024, + .height= 768, }, }); @@ -588,539 +47,49 @@ void run_app(Arena* arena) failed_execution(); } - VkSurfaceKHR surface; - { -#ifdef VK_USE_PLATFORM_WIN32_KHR - VkWin32SurfaceCreateInfoKHR create_info = { - .sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, - .pNext = 0, - .flags = 0, - .hinstance = os_windows_get_module_handle(), - .hwnd = graphics_win32_window_get(window), - }; - vkok(vkCreateWin32SurfaceKHR(instance, &create_info, allocation_callbacks, &surface)); -#endif -#ifdef VK_USE_PLATFORM_XLIB_KHR - VkXlibSurfaceCreateInfoKHR create_info = { - .sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, - .pNext = 0, - .flags = 0, - .dpy = graphics_x11_display_get(), - .window = graphics_x11_window_get(window), - }; - vkok(vkCreateXlibSurfaceKHR(instance, &create_info, allocation_callbacks, &surface)); -#endif -#ifdef VK_USE_PLATFORM_WAYLAND_KHR - VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, -#endif -#ifdef VK_USE_PLATFORM_MACOS_MVK - VK_KHR_COCOA_SURFACE_EXTENSION_NAME, -#endif - } + auto initial_window_size = graphics_window_size_get(window); - VkPhysicalDevice physical_device; - { - u32 physical_device_count; - VkPhysicalDevice physical_devices[256]; - vkok(vkEnumeratePhysicalDevices(instance, &physical_device_count, 0)); + Renderer* renderer = renderer_initialize(); + RenderWindow* render_window = renderer_window_initialize(renderer, window); - if (physical_device_count == 0) - { - failed_execution(); - } - - if (physical_device_count > array_length(physical_devices)) - { - failed_execution(); - } - - vkok(vkEnumeratePhysicalDevices(instance, &physical_device_count, physical_devices)); - - physical_device = physical_devices[0]; - } - - VkDevice device; - u32 graphics_queue_family_index; - u32 present_queue_family_index; - { - VkPhysicalDeviceProperties properties; - vkGetPhysicalDeviceProperties(physical_device, &properties); - - u32 queue_count; - vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_count, 0); - - VkQueueFamilyProperties queue_properties[64]; - if (queue_count > array_length(queue_properties)) - { - failed_execution(); - } - - vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_count, queue_properties); - - for (graphics_queue_family_index = 0; graphics_queue_family_index < queue_count; graphics_queue_family_index += 1) - { - VkQueueFamilyProperties* properties = &queue_properties[graphics_queue_family_index]; - if (properties->queueFlags & VK_QUEUE_GRAPHICS_BIT) - { - break; - } - } - - if (graphics_queue_family_index == queue_count) - { - failed_execution(); - } - - for (present_queue_family_index = 0; present_queue_family_index < queue_count; present_queue_family_index += 1) - { - VkBool32 support; - vkok(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, present_queue_family_index, surface, &support)); - if (support) - { - break; - } - } - - if (present_queue_family_index == queue_count) - { - failed_execution(); - } - - if (present_queue_family_index != graphics_queue_family_index) - { - failed_execution(); - } - - f32 queue_priorities[] = { 1.0f }; - VkDeviceQueueCreateInfo queue_create_infos[] = { - { - .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, - .queueFamilyIndex = graphics_queue_family_index, - .queueCount = array_length(queue_priorities), - .pQueuePriorities = queue_priorities, - }, - }; - - const char* extensions[] = - { - VK_KHR_SWAPCHAIN_EXTENSION_NAME, - }; - - VkPhysicalDeviceVulkan13Features features13 = { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES, - .dynamicRendering = 1, - .synchronization2 = 1, - }; - - VkPhysicalDeviceVulkan12Features features12 = { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES, - .bufferDeviceAddress = 1, - .descriptorIndexing = 1, - .pNext = &features13, - }; - - VkPhysicalDeviceFeatures2 features = { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, - .features = { - }, - .pNext = &features12, - }; - - VkDeviceCreateInfo ci = { - .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, - .ppEnabledExtensionNames = extensions, - .enabledExtensionCount = array_length(extensions), - .pQueueCreateInfos = queue_create_infos, - .queueCreateInfoCount = array_length(queue_create_infos), - .pNext = &features, - }; - - vkok(vkCreateDevice(physical_device, &ci, allocation_callbacks, &device)); - } - - VkQueue graphics_queue; - vkGetDeviceQueue(device, graphics_queue_family_index, 0, &graphics_queue); - - VkSurfaceCapabilitiesKHR original_capabilities; - vkok(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, &original_capabilities)); - - VkSwapchainKHR swapchain = 0; - - u32 queue_family_indices[] = { graphics_queue_family_index }; - VkImageUsageFlags swapchain_image_usage_flags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; - VkFormat common_image_format = VK_FORMAT_B8G8R8A8_UNORM; - VkSwapchainCreateInfoKHR swapchain_create_info = { - .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, - .pNext = 0, - .flags = 0, - .surface = surface, - .minImageCount = original_capabilities.minImageCount, - .imageFormat = common_image_format, - .imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, - .imageExtent = original_capabilities.currentExtent, - .imageArrayLayers = 1, - .imageUsage = swapchain_image_usage_flags, - .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, - .queueFamilyIndexCount = array_length(queue_family_indices), - .pQueueFamilyIndices = queue_family_indices, - .preTransform = original_capabilities.currentTransform, - .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, - .presentMode = VK_PRESENT_MODE_FIFO_KHR, - .clipped = 0, - .oldSwapchain = swapchain, + String shader_source_paths[] = { + strlit("bootstrap/shaders/font.vert"), + strlit("bootstrap/shaders/font.frag"), }; - - { - VkSwapchainKHR new_swapchain; - vkok(vkCreateSwapchainKHR(device, &swapchain_create_info, allocation_callbacks, &new_swapchain)); - swapchain = new_swapchain; - } - - VkImage swapchain_image_buffer[16]; - VkImageView swapchain_image_view_buffer[array_length(swapchain_image_buffer)]; - u32 swapchain_image_count; - { - vkok(vkGetSwapchainImagesKHR(device, swapchain, &swapchain_image_count, 0)); - - if (swapchain_image_count == 0) - { - failed_execution(); - } - - if (swapchain_image_count > array_length(swapchain_image_buffer)) - { - failed_execution(); - } - - vkok(vkGetSwapchainImagesKHR(device, swapchain, &swapchain_image_count, swapchain_image_buffer)); - - // VkImageViewUsageCreateInfo image_view_usage_create_info = { - // .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, - // .pNext = 0, - // .usage = swapchain_create_info.imageUsage, - // }; - - for (u32 i = 0; i < swapchain_image_count; i += 1) - { - VkImageViewCreateInfo create_info = { - .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - // .pNext = &image_view_usage_create_info, - .flags = 0, - .image = swapchain_image_buffer[i], - .viewType = VK_IMAGE_VIEW_TYPE_2D, - .format = swapchain_create_info.imageFormat, - .components = { - .r = VK_COMPONENT_SWIZZLE_IDENTITY, - .g = VK_COMPONENT_SWIZZLE_IDENTITY, - .b = VK_COMPONENT_SWIZZLE_IDENTITY, - .a = VK_COMPONENT_SWIZZLE_IDENTITY, + PipelineLayoutCreate pipeline_layouts[] = { + (PipelineLayoutCreate) { + .push_constant_ranges = array_to_slice(((PushConstantRange[]){ + (PushConstantRange) { + .offset = 0, + .size = sizeof(GPUDrawPushConstants), + .stage = SHADER_STAGE_VERTEX, }, - .subresourceRange = { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .baseMipLevel = 0, - .levelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1, + })), + .descriptor_set_layouts = array_to_slice(((DescriptorSetLayout[]){ + (DescriptorSetLayout) { + .bindings = array_to_slice(((DescriptorSetLayoutBinding[]) { + { + .binding = 0, + .type = DESCRIPTOR_TYPE_IMAGE_PLUS_SAMPLER, + .stage = SHADER_STAGE_FRAGMENT, + .count = 1, + }, + })), }, - }; - - vkok(vkCreateImageView(device, &create_info, allocation_callbacks, &swapchain_image_view_buffer[i])); - } - } - - VkPhysicalDeviceMemoryProperties physical_device_memory_properties; - vkGetPhysicalDeviceMemoryProperties(physical_device, &physical_device_memory_properties); - - VulkanImage render_image = vk_image_create(device, allocation_callbacks, physical_device_memory_properties, (VulkanImageCreate) { - .width = initial_width, - .height = initial_height, - .mip_levels = 1, - .format = common_image_format, - .usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, - }); - - VkCommandPool command_pools[frame_overlap]; - VkCommandBuffer command_buffers[frame_overlap]; - ImmediateContext immediate; - immediate.device = device; - immediate.queue = graphics_queue; - { - VkCommandPoolCreateInfo create_info = { - .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, - .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, - .queueFamilyIndex = graphics_queue_family_index, - }; - - for (u32 i = 0; i < frame_overlap; i += 1) - { - vkok(vkCreateCommandPool(device, &create_info, allocation_callbacks, &command_pools[i])); - - VkCommandBufferAllocateInfo command_buffer_allocate_info = { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - .commandPool = command_pools[i], - .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, - .commandBufferCount = 1, - }; - - vkok(vkAllocateCommandBuffers(device, &command_buffer_allocate_info, &command_buffers[i])); - } - - vkok(vkCreateCommandPool(device, &create_info, allocation_callbacks, &immediate.command_pool)); - - VkCommandBufferAllocateInfo command_buffer_allocate_info = { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - .commandPool = immediate.command_pool, - .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, - .commandBufferCount = 1, - }; - - vkok(vkAllocateCommandBuffers(device, &command_buffer_allocate_info, &immediate.command_buffer)); - } - - VkFence render_fences[frame_overlap]; - VkSemaphore swapchain_semaphores[frame_overlap]; - VkSemaphore render_semaphores[frame_overlap]; - { - VkFenceCreateInfo fence_create_info = { - .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, - .flags = VK_FENCE_CREATE_SIGNALED_BIT, - }; - - VkSemaphoreCreateInfo semaphore_create_info = { - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, - .flags = 0, - }; - - for (u32 i = 0; i < frame_overlap; i += 1) - { - vkok(vkCreateFence(device, &fence_create_info, allocation_callbacks, &render_fences[i])); - vkok(vkCreateSemaphore(device, &semaphore_create_info, allocation_callbacks, &render_semaphores[i])); - vkok(vkCreateSemaphore(device, &semaphore_create_info, allocation_callbacks, &swapchain_semaphores[i])); - } - - vkok(vkCreateFence(device, &fence_create_info, allocation_callbacks, &immediate.fence)); - } - - VkDescriptorSetLayoutBinding descriptor_set_layout_bindings[] = { - { - .binding = 0, - .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - .descriptorCount = 1, - .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, - .pImmutableSamplers = 0, + })), }, - // { - // .binding = 1, - // .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - // .descriptorCount = 1, - // .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, - // .pImmutableSamplers = 0, - // }, }; - VkDescriptorSetLayout descriptor_set_layout; - { - VkDescriptorSetLayoutCreateInfo create_info = { - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, - .pNext = 0, - .flags = 0, - .bindingCount = array_length(descriptor_set_layout_bindings), - .pBindings = descriptor_set_layout_bindings, - }; - - vkok(vkCreateDescriptorSetLayout(device, &create_info, allocation_callbacks, &descriptor_set_layout)); - } - - VkDescriptorSetLayout descriptor_set_layouts[] = { descriptor_set_layout }; - VkPipeline graphics_pipeline; - VkPipelineLayout graphics_pipeline_layout; - { - VkShaderModule vertex_shader = vk_shader_module_create(arena, device, allocation_callbacks, strlit("bootstrap/shaders/font.vert"), SHADER_STAGE_VERTEX); - VkShaderModule fragment_shader = vk_shader_module_create(arena, device, allocation_callbacks, strlit("bootstrap/shaders/font.frag"), SHADER_STAGE_FRAGMENT); - - VkPushConstantRange push_constant_ranges[] = { - { - .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, - .offset = 0, - .size = sizeof(GPUDrawPushConstants), - } - }; - - VkPipelineLayoutCreateInfo create_info = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, - .flags = 0, - .setLayoutCount = array_length(descriptor_set_layouts), - .pSetLayouts = descriptor_set_layouts, - .pushConstantRangeCount = array_length(push_constant_ranges), - .pPushConstantRanges = push_constant_ranges, - }; - - vkok(vkCreatePipelineLayout(device, &create_info, allocation_callbacks, &graphics_pipeline_layout)); - - VkShaderModule shaders[] = { - vertex_shader, - fragment_shader, - }; - - VkShaderStageFlags stages[] = { VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_FRAGMENT_BIT }; - VkPipelineShaderStageCreateInfo shader_create_infos[2]; - - for (u32 i = 0; i < array_length(shaders); i += 1) - { - shader_create_infos[i] = (VkPipelineShaderStageCreateInfo) { - .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - .pNext = 0, - .flags = 0, - .stage = stages[i], - .module = shaders[i], - .pName = "main", - .pSpecializationInfo = 0, - }; - } - - VkPipelineVertexInputStateCreateInfo vertex_input_state_create_info = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - .pNext = 0, - .flags = 0, - .vertexBindingDescriptionCount = 0, - .pVertexBindingDescriptions = 0, - .vertexAttributeDescriptionCount = 0, - .pVertexAttributeDescriptions = 0, - }; - - VkPipelineInputAssemblyStateCreateInfo input_assembly_state_create_info = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, - .pNext = 0, - .flags = 0, - .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, - .primitiveRestartEnable = VK_FALSE, - }; - - VkPipelineViewportStateCreateInfo viewport_state_create_info = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, - .pNext = 0, - .viewportCount = 1, - .scissorCount = 1, - }; - - VkPipelineRasterizationStateCreateInfo rasterization_state_create_info = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, - .pNext = 0, - .flags = 0, - .depthClampEnable = 0, - .rasterizerDiscardEnable = 0, - .polygonMode = VK_POLYGON_MODE_FILL, - .cullMode = VK_CULL_MODE_NONE, - .frontFace = VK_FRONT_FACE_CLOCKWISE, - .depthBiasEnable = 0, - .depthBiasConstantFactor = 0, - .depthBiasClamp = 0, - .depthBiasSlopeFactor = 0, - .lineWidth = 1.0f, - }; - - VkPipelineMultisampleStateCreateInfo multisample_state_create_info = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, - .pNext = 0, - .flags = 0, - .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, - .sampleShadingEnable = 0, - .minSampleShading = 1.0f, - .pSampleMask = 0, - .alphaToCoverageEnable = 0, - .alphaToOneEnable = 0, - }; - - VkPipelineDepthStencilStateCreateInfo depth_stencil_state_create_info = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, - .pNext = 0, - .flags = 0, - .depthTestEnable = 0, - .depthWriteEnable = 0, - .depthCompareOp = VK_COMPARE_OP_NEVER, - .depthBoundsTestEnable = 0, - .stencilTestEnable = 0, - .front = {}, - .back = {}, - .minDepthBounds = 0.0f, - .maxDepthBounds = 1.0f, - }; - - VkPipelineColorBlendAttachmentState attachments[] = { - { - .blendEnable = 1, - .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA, - .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, - .colorBlendOp = VK_BLEND_OP_ADD, - .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, - .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, - .alphaBlendOp = VK_BLEND_OP_ADD, - .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, - }, - }; - - VkPipelineColorBlendStateCreateInfo color_blend_state_create_info = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, - .pNext = 0, - .flags = 0, - .logicOpEnable = VK_FALSE, - .logicOp = VK_LOGIC_OP_COPY, - .attachmentCount = array_length(attachments), - .pAttachments = attachments, - .blendConstants = {}, - }; - - VkDynamicState states[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; - - VkPipelineDynamicStateCreateInfo dynamic_state_create_info = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, - .pNext = 0, - .flags = 0, - .dynamicStateCount = array_length(states), - .pDynamicStates = states, - }; - - VkFormat color_attachment_formats[] = { - common_image_format, - }; - - VkPipelineRenderingCreateInfo rendering_create_info = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, - .pNext = 0, - .viewMask = 0, - .colorAttachmentCount = array_length(color_attachment_formats), - .pColorAttachmentFormats = color_attachment_formats, - .depthAttachmentFormat = 0, - .stencilAttachmentFormat = 0, - }; - - VkGraphicsPipelineCreateInfo create_infos[] = { - { - .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, - .pNext = &rendering_create_info, - .flags = 0, - .stageCount = array_length(stages), - .pStages = shader_create_infos, - .pVertexInputState = &vertex_input_state_create_info, - .pInputAssemblyState = &input_assembly_state_create_info, - .pTessellationState = 0, - .pViewportState = &viewport_state_create_info, - .pRasterizationState = &rasterization_state_create_info, - .pMultisampleState = &multisample_state_create_info, - .pDepthStencilState = &depth_stencil_state_create_info, - .pColorBlendState = &color_blend_state_create_info, - .pDynamicState = &dynamic_state_create_info, - .layout = graphics_pipeline_layout, - .renderPass = 0, - .subpass = 0, - .basePipelineHandle = 0, - .basePipelineIndex = 0, - }, - }; - - VkPipelineCache pipeline_cache = 0; - vkok(vkCreateGraphicsPipelines(device, pipeline_cache, array_length(create_infos), create_infos, allocation_callbacks, &graphics_pipeline)); - } - + PipelineCreate pipeline_create[] = { + (PipelineCreate) { + .shader_source_indices = array_to_slice(((u16[]){0, 1})), + .layout_index = 0, + }, + }; + auto pipeline_index = renderer_graphics_pipelines_create(renderer, arena, (GraphicsPipelinesCreate){ + .layouts = array_to_slice(pipeline_layouts), + .pipelines = array_to_slice(pipeline_create), + .shader_sources = array_to_slice(shader_source_paths), + }); auto font_path = #ifdef _WIN32 strlit("C:/Users/David/Downloads/Fira_Sans/FiraSans-Regular.ttf") @@ -1133,109 +102,26 @@ strlit("/usr/share/fonts/TTF/FiraSans-Regular.ttf") .font_path = font_path, .text_height = 72, }); - auto texture_atlas_image = vk_image_from_texture(device, allocation_callbacks, immediate, physical_device_memory_properties, (TextureMemory) { + auto texture_atlas_image = renderer_texture_create(renderer, (TextureMemory) { .pointer = texture_atlas.pointer, .width = texture_atlas.width, .height = texture_atlas.height, - .channel_count = 1, .depth = 1, - }, VK_FORMAT_R8_UNORM); - -// auto texture_path = -// #ifdef _WIN32 -// strlit("C:/Users/david/Pictures/buster.jpg"); -// #elif defined(__linux__) -// strlit("/home/david/Pictures/buster.jpeg"); -// #else -// #endif -// auto texture = texture_load_from_file(arena, texture_path); -// auto texture_image = vk_image_from_texture(device, allocation_callbacks, immediate, physical_device_memory_properties, texture, VK_FORMAT_R8G8B8A8_SRGB); - - VkSampler sampler; - { - VkFilter sampler_filter = VK_FILTER_LINEAR; - VkSamplerCreateInfo create_info = { - .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, - .pNext = 0, - .flags = 0, - .magFilter = sampler_filter, - .minFilter = sampler_filter, - .mipmapMode = 0, - .addressModeU = 0, - .addressModeV = 0, - .addressModeW = 0, - .mipLodBias = 0, - .anisotropyEnable = 0, - .maxAnisotropy = 0, - .compareEnable = 0, - .compareOp = 0, - .minLod = 0, - .maxLod = 0, - .borderColor = 0, - .unnormalizedCoordinates = 0, - }; - - vkok(vkCreateSampler(device, &create_info, allocation_callbacks, &sampler)); - } - - VkDescriptorPool descriptor_pools[frame_overlap]; - VkDescriptorSet descriptor_sets[frame_overlap]; - for (u32 i = 0; i < frame_overlap; i += 1) - { - VkDescriptorPoolSize pool_sizes[] = { - { - .type = descriptor_set_layout_bindings[0].descriptorType, - .descriptorCount = array_length(descriptor_set_layout_bindings), + .format = R8_UNORM, + }); + DescriptorSetUpdate descriptor_set_updates[] = { + { + .set = { .value = 0 }, + .type = DESCRIPTOR_TYPE_IMAGE_PLUS_SAMPLER, + .binding = 0, + .descriptor_count = 1, + .textures = { + [0] = texture_atlas_image, }, - }; - VkDescriptorPoolCreateInfo create_info = { - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, - .pNext = 0, - .flags = 0, - .maxSets = 1, - .poolSizeCount = array_length(pool_sizes), - .pPoolSizes = pool_sizes, - }; + }, + }; - vkok(vkCreateDescriptorPool(device, &create_info, allocation_callbacks, &descriptor_pools[i])); - - VkDescriptorSetAllocateInfo allocate_info = { - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, - .pNext = 0, - .descriptorPool = descriptor_pools[i], - .descriptorSetCount = array_length(descriptor_set_layouts), - .pSetLayouts = descriptor_set_layouts, - }; - - vkok(vkAllocateDescriptorSets(device, &allocate_info, &descriptor_sets[i])); - - VkDescriptorImageInfo image_infos[] = { - { - .sampler = sampler, - .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - .imageView = texture_atlas_image.view, - }, - }; - - VkWriteDescriptorSet write_descriptor_sets[] = { - { - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .pNext = 0, - .dstSet = descriptor_sets[i], - .dstBinding = 0, - .dstArrayElement = 0, - .descriptorCount = array_length(image_infos), - .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - .pImageInfo = image_infos, - .pBufferInfo = 0, - .pTexelBufferView = 0, - }, - }; - - u32 descriptor_copy_count = 0; - VkCopyDescriptorSet* descriptor_copies = 0; - vkUpdateDescriptorSets(device, array_length(write_descriptor_sets), write_descriptor_sets, descriptor_copy_count, descriptor_copies); - } + renderer_update_pipeline_resources(renderer, pipeline_index, (Slice(DescriptorSetUpdate)) array_to_slice(descriptor_set_updates)); Vec4 color = {1, 1, 1, 1}; static_assert(sizeof(color) == 4 * sizeof(float)); @@ -1244,8 +130,8 @@ strlit("/usr/share/fonts/TTF/FiraSans-Regular.ttf") VirtualBuffer(Vertex) vertices = {}; VirtualBuffer(u32) indices = {}; u32 index_offset = 0; - auto x_offset = initial_width / 2; - auto y_offset = initial_height / 2; + auto x_offset = initial_window_size.width / 2; + auto y_offset = initial_window_size.height / 2; for (u64 i = 0; i < string.length; i += 1, index_offset += 4) { @@ -1295,284 +181,90 @@ strlit("/usr/share/fonts/TTF/FiraSans-Regular.ttf") *vb_add(&indices, 1) = index_offset + 2; auto kerning = (texture_atlas.kerning_tables + ch * 256)[string.pointer[i + 1]]; - print("Advance: {u32}. Kerning: {s32}\n", character->advance, kerning); + // print("Advance: {u32}. Kerning: {s32}\n", character->advance, kerning); x_offset += character->advance + kerning; } auto vertex_buffer_size = sizeof(*vertices.pointer) * vertices.length; auto index_buffer_size = sizeof(*indices.pointer) * indices.length; - VulkanBuffer vertex_buffer = vk_buffer_create(device, allocation_callbacks, physical_device_memory_properties, vertex_buffer_size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - VulkanBuffer index_buffer = vk_buffer_create(device, allocation_callbacks, physical_device_memory_properties, index_buffer_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - VkBufferDeviceAddressInfo device_address_info = { - .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, - .buffer = vertex_buffer.handle, - }; - VkDeviceAddress vertex_buffer_device_address = vkGetBufferDeviceAddress(device, &device_address_info); + auto vertex_buffer = renderer_buffer_create(renderer, vertex_buffer_size, BUFFER_TYPE_VERTEX); + auto vertex_buffer_device_address = buffer_address(vertex_buffer); + auto index_buffer = renderer_buffer_create(renderer, index_buffer_size, BUFFER_TYPE_INDEX); + auto staging_buffer = renderer_buffer_create(renderer, vertex_buffer_size + index_buffer_size, BUFFER_TYPE_STAGING); - VulkanBuffer staging_buffer = vk_buffer_create(device, allocation_callbacks, physical_device_memory_properties, vertex_buffer.size + index_buffer.size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); - - { - memcpy(staging_buffer.cpu_data, vertices.pointer, vertex_buffer_size); - memcpy((u8*)staging_buffer.cpu_data + vertex_buffer_size, indices.pointer, index_buffer_size); - - immediate_start(immediate); - - VkBufferCopy vertex_copies[] = + renderer_copy_to_host(staging_buffer, (Slice(HostBufferCopy)) array_to_slice(((HostBufferCopy[]) { { - { - .srcOffset = 0, - .dstOffset= 0, - .size = vertex_buffer.size, - } - }; - - vkCmdCopyBuffer(immediate.command_buffer, staging_buffer.handle, vertex_buffer.handle, array_length(vertex_copies), vertex_copies); - - VkBufferCopy index_copies[] = + .destination_offset = 0, + .source = { + .pointer = (u8*)vertices.pointer, + .length = vertex_buffer_size, + }, + }, { - { - .srcOffset = vertex_buffer.size, - .dstOffset= 0, - .size = index_buffer.size, - } - }; + .destination_offset = vertex_buffer_size, + .source = { + .pointer = (u8*)indices.pointer, + .length = index_buffer_size, + }, + }, + }))); - vkCmdCopyBuffer(immediate.command_buffer, staging_buffer.handle, index_buffer.handle, array_length(index_copies), index_copies); + renderer_copy_to_local(renderer, (Slice(LocalBufferCopy)) array_to_slice(((LocalBufferCopy[]) { + { + .destination = vertex_buffer, + .source = staging_buffer, + .regions = array_to_slice(((LocalBufferCopyRegion[]) { + { + .source_offset = 0, + .destination_offset = 0, + .size = vertex_buffer_size, + }, + })), + }, + { + .destination = index_buffer, + .source = staging_buffer, + .regions = array_to_slice(((LocalBufferCopyRegion[]) { + { + .source_offset = vertex_buffer_size, + .destination_offset = 0, + .size = index_buffer_size, + }, + })), + }, + }))); - immediate_end(immediate); - } - - u32 frame_completed = 0; - for (u32 frame_number = 0; !graphics_window_should_close(window); frame_number += frame_completed) + while (!graphics_window_should_close(window)) { - frame_completed = 0; graphics_poll_events(); - auto window_size = graphics_window_size_get(window); - auto width = window_size.width; - auto height = window_size.height; + auto frame_window_size = renderer_window_frame_begin(renderer, render_window); - if (width == 0 || height == 0) + window_command_begin(render_window); + + window_bind_pipeline(render_window, pipeline_index); + window_bind_pipeline_descriptor_sets(render_window, pipeline_index); + window_bind_index_buffer(render_window, index_buffer, 0, INDEX_TYPE_U32); + GPUDrawPushConstants push_constants = { + .vertex_buffer = vertex_buffer_device_address, + .width = (f32)frame_window_size.width, + .height = (f32)frame_window_size.height, + }; + window_push_constants(render_window, pipeline_index, (SliceP(void)) array_to_slice(((void*[]) {&push_constants}))); + + window_render_begin(render_window); { - trap(); + window_draw_indexed(render_window, indices.length, 1, 0, 0, 0); } + window_render_end(render_window); - u32 frame_index = frame_number % frame_overlap; - u32 swapchain_image_index; + window_command_end(render_window); - { - auto timeout = ~(u64)0; - - u32 fence_count = 1; - VkBool32 wait_all = 1; - vkok(vkWaitForFences(device, fence_count, &render_fences[frame_index], wait_all, timeout)); - VkFence image_fence = 0; - vkok_swapchain(vkAcquireNextImageKHR(device, swapchain, timeout, swapchain_semaphores[frame_index], image_fence, &swapchain_image_index)); - vkok(vkResetFences(device, fence_count, &render_fences[frame_index])); - } - - VkCommandBuffer command_buffer = command_buffers[frame_index]; - - VkCommandBufferResetFlags reset_flags = 0; - vkok(vkResetCommandBuffer(command_buffer, reset_flags)); - - // Record the commands - { - { - VkCommandBufferBeginInfo command_buffer_begin_info = { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, - .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, - }; - vkok(vkBeginCommandBuffer(command_buffer, &command_buffer_begin_info)); - } - - vk_image_transition(command_buffer, render_image.handle, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - - VkRenderingAttachmentInfo color_attachments[] = { - { - .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, - .imageView = render_image.view, - .imageLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, - .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, - .storeOp = VK_ATTACHMENT_STORE_OP_STORE, - .clearValue = { .color = { .float32 = { 255.0f, 0.0f, 255.0f, 1.0f } } }, - }, - }; - - VkRenderingInfo rendering_info = { - .sType = VK_STRUCTURE_TYPE_RENDERING_INFO, - .renderArea = { - .extent = { - .width = initial_width, - .height = initial_height, - }, - }, - .layerCount = 1, - .colorAttachmentCount = array_length(color_attachments), - .pColorAttachments = color_attachments, - }; - - vkCmdBeginRendering(command_buffer, &rendering_info); - - vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline); - - // Bind texture - u32 first_set = 0; - u32 descriptor_set_count = 1; - u32 dynamic_offset_count = 0; - u32* dynamic_offsets = 0; - vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline_layout, first_set, descriptor_set_count, &descriptor_sets[frame_index], dynamic_offset_count, dynamic_offsets); - - VkViewport viewports[] = { - { - .x = 0, - .y = 0, - .width = initial_width, - .height = initial_height, - .minDepth = 0.0f, - .maxDepth = 1.0f, - } - }; - - u32 first_viewport = 0; - vkCmdSetViewport(command_buffer, first_viewport, array_length(viewports), viewports); - - VkRect2D scissors[] = { - { - .offset = { - .x = 0, - .y = 0, - }, - .extent = { - .width = initial_width, - .height = initial_height, - }, - } - }; - - u32 first_scissor = 0; - vkCmdSetScissor(command_buffer, first_scissor, array_length(scissors), scissors); - - GPUDrawPushConstants push_constants = { - .vertex_buffer = vertex_buffer_device_address, - .width = (f32)width, - .height = (f32)height, - }; - VkShaderStageFlags shader_stage_flags = VK_SHADER_STAGE_VERTEX_BIT; - u32 push_constant_offset = 0; - u32 push_constant_size = sizeof(push_constants); - vkCmdPushConstants(command_buffer, graphics_pipeline_layout, shader_stage_flags, push_constant_offset, push_constant_size, &push_constants); - - VkDeviceSize index_buffer_offset = 0; - VkIndexType index_type = VK_INDEX_TYPE_UINT32; - vkCmdBindIndexBuffer(command_buffer, index_buffer.handle, index_buffer_offset, index_type); - - vkCmdDrawIndexed(command_buffer, indices.length, 1, 0, 0, 0); - - vkCmdEndRendering(command_buffer); - - vk_image_transition(command_buffer, render_image.handle, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - - VkImage swapchain_image = swapchain_image_buffer[swapchain_image_index]; - vk_image_transition(command_buffer, swapchain_image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - - vk_image_copy(command_buffer, (VulkanCopyImageArgs) { - .source = { - .handle = render_image.handle, - .extent = { - .width = initial_width, - .height = initial_height, - }, - }, - .destination = { - .handle = swapchain_image, - .extent = { - .width = initial_width, - .height = initial_height, - }, - }, - }); - - vk_image_transition(command_buffer, swapchain_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); - - vkok(vkEndCommandBuffer(command_buffer)); - } - - VkCommandBufferSubmitInfo command_buffer_submit_info[] = { - { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO, - .commandBuffer = command_buffer, - .deviceMask = 0, - }, - }; - - VkSemaphore swapchain_semaphore = swapchain_semaphores[frame_index]; - VkSemaphoreSubmitInfo wait_semaphore_submit_info[] = { - { - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, - .semaphore = swapchain_semaphore, - .stageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, - .deviceIndex = 0, - .value = 1, - }, - }; - - VkSemaphore render_semaphore = render_semaphores[frame_index]; - VkSemaphoreSubmitInfo signal_semaphore_submit_info[] = { - { - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, - .semaphore = render_semaphore, - .stageMask = VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT, - .deviceIndex = 0, - .value = 1, - }, - }; - - VkSubmitInfo2 submit_info[] = { - { - .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, - .flags = 0, - .waitSemaphoreInfoCount = array_length(wait_semaphore_submit_info), - .pWaitSemaphoreInfos = wait_semaphore_submit_info, - .signalSemaphoreInfoCount = array_length(signal_semaphore_submit_info), - .pSignalSemaphoreInfos = signal_semaphore_submit_info, - .commandBufferInfoCount = array_length(command_buffer_submit_info), - .pCommandBufferInfos = command_buffer_submit_info, - }, - }; - - VkFence render_fence = render_fences[frame_index]; - vkok(vkQueueSubmit2(graphics_queue, array_length(submit_info), submit_info, render_fence)); - - VkSwapchainKHR swapchains[] = { swapchain }; - VkSemaphore wait_semaphores[] = { render_semaphore }; - VkResult results[array_length(swapchains)]; - - VkPresentInfoKHR present_info = { - .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, - .waitSemaphoreCount = array_length(wait_semaphores), - .pWaitSemaphores = wait_semaphores, - .swapchainCount = array_length(swapchains), - .pSwapchains = swapchains, - .pImageIndices = &swapchain_image_index, - .pResults = results, - }; - - vkok_swapchain(vkQueuePresentKHR(graphics_queue, &present_info)); - - frame_completed = 1; + renderer_window_frame_end(renderer, render_window); } - // { - // VkResult result = vkDeviceWaitIdle(device); - // if (result != VK_SUCCESS) - // { - // failed_execution(); - // } - // } - // - // vkDestroyInstance(instance, allocation_callbacks); + // TODO: deinitialization } #endif diff --git a/bootstrap/include/std/base.h b/bootstrap/include/std/base.h index 899d0cb..637ded7 100644 --- a/bootstrap/include/std/base.h +++ b/bootstrap/include/std/base.h @@ -77,6 +77,7 @@ declare_slice(s32); declare_slice(s64); declare_slice_p(char); +declare_slice_p(void); typedef Slice(u8) String; declare_slice(String); diff --git a/bootstrap/include/bloat-buster/font.h b/bootstrap/include/std/font_provider.h similarity index 100% rename from bootstrap/include/bloat-buster/font.h rename to bootstrap/include/std/font_provider.h diff --git a/bootstrap/include/std/graphics.h b/bootstrap/include/std/graphics.h index 97d7266..36712fc 100644 --- a/bootstrap/include/std/graphics.h +++ b/bootstrap/include/std/graphics.h @@ -1,3 +1,5 @@ +#pragma once + #include #include diff --git a/bootstrap/include/bloat-buster/image_loader.h b/bootstrap/include/std/image_loader.h similarity index 50% rename from bootstrap/include/bloat-buster/image_loader.h rename to bootstrap/include/std/image_loader.h index c75127f..fde4fd0 100644 --- a/bootstrap/include/bloat-buster/image_loader.h +++ b/bootstrap/include/std/image_loader.h @@ -1,13 +1,7 @@ +#pragma once + #include #include - -STRUCT(TextureMemory) -{ - u8* pointer; - u32 width; - u32 height; - u32 channel_count; - u32 depth; -}; +#include EXPORT TextureMemory texture_load_from_file(Arena* arena, String path); diff --git a/bootstrap/include/std/render.h b/bootstrap/include/std/render.h index e69de29..2e51525 100644 --- a/bootstrap/include/std/render.h +++ b/bootstrap/include/std/render.h @@ -0,0 +1,183 @@ +#pragma once + +#include + +#include + +#define frame_overlap (2) + +typedef struct Renderer Renderer; +typedef struct RenderWindow RenderWindow; +typedef struct Pipeline Pipeline; + +typedef enum IndexType : u8 +{ + INDEX_TYPE_U16, + INDEX_TYPE_U32, +} IndexType; + +typedef enum TextureFormat : u8 +{ + R8_UNORM, + R8G8B8A8_SRGB, +} TextureFormat; + +STRUCT(TextureMemory) +{ + u8* pointer; + u32 width; + u32 height; + u32 depth; + TextureFormat format; +}; + +typedef enum ShaderStage : u8 +{ + SHADER_STAGE_VERTEX, + SHADER_STAGE_FRAGMENT, +} ShaderStage; + +STRUCT(PipelineCreate) +{ + Slice(u16) shader_source_indices; + u16 layout_index; +}; +declare_slice(PipelineCreate); + +STRUCT(PushConstantRange) +{ + u16 offset; + u16 size; + ShaderStage stage; +}; +declare_slice(PushConstantRange); + +typedef enum DescriptorType : u8 +{ + DESCRIPTOR_TYPE_IMAGE_PLUS_SAMPLER, + DESCRIPTOR_TYPE_COUNT, +} DescriptorType; + +STRUCT(DescriptorSetLayoutBinding) +{ + u8 binding; + DescriptorType type; + ShaderStage stage; + u8 count; +}; +declare_slice(DescriptorSetLayoutBinding); + +STRUCT(DescriptorSetLayout) +{ + Slice(DescriptorSetLayoutBinding) bindings; +}; +declare_slice(DescriptorSetLayout); + +STRUCT(PipelineLayoutCreate) +{ + Slice(PushConstantRange) push_constant_ranges; + Slice(DescriptorSetLayout) descriptor_set_layouts; +}; +declare_slice(PipelineLayoutCreate); + +STRUCT(GraphicsPipelinesCreate) +{ + Slice(String) shader_sources; + Slice(PipelineLayoutCreate) layouts; + Slice(PipelineCreate) pipelines; +}; + +STRUCT(TextureIndex) +{ + u32 value; +}; + +STRUCT(PipelineIndex) +{ + u32 value; +}; + +STRUCT(PipelineLayoutIndex) +{ + u32 value; +}; + +STRUCT(DescriptorSetIndex) +{ + u32 value; +}; + +#define MAX_TEXTURE_UPDATE_COUNT (32) +#define MAX_DESCRIPTOR_SET_UPDATE_COUNT (16) +STRUCT(DescriptorSetUpdate) +{ + DescriptorSetIndex set; + DescriptorType type; + u32 binding; + u32 descriptor_count; + union + { + TextureIndex textures[MAX_TEXTURE_UPDATE_COUNT]; + }; +}; +declare_slice(DescriptorSetUpdate); + +typedef enum BufferType : u8 +{ + BUFFER_TYPE_VERTEX, + BUFFER_TYPE_INDEX, + BUFFER_TYPE_STAGING, +} BufferType; + +STRUCT(BufferIndex) +{ + u32 value; +}; + +STRUCT(HostBufferCopy) +{ + String source; + u64 destination_offset; +}; +declare_slice(HostBufferCopy); + +STRUCT(LocalBufferCopyRegion) +{ + u64 source_offset; + u64 destination_offset; + u64 size; +}; +declare_slice(LocalBufferCopyRegion); + +STRUCT(LocalBufferCopy) +{ + BufferIndex destination; + BufferIndex source; + Slice(LocalBufferCopyRegion) regions; +}; +declare_slice(LocalBufferCopy); + +#define MAX_LOCAL_BUFFER_COPY_COUNT (16) + +EXPORT Renderer* renderer_initialize(); +EXPORT RenderWindow* renderer_window_initialize(Renderer* renderer, GraphicsWindow* window); +EXPORT PipelineIndex renderer_graphics_pipelines_create(Renderer* renderer, Arena* arena, GraphicsPipelinesCreate create_data); +EXPORT PipelineLayoutIndex renderer_pipeline_get_layout(PipelineIndex pipeline); +EXPORT GraphicsWindowSize renderer_window_frame_begin(Renderer* renderer, RenderWindow* window); +EXPORT void renderer_window_frame_end(Renderer* renderer, RenderWindow* window); +EXPORT TextureIndex renderer_texture_create(Renderer* renderer, TextureMemory texture_memory); +EXPORT BufferIndex renderer_buffer_create(Renderer* renderer, u64 size, BufferType type); +EXPORT void renderer_update_pipeline_resources(Renderer* renderer, PipelineIndex pipeline_index, Slice(DescriptorSetUpdate) descriptor_updates); +EXPORT void renderer_copy_to_host(BufferIndex buffer_index, Slice(HostBufferCopy) regions); +EXPORT void renderer_copy_to_local(Renderer* renderer, Slice(LocalBufferCopy) copies); +EXPORT void window_command_begin(RenderWindow* window); +EXPORT void window_command_end(RenderWindow* window); +EXPORT void window_render_begin(RenderWindow* window); +EXPORT void window_render_end(RenderWindow* window); + +EXPORT void window_bind_pipeline(RenderWindow* window, PipelineIndex pipeline_index); +EXPORT void window_bind_pipeline_descriptor_sets(RenderWindow* window, PipelineIndex pipeline_index); +EXPORT void window_bind_index_buffer(RenderWindow* window, BufferIndex index_buffer, u64 offset, IndexType index_type); +EXPORT void window_push_constants(RenderWindow* window, PipelineIndex pipeline_index, SliceP(void) memories); +EXPORT u64 buffer_address(BufferIndex buffer_index); +EXPORT void window_draw_indexed(RenderWindow* window, u32 index_count, u32 instance_count, u32 first_index, s32 vertex_offset, u32 first_instance); diff --git a/bootstrap/include/bloat-buster/shader_compilation.h b/bootstrap/include/std/shader_compilation.h similarity index 56% rename from bootstrap/include/bloat-buster/shader_compilation.h rename to bootstrap/include/std/shader_compilation.h index 8125798..5620900 100644 --- a/bootstrap/include/bloat-buster/shader_compilation.h +++ b/bootstrap/include/std/shader_compilation.h @@ -1,10 +1,8 @@ +#pragma once + #include #include -typedef enum ShaderStage : u8 -{ - SHADER_STAGE_VERTEX, - SHADER_STAGE_FRAGMENT, -} ShaderStage; +#include EXPORT String compile_shader(Arena* arena, String path, ShaderStage shader_stage); diff --git a/bootstrap/runner/runner.c b/bootstrap/runner/runner.c index e5477b4..b8cbbd9 100644 --- a/bootstrap/runner/runner.c +++ b/bootstrap/runner/runner.c @@ -104,6 +104,7 @@ fn void run_tests(Arena* arena, String compiler_path, TestOptions const * const run_command(arena, (CStringSlice) array_to_slice(arguments), envp); +#if BB_CI // if (compiler_backend != COMPILER_BACKEND_INTERPRETER) { auto executable = binary_path_from_options(arena, (BinaryPathOptions) { @@ -119,6 +120,7 @@ fn void run_tests(Arena* arena, String compiler_path, TestOptions const * const }; run_command(arena, (CStringSlice) array_to_slice(run_arguments), envp); } +#endif } } } diff --git a/bootstrap/std/font_provider.c b/bootstrap/std/font_provider.c index aa4d1ec..72d283c 100644 --- a/bootstrap/std/font_provider.c +++ b/bootstrap/std/font_provider.c @@ -1,8 +1,11 @@ -#include +#include #define STBTT_STATIC #define STB_TRUETYPE_IMPLEMENTATION +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" #include +#pragma clang diagnostic pop TextureAtlas font_create_texture_atlas(Arena* arena, TextureAtlasCreate create) { @@ -75,7 +78,7 @@ TextureAtlas font_create_texture_atlas(Arena* arena, TextureAtlasCreate create) character->width = width; character->height = height; - print("Drawing codepoint '{c}' ({u32}x{u32}) at ({u32}, {u32}). Offsets: ({s32}, {s32})\n", ch, width, height, x, y, character->x_offset, character->y_offset); + // print("Drawing codepoint '{c}' ({u32}x{u32}) at ({u32}, {u32}). Offsets: ({s32}, {s32})\n", ch, width, height, x, y, character->x_offset, character->y_offset); auto* source = bitmap; auto* destination = result.pointer; @@ -89,23 +92,23 @@ TextureAtlas font_create_texture_atlas(Arena* arena, TextureAtlasCreate create) } } - for (u32 bitmap_y = y; bitmap_y < y + height; bitmap_y += 1) - { - for (u32 bitmap_x = x; bitmap_x < x + width; bitmap_x += 1) - { - auto x = result.pointer[bitmap_y * result.width + bitmap_x]; - if (x) - { - print("[x]"); - } - else - { - print("[ ]"); - } - } - - print("\n"); - } + // for (u32 bitmap_y = y; bitmap_y < y + height; bitmap_y += 1) + // { + // for (u32 bitmap_x = x; bitmap_x < x + width; bitmap_x += 1) + // { + // auto x = result.pointer[bitmap_y * result.width + bitmap_x]; + // if (x) + // { + // print("[x]"); + // } + // else + // { + // print("[ ]"); + // } + // } + // + // print("\n"); + // } x += width; diff --git a/bootstrap/bloat-buster/image_loader.c b/bootstrap/std/image_loader.c similarity index 70% rename from bootstrap/bloat-buster/image_loader.c rename to bootstrap/std/image_loader.c index d041af7..e5be1de 100644 --- a/bootstrap/bloat-buster/image_loader.c +++ b/bootstrap/std/image_loader.c @@ -1,7 +1,12 @@ -#include +#include +#define STB_IMAGE_STATIC #define STB_IMAGE_IMPLEMENTATION +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" #include +#pragma clang diagnostic pop + EXPORT TextureMemory texture_load_from_file(Arena* arena, String path) { @@ -16,7 +21,7 @@ EXPORT TextureMemory texture_load_from_file(Arena* arena, String path) .pointer = buffer, .width = width, .height = height, - .channel_count = channels, + .format = R8G8B8A8_SRGB, .depth = 1, }; } diff --git a/bootstrap/std/render.c b/bootstrap/std/render.c index e69de29..778d215 100644 --- a/bootstrap/std/render.c +++ b/bootstrap/std/render.c @@ -0,0 +1,1843 @@ +#include +#include +#include +#include + +#include + +STRUCT(VulkanImageCreate) +{ + u32 width; + u32 height; + u32 mip_levels; + VkFormat format; + VkImageUsageFlags usage; +}; + +STRUCT(VulkanImage) +{ + VkImage handle; + VkImageView view; + VkDeviceMemory memory; + VkFormat format; +}; + +[[noreturn]] [[gnu::cold]] fn void wrong_vulkan_result(VkResult result, String call_string, String file, int line) +{ + unused(result); + unused(call_string); + unused(file); + unused(line); + trap(); +} + +#define vkok(call) do {\ + VkResult _r_e_s_u_l_t_ = call; \ + if (unlikely(_r_e_s_u_l_t_ != VK_SUCCESS)) wrong_vulkan_result(_r_e_s_u_l_t_, strlit(#call), strlit(__FILE__), __LINE__); \ +} while(0) + +#define vkok_swapchain(call) do {\ + VkResult result = call; \ + if (unlikely(result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)) wrong_vulkan_result(result, strlit(#call), strlit(__FILE__), __LINE__); \ +} while(0) + +fn u8 vk_layer_is_supported(String layer_name) +{ + assert(layer_name.pointer[layer_name.length] == 0); + + VkLayerProperties layers[256]; + u32 layer_count; + + vkok(vkEnumerateInstanceLayerProperties(&layer_count, 0)); + + if (layer_count > array_length(layers)) + { + failed_execution(); + } + + vkok(vkEnumerateInstanceLayerProperties(&layer_count, layers)); + + u8 supported = 0; + for (u32 i = 0; i < layer_count; i += 1) + { + VkLayerProperties* properties = &layers[i]; + + auto candidate_layer_name = cstr(properties->layerName); + if (s_equal(candidate_layer_name, layer_name)) + { + supported = 1; + break; + } + } + + return supported; +} + +fn VkBool32 VKAPI_CALL debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, VkDebugUtilsMessageTypeFlagsEXT message_type, const VkDebugUtilsMessengerCallbackDataEXT* callback_data, void* user_data) +{ + unused(message_severity); + unused(message_type); + unused(user_data); + print("Validation message ({cstr}): {cstr}\n", callback_data->pMessageIdName ? callback_data->pMessageIdName : "ID_NONE", callback_data->pMessage); + if (message_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) + { + failed_execution(); + } + return VK_FALSE; +} + +fn VkDeviceMemory vk_allocate_memory(VkDevice device, const VkAllocationCallbacks* allocation_callbacks, VkPhysicalDeviceMemoryProperties memory_properties, VkMemoryRequirements memory_requirements, VkMemoryPropertyFlags flags, u8 use_device_address_bit) +{ + u32 memory_type_index; + for (memory_type_index = 0; memory_type_index < memory_properties.memoryTypeCount; memory_type_index += 1) + { + auto memory_type = memory_properties.memoryTypes[memory_type_index]; + + if ((memory_requirements.memoryTypeBits & (1 << memory_type_index)) != 0 && (memory_type.propertyFlags & flags) == flags) + { + break; + } + } + + if (memory_type_index == memory_properties.memoryTypeCount) + { + failed_execution(); + } + + VkMemoryAllocateInfo allocate_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .allocationSize = memory_requirements.size, + .memoryTypeIndex = memory_type_index, + }; + + VkMemoryAllocateFlagsInfo flags_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO, + .pNext = 0, + .flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT, + .deviceMask = 1, + }; + + if (use_device_address_bit) + { + allocate_info.pNext = &flags_info; + } + + VkDeviceMemory memory = 0; + vkok(vkAllocateMemory(device, &allocate_info, allocation_callbacks, &memory)); + + return memory; +} + +STRUCT(ImmediateContext) +{ + VkDevice device; + VkFence fence; + VkCommandBuffer command_buffer; + VkCommandPool command_pool; + VkQueue queue; +}; + +fn void immediate_start(ImmediateContext context) +{ + VkFence fences[] = { context.fence }; + VkCommandBufferResetFlags reset_flags = 0; + + vkok(vkResetFences(context.device, array_length(fences), fences)); + vkok(vkResetCommandBuffer(context.command_buffer, reset_flags)); + + VkCommandBufferBeginInfo command_buffer_begin_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, + }; + vkok(vkBeginCommandBuffer(context.command_buffer, &command_buffer_begin_info)); +} + +fn void immediate_end(ImmediateContext context) +{ + VkFence fences[] = { context.fence }; + + vkok(vkEndCommandBuffer(context.command_buffer)); + + VkCommandBufferSubmitInfo command_buffer_submit_infos[] = { + { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO, + .pNext = 0, + .deviceMask = 0, + .commandBuffer = context.command_buffer, + } + }; + + VkSubmitFlags submit_flags = 0; + + VkSubmitInfo2 submit_info[] = { + { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, + .pNext = 0, + .flags = submit_flags, + .waitSemaphoreInfoCount = 0, + .pWaitSemaphoreInfos = 0, + .commandBufferInfoCount = array_length(command_buffer_submit_infos), + .pCommandBufferInfos = command_buffer_submit_infos, + .signalSemaphoreInfoCount = 0, + .pSignalSemaphoreInfos = 0, + } + }; + + vkok(vkQueueSubmit2(context.queue, array_length(submit_info), submit_info, context.fence)); + VkBool32 wait_all = 1; + auto timeout = ~(u64)0; + vkok(vkWaitForFences(context.device, array_length(fences), fences, wait_all, timeout)); +} + +fn VulkanImage vk_image_create(VkDevice device, const VkAllocationCallbacks* allocation_callbacks, VkPhysicalDeviceMemoryProperties memory_properties, VulkanImageCreate create) +{ + assert(create.width); + assert(create.height); + VulkanImage result = {}; + result.format = create.format; + + VkImageCreateInfo create_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .pNext = 0, + .flags = 0, + .imageType = VK_IMAGE_TYPE_2D, + .format = create.format, + .extent = { + .width = create.width, + .height = create.height, + .depth = 1, + }, + .mipLevels = create.mip_levels, + .arrayLayers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = create.usage, + .sharingMode = 0, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = 0, + .initialLayout = 0, + }; + vkok(vkCreateImage(device, &create_info, allocation_callbacks, &result.handle)); + + VkMemoryRequirements memory_requirements; + vkGetImageMemoryRequirements(device, result.handle, &memory_requirements); + + VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + u8 use_device_address_bit = 0; + result.memory = vk_allocate_memory(device, allocation_callbacks, memory_properties, memory_requirements, flags, use_device_address_bit); + + VkDeviceSize memory_offset = 0; + vkok(vkBindImageMemory(device, result.handle, result.memory, memory_offset)); + + VkImageViewCreateInfo view_create_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .image = result.handle, + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = create_info.format, + .subresourceRange = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = create.mip_levels, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + + vkok(vkCreateImageView(device, &view_create_info, allocation_callbacks, &result.view)); + return result; +} + +fn void vk_image_transition(VkCommandBuffer command_buffer, VkImage image, VkImageLayout old_layout, VkImageLayout new_layout) +{ + VkImageMemoryBarrier2 image_barrier = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, + .srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + .srcAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT, + .dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + .dstAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT | VK_ACCESS_2_MEMORY_READ_BIT, + .oldLayout = old_layout, + .newLayout = new_layout, + .image = image, + .subresourceRange = { + .aspectMask = (new_layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = VK_REMAINING_MIP_LEVELS, + .baseArrayLayer = 0, + .layerCount = VK_REMAINING_ARRAY_LAYERS, + }, + }; + + VkDependencyInfo dependency_info = { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .imageMemoryBarrierCount = 1, + .pImageMemoryBarriers = &image_barrier, + }; + + vkCmdPipelineBarrier2(command_buffer, &dependency_info); +} + +STRUCT(VulkanCopyImage) +{ + VkImage handle; + VkExtent2D extent; +}; + +STRUCT(VulkanCopyImageArgs) +{ + VulkanCopyImage source; + VulkanCopyImage destination; +}; + +fn void vk_image_copy(VkCommandBuffer command_buffer, VulkanCopyImageArgs args) +{ + VkImageSubresourceLayers subresource_layers = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1, + }; + VkImageBlit2 blit_regions[] = { + { + .sType = VK_STRUCTURE_TYPE_IMAGE_BLIT_2, + .pNext = 0, + .srcSubresource = subresource_layers, + .srcOffsets = { + [1] = { + .x = args.source.extent.width, + .y = args.source.extent.height, + .z = 1, + }, + }, + .dstSubresource = subresource_layers, + .dstOffsets = { + [1] = { + .x = args.destination.extent.width, + .y = args.destination.extent.height, + .z = 1, + }, + }, + }, + }; + + VkBlitImageInfo2 blit_info = { + .sType = VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2, + .pNext = 0, + .srcImage = args.source.handle, + .srcImageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + .dstImage = args.destination.handle, + .dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .regionCount = array_length(blit_regions), + .pRegions = blit_regions, + .filter = VK_FILTER_LINEAR, + }; + + vkCmdBlitImage2(command_buffer, &blit_info); +} + +STRUCT(Renderer) +{ + VkInstance instance; + VkAllocationCallbacks* allocator; + VkPhysicalDevice physical_device; + VkDevice device; + VkQueue graphics_queue; + u32 graphics_queue_family_index; + VkSampler sampler; + ImmediateContext immediate; + VkPhysicalDeviceMemoryProperties memory_properties; +}; + +#define MAX_SWAPCHAIN_IMAGE_COUNT (16) +#define MAX_FRAMES (2) + +STRUCT(WindowFrame) +{ + VkCommandPool command_pool; + VkCommandBuffer command_buffer; + VkSemaphore swapchain_semaphore; + VkSemaphore render_semaphore; + VkFence render_fence; +}; + +STRUCT(RenderWindow) +{ + GraphicsWindow* graphics_window; + VkSwapchainKHR swapchain; + VulkanImage render_image; + u32 width; + u32 height; + u32 last_width; + u32 last_height; + u32 frame_index; + u32 swapchain_image_index; + u32 swapchain_image_count; + VkImage swapchain_images[MAX_SWAPCHAIN_IMAGE_COUNT]; + VkImageView swapchain_image_views[MAX_SWAPCHAIN_IMAGE_COUNT]; + VkFormat swapchain_image_format; + WindowFrame frames[MAX_FRAMES]; +}; + +global_variable Renderer renderer_memory; +global_variable RenderWindow renderer_window_memory; + +Renderer* renderer_initialize() +{ + Renderer* result = &renderer_memory; + vkok(volkInitialize()); + + { + auto debug_layer = strlit("VK_LAYER_KHRONOS_validation"); + if (!vk_layer_is_supported(debug_layer)) + { + failed_execution(); + } + const char* layers[] = + { + string_to_c(debug_layer), + }; + + auto api_version = volkGetInstanceVersion(); + if (api_version < VK_API_VERSION_1_3) + { + failed_execution(); + } + + const char* extensions[] = { + VK_EXT_DEBUG_UTILS_EXTENSION_NAME, + VK_KHR_SURFACE_EXTENSION_NAME, +#ifdef VK_USE_PLATFORM_WIN32_KHR + VK_KHR_WIN32_SURFACE_EXTENSION_NAME, +#endif +#ifdef VK_USE_PLATFORM_XLIB_KHR + VK_KHR_XLIB_SURFACE_EXTENSION_NAME, +#endif +#ifdef VK_USE_PLATFORM_WAYLAND_KHR + VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, +#endif +#ifdef VK_USE_PLATFORM_MACOS_MVK + VK_KHR_COCOA_SURFACE_EXTENSION_NAME, +#endif + }; + + + VkValidationFeatureEnableEXT enabled_validation_features[] = + { + VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT, + }; + + VkDebugUtilsMessengerCreateInfoEXT msg_ci = { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + .pNext = 0, + .flags = 0, + .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, + .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_DEVICE_ADDRESS_BINDING_BIT_EXT, + .pfnUserCallback = debug_callback, + .pUserData = 0, + }; + + u8 enable_shader_debug_printf = 0; + + VkValidationFeaturesEXT validation_features = { + .sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT, + .enabledValidationFeatureCount = array_length(enabled_validation_features), + .pEnabledValidationFeatures = enabled_validation_features, + .pNext = &msg_ci, + }; + + VkApplicationInfo app_info = { + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .apiVersion = api_version, + }; + + VkInstanceCreateInfo ci = { + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pApplicationInfo = &app_info, + .ppEnabledLayerNames = layers, + .enabledLayerCount = array_length(layers), + .ppEnabledExtensionNames = extensions, + .enabledExtensionCount = array_length(extensions), + .pNext = enable_shader_debug_printf ? (const void*)&validation_features : (const void*)&msg_ci, + }; + + vkok(vkCreateInstance(&ci, result->allocator, &result->instance)); + volkLoadInstance(result->instance); + + VkDebugUtilsMessengerEXT messenger; + vkok(vkCreateDebugUtilsMessengerEXT(result->instance, &msg_ci, result->allocator, &messenger)); + } + + + { + u32 physical_device_count; + VkPhysicalDevice physical_devices[256]; + vkok(vkEnumeratePhysicalDevices(result->instance, &physical_device_count, 0)); + + if (physical_device_count == 0) + { + failed_execution(); + } + + if (physical_device_count > array_length(physical_devices)) + { + failed_execution(); + } + + vkok(vkEnumeratePhysicalDevices(result->instance, &physical_device_count, physical_devices)); + + result->physical_device = physical_devices[0]; + } + + u32 graphics_queue_family_index; + { + u32 present_queue_family_index; + VkPhysicalDeviceProperties properties; + vkGetPhysicalDeviceProperties(result->physical_device, &properties); + + u32 queue_count; + vkGetPhysicalDeviceQueueFamilyProperties(result->physical_device, &queue_count, 0); + + VkQueueFamilyProperties queue_properties[64]; + if (queue_count > array_length(queue_properties)) + { + failed_execution(); + } + + vkGetPhysicalDeviceQueueFamilyProperties(result->physical_device, &queue_count, queue_properties); + + for (graphics_queue_family_index = 0; graphics_queue_family_index < queue_count; graphics_queue_family_index += 1) + { + VkQueueFamilyProperties* properties = &queue_properties[graphics_queue_family_index]; + if (properties->queueFlags & VK_QUEUE_GRAPHICS_BIT) + { + break; + } + } + + if (graphics_queue_family_index == queue_count) + { + failed_execution(); + } + + present_queue_family_index = 0; + // for (present_queue_family_index = 0; present_queue_family_index < queue_count; present_queue_family_index += 1) + // { + // VkBool32 support; + // vkok(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, present_queue_family_index, surface, &support)); + // if (support) + // { + // break; + // } + // } + + if (present_queue_family_index == queue_count) + { + failed_execution(); + } + + if (present_queue_family_index != graphics_queue_family_index) + { + failed_execution(); + } + + f32 queue_priorities[] = { 1.0f }; + VkDeviceQueueCreateInfo queue_create_infos[] = { + { + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .queueFamilyIndex = graphics_queue_family_index, + .queueCount = array_length(queue_priorities), + .pQueuePriorities = queue_priorities, + }, + }; + + const char* extensions[] = + { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + }; + + VkPhysicalDeviceVulkan13Features features13 = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES, + .dynamicRendering = 1, + .synchronization2 = 1, + }; + + VkPhysicalDeviceVulkan12Features features12 = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES, + .bufferDeviceAddress = 1, + .descriptorIndexing = 1, + .pNext = &features13, + }; + + VkPhysicalDeviceFeatures2 features = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, + .features = { + }, + .pNext = &features12, + }; + + VkDeviceCreateInfo ci = { + .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .ppEnabledExtensionNames = extensions, + .enabledExtensionCount = array_length(extensions), + .pQueueCreateInfos = queue_create_infos, + .queueCreateInfoCount = array_length(queue_create_infos), + .pNext = &features, + }; + + vkok(vkCreateDevice(result->physical_device, &ci, result->allocator, &result->device)); + } + + vkGetDeviceQueue(result->device, graphics_queue_family_index, 0, &result->graphics_queue); + + result->immediate.device = result->device; + result->immediate.queue = result->graphics_queue; + + VkCommandPoolCreateInfo create_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, + .queueFamilyIndex = graphics_queue_family_index, + }; + vkok(vkCreateCommandPool(result->device, &create_info, result->allocator, &result->immediate.command_pool)); + + VkCommandBufferAllocateInfo command_buffer_allocate_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .commandPool = result->immediate.command_pool, + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = 1, + }; + + vkok(vkAllocateCommandBuffers(result->device, &command_buffer_allocate_info, &result->immediate.command_buffer)); + VkFenceCreateInfo fence_create_info = { + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .flags = VK_FENCE_CREATE_SIGNALED_BIT, + }; + vkok(vkCreateFence(result->device, &fence_create_info, result->allocator, &result->immediate.fence)); + + { + VkFilter sampler_filter = VK_FILTER_LINEAR; + VkSamplerCreateInfo create_info = { + .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + .pNext = 0, + .flags = 0, + .magFilter = sampler_filter, + .minFilter = sampler_filter, + .mipmapMode = 0, + .addressModeU = 0, + .addressModeV = 0, + .addressModeW = 0, + .mipLodBias = 0, + .anisotropyEnable = 0, + .maxAnisotropy = 0, + .compareEnable = 0, + .compareOp = 0, + .minLod = 0, + .maxLod = 0, + .borderColor = 0, + .unnormalizedCoordinates = 0, + }; + + vkok(vkCreateSampler(result->device, &create_info, result->allocator, &result->sampler)); + } + + return result; +} + +RenderWindow* renderer_window_initialize(Renderer* renderer, GraphicsWindow* window) +{ + RenderWindow* result = &renderer_window_memory; + result->graphics_window = window; + VkSurfaceKHR surface; + { +#ifdef VK_USE_PLATFORM_WIN32_KHR + VkWin32SurfaceCreateInfoKHR create_info = { + .sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, + .pNext = 0, + .flags = 0, + .hinstance = os_windows_get_module_handle(), + .hwnd = graphics_win32_window_get(window), + }; + vkok(vkCreateWin32SurfaceKHR(renderer->instance, &create_info, renderer->allocator, &surface)); +#endif +#ifdef VK_USE_PLATFORM_XLIB_KHR + VkXlibSurfaceCreateInfoKHR create_info = { + .sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, + .pNext = 0, + .flags = 0, + .dpy = graphics_x11_display_get(), + .window = graphics_x11_window_get(window), + }; + vkok(vkCreateXlibSurfaceKHR(renderer->instance, &create_info, renderer->allocator, &surface)); +#endif +#ifdef VK_USE_PLATFORM_WAYLAND_KHR + VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, +#endif +#ifdef VK_USE_PLATFORM_MACOS_MVK + VK_KHR_COCOA_SURFACE_EXTENSION_NAME, +#endif + } + + VkSurfaceCapabilitiesKHR original_capabilities; + vkok(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(renderer->physical_device, surface, &original_capabilities)); + + u32 queue_family_indices[] = { renderer->graphics_queue_family_index }; + VkImageUsageFlags swapchain_image_usage_flags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + result->swapchain_image_format = VK_FORMAT_B8G8R8A8_UNORM; + result->width = original_capabilities.currentExtent.width; + result->height = original_capabilities.currentExtent.height; + result->last_width = result->width; + result->last_height = result->height; + VkSwapchainCreateInfoKHR swapchain_create_info = { + .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, + .pNext = 0, + .flags = 0, + .surface = surface, + .minImageCount = original_capabilities.minImageCount, + .imageFormat = result->swapchain_image_format, + .imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, + .imageExtent = original_capabilities.currentExtent, + .imageArrayLayers = 1, + .imageUsage = swapchain_image_usage_flags, + .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = array_length(queue_family_indices), + .pQueueFamilyIndices = queue_family_indices, + .preTransform = original_capabilities.currentTransform, + .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + .presentMode = VK_PRESENT_MODE_FIFO_KHR, + .clipped = 0, + .oldSwapchain = result->swapchain, + }; + + { + VkSwapchainKHR new_swapchain; + vkok(vkCreateSwapchainKHR(renderer->device, &swapchain_create_info, renderer->allocator, &new_swapchain)); + result->swapchain = new_swapchain; + } + + { + vkok(vkGetSwapchainImagesKHR(renderer->device, result->swapchain, &result->swapchain_image_count, 0)); + + if (result->swapchain_image_count == 0) + { + failed_execution(); + } + + if (result->swapchain_image_count > array_length(result->swapchain_images)) + { + failed_execution(); + } + + vkok(vkGetSwapchainImagesKHR(renderer->device, result->swapchain, &result->swapchain_image_count, result->swapchain_images)); + + // VkImageViewUsageCreateInfo image_view_usage_create_info = { + // .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, + // .pNext = 0, + // .usage = swapchain_create_info.imageUsage, + // }; + + for (u32 i = 0; i < result->swapchain_image_count; i += 1) + { + VkImageViewCreateInfo create_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + // .pNext = &image_view_usage_create_info, + .flags = 0, + .image = result->swapchain_images[i], + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = swapchain_create_info.imageFormat, + .components = { + .r = VK_COMPONENT_SWIZZLE_IDENTITY, + .g = VK_COMPONENT_SWIZZLE_IDENTITY, + .b = VK_COMPONENT_SWIZZLE_IDENTITY, + .a = VK_COMPONENT_SWIZZLE_IDENTITY, + }, + .subresourceRange = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + + vkok(vkCreateImageView(renderer->device, &create_info, renderer->allocator, &result->swapchain_image_views[i])); + } + } + + vkGetPhysicalDeviceMemoryProperties(renderer->physical_device, &renderer->memory_properties); + + auto initial_window_size = graphics_window_size_get(window); + + result->render_image = vk_image_create(renderer->device, renderer->allocator, renderer->memory_properties, (VulkanImageCreate) { + .width = initial_window_size.width, + .height = initial_window_size.height, + .mip_levels = 1, + .format = result->swapchain_image_format, + .usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + }); + + VkCommandPoolCreateInfo command_pool_create_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, + .queueFamilyIndex = renderer->graphics_queue_family_index, + }; + + VkFenceCreateInfo fence_create_info = { + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .flags = VK_FENCE_CREATE_SIGNALED_BIT, + }; + + VkSemaphoreCreateInfo semaphore_create_info = { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + .flags = 0, + }; + + for (u32 i = 0; i < MAX_FRAMES; i += 1) + { + WindowFrame* frame = &result->frames[i]; + vkok(vkCreateCommandPool(renderer->device, &command_pool_create_info, renderer->allocator, &frame->command_pool)); + + VkCommandBufferAllocateInfo command_buffer_allocate_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .commandPool = frame->command_pool, + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = 1, + }; + + vkok(vkAllocateCommandBuffers(renderer->device, &command_buffer_allocate_info, &frame->command_buffer)); + vkok(vkCreateFence(renderer->device, &fence_create_info, renderer->allocator, &frame->render_fence)); + vkok(vkCreateSemaphore(renderer->device, &semaphore_create_info, renderer->allocator, &frame->render_semaphore)); + vkok(vkCreateSemaphore(renderer->device, &semaphore_create_info, renderer->allocator, &frame->swapchain_semaphore)); + } + + return result; +} + +#define MAX_DESCRIPTOR_SETS (16) +#define MAX_PUSH_CONSTANT_RANGES (16) + +STRUCT(PipelineLayout) +{ + VkPipelineLayout handle; + u32 descriptor_set_count; + VkDescriptorSet descriptor_sets[MAX_DESCRIPTOR_SETS]; + u32 push_constant_range_count; + VkPushConstantRange push_constant_ranges[MAX_DESCRIPTOR_SETS]; +}; + +STRUCT(Pipeline) +{ + VkPipeline handle; + PipelineLayoutIndex layout; +}; + +#define MAX_PIPELINES (16) +global_variable PipelineLayout pipeline_layouts[MAX_PIPELINES]; +global_variable Pipeline pipelines[MAX_PIPELINES]; + +STRUCT(GPUDrawPushConstants) +{ + VkDeviceAddress vertex_buffer; + f32 width; + f32 height; +}; + +#define MAX_SHADER_MODULE_COUNT_PER_PIPELINE (16) +fn VkShaderStageFlags vulkan_shader_stage_from_path(String shader_source_path) +{ + VkShaderStageFlags shader_stage; + if (string_ends_with(shader_source_path, strlit(".vert"))) + { + shader_stage = VK_SHADER_STAGE_VERTEX_BIT; + } + else if (string_ends_with(shader_source_path, strlit(".frag"))) + { + shader_stage = VK_SHADER_STAGE_FRAGMENT_BIT; + } + else + { + failed_execution(); + } + + return shader_stage; +} + +fn VkShaderStageFlags vulkan_shader_stage(ShaderStage shader_stage) +{ + VkShaderStageFlags result; + + switch (shader_stage) + { + case SHADER_STAGE_VERTEX: + result = VK_SHADER_STAGE_VERTEX_BIT; + break; + case SHADER_STAGE_FRAGMENT: + result = VK_SHADER_STAGE_FRAGMENT_BIT; + break; + } + + return result; +} + +fn ShaderStage shader_stage_from_path(String shader_source_path) +{ + ShaderStage shader_stage; + if (string_ends_with(shader_source_path, strlit(".vert"))) + { + shader_stage = SHADER_STAGE_VERTEX; + } + else if (string_ends_with(shader_source_path, strlit(".frag"))) + { + shader_stage = SHADER_STAGE_FRAGMENT; + } + else + { + failed_execution(); + } + + return shader_stage; +} + +fn VkDescriptorType vulkan_descriptor_type(DescriptorType type) +{ + VkDescriptorType result; + + switch (type) + { + case DESCRIPTOR_TYPE_IMAGE_PLUS_SAMPLER: + result = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + break; + case DESCRIPTOR_TYPE_COUNT: + unreachable(); + } + + return result; +} + +PipelineIndex renderer_graphics_pipelines_create(Renderer* renderer, Arena* arena, GraphicsPipelinesCreate create_data) +{ + auto graphics_pipeline_count = create_data.pipelines.length; + assert(graphics_pipeline_count); + auto pipeline_layout_count = create_data.layouts.length; + assert(pipeline_layout_count); + assert(pipeline_layout_count <= graphics_pipeline_count); + auto shader_count = create_data.shader_sources.length; + + if (graphics_pipeline_count > MAX_PIPELINES) + { + failed_execution(); + } + + VkPipeline pipeline_handles[MAX_PIPELINES]; + VkPipelineShaderStageCreateInfo shader_create_infos[MAX_SHADER_MODULE_COUNT_PER_PIPELINE]; + VkGraphicsPipelineCreateInfo graphics_pipeline_create_infos[MAX_PIPELINES]; + + VkPipelineVertexInputStateCreateInfo vertex_input_state_create_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .pNext = 0, + .flags = 0, + .vertexBindingDescriptionCount = 0, + .pVertexBindingDescriptions = 0, + .vertexAttributeDescriptionCount = 0, + .pVertexAttributeDescriptions = 0, + }; + + VkPipelineInputAssemblyStateCreateInfo input_assembly_state_create_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .pNext = 0, + .flags = 0, + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + .primitiveRestartEnable = VK_FALSE, + }; + + VkPipelineViewportStateCreateInfo viewport_state_create_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .pNext = 0, + .viewportCount = 1, + .scissorCount = 1, + }; + + VkPipelineRasterizationStateCreateInfo rasterization_state_create_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .pNext = 0, + .flags = 0, + .depthClampEnable = 0, + .rasterizerDiscardEnable = 0, + .polygonMode = VK_POLYGON_MODE_FILL, + .cullMode = VK_CULL_MODE_NONE, + .frontFace = VK_FRONT_FACE_CLOCKWISE, + .depthBiasEnable = 0, + .depthBiasConstantFactor = 0, + .depthBiasClamp = 0, + .depthBiasSlopeFactor = 0, + .lineWidth = 1.0f, + }; + + VkPipelineMultisampleStateCreateInfo multisample_state_create_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .pNext = 0, + .flags = 0, + .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, + .sampleShadingEnable = 0, + .minSampleShading = 1.0f, + .pSampleMask = 0, + .alphaToCoverageEnable = 0, + .alphaToOneEnable = 0, + }; + + VkPipelineDepthStencilStateCreateInfo depth_stencil_state_create_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, + .pNext = 0, + .flags = 0, + .depthTestEnable = 0, + .depthWriteEnable = 0, + .depthCompareOp = VK_COMPARE_OP_NEVER, + .depthBoundsTestEnable = 0, + .stencilTestEnable = 0, + .front = {}, + .back = {}, + .minDepthBounds = 0.0f, + .maxDepthBounds = 1.0f, + }; + + VkPipelineColorBlendAttachmentState attachments[] = { + { + .blendEnable = 1, + .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA, + .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .colorBlendOp = VK_BLEND_OP_ADD, + .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, + .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, + .alphaBlendOp = VK_BLEND_OP_ADD, + .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, + }, + }; + + VkPipelineColorBlendStateCreateInfo color_blend_state_create_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .pNext = 0, + .flags = 0, + .logicOpEnable = VK_FALSE, + .logicOp = VK_LOGIC_OP_COPY, + .attachmentCount = array_length(attachments), + .pAttachments = attachments, + .blendConstants = {}, + }; + + VkDynamicState states[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; + + VkPipelineDynamicStateCreateInfo dynamic_state_create_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .pNext = 0, + .flags = 0, + .dynamicStateCount = array_length(states), + .pDynamicStates = states, + }; + + // TODO: abstract away + VkFormat common_image_format = VK_FORMAT_B8G8R8A8_UNORM; + VkFormat color_attachment_formats[] = { + common_image_format, + }; + + VkPipelineRenderingCreateInfo rendering_create_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, + .pNext = 0, + .viewMask = 0, + .colorAttachmentCount = array_length(color_attachment_formats), + .pColorAttachmentFormats = color_attachment_formats, + .depthAttachmentFormat = 0, + .stencilAttachmentFormat = 0, + }; + + auto* shader_modules = arena_allocate(arena, VkShaderModule, shader_count); + + for (u64 i = 0; i < shader_count; i += 1) + { + String shader_source_path = create_data.shader_sources.pointer[i]; + + ShaderStage shader_stage = shader_stage_from_path(shader_source_path); + + auto binary = compile_shader(arena, shader_source_path, shader_stage); + + VkShaderModuleCreateInfo create_info = { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .codeSize = binary.length, + .pCode = (u32*)binary.pointer, + }; + + vkok(vkCreateShaderModule(renderer->device, &create_info, renderer->allocator, &shader_modules[i])); + } + + // auto* pipeline_layouts = arena_allocate(arena, VkPipelineLayout, pipeline_layout_count); + + for (u64 i = 0; i < pipeline_layout_count; i += 1) + { + auto create = create_data.layouts.pointer[i]; + auto descriptor_set_layout_count = create.descriptor_set_layouts.length; + auto push_constant_range_count = create.push_constant_ranges.length; + pipeline_layouts[i].descriptor_set_count = descriptor_set_layout_count; + pipeline_layouts[i].push_constant_range_count = push_constant_range_count; + +#define MAX_DESCRIPTOR_SET_LAYOUT_COUNT (16) + VkDescriptorSetLayout descriptor_set_layouts[MAX_DESCRIPTOR_SET_LAYOUT_COUNT]; + if (descriptor_set_layout_count > MAX_DESCRIPTOR_SET_LAYOUT_COUNT) + { + failed_execution(); + } + + u16 descriptor_type_counter[DESCRIPTOR_TYPE_COUNT] = {}; + + for (u64 i = 0; i < descriptor_set_layout_count; i += 1) + { + auto set_layout_create = create.descriptor_set_layouts.pointer[i]; + auto binding_count = set_layout_create.bindings.length; + +#define MAX_DESCRIPTOR_SET_LAYOUT_BINDING_COUNT (16) + VkDescriptorSetLayoutBinding bindings[MAX_DESCRIPTOR_SET_LAYOUT_BINDING_COUNT]; + + for (u64 i = 0; i < binding_count; i += 1) + { + auto binding_descriptor = set_layout_create.bindings.pointer[i]; + auto* counter_ptr = &descriptor_type_counter[binding_descriptor.type]; + auto old_counter = *counter_ptr; + *counter_ptr = old_counter + binding_descriptor.count; + + VkDescriptorType descriptor_type = vulkan_descriptor_type(binding_descriptor.type); + + VkShaderStageFlags shader_stage = vulkan_shader_stage(binding_descriptor.stage); + + bindings[i] = (VkDescriptorSetLayoutBinding) { + .binding = binding_descriptor.binding, + .descriptorType = descriptor_type, + .descriptorCount = binding_descriptor.count, + .stageFlags = shader_stage, + .pImmutableSamplers = 0, + }; + } + + VkDescriptorSetLayoutCreateInfo create_info = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .pNext = 0, + .flags = 0, + .bindingCount = binding_count, + .pBindings = bindings, + }; + + vkok(vkCreateDescriptorSetLayout(renderer->device, &create_info, renderer->allocator, &descriptor_set_layouts[i])); + } + + { + VkDescriptorPoolSize pool_sizes[DESCRIPTOR_TYPE_COUNT]; + u32 pool_size_count = 0; + + for (DescriptorType i = 0; i < DESCRIPTOR_TYPE_COUNT; i += 1) + { + auto count = descriptor_type_counter[i]; + if (count) + { + auto* pool_size = &pool_sizes[pool_size_count]; + pool_size_count += 1; + + *pool_size = (VkDescriptorPoolSize) { + .type = vulkan_descriptor_type(i), + .descriptorCount = count, + }; + } + } + + VkDescriptorPoolCreateInfo create_info = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .pNext = 0, + .flags = 0, + .maxSets = descriptor_set_layout_count, + .poolSizeCount = pool_size_count, + .pPoolSizes = pool_sizes, + }; + + VkDescriptorPool descriptor_pool; + vkok(vkCreateDescriptorPool(renderer->device, &create_info, renderer->allocator, &descriptor_pool)); + + VkDescriptorSetAllocateInfo allocate_info = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .pNext = 0, + .descriptorPool = descriptor_pool, + .descriptorSetCount = descriptor_set_layout_count, + .pSetLayouts = descriptor_set_layouts, + }; + + vkok(vkAllocateDescriptorSets(renderer->device, &allocate_info, pipeline_layouts[i].descriptor_sets)); + } + + if (push_constant_range_count > MAX_PUSH_CONSTANT_RANGES) + { + failed_execution(); + } + + for (u64 i = 0; i < push_constant_range_count; i += 1) + { + auto push_constant_descriptor = create.push_constant_ranges.pointer[i]; + pipeline_layouts[i].push_constant_ranges[i] = (VkPushConstantRange) { + .stageFlags = vulkan_shader_stage(push_constant_descriptor.stage), + .offset = push_constant_descriptor.offset, + .size = push_constant_descriptor.size, + }; + } + + VkPipelineLayoutCreateInfo create_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .pNext = 0, + .flags = 0, + .setLayoutCount = descriptor_set_layout_count, + .pSetLayouts = descriptor_set_layouts, + .pushConstantRangeCount = push_constant_range_count, + .pPushConstantRanges = pipeline_layouts[i].push_constant_ranges, + }; + + vkok(vkCreatePipelineLayout(renderer->device, &create_info, renderer->allocator, &pipeline_layouts[i].handle)); + } + + for (u64 i = 0; i < graphics_pipeline_count; i += 1) + { + auto create = create_data.pipelines.pointer[i]; + auto pipeline_shader_count = create.shader_source_indices.length; + if (pipeline_shader_count > MAX_SHADER_MODULE_COUNT_PER_PIPELINE) + { + failed_execution(); + } + + for (u64 i = 0; i < pipeline_shader_count; i += 1) + { + auto shader_index = create.shader_source_indices.pointer[i]; + auto shader_source_path = create_data.shader_sources.pointer[shader_index]; + + shader_create_infos[i] = (VkPipelineShaderStageCreateInfo) { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .pNext = 0, + .flags = 0, + .stage = vulkan_shader_stage_from_path(shader_source_path), + .module = shader_modules[i], + .pName = "main", + .pSpecializationInfo = 0, + }; + } + + graphics_pipeline_create_infos[i] = (VkGraphicsPipelineCreateInfo) + { + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .pNext = &rendering_create_info, + .flags = 0, + .stageCount = shader_count, + .pStages = shader_create_infos, + .pVertexInputState = &vertex_input_state_create_info, + .pInputAssemblyState = &input_assembly_state_create_info, + .pTessellationState = 0, + .pViewportState = &viewport_state_create_info, + .pRasterizationState = &rasterization_state_create_info, + .pMultisampleState = &multisample_state_create_info, + .pDepthStencilState = &depth_stencil_state_create_info, + .pColorBlendState = &color_blend_state_create_info, + .pDynamicState = &dynamic_state_create_info, + .layout = pipeline_layouts[create.layout_index].handle, + .renderPass = 0, + .subpass = 0, + .basePipelineHandle = 0, + .basePipelineIndex = 0, + }; + } + + VkPipelineCache pipeline_cache = 0; + vkok(vkCreateGraphicsPipelines(renderer->device, pipeline_cache, graphics_pipeline_count, graphics_pipeline_create_infos, renderer->allocator, pipeline_handles)); + + for (u32 i = 0; i < graphics_pipeline_count; i += 1) + { + pipelines[i] = (Pipeline) { + .handle = pipeline_handles[i], + .layout = { .value = create_data.pipelines.pointer[i].layout_index }, + }; + } + + return (PipelineIndex){ .value = 0 }; +} + +fn WindowFrame* window_frame(RenderWindow* window) +{ + return &window->frames[window->frame_index % MAX_FRAMES]; +} + +// TODO: this might be the wrong abstraction layer +fn void queue_submit(Renderer* renderer, RenderWindow* window) +{ + auto* frame = window_frame(window); + + VkCommandBufferSubmitInfo command_buffer_submit_info[] = { + { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO, + .commandBuffer = frame->command_buffer, + .deviceMask = 0, + }, + }; + + VkSemaphoreSubmitInfo wait_semaphore_submit_info[] = { + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .semaphore = frame->swapchain_semaphore, + .stageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, + .deviceIndex = 0, + .value = 1, + }, + }; + + VkSemaphoreSubmitInfo signal_semaphore_submit_info[] = { + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .semaphore = frame->render_semaphore, + .stageMask = VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT, + .deviceIndex = 0, + .value = 1, + }, + }; + + VkSubmitInfo2 submit_info[] = { + { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, + .flags = 0, + .waitSemaphoreInfoCount = array_length(wait_semaphore_submit_info), + .pWaitSemaphoreInfos = wait_semaphore_submit_info, + .signalSemaphoreInfoCount = array_length(signal_semaphore_submit_info), + .pSignalSemaphoreInfos = signal_semaphore_submit_info, + .commandBufferInfoCount = array_length(command_buffer_submit_info), + .pCommandBufferInfos = command_buffer_submit_info, + }, + }; + + vkok(vkQueueSubmit2(renderer->graphics_queue, array_length(submit_info), submit_info, frame->render_fence)); +} + +fn void queue_present(Renderer* renderer, RenderWindow* window) +{ + auto* frame = window_frame(window); + const VkSwapchainKHR swapchains[] = { window->swapchain }; + const u32 swapchain_image_indices[] = { window->swapchain_image_index }; + const VkSemaphore wait_semaphores[] = { frame->render_semaphore }; + VkResult results[array_length(swapchains)]; + + VkPresentInfoKHR present_info = { + .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + .waitSemaphoreCount = array_length(wait_semaphores), + .pWaitSemaphores = wait_semaphores, + .swapchainCount = array_length(swapchains), + .pSwapchains = swapchains, + .pImageIndices = swapchain_image_indices, + .pResults = results, + }; + + vkok_swapchain(vkQueuePresentKHR(renderer->graphics_queue, &present_info)); + + for (u32 i = 0; i < array_length(results); i += 1) + { + vkok_swapchain(results[i]); + } +} + +GraphicsWindowSize renderer_window_frame_begin(Renderer* renderer, RenderWindow* window) +{ + auto* frame = window_frame(window); + auto timeout = ~(u64)0; + + u32 fence_count = 1; + VkBool32 wait_all = 1; + vkok(vkWaitForFences(renderer->device, fence_count, &frame->render_fence, wait_all, timeout)); + VkFence image_fence = 0; + vkok_swapchain(vkAcquireNextImageKHR(renderer->device, window->swapchain, timeout, frame->swapchain_semaphore, image_fence, &window->swapchain_image_index)); + vkok(vkResetFences(renderer->device, fence_count, &frame->render_fence)); + + VkCommandBufferResetFlags reset_flags = 0; + vkok(vkResetCommandBuffer(frame->command_buffer, reset_flags)); + + window->last_width = window->width; + window->last_height = window->height; + auto window_size = graphics_window_size_get(window->graphics_window); + window->width = window_size.width; + window->height = window_size.height; + + return window_size; +} + +void renderer_window_frame_end(Renderer* renderer, RenderWindow* window) +{ + queue_submit(renderer, window); + + queue_present(renderer, window); + + window->frame_index += 1; +} + +void window_command_begin(RenderWindow* window) +{ + auto* frame = window_frame(window); + VkCommandBufferBeginInfo command_buffer_begin_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, + }; + vkok(vkBeginCommandBuffer(frame->command_buffer, &command_buffer_begin_info)); +} + +void window_command_end(RenderWindow* window) +{ + auto* frame = window_frame(window); + vkok(vkEndCommandBuffer(frame->command_buffer)); +} + +void window_render_begin(RenderWindow* window) +{ + auto* frame = window_frame(window); + vk_image_transition(frame->command_buffer, window->render_image.handle, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + + VkViewport viewports[] = { + { + .x = 0, + .y = 0, + .width = window->width, + .height = window->height, + .minDepth = 0.0f, + .maxDepth = 1.0f, + } + }; + + u32 first_viewport = 0; + vkCmdSetViewport(frame->command_buffer, first_viewport, array_length(viewports), viewports); + + VkRect2D scissors[] = { + { + .offset = { + .x = 0, + .y = 0, + }, + .extent = { + .width = window->width, + .height = window->height, + }, + } + }; + + u32 first_scissor = 0; + vkCmdSetScissor(frame->command_buffer, first_scissor, array_length(scissors), scissors); + + VkRenderingAttachmentInfo color_attachments[] = { + { + .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, + .imageView = window->render_image.view, + .imageLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .clearValue = { .color = { .float32 = { 255.0f, 0.0f, 255.0f, 1.0f } } }, + }, + }; + + VkRenderingInfo rendering_info = { + .sType = VK_STRUCTURE_TYPE_RENDERING_INFO, + .renderArea = { + .extent = { + .width = window->width, + .height = window->height, + }, + }, + .layerCount = 1, + .colorAttachmentCount = array_length(color_attachments), + .pColorAttachments = color_attachments, + }; + + vkCmdBeginRendering(frame->command_buffer, &rendering_info); +} + +void window_render_end(RenderWindow* window) +{ + auto* frame = window_frame(window); + vkCmdEndRendering(frame->command_buffer); + + vk_image_transition(frame->command_buffer, window->render_image.handle, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + + VkImage swapchain_image = window->swapchain_images[window->swapchain_image_index]; + vk_image_transition(frame->command_buffer, swapchain_image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + vk_image_copy(frame->command_buffer, (VulkanCopyImageArgs) { + .source = { + .handle = window->render_image.handle, + .extent = { + .width = window->width, + .height = window->height, + }, + }, + .destination = { + .handle = swapchain_image, + .extent = { + .width = window->width, + .height = window->height, + }, + }, + }); + + vk_image_transition(frame->command_buffer, swapchain_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); +} + +STRUCT(VulkanBuffer) +{ + VkBuffer handle; + VkDeviceMemory gpu_data; + u64 address; + VkDeviceSize size; +}; + +fn VulkanBuffer vk_buffer_create(VkDevice device, const VkAllocationCallbacks* allocation_callbacks, VkPhysicalDeviceMemoryProperties physical_device_memory_properties, VkDeviceSize buffer_size, VkBufferUsageFlags usage_flags, VkMemoryPropertyFlags memory_flags) +{ + VulkanBuffer result = { + .size = buffer_size, + }; + + VkBufferCreateInfo create_info = { + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = 0, + .flags = 0, + .size = buffer_size, + .usage = usage_flags, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = 0, + }; + vkok(vkCreateBuffer(device, &create_info, allocation_callbacks, &result.handle)); + + VkMemoryRequirements memory_requirements; + vkGetBufferMemoryRequirements(device, result.handle, &memory_requirements); + + u8 use_device_address_bit = !!(create_info.usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT); + result.gpu_data = vk_allocate_memory(device, allocation_callbacks, physical_device_memory_properties, memory_requirements, memory_flags, use_device_address_bit); + + VkDeviceSize memory_offset = 0; + vkok(vkBindBufferMemory(device, result.handle, result.gpu_data, memory_offset)); + + u8 map_memory = !!(memory_flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); + assert(((map_memory | use_device_address_bit) == 0) | (map_memory == !use_device_address_bit)); + if (map_memory) + { + void* data = 0; + VkDeviceSize offset = 0; + VkMemoryMapFlags map_flags = 0; + vkok(vkMapMemory(device, result.gpu_data, offset, memory_requirements.size, map_flags, &data)); + result.address = (u64)data; + } + + if (use_device_address_bit) + { + VkBufferDeviceAddressInfo device_address_info = { + .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, + .pNext = 0, + .buffer = result.handle, + }; + result.address = vkGetBufferDeviceAddress(device, &device_address_info); + } + + return result; +} + +#define MAX_TEXTURES (16) +STRUCT(VulkanTexture) +{ + VulkanImage image; + VkSampler sampler; +}; +global_variable VulkanTexture textures[MAX_TEXTURES]; +global_variable u32 texture_count; + +fn VkFormat vk_texture_format(TextureFormat format) +{ + VkFormat result; + switch (format) + { + case R8_UNORM: + result = VK_FORMAT_R8_UNORM; + break; + case R8G8B8A8_SRGB: + result = VK_FORMAT_R8G8B8A8_SRGB; + break; + } + + return result; +} + +fn u32 format_channel_count(TextureFormat format) +{ + switch (format) + { + case R8_UNORM: + return 1; + case R8G8B8A8_SRGB: + return 4; + } +} + +TextureIndex renderer_texture_create(Renderer* renderer, TextureMemory texture_memory) +{ + assert(texture_memory.depth == 1); + + auto texture_index = texture_count; + texture_count += 1; + auto* texture = &textures[texture_index]; + texture->image = vk_image_create(renderer->device, renderer->allocator, renderer->memory_properties, (VulkanImageCreate) { + .width = texture_memory.width, + .height = texture_memory.height, + .mip_levels = 1, + .format = vk_texture_format(texture_memory.format), + .usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, + }); + texture->sampler = renderer->sampler; + + auto image_size = (u64)texture_memory.depth * texture_memory.width * texture_memory.height * format_channel_count(texture_memory.format); + VkBufferUsageFlags buffer_usage_flags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + VkMemoryPropertyFlags buffer_memory_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + auto transfer_buffer = vk_buffer_create(renderer->device, renderer->allocator, renderer->memory_properties, image_size, buffer_usage_flags, buffer_memory_flags); + memcpy((void*)transfer_buffer.address, texture_memory.pointer, image_size); + + immediate_start(renderer->immediate); + + vk_image_transition(renderer->immediate.command_buffer, texture->image.handle, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + VkBufferImageCopy copy_regions[] = { + { + .bufferOffset = 0, + .bufferRowLength = 0, + .bufferImageHeight = 0, + .imageSubresource = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1, + }, + .imageOffset = { + .x = 0, + .y = 0, + .z = 0, + }, + .imageExtent = { + .width = texture_memory.width, + .height = texture_memory.height, + .depth = texture_memory.depth, + }, + } + }; + + vkCmdCopyBufferToImage(renderer->immediate.command_buffer, transfer_buffer.handle, texture->image.handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, array_length(copy_regions), copy_regions); + + vk_image_transition(renderer->immediate.command_buffer, texture->image.handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + immediate_end(renderer->immediate); + + return (TextureIndex) { .value = texture_index }; +} + +PipelineLayoutIndex renderer_pipeline_get_layout(PipelineIndex pipeline) +{ + return pipelines[pipeline.value].layout; +} + +void renderer_update_pipeline_resources(Renderer* renderer, PipelineIndex pipeline_index, Slice(DescriptorSetUpdate) descriptor_updates) +{ + if (descriptor_updates.length > MAX_DESCRIPTOR_SET_UPDATE_COUNT) + { + failed_execution(); + } + + Pipeline* pipeline = &pipelines[pipeline_index.value]; + PipelineLayout* layout = &pipeline_layouts[pipeline->layout.value]; + + VkWriteDescriptorSet write_descriptor_sets[MAX_DESCRIPTOR_SET_UPDATE_COUNT]; + VkDescriptorImageInfo images[MAX_DESCRIPTOR_SET_UPDATE_COUNT][MAX_TEXTURE_UPDATE_COUNT]; + + for (u64 i = 0; i < descriptor_updates.length; i += 1) + { + DescriptorSetUpdate* in_update = &descriptor_updates.pointer[i]; + VkWriteDescriptorSet* out_update = &write_descriptor_sets[i]; + *out_update = (VkWriteDescriptorSet) + { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .pNext = 0, + .dstSet = layout->descriptor_sets[in_update->set.value], + .dstBinding = in_update->binding, + .dstArrayElement = 0, + .descriptorCount = in_update->descriptor_count, + .descriptorType = vulkan_descriptor_type(in_update->type), + .pImageInfo = 0, + .pBufferInfo = 0, + .pTexelBufferView = 0, + }; + + switch (in_update->type) + { + case DESCRIPTOR_TYPE_IMAGE_PLUS_SAMPLER: + { + auto* image_pointer = images[i]; + out_update->pImageInfo = image_pointer; + for (u32 i = 0; i < in_update->descriptor_count; i += 1) + { + VkDescriptorImageInfo* descriptor_image = &image_pointer[i]; + VulkanTexture* texture = &textures[in_update->textures[i].value]; + *descriptor_image = (VkDescriptorImageInfo) { + .sampler = texture->sampler, + .imageView = texture->image.view, + .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // TODO: specify + }; + } + } break; + case DESCRIPTOR_TYPE_COUNT: + unreachable(); + } + } + + u32 descriptor_copy_count = 0; + VkCopyDescriptorSet* descriptor_copies = 0; + vkUpdateDescriptorSets(renderer->device, descriptor_updates.length, write_descriptor_sets, descriptor_copy_count, descriptor_copies); +} + +#define MAX_BUFFER_COUNT (32) +global_variable VulkanBuffer buffers[MAX_BUFFER_COUNT]; +global_variable u32 buffer_count; + +BufferIndex renderer_buffer_create(Renderer* renderer, u64 size, BufferType type) +{ + auto buffer_index = buffer_count; + if (unlikely(buffer_index == MAX_BUFFER_COUNT)) + { + failed_execution(); + } + + u8 is_dst = (type == BUFFER_TYPE_VERTEX) | (type == BUFFER_TYPE_INDEX); + u8 is_src = type == BUFFER_TYPE_STAGING; + + VkBufferUsageFlags usage = + (VK_BUFFER_USAGE_TRANSFER_DST_BIT * is_dst) | + (VK_BUFFER_USAGE_TRANSFER_SRC_BIT * is_src) | + ((VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) * (type == BUFFER_TYPE_VERTEX)) | + (VK_BUFFER_USAGE_INDEX_BUFFER_BIT * (type == BUFFER_TYPE_INDEX)); + VkMemoryPropertyFlags memory_flags = + (VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT * is_dst) | + ((VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) * is_src); + buffers[buffer_index] = vk_buffer_create(renderer->device, renderer->allocator, renderer->memory_properties, size, usage, memory_flags); + buffer_count = buffer_index + 1; + + return (BufferIndex){ .value = buffer_index }; +} + +void renderer_copy_to_host(BufferIndex buffer_index, Slice(HostBufferCopy) regions) +{ + VulkanBuffer* buffer = &buffers[buffer_index.value]; + auto* buffer_pointer = (u8*)buffer->address; + + for (u64 i = 0; i < regions.length; i += 1) + { + auto region = regions.pointer[i]; + memcpy(buffer_pointer + region.destination_offset, region.source.pointer, region.source.length); + } +} + +void renderer_copy_to_local(Renderer* renderer, Slice(LocalBufferCopy) copies) +{ + immediate_start(renderer->immediate); + + for (u64 i = 0; i < copies.length; i += 1) + { + auto copy = copies.pointer[i]; + auto* source_buffer = &buffers[copy.source.value]; + auto* destination_buffer = &buffers[copy.destination.value]; + + VkBufferCopy2 buffer_copies[MAX_LOCAL_BUFFER_COPY_COUNT]; + + for (u64 i = 0; i < copy.regions.length; i += 1) + { + auto copy_region = copy.regions.pointer[i]; + buffer_copies[i] = (VkBufferCopy2) { + .sType = VK_STRUCTURE_TYPE_BUFFER_COPY_2, + .pNext = 0, + .srcOffset = copy_region.source_offset, + .dstOffset = copy_region.destination_offset, + .size = copy_region.size, + }; + } + + VkCopyBufferInfo2 info = { + .sType = VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2, + .pNext = 0, + .srcBuffer = source_buffer->handle, + .dstBuffer = destination_buffer->handle, + .regionCount = copy.regions.length, + .pRegions = buffer_copies, + }; + + vkCmdCopyBuffer2(renderer->immediate.command_buffer, &info); + } + + immediate_end(renderer->immediate); +} + +void window_bind_pipeline(RenderWindow* window, PipelineIndex pipeline_index) +{ + auto* frame = window_frame(window); + auto* pipeline = &pipelines[pipeline_index.value]; + vkCmdBindPipeline(frame->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->handle); +} + +void window_bind_index_buffer(RenderWindow* window, BufferIndex index_buffer, u64 offset, IndexType index_type) +{ + auto* frame = window_frame(window); + auto* buffer = &buffers[index_buffer.value]; + VkIndexType vk_index_type; + switch (index_type) + { + case INDEX_TYPE_U16: + vk_index_type = VK_INDEX_TYPE_UINT16; + break; + case INDEX_TYPE_U32: + vk_index_type = VK_INDEX_TYPE_UINT32; + break; + } + vkCmdBindIndexBuffer(frame->command_buffer, buffer->handle, offset, vk_index_type); +} + +void window_bind_pipeline_descriptor_sets(RenderWindow* window, PipelineIndex pipeline_index) +{ + auto* pipeline = &pipelines[pipeline_index.value]; + auto* pipeline_layout = &pipeline_layouts[pipeline->layout.value]; + auto* frame = window_frame(window); + + u32 dynamic_offset_count = 0; + u32* dynamic_offsets = 0; + u32 first_set = 0; + vkCmdBindDescriptorSets(frame->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout->handle, first_set, pipeline_layout->descriptor_set_count, pipeline_layout->descriptor_sets, dynamic_offset_count, dynamic_offsets); +} + +void window_push_constants(RenderWindow* window, PipelineIndex pipeline_index, SliceP(void) memories) +{ + auto* pipeline = &pipelines[pipeline_index.value]; + auto* pipeline_layout = &pipeline_layouts[pipeline->layout.value]; + auto* frame = window_frame(window); + + if (memories.length != pipeline_layout->push_constant_range_count) + { + failed_execution(); + } + + for (u64 i = 0; i < memories.length; i += 1) + { + auto* memory = memories.pointer[i]; + auto push_constant_range = pipeline_layout->push_constant_ranges[i]; + vkCmdPushConstants(frame->command_buffer, pipeline_layout->handle, push_constant_range.stageFlags, push_constant_range.offset, push_constant_range.size, memory); + } +} + +u64 buffer_address(BufferIndex buffer_index) +{ + auto* buffer = &buffers[buffer_index.value]; + return buffer->address; +} + +void window_draw_indexed(RenderWindow* window, u32 index_count, u32 instance_count, u32 first_index, s32 vertex_offset, u32 first_instance) +{ + auto* frame = window_frame(window); + vkCmdDrawIndexed(frame->command_buffer, index_count, instance_count, first_index, vertex_offset, first_instance); +} diff --git a/bootstrap/bloat-buster/shader_compilation.c b/bootstrap/std/shader_compilation.c similarity index 98% rename from bootstrap/bloat-buster/shader_compilation.c rename to bootstrap/std/shader_compilation.c index 8924e83..fb3b576 100644 --- a/bootstrap/bloat-buster/shader_compilation.c +++ b/bootstrap/std/shader_compilation.c @@ -1,4 +1,4 @@ -#include +#include #include