#include #include #include #include #include #include #include #include #include #include "gfx_rendering_api.h" #include "gfx_pc.h" #include "gfx_window_manager_api.h" static VkInstance instance = VK_NULL_HANDLE; static VkPhysicalDevice physical_device = VK_NULL_HANDLE; static VkDevice device = VK_NULL_HANDLE; static VkQueue graphics_queue = VK_NULL_HANDLE; static VkQueue present_queue = VK_NULL_HANDLE; static VkCommandPool command_pool = VK_NULL_HANDLE; static VkSwapchainKHR swapchain = VK_NULL_HANDLE; static VkFormat surface_format; static std::vector swapchain_images; static std::vector swapchain_views; static VkRenderPass render_pass = VK_NULL_HANDLE; static VkImage depth_image = VK_NULL_HANDLE; static VkDeviceMemory depth_memory = VK_NULL_HANDLE; static VkImageView depth_view = VK_NULL_HANDLE; static std::vector swapchain_framebuffers; // TODO: removed hardcoded 3 frame queue, should be variable static std::array command_buffers; static std::array image_available; static std::array render_finished; static std::array in_flight; static uint32_t current_frame = 0; static uint32_t image_index = 0; static VkCommandBuffer current_cmd = VK_NULL_HANDLE; static VkPipeline pipeline = VK_NULL_HANDLE; static VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; VKAPI_ATTR VkBool32 VKAPI_CALL gfx_vulkan_debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) { printf("%s\n", pCallbackData->pMessage); return VK_FALSE; } static bool gfx_vulkan_renderer_z_is_from_0_to_1(void) { return false; } static VkShaderModule gfx_vulkan_create_shader_module(const uint32_t* code, const int length) { VkShaderModuleCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; create_info.codeSize = length; create_info.pCode = reinterpret_cast(code); VkShaderModule shader_module; vkCreateShaderModule(device, &create_info, nullptr, &shader_module); return shader_module; } // TODO: will be removed, just used for testing static VkShaderModule gfx_vulkan_load_shader(const char* path) { std::ifstream file(path, std::ios::ate | std::ios::binary); size_t fileSize = (size_t) file.tellg(); std::vector buffer(fileSize); file.seekg(0); file.read(buffer.data(), fileSize); return gfx_vulkan_create_shader_module(reinterpret_cast(buffer.data()), fileSize); } // TODO: currently no-op for testing triangle draw static void gfx_vulkan_create_pipeline() { VkPipelineShaderStageCreateInfo vertex_stage = {}; vertex_stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; vertex_stage.stage = VK_SHADER_STAGE_VERTEX_BIT; vertex_stage.module = gfx_vulkan_load_shader("vert.spv"); vertex_stage.pName = "main"; VkPipelineShaderStageCreateInfo fragment_stage = {}; fragment_stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; fragment_stage.stage = VK_SHADER_STAGE_FRAGMENT_BIT; fragment_stage.module = gfx_vulkan_load_shader("frag.spv"); fragment_stage.pName = "main"; std::array shader_stages = { vertex_stage, fragment_stage }; VkVertexInputBindingDescription binding = {}; binding.stride = sizeof(float) * 3; VkVertexInputAttributeDescription position_attribute = {}; position_attribute.format = VK_FORMAT_R32G32B32_SFLOAT; position_attribute.format = VK_FORMAT_R32G32B32_SFLOAT; const std::array attributes = { position_attribute }; VkPipelineVertexInputStateCreateInfo vertex_input_state = {}; vertex_input_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; vertex_input_state.vertexBindingDescriptionCount = 1; vertex_input_state.pVertexBindingDescriptions = &binding; vertex_input_state.vertexAttributeDescriptionCount = attributes.size(); vertex_input_state.pVertexAttributeDescriptions = attributes.data(); VkPipelineInputAssemblyStateCreateInfo input_assembly = {}; input_assembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; VkViewport viewport = {}; viewport.width = 640; viewport.height = 480; viewport.maxDepth = 1.0f; VkRect2D scissor = {}; scissor.extent.width = 640; scissor.extent.height = 480; VkPipelineViewportStateCreateInfo viewport_state = {}; viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; viewport_state.viewportCount = 1; viewport_state.pViewports = &viewport; viewport_state.scissorCount = 1; viewport_state.pScissors = &scissor; VkPipelineRasterizationStateCreateInfo rasterizer = {}; rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; rasterizer.lineWidth = 1.0f; rasterizer.cullMode = VK_CULL_MODE_BACK_BIT; rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; VkPipelineMultisampleStateCreateInfo multisampling = {}; multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; VkPipelineColorBlendAttachmentState color_blend_attachment = {}; color_blend_attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; VkPipelineColorBlendStateCreateInfo color_blending = {}; color_blending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; color_blending.attachmentCount = 1; color_blending.pAttachments = &color_blend_attachment; VkPipelineDynamicStateCreateInfo dynamic_state = {}; dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; VkPipelineLayoutCreateInfo pipeline_layout_create_info = {}; pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; vkCreatePipelineLayout(device, &pipeline_layout_create_info, nullptr, &pipeline_layout); VkPipelineDepthStencilStateCreateInfo depth_stencil = {}; depth_stencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; depth_stencil.depthTestEnable = VK_TRUE; depth_stencil.depthWriteEnable = VK_TRUE; depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS; depth_stencil.maxDepthBounds = 1.0f; VkGraphicsPipelineCreateInfo pipeline_create_info = {}; pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; pipeline_create_info.stageCount = shader_stages.size(); pipeline_create_info.pStages = shader_stages.data(); pipeline_create_info.pVertexInputState = &vertex_input_state; pipeline_create_info.pInputAssemblyState = &input_assembly; pipeline_create_info.pViewportState = &viewport_state; pipeline_create_info.pRasterizationState = &rasterizer; pipeline_create_info.pMultisampleState = &multisampling; pipeline_create_info.pColorBlendState = &color_blending; pipeline_create_info.pDynamicState = &dynamic_state; pipeline_create_info.pDepthStencilState = &depth_stencil; pipeline_create_info.layout = pipeline_layout; pipeline_create_info.renderPass = render_pass; vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipeline_create_info, nullptr, &pipeline); } static struct ShaderProgram *gfx_vulkan_renderer_create_and_load_new_shader(uint32_t shader_id) { gfx_vulkan_create_pipeline(); return NULL; } static struct ShaderProgram *gfx_vulkan_renderer_lookup_shader(uint32_t shader_id) { return NULL; } static void gfx_vulkan_renderer_shader_get_info(struct ShaderProgram *prg, uint8_t *num_inputs, bool used_textures[2]) { *num_inputs = 0; used_textures[0] = false; used_textures[1] = false; } static uint32_t gfx_vulkan_renderer_new_texture(void) { return 0; } static uint32_t gfx_vulkan_find_memory_type(uint32_t type_filter, VkMemoryPropertyFlags properties) { VkPhysicalDeviceMemoryProperties memory_properties; vkGetPhysicalDeviceMemoryProperties(physical_device, &memory_properties); for (uint32_t i = 0; i < memory_properties.memoryTypeCount; i++) { if ((type_filter & (1 << i)) && (memory_properties.memoryTypes[i].propertyFlags & properties) == properties) { return i; } } return -1; } static void gfx_vulkan_create_instance() { std::vector instance_extensions = {"VK_EXT_debug_utils"}; uint32_t extension_count = 0; vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr); std::vector extensions(extension_count); vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, extensions.data()); for(auto& extension : extensions) { if (strstr(extension.extensionName, "surface") != nullptr) { instance_extensions.push_back(extension.extensionName); } if (strstr(extension.extensionName, "VK_KHR_get_physical_device_properties2") != nullptr) { instance_extensions.push_back(extension.extensionName); } } VkDebugUtilsMessengerCreateInfoEXT debug_create_info = {}; debug_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; debug_create_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; debug_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; debug_create_info.pfnUserCallback = gfx_vulkan_debug_callback; VkInstanceCreateInfo create_info = {}; create_info.pNext = &debug_create_info; create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; create_info.ppEnabledExtensionNames = instance_extensions.data(); create_info.enabledExtensionCount = instance_extensions.size(); vkCreateInstance(&create_info, nullptr, &instance); printf("Created vulkan instance!\n"); } static void gfx_vulkan_create_command_pool(const int graphics_family_index) { VkCommandPoolCreateInfo pool_create_info = {}; pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; pool_create_info.queueFamilyIndex = graphics_family_index; pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; vkCreateCommandPool(device, &pool_create_info, nullptr, &command_pool); } static void gfx_vulkan_create_device() { // pick physical device uint32_t device_count = 0; vkEnumeratePhysicalDevices(instance, &device_count, nullptr); std::vector devices(device_count); vkEnumeratePhysicalDevices(instance, &device_count, devices.data()); for (auto device : devices) { VkPhysicalDeviceProperties device_properties; vkGetPhysicalDeviceProperties(device, &device_properties); printf("GPU Found: %s\n", device_properties.deviceName); } physical_device = devices[0]; uint32_t extension_count = 0; vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &extension_count, nullptr); std::vector extension_properties(extension_count); vkEnumerateDeviceExtensionProperties( physical_device, nullptr, &extension_count, extension_properties.data()); uint32_t graphics_family_index = 0, present_family_index = 0; // create logical device uint32_t queue_family_count = 0; vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, nullptr); std::vector queueFamilies(queue_family_count); vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, queueFamilies.data()); int i = 0; for (const auto&queue_family : queueFamilies) { if (queue_family.queueCount > 0 && queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) { graphics_family_index = i; } i++; } std::vector queue_create_infos; if (graphics_family_index == present_family_index) { VkDeviceQueueCreateInfo queue_create_info = {}; queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queue_create_info.queueFamilyIndex = graphics_family_index; queue_create_info.queueCount = 1; float queuePriority = 1.0f; queue_create_info.pQueuePriorities = &queuePriority; queue_create_infos.push_back(queue_create_info); } else { // graphics { VkDeviceQueueCreateInfo queue_create_info = {}; queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queue_create_info.queueFamilyIndex = graphics_family_index; queue_create_info.queueCount = 1; float queuePriority = 1.0f; queue_create_info.pQueuePriorities = &queuePriority; queue_create_infos.push_back(queue_create_info); } // present { VkDeviceQueueCreateInfo queue_create_info = {}; queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queue_create_info.queueFamilyIndex = present_family_index; queue_create_info.queueCount = 1; float queuePriority = 1.0f; queue_create_info.pQueuePriorities = &queuePriority; queue_create_infos.push_back(queue_create_info); } } std::array device_extensions = {"VK_KHR_swapchain"}; VkDeviceCreateInfo device_create_info = {}; device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; device_create_info.pQueueCreateInfos = queue_create_infos.data(); device_create_info.queueCreateInfoCount = static_cast(queue_create_infos.size()); device_create_info.ppEnabledExtensionNames = device_extensions.data(); device_create_info.enabledExtensionCount = device_extensions.size(); vkCreateDevice(physical_device, &device_create_info, nullptr, &device); printf("Created vulkan device!\n"); vkGetDeviceQueue(device, graphics_family_index, 0, &graphics_queue); vkGetDeviceQueue(device, present_family_index, 0, &present_queue); gfx_vulkan_create_command_pool(graphics_family_index); } static void gfx_vulkan_create_swapchain() { vkQueueWaitIdle(present_queue); // create surface from wapi VkSurfaceKHR surface = static_cast(gfx_get_current_windowing_api()->create_surface(instance)); VkBool32 supported; vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, 0, surface, &supported); // query swapchain support VkSurfaceCapabilitiesKHR capabilities; vkGetPhysicalDeviceSurfaceCapabilitiesKHR( physical_device, surface, &capabilities); std::vector formats; uint32_t format_count; vkGetPhysicalDeviceSurfaceFormatsKHR( physical_device, surface, &format_count, nullptr); formats.resize(format_count); vkGetPhysicalDeviceSurfaceFormatsKHR( physical_device, surface, &format_count, formats.data()); std::vector present_modes; uint32_t present_mode_count; vkGetPhysicalDeviceSurfacePresentModesKHR( physical_device, surface, &present_mode_count, nullptr); present_modes.resize(present_mode_count); vkGetPhysicalDeviceSurfacePresentModesKHR( physical_device, surface, &present_mode_count, present_modes.data()); // choosing swapchain features surface_format = formats[0].format; for (const auto& available_format : formats) { if (available_format.format == VK_FORMAT_B8G8R8A8_UNORM && available_format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { surface_format = available_format.format; } } VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR; for (const auto& available_mode : present_modes) { if (available_mode == VK_PRESENT_MODE_MAILBOX_KHR) { present_mode = available_mode; } } uint32_t image_count = capabilities.minImageCount + 1; if (capabilities.maxImageCount > 0 && image_count > capabilities.maxImageCount) { image_count = capabilities.maxImageCount; } // create swapchain VkSwapchainCreateInfoKHR swapchain_create_info = {}; swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapchain_create_info.surface = surface; swapchain_create_info.minImageCount = image_count; swapchain_create_info.imageFormat = surface_format; swapchain_create_info.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; // FIXME: hardcoded swapchain_create_info.imageExtent.width = 640; // FIXME: hardcoded swapchain_create_info.imageExtent.height = 480; swapchain_create_info.imageArrayLayers = 1; swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swapchain_create_info.preTransform = capabilities.currentTransform; swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; swapchain_create_info.presentMode = present_mode; swapchain_create_info.clipped = VK_TRUE; VkSwapchainKHR old_swapchain = swapchain; swapchain_create_info.oldSwapchain = old_swapchain; vkCreateSwapchainKHR(device, &swapchain_create_info, nullptr, &swapchain); if(old_swapchain != VK_NULL_HANDLE) { vkDestroySwapchainKHR(device, old_swapchain, nullptr); } vkGetSwapchainImagesKHR(device, swapchain, &image_count, nullptr); swapchain_images.resize(image_count); vkGetSwapchainImagesKHR(device, swapchain, &image_count, swapchain_images.data()); swapchain_views.resize(swapchain_images.size()); for (size_t i = 0; i < swapchain_images.size(); i++) { VkImageViewCreateInfo view_create_info = {}; view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; view_create_info.image = swapchain_images[i]; view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; view_create_info.format = surface_format; view_create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; view_create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; view_create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; view_create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; view_create_info.subresourceRange.baseMipLevel = 0; view_create_info.subresourceRange.levelCount = 1; view_create_info.subresourceRange.baseArrayLayer = 0; view_create_info.subresourceRange.layerCount = 1; vkCreateImageView(device, &view_create_info, nullptr,&swapchain_views[i]); } printf("Initialized swap chain!\n"); } static void gfx_vulkan_create_render_pass() { VkAttachmentDescription color_attachment = {}; color_attachment.format = surface_format; color_attachment.samples = VK_SAMPLE_COUNT_1_BIT; color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; color_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; VkAttachmentReference color_attachment_ref = {}; color_attachment_ref.attachment = 0; color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; VkAttachmentDescription depth_attachment = {}; depth_attachment.format = VK_FORMAT_D32_SFLOAT; depth_attachment.samples = VK_SAMPLE_COUNT_1_BIT; depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; depth_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; depth_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; depth_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; depth_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; depth_attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; VkAttachmentReference depth_attachment_ref = {}; depth_attachment_ref.attachment = 1; depth_attachment_ref.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; VkSubpassDependency dependency = {}; dependency.srcSubpass = VK_SUBPASS_EXTERNAL; dependency.dstSubpass = 0; dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; dependency.srcAccessMask = 0; dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; dependency.dependencyFlags = 0; VkSubpassDescription subpass = {}; subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass.colorAttachmentCount = 1; subpass.pColorAttachments = &color_attachment_ref; subpass.pDepthStencilAttachment = &depth_attachment_ref; std::array attachments = { color_attachment, depth_attachment }; VkRenderPassCreateInfo render_pass_create_info = {}; render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; render_pass_create_info.attachmentCount = attachments.size(); render_pass_create_info.pAttachments = attachments.data(); render_pass_create_info.subpassCount = 1; render_pass_create_info.pSubpasses = &subpass; render_pass_create_info.dependencyCount = 1; render_pass_create_info.pDependencies = &dependency; vkCreateRenderPass(device, &render_pass_create_info, nullptr, &render_pass); } static void gfx_vulkan_create_sync() { for(int i = 0; i < 3; i++) { VkCommandBufferAllocateInfo allocate_info = {}; allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocate_info.commandPool = command_pool; allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; allocate_info.commandBufferCount = 1; vkAllocateCommandBuffers(device, &allocate_info, &command_buffers[i]); } VkSemaphoreCreateInfo semaphore_create_info = {}; semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; VkFenceCreateInfo fence_create_info = {}; fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fence_create_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; for (size_t i = 0; i < 3; i++) { vkCreateSemaphore(device, &semaphore_create_info, nullptr, &image_available[i]); vkCreateSemaphore(device, &semaphore_create_info, nullptr, &render_finished[i]); vkCreateFence(device, &fence_create_info, nullptr, &in_flight[i]); } } static void gfx_vulkan_create_depth() { VkImageCreateInfo image_create_info = {}; image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image_create_info.imageType = VK_IMAGE_TYPE_2D; image_create_info.extent.width = 640; image_create_info.extent.height = 480; image_create_info.extent.depth = 1; image_create_info.mipLevels = 1; image_create_info.arrayLayers = 1; image_create_info.format = VK_FORMAT_D32_SFLOAT; image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; image_create_info.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; vkCreateImage(device, &image_create_info, nullptr, &depth_image); VkMemoryRequirements memory_requirements; vkGetImageMemoryRequirements(device, depth_image, &memory_requirements); VkMemoryAllocateInfo allocate_info = {}; allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocate_info.allocationSize = memory_requirements.size; allocate_info.memoryTypeIndex = gfx_vulkan_find_memory_type(memory_requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); vkAllocateMemory(device, &allocate_info, nullptr, &depth_memory); vkBindImageMemory(device, depth_image, depth_memory, 0); VkImageViewCreateInfo view_create_info = {}; view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; view_create_info.image = depth_image; view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; view_create_info.format = VK_FORMAT_D32_SFLOAT; view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; view_create_info.subresourceRange.levelCount = 1; view_create_info.subresourceRange.layerCount = 1; vkCreateImageView(device, &view_create_info, nullptr, &depth_view); } static void gfx_vulkan_create_framebuffers() { swapchain_framebuffers.resize(swapchain_views.size()); for (size_t i = 0; i < swapchain_framebuffers.size(); i++) { std::array attachments = {swapchain_views[i], depth_view}; VkFramebufferCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; create_info.renderPass = render_pass; create_info.attachmentCount = attachments.size(); create_info.pAttachments = attachments.data(); create_info.width = 640; create_info.height = 480; create_info.layers = 1; vkCreateFramebuffer(device, &create_info, nullptr, &swapchain_framebuffers[i]); } } static void gfx_vulkan_renderer_init(void) { gfx_vulkan_create_instance(); gfx_vulkan_create_device(); gfx_vulkan_create_swapchain(); gfx_vulkan_create_render_pass(); gfx_vulkan_create_sync(); gfx_vulkan_create_depth(); gfx_vulkan_create_framebuffers(); } static void gfx_vulkan_renderer_on_resize(void) { // doesn't seem to be called? } static void gfx_vulkan_renderer_start_frame(void) { vkWaitForFences( device, 1, &in_flight[current_frame], VK_TRUE, std::numeric_limits::max()); image_index = 0; VkResult result = vkAcquireNextImageKHR( device, swapchain, std::numeric_limits::max(), image_available[current_frame], VK_NULL_HANDLE, &image_index); if (result == VK_ERROR_OUT_OF_DATE_KHR) { printf("Swapchain is out of date!\n"); return; } current_cmd = command_buffers[current_frame]; VkCommandBufferBeginInfo buffer_begin = {}; buffer_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; buffer_begin.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; vkBeginCommandBuffer(current_cmd, &buffer_begin); VkRenderPassBeginInfo render_pass_begin = {}; render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; render_pass_begin.renderPass = render_pass; render_pass_begin.framebuffer = swapchain_framebuffers[image_index]; std::array clear_values = {}; clear_values[0].color.float32[0] = 0.8; clear_values[0].color.float32[1] = 0.8; clear_values[0].color.float32[2] = 0.8; clear_values[0].color.float32[3] = 1.0; clear_values[1].depthStencil = {1.0f, 0}; render_pass_begin.clearValueCount = clear_values.size(); render_pass_begin.pClearValues = clear_values.data(); render_pass_begin.renderArea.extent.width = 640; render_pass_begin.renderArea.extent.height = 480; vkCmdBeginRenderPass(current_cmd, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE); } /* draw commands */ static void gfx_vulkan_renderer_select_texture(int tile, uint32_t texture_id) { } static void gfx_vulkan_renderer_upload_texture(const uint8_t *rgba32_buf, int width, int height) { } static void gfx_vulkan_renderer_set_sampler_parameters(int tile, bool linear_filter, uint32_t cms, uint32_t cmt) { } static void gfx_vulkan_renderer_set_depth_test(bool depth_test) { } static void gfx_vulkan_renderer_set_depth_mask(bool z_upd) { } static void gfx_vulkan_renderer_set_zmode_decal(bool zmode_decal) { } static void gfx_vulkan_renderer_set_viewport(int x, int y, int width, int height) { } static void gfx_vulkan_renderer_set_scissor(int x, int y, int width, int height) { } static void gfx_vulkan_renderer_set_use_alpha(bool use_alpha) { } static void gfx_vulkan_renderer_unload_shader(struct ShaderProgram *old_prg) { } static void gfx_vulkan_renderer_load_shader(struct ShaderProgram *new_prg) { } static void gfx_vulkan_renderer_draw_triangles(float buf_vbo[], size_t buf_vbo_len, size_t buf_vbo_num_tris) { // FIXME: uh no vkCmdBindPipeline(current_cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); vkCmdDraw(current_cmd, buf_vbo_num_tris, 1, 0, 0); } /* end draw commands */ static void gfx_vulkan_renderer_end_frame(void) { vkCmdEndRenderPass(current_cmd); vkEndCommandBuffer(current_cmd); } static void gfx_vulkan_renderer_finish_render(void) { VkSubmitInfo submit_info = {}; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; VkSemaphore wait_semaphores[] = {image_available[current_frame]}; VkPipelineStageFlags wait_stages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; submit_info.waitSemaphoreCount = 1; submit_info.pWaitSemaphores = wait_semaphores; submit_info.pWaitDstStageMask = wait_stages; submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = ¤t_cmd; VkSemaphore signal_semaphores[] = {render_finished[current_frame]}; submit_info.signalSemaphoreCount = 1; submit_info.pSignalSemaphores = signal_semaphores; vkResetFences(device, 1, &in_flight[current_frame]); if (vkQueueSubmit(graphics_queue, 1, &submit_info, in_flight[current_frame]) != VK_SUCCESS) { return; } // present VkPresentInfoKHR present_info = {}; present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; present_info.waitSemaphoreCount = 1; present_info.pWaitSemaphores = signal_semaphores; VkSwapchainKHR swapChains[] = {swapchain}; present_info.swapchainCount = 1; present_info.pSwapchains = swapChains; present_info.pImageIndices = &image_index; vkQueuePresentKHR(present_queue, &present_info); current_frame = (current_frame + 1) % 3; } static const char* gfx_vulkan_get_name() { return "Vulkan"; } struct GfxRenderingAPI gfx_vulkan_api = { gfx_vulkan_renderer_z_is_from_0_to_1, gfx_vulkan_renderer_unload_shader, gfx_vulkan_renderer_load_shader, gfx_vulkan_renderer_create_and_load_new_shader, gfx_vulkan_renderer_lookup_shader, gfx_vulkan_renderer_shader_get_info, gfx_vulkan_renderer_new_texture, gfx_vulkan_renderer_select_texture, gfx_vulkan_renderer_upload_texture, gfx_vulkan_renderer_set_sampler_parameters, gfx_vulkan_renderer_set_depth_test, gfx_vulkan_renderer_set_depth_mask, gfx_vulkan_renderer_set_zmode_decal, gfx_vulkan_renderer_set_viewport, gfx_vulkan_renderer_set_scissor, gfx_vulkan_renderer_set_use_alpha, gfx_vulkan_renderer_draw_triangles, gfx_vulkan_renderer_init, gfx_vulkan_renderer_on_resize, gfx_vulkan_renderer_start_frame, gfx_vulkan_renderer_end_frame, gfx_vulkan_renderer_finish_render, gfx_vulkan_get_name, };